目录

  • 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

一、游戏规则

  1. 点击飞碟来摧毁它
  2. 当飞碟飞出屏幕时,损失生命值,生命值归零时游戏结束
  3. 摧毁飞碟会获得点数,随着点数的升高,游戏难度加大
  4. 可以通过Easy,Normal,Hard选项手动调节基础游戏难度(也就是倍速)
  5. 通过Pause暂停游戏;
  6. 通过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相关推荐

  1. 3D游戏编程与设计作业6-Unity实现打飞碟游戏改进版(Hit UFO)

    改进飞碟(Hit UFO)游戏 游戏内容要求 按adapter模式设计图修改飞碟游戏 使它同时支持物理运动与运动学(交换)运动 编程实践 本次作业直接在上一次打飞碟游戏的基础上增加adapter设计模 ...

  2. 3D游戏编程学习笔记(五):与游戏世界交互

    一.前言 本次3D游戏编程我们将设计一个简单打飞碟(Hit UFO)有游戏. 二.游戏基本内容及规定 游戏基本内容 游戏有 n 个 round,每个 round 都包括10 次 trial: 每个 t ...

  3. ch05与游戏世界交互——鼠标打飞碟小游戏

    游戏内容要求: 游戏有 n 个 round,每个 round 都包括10 次 trial. 每个 trial 的飞碟的色彩.大小.发射位置.速度.角度.同时出现的个数都可能不同.它们由该 round ...

  4. 3D Game Pr ramming Design(五):与游戏世界交互(对象池)

    把核心框架实现了,没有做界面 PS:让我想起来以前用XNA写了半个暑假的简陋版抢滩登陆,老辛苦还丑,现在的可视化引擎比以前的强大太多了 框架是以前写的老框架的延伸,直接看UML图吧 TotalMana ...

  5. Unity3d Note5(鼠标打飞碟(Hit UFO)游戏)

    1.作业要求 2.具体设计 (1).制备预制体作为飞碟 (2).了解一下Singleton模板类 (3).了解一下工厂模式 (3).设计具体要实现的类 3.程序代码 成果视频 1.作业要求 编写一个简 ...

  6. 改进飞碟(Hit UFO)游戏

    1.改进飞碟(Hit UFO)游戏: 游戏内容要求: 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 新增的类或者有修改的类如下: ActionManagerAd ...

  7. unity实现鼠标打飞碟(Hit UFO)游戏

    unity实现鼠标打飞碟(Hit UFO)游戏 游戏规则及要求 规则:玩家初始有5条生命,每漏过一个飞碟,生命减一.游戏分数的增加与命中飞碟时的位置有关,越早击中飞碟分数越高.游戏有四档难度,随分数递 ...

  8. 物体碰撞和检测——Hit UFO改进版射箭游戏

    文章目录 Hit UFO改进版 一.改进要求 二.MVC图 三.gitee 四.程序实现 4.1 FirstController 4.2 Interface 4.3 ActionManagerAdap ...

  9. Unity游戏Hit UFO实现

    Unity游戏Hit UFO 实现 一.游戏内容 游戏有n个round,每个round都包括10次trial 每个trail的飞碟颜色.大小.发射位置.速度.角度.同时出现的个数不同. 每个飞碟出现有 ...

最新文章

  1. 这玩意比ThreadLocal叼多了,吓得我赶紧分享出来。
  2. 圆你“鸟人”梦,全身VR模拟飞行器Birdly带你飞
  3. 远程计算机未能及时反应,Win10无法打开软件提示“服务器没有及时响应或控制请求”怎么办...
  4. Console-算法[for]-打印出杨辉三角形
  5. __declspec(dllexport)、__declspec(dllimport)详解
  6. build vue3 后压缩的文件在哪_Vue 3学习:4. 集成vuex
  7. 洛谷——P2077 红绿灯
  8. 调一下电脑底色,保护眼睛哦
  9. 微信小程序 16 登录界面
  10. 内网穿透端口映射工具
  11. PID算法与PID自整定算法
  12. 证件照怎么换底色?不用ps,Word就能一键更换红白蓝底色
  13. 利用JavaScript在canvas中画一棵树
  14. 微软Project Online落地中国
  15. Typora常用快捷键(MarkDown)
  16. 百度编辑器上传视频配置
  17. [QMT]09-下载历史行情数据到本地
  18. 浅谈航飞重叠度,利用小工具计算大疆精灵、M300、垂起固定翼航飞重叠度——拒绝航飞空洞
  19. [转]MySQL 5.7 新特性大全和未来展望
  20. C++多线程编程的几种实现方式小结

热门文章

  1. Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.Configurati
  2. Westrock Coffee拟曲线上市:作价11亿美元 路演PPT曝光
  3. Unity 关于MatchVS使用static类型导致GameObject.Find与Action等不可用的解决方法
  4. [案例分享]激活电力价值,八大案例深度解析电力大数据应用
  5. 【自己制作数据集】制作标注并生成mask
  6. What is 'Signal 15' ?
  7. 《SCDA:Adapting Object Detectors via Selective Cross-Domain Alignment》论文笔记
  8. Python-Tkinter 电子记事本
  9. pytroch:model.train()、model.eval()的使用
  10. OCR识别-实际应用案例