欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HW6 物理系统与碰撞

程序员文章站 2022-07-12 23:39:03
...

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. 游戏运行效果如下:
    HW6 物理系统与碰撞
    HW6 物理系统与碰撞

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

相关标签: 3D游戏