HW6 物理系统与碰撞
程序员文章站
2022-07-12 23:39:03
...
1、改进飞碟(Hit UFO)游戏:
- 游戏内容要求:
- 按 adapter模式 设计图修改飞碟游戏
- 使它同时支持物理运动与运动学(变换)运动
设计思路:
在作业5的基础上结构未有较大改变,只是按照本次作业的要求修改了代码。
实现过程:
-
修改BaseCode.cs:
-
在作业5的基础上,新增一个mode,使UFO同时支持物理运动(受重力影响)和运动学运动(不受重力影响),通过枚举类型实现,代码如下:
public enum ActionMode {PHYSICS, KINEMATIC}
-
新增一个根据mode控制飞碟飞行属性的接口IActionManager,代码如下:
public interface IActionManager { GameObject GetDisk(int round, ActionMode mode); }
修改后的BaseCode.cs总体代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UFO; //基础属性 namespace UFO { public class Disk : MonoBehaviour { public float size; //大小 public Color color; //颜色 public float speed; //速度 public Vector3 position; //初始位置 public Vector3 direction; //运动方向 } public class Director : System.Object { private static Director _instance; public ISceneController currentSceneController { get; set; } public static Director getInstance() { if (_instance == null) { _instance = new Director(); } return _instance; } } public enum ActionMode {PHYSICS, KINEMATIC} public interface ISceneController { // 加载场景 void Init (); SceneController getSceneController(); ActionMode getMode(); void setMode(ActionMode mode); int getGameBegin(); void setGameBegin(int g); } public interface IActionManager { GameObject GetDisk(int round, ActionMode mode); } }
-
-
修改DiskFactory.cs:
新增实现IActionManager接口的功能,将作业5中设定的飞碟皆受重力作用修改为仅当mode为PHYSICS时增加Rigidbody,即移除原本的刚体组件,并仅当mode为PHYSICS时添加重力作用:
if(mode == ActionMode.PHYSICS) { newDisk.AddComponent<Rigidbody>(); newDisk.GetComponent<Rigidbody>().AddForce(Vector3.down * 9.8f, ForceMode.Acceleration); }
-
FirstSceneController.cs:
-
新增get、set方法;
-
增加mode作为成员变量,并将其传递给DiskFactory的GetDisk()函数生成所需的UFO;
总体代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UFO; 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; } } } public class FirstSceneController : MonoBehaviour, ISceneController { public int diskFlyTimes; // 已经发射的飞碟个数,每回合10个,最多30个 public float time; // 时间,用于控制飞碟发射间隔 public int round; // 当前回合数 public Queue<GameObject> diskQueue = new Queue<GameObject>(); // 飞碟队列 public SceneController sceneCtrl; public int gameBegin; public ActionMode mode; // 选择模式 public ActionMode getMode() { return mode; } public void setMode(ActionMode m) { mode = m; } // Start is called before the first frame update void Start() { // 当前场景控制器 Director.getInstance().currentSceneController = this; this.gameObject.AddComponent<DiskFactory>(); this.gameObject.AddComponent<UserGUI>(); Director.getInstance().currentSceneController.Init(); // 初始化FirstSceneController相关数据 } // 初始化每个回合的飞碟队列,每个回合的飞碟属性不同 void initQueue() { diskQueue.Clear(); for(int i = 0; i < 10; i++) diskQueue.Enqueue(Singleton<DiskFactory>.Instance.GetDisk(round, getMode())); } // Update is called once per frame void Update() { if(gameBegin == 1) { // round = sceneCtrl.getRound(); time += Time.deltaTime; // 发射飞碟的间隔回合数成反比 if(time >= 2.0f - 0.3 * round) { if(diskFlyTimes >= 30) { // 游戏结束 Reset(); } else if ((diskFlyTimes % 10) == 0 ) { // 更新回合(此步骤必须在发射飞碟前面) round++; // 在initQueue()之前 sceneCtrl.addRound(); // 回合数增加 initQueue(); // 初始化新的飞盘队列 } if (diskFlyTimes < 30) { time = 0; ThrowDisk(); // 发射飞盘 diskFlyTimes++; // 飞盘数增加 sceneCtrl.addTotal(); // 综费盘数增加 } } } } public void ThrowDisk() { if(diskQueue.Count > 0) { GameObject disk = diskQueue.Dequeue(); disk.GetComponent<Renderer>().material.color = disk.GetComponent<Disk>().color; disk.transform.position = disk.GetComponent<Disk>().position; disk.transform.localScale = disk.GetComponent<Disk>().size * disk.transform.localScale; disk.SetActive(true); disk.AddComponent<ActionManager>(); disk.GetComponent<ActionManager>().diskFly(disk.GetComponent<Disk>().direction, disk.GetComponent<Disk>().speed); } } public void Init() { sceneCtrl = new SceneController(); // SceneController元素归0 diskFlyTimes = 0; time = 0; round = 0; gameBegin = 0; diskQueue.Clear(); // 清空飞盘队列 } public SceneController getSceneController() { // 返回SceneController return sceneCtrl; } public int getGameBegin() { return gameBegin; } public void setGameBegin(int g) { gameBegin = g; } void Reset() { // 游戏重置 this.gameObject.GetComponent<UserGUI>().reset = 1; } }
-
-
UserGUI.cs:
-
新增模式选择功能,代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UFO; public class UserGUI : MonoBehaviour { public int reset; GUIStyle style; GUIStyle buttonStyle; ActionMode mode; // Start is called before the first frame update void Start() { // 初始化为1,选择模式 reset = 1; style = new GUIStyle(); style.fontSize = 30; style.normal.textColor = Color.green; buttonStyle = new GUIStyle("button"); buttonStyle.fontSize = 30; buttonStyle.normal.textColor = Color.green; } // Update is called once per frame void Update() { } private void OnGUI() { if(reset == 1) { if(GUI.Button(new Rect(100, 250, 200, 80), "KINEMATIC", buttonStyle)){ mode = ActionMode.KINEMATIC; Director.getInstance().currentSceneController.setMode(mode); Director.getInstance().currentSceneController.Init(); Director.getInstance().currentSceneController.setGameBegin(1); reset = 0; return; }else if(GUI.Button(new Rect(500, 250, 200, 80), "PHYSICS", buttonStyle)){ mode = ActionMode.PHYSICS; Director.getInstance().currentSceneController.setMode(mode); Director.getInstance().currentSceneController.Init(); Director.getInstance().currentSceneController.setGameBegin(1); reset = 0; return; } }else if(reset == 0) { int round = Director.getInstance().currentSceneController.getSceneController().getRound(); int total = Director.getInstance().currentSceneController.getSceneController().getTotal(); int score = Director.getInstance().currentSceneController.getSceneController().getScore(); string text = "Round: " + round.ToString() + "\nTotal: " + total.ToString() + "\nScores: " + score.ToString(); GUI.Label(new Rect(10, 10, Screen.width, 50),text,style); } } }
-
-
游戏运行效果如下:
上一篇: [每日一题] 135. 将有序数组转换为二叉搜索树(BST树、递归、多方法)
下一篇: 杂