HW6 物理系统与碰撞

1、改进飞碟(Hit UFO)游戏:

  • 游戏内容要求:
    1. adapter模式 设计图修改飞碟游戏
    2. 使它同时支持物理运动与运动学(变换)运动

设计思路:

​ 在作业5的基础上结构未有较大改变,只是按照本次作业的要求修改了代码。

实现过程:

  1. 修改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);
      	}
      }
      
  2. 修改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);
            }
    
  3. 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;
          }
      
      }
      
      
  4. 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);      
              }
          }
      
      }
      
  5. 游戏运行效果如下:
    在这里插入图片描述
    在这里插入图片描述

项目地址:
https://gitee.com/liuhz5/game-unity/tree/master/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值