与游戏世界交互——Hit UFO
目录
- Hit UFO
- 一、游戏规则
- 二、gitee
- 三、程序实现
- 3.1 SSDirector.cs
- 3.2 SSAction.cs
- 3.3 SSActionManager.cs
- 3.4 SequenceAction.cs
- 3.5 Interface.cs
- 3.6 Singleton.cs
- 3.7 UFOFlyAction.cs
- 3.8 DiskFactory.cs
- 3.9 FirstController.cs
- 3.10 ScoreRecorder
- 3.11 UserGUI
- 四、效果展示
- 五、编写一个简单的自定义 Component
Hit UFO
一、游戏规则
- 点击飞碟来摧毁它
- 当飞碟飞出屏幕时,损失生命值,生命值归零时游戏结束
- 摧毁飞碟会获得点数,随着点数的升高,游戏难度加大
- 可以通过Easy,Normal,Hard选项手动调节基础游戏难度(也就是倍速)
- 通过Pause暂停游戏;
- 通过Start,Restart按钮开始和重置游戏
二、gitee
gitee
三、程序实现
本次作业中,还是采用了前几次作业的UML架构,所以顶层文件结构基本没有变化;
3.1 SSDirector.cs
和前几次的基本相同,作为导演类来监视游戏的运行,由于只有一个界面,所以其实连页面转换的作用也莫得,代码和之前一样;
public class SSDirector : System.Object
{private static SSDirector _instance; public ISceneController CurrentScenceController { get; set; }public static SSDirector GetInstance(){if (_instance == null){_instance = new SSDirector();}return _instance;}
}
3.2 SSAction.cs
动作基类
public class SSAction : ScriptableObject
{public bool enable = true; public bool destroy = false; public GameObject gameobject; public Transform transform; public ISSActionCallback callback; public virtual void Start(){throw new System.NotImplementedException();}public virtual void Update(){throw new System.NotImplementedException();}
}
3.3 SSActionManager.cs
动作管理类:实现动作的加入,调用,销毁
public class SSActionManager : MonoBehaviour, ISSActionCallback
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); private List<SSAction> waitingAdd = new List<SSAction>(); private List<int> waitingDelete = new List<int>(); protected void Update(){foreach (SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac; }waitingAdd.Clear();foreach (KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if (ac.destroy) {waitingDelete.Add(ac.GetInstanceID());}else if (ac.enable){ac.Update();}}foreach (int key in waitingDelete){SSAction ac = actions[key];actions.Remove(key);Destroy(ac);}waitingDelete.Clear();}public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager){action.gameobject = gameobject;action.transform = gameobject.transform;action.callback = manager;waitingAdd.Add(action);action.Start();}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){}
}
3.4 SequenceAction.cs
实现动作的排队执行(见上一次作业的动作分离)
public class SequenceAction : SSAction, ISSActionCallback
{public List<SSAction> sequence; public int repeat = -1; public int start = 0; public override void Update(){if (sequence.Count == 0) return;if (start < sequence.Count && Time.timeScale != 0){sequence[start].Update(); }}public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null){source.destroy = false; this.start++;if (this.start >= sequence.Count){this.start = 0;if (repeat > 0) repeat--;if (repeat == 0){this.destroy = true;this.callback.SSActionEvent(this); }}}public override void Start(){foreach (SSAction action in sequence){action.gameobject = this.gameobject;action.transform = this.transform;action.callback = this; action.Start();}}}
3.5 Interface.cs
程序接口,包括场景接口,用户行为接口,动作管理接口
public interface ISceneController
{void LoadResources();
}public interface IUserAction
{void Hit(Vector3 pos);int GetScore();void GameOver();void ReStart();void BeginGame();
}
public enum SSActionEventType : int { Started, Competeted }
public interface ISSActionCallback
{void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,int intParam = 0, string strParam = null, Object objectParam = null);
}
3.6 Singleton.cs
实现工厂的场景单实例,使用课件上的代码实现
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{protected static T instance;public static T Instance{get{if (instance == null){instance = (T)FindObjectOfType(typeof(T));if (instance == null){Debug.LogError("An instance of " + typeof(T)+ " is needed in the scene, but there is none.");}}return instance;}}
}
3.7 UFOFlyAction.cs
实现飞碟的飞行
- 实现飞碟的类抛物线运行方式;
- 调用update来实现飞碟的实际运动
public override void Update(){Debug.Log("UPdate, time.scale = "+ Time.timeScale);if (Time.timeScale == 0) return;time += Time.fixedDeltaTime;gravity_vector.y = gravity * time;transform.position += (start_vector + gravity_vector) * Time.fixedDeltaTime;current_angle.z = Mathf.Atan((start_vector.y + gravity_vector.y) / start_vector.x) * Mathf.Rad2Deg;transform.eulerAngles = current_angle;if (this.transform.position.y < -10){this.destroy = true;this.callback.SSActionEvent(this);}}
3.8 DiskFactory.cs
工厂类:用于在需要飞碟时,实例化新的飞碟,并在使用完成时,将对应的disk收回
public GameObject GetDisk(int round){int choice = 0;int scope1 = 1, scope2 = 4, scope3 = 7; float start_y = -10f; string tag;disk_prefab = null;if (round == 1){choice = Random.Range(0, scope1);}else if(round == 2){choice = Random.Range(0, scope2);}else{choice = Random.Range(0, scope3);}if(choice <= scope1){tag = "disk1";}else if(choice <= scope2 && choice > scope1){tag = "disk2";}else{tag = "disk3";}for(int i=0;i<free.Count;i++){if(free[i].tag == tag){disk_prefab = free[i].gameObject;free.Remove(free[i]);break;}}if(disk_prefab == null){if (tag == "disk1"){disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk1"), new Vector3(0, start_y, 0), Quaternion.identity);disk_prefab.GetComponent<Renderer>().material.color = Color.green;}else if (tag == "disk2"){disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk2"), new Vector3(0, start_y, 0), Quaternion.identity);disk_prefab.GetComponent<Renderer>().material.color = Color.blue;}else{disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk3"), new Vector3(0, start_y, 0), Quaternion.identity);disk_prefab.GetComponent<Renderer>().material.color = Color.red;}float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;disk_prefab.GetComponent<DiskData>().direction = new Vector3(ran_x, start_y, 0);disk_prefab.transform.localScale = disk_prefab.GetComponent<DiskData>().scale;}used.Add(disk_prefab.GetComponent<DiskData>());return disk_prefab;}public void FreeDisk(GameObject disk){for(int i = 0;i < used.Count; i++){if (disk.GetInstanceID() == used[i].gameObject.GetInstanceID()){used[i].gameObject.SetActive(false);free.Add(used[i]);used.Remove(used[i]);break;}}}
3.9 FirstController.cs
主控制器,挂载在GameObject上进行初始化,进行资源的加载以及游戏用户行动函数的实现;
- 首先还是和之前的相似,在start加载初始元素
void Start (){SSDirector director = SSDirector.GetInstance(); director.CurrentScenceController = this; disk_factory = Singleton<DiskFactory>.Instance;score_recorder = Singleton<ScoreRecorder>.Instance;action_manager = gameObject.AddComponent<FlyActionManager>() as FlyActionManager;user_gui = gameObject.AddComponent<UserGUI>() as UserGUI;}
- 之后再update中根据是否点击了开始,来选择加载开始界面或者是游戏界面
void Update (){if(game_start){if (game_over){CancelInvoke("LoadResources");}if (!playing_game){InvokeRepeating("LoadResources", 1f, speed);playing_game = true;}SendDisk();if (score_recorder.score >= score_round2 && round == 1){round = 2;speed = speed - 0.6f;CancelInvoke("LoadResources");playing_game = false;}else if (score_recorder.score >= score_round3 && round == 2){round = 3;speed = speed - 0.5f;CancelInvoke("LoadResources");playing_game = false;}}}
- sendDisk函数用于随机发射飞碟:
private void SendDisk(){float position_x = 16; if (disk_queue.Count != 0){GameObject disk = disk_queue.Dequeue();disk_notshot.Add(disk);disk.SetActive(true);float ran_y = Random.Range(1f, 4f);float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;disk.GetComponent<DiskData>().direction = new Vector3(ran_x, ran_y, 0);Vector3 position = new Vector3(-disk.GetComponent<DiskData>().direction.x * position_x, ran_y, 0);disk.transform.position = position;float power = Random.Range(10f, 15f);float angle = Random.Range(15f, 28f);action_manager.UFOFly(disk,angle,power);}for (int i = 0; i < disk_notshot.Count; i++){GameObject temp = disk_notshot[i];if (temp.transform.position.y < -10 && temp.gameObject.activeSelf == true){disk_factory.FreeDisk(disk_notshot[i]);disk_notshot.Remove(disk_notshot[i]);user_gui.ReduceBlood();}}}
- Hit使用Ray射线来进行击中飞碟的判断
public void Hit(Vector3 pos){Ray ray = Camera.main.ScreenPointToRay(pos);RaycastHit[] hits;hits = Physics.RaycastAll(ray);bool not_hit = false;for (int i = 0; i < hits.Length; i++){RaycastHit hit = hits[i];if (hit.collider.gameObject.GetComponent<DiskData>() != null){for (int j = 0; j < disk_notshot.Count; j++){if (hit.collider.gameObject.GetInstanceID() == disk_notshot[j].gameObject.GetInstanceID()){not_hit = true;}}if(!not_hit){return;}disk_notshot.Remove(hit.collider.gameObject);score_recorder.Record(hit.collider.gameObject);StartCoroutine(WaitingParticle(0.08f, hit, disk_factory, hit.collider.gameObject));break;}}}
3.10 ScoreRecorder
用于记录得分情况
public class ScoreRecorder : MonoBehaviour
{public int score; //分数void Start (){score = 0;}public void Record(GameObject disk){int temp = disk.GetComponent<DiskData>().score;score = temp + score;}
}
3.11 UserGUI
实现提示语和积分的记录,以及暂停和难度选择等按钮
void OnGUI (){bold_style.normal.textColor = new Color(1, 0, 0);bold_style.fontSize = 16;text_style.normal.textColor = new Color(0,0,0, 1);text_style.fontSize = 16;score_style.normal.textColor = new Color(1,0,1,1);score_style.fontSize = 16;over_style.normal.textColor = new Color(1, 0, 0);over_style.fontSize = 25;if (game_start){Debug.Log("Time scale:" + Time.timeScale);//用户射击if (Input.GetButtonDown("Fire1")){Vector3 pos = Input.mousePosition;action.Hit(pos);}GUI.Label(new Rect(10, 5, 200, 50), "分数:" + action.GetScore().ToString(), text_style);if (action.GetScore() < 10){GUI.Label(new Rect(10, 55, 200, 50), "Round: 1" , text_style);}else if (action.GetScore() >= 10 && action.GetScore() <20){GUI.Label(new Rect(10, 55, 200, 50), "Round: 2", text_style);}else{GUI.Label(new Rect(10, 55, 200, 50), "Round: 3", text_style);}if (GUI.Button(new Rect(Screen.width / 2 - 100, 20, 50, 50), "Pause")){Time.timeScale = 0;}if (GUI.Button(new Rect(Screen.width / 2 - 30 , 20, 50, 50), "Easy")){Time.timeScale = 0.5f;}if (GUI.Button(new Rect(Screen.width / 2 + 40, 20, 50, 50), "Normal")){Time.timeScale = 1;}if (GUI.Button(new Rect(Screen.width / 2 + 100, 20, 50, 50), "Hard")){Time.timeScale = 2;}GUI.Label(new Rect(Screen.width - 120, 5, 50, 50), "生命:" + life, text_style);//游戏结束if (life == 0){high_score = high_score > action.GetScore() ? high_score : action.GetScore();GUI.Label(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 250, 100, 100), "Game Over", over_style);GUI.Label(new Rect(Screen.width / 2 - 10, Screen.width / 2 - 200, 50, 50), "Rank:"+ action.GetScore(), text_style);//GUI.Label(new Rect(Screen.width / 2 + 50, Screen.width / 2 - 200, 50, 50), high_score.ToString(), text_style);if (GUI.Button(new Rect(Screen.width / 2 - 20, Screen.width / 2 - 150, 100, 50), "Restart")){life = 6;action.ReStart();return;}action.GameOver();}}else{GUI.Label(new Rect(Screen.width / 2 - 30, Screen.width / 2 - 350, 100, 100), "Hit UFO!", over_style);GUI.Label(new Rect(Screen.width / 2 -10, Screen.width / 2 - 300, 400, 100), "Rule:", text_style);GUI.Label(new Rect(Screen.width / 2 - 50, Screen.width / 2 - 280, 400, 100), "Use mouse hit the UFO", text_style);GUI.Label(new Rect(Screen.width / 2 - 60, Screen.width / 2 - 260, 400, 100), "Button Pause to stop Game", text_style);GUI.Label(new Rect(Screen.width / 2 - 160, Screen.width / 2 - 240, 400, 100), "Button Easy to change into easy game, UFO speed = 0.5x", text_style);GUI.Label(new Rect(Screen.width / 2 - 165, Screen.width / 2 - 220, 400, 100), "Button Normal to change into Normal game, UFO speed = 1x", text_style);GUI.Label(new Rect(Screen.width / 2 - 165, Screen.width / 2 - 200, 400, 100), "Button Normal to change into Hard game, UFO speed = 2x", text_style);if (GUI.Button(new Rect(Screen.width / 2 - 20, Screen.width / 2-150, 100, 50), "Start")){game_start = true;action.BeginGame();}}}
四、效果展示
五、编写一个简单的自定义 Component
- 实现自定义组件,编辑并赋予飞碟一些属性
我们尝试自制几个飞碟的预设,并在游戏中工厂类”生产“飞碟时,加入我们自己编写的Component预设,我们再组件中,设定了飞碟的颜色,大小,位置和分值,可以通过组件直接调整飞碟对应属性
首先先自己做飞碟的预设:这里因为大小等信息我们通过Component来进行调整,所以我们的预设做的比较模糊就可以了,不需要调整具体形状
再预设中加入我们自己的Component,来及进行对应属性的直接管理
具体代码如下:
public class DiskData : MonoBehaviour
{public int score; public Color color = Color.blue; public Vector3 direction; public Vector3 scale;
}
运行时截图:
与游戏世界交互——Hit UFO相关推荐
- 3D游戏编程与设计作业6-Unity实现打飞碟游戏改进版(Hit UFO)
改进飞碟(Hit UFO)游戏 游戏内容要求 按adapter模式设计图修改飞碟游戏 使它同时支持物理运动与运动学(交换)运动 编程实践 本次作业直接在上一次打飞碟游戏的基础上增加adapter设计模 ...
- 3D游戏编程学习笔记(五):与游戏世界交互
一.前言 本次3D游戏编程我们将设计一个简单打飞碟(Hit UFO)有游戏. 二.游戏基本内容及规定 游戏基本内容 游戏有 n 个 round,每个 round 都包括10 次 trial: 每个 t ...
- ch05与游戏世界交互——鼠标打飞碟小游戏
游戏内容要求: 游戏有 n 个 round,每个 round 都包括10 次 trial. 每个 trial 的飞碟的色彩.大小.发射位置.速度.角度.同时出现的个数都可能不同.它们由该 round ...
- 3D Game Pr ramming Design(五):与游戏世界交互(对象池)
把核心框架实现了,没有做界面 PS:让我想起来以前用XNA写了半个暑假的简陋版抢滩登陆,老辛苦还丑,现在的可视化引擎比以前的强大太多了 框架是以前写的老框架的延伸,直接看UML图吧 TotalMana ...
- Unity3d Note5(鼠标打飞碟(Hit UFO)游戏)
1.作业要求 2.具体设计 (1).制备预制体作为飞碟 (2).了解一下Singleton模板类 (3).了解一下工厂模式 (3).设计具体要实现的类 3.程序代码 成果视频 1.作业要求 编写一个简 ...
- 改进飞碟(Hit UFO)游戏
1.改进飞碟(Hit UFO)游戏: 游戏内容要求: 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 新增的类或者有修改的类如下: ActionManagerAd ...
- unity实现鼠标打飞碟(Hit UFO)游戏
unity实现鼠标打飞碟(Hit UFO)游戏 游戏规则及要求 规则:玩家初始有5条生命,每漏过一个飞碟,生命减一.游戏分数的增加与命中飞碟时的位置有关,越早击中飞碟分数越高.游戏有四档难度,随分数递 ...
- 物体碰撞和检测——Hit UFO改进版射箭游戏
文章目录 Hit UFO改进版 一.改进要求 二.MVC图 三.gitee 四.程序实现 4.1 FirstController 4.2 Interface 4.3 ActionManagerAdap ...
- Unity游戏Hit UFO实现
Unity游戏Hit UFO 实现 一.游戏内容 游戏有n个round,每个round都包括10次trial 每个trail的飞碟颜色.大小.发射位置.速度.角度.同时出现的个数不同. 每个飞碟出现有 ...
最新文章
- 这玩意比ThreadLocal叼多了,吓得我赶紧分享出来。
- 圆你“鸟人”梦,全身VR模拟飞行器Birdly带你飞
- 远程计算机未能及时反应,Win10无法打开软件提示“服务器没有及时响应或控制请求”怎么办...
- Console-算法[for]-打印出杨辉三角形
- __declspec(dllexport)、__declspec(dllimport)详解
- build vue3 后压缩的文件在哪_Vue 3学习:4. 集成vuex
- 洛谷——P2077 红绿灯
- 调一下电脑底色,保护眼睛哦
- 微信小程序 16 登录界面
- 内网穿透端口映射工具
- PID算法与PID自整定算法
- 证件照怎么换底色?不用ps,Word就能一键更换红白蓝底色
- 利用JavaScript在canvas中画一棵树
- 微软Project Online落地中国
- Typora常用快捷键(MarkDown)
- 百度编辑器上传视频配置
- [QMT]09-下载历史行情数据到本地
- 浅谈航飞重叠度,利用小工具计算大疆精灵、M300、垂起固定翼航飞重叠度——拒绝航飞空洞
- [转]MySQL 5.7 新特性大全和未来展望
- C++多线程编程的几种实现方式小结
热门文章
- Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.Configurati
- Westrock Coffee拟曲线上市:作价11亿美元 路演PPT曝光
- Unity 关于MatchVS使用static类型导致GameObject.Find与Action等不可用的解决方法
- [案例分享]激活电力价值,八大案例深度解析电力大数据应用
- 【自己制作数据集】制作标注并生成mask
- What is 'Signal 15' ?
- 《SCDA:Adapting Object Detectors via Selective Cross-Domain Alignment》论文笔记
- Python-Tkinter 电子记事本
- pytroch:model.train()、model.eval()的使用
- OCR识别-实际应用案例