3dgame 作業6
1. 作業內容
改進飛碟(Hit UFO)游戲:
游戲內容要求:
按 adapter模式 設計圖修改飛碟游戲 使它同時支持物理運動與運動學(變換)運動
2. 游戲配置
游戲中共有三種飛碟,創建好三個飛碟的預制類。
在三個預制類中分別添加Disk腳本,并且設置好每個預制類的大小。
創建好三種飛碟不同的材質,并添加。
創建一個空對象,并將SceneController添加到該對象中,即可運行。
3. UML類圖
與上一次作業相比,多了一個PhysicAction用于給物體添加重力影響,還有就是添加了一個ActionAdapter,與PhysicAction 和MoveToAction關聯,從而從而使得SceneController更加容易的調用物體運動的方法。
4. 分析
1. 適配器模式(Adapter Pattern):
將一個接口轉換成客戶希望的另一個接口,使接口不兼容的那些類可以一起工作。適配器模式既可以作為類結構型模式,也可以作為對象結構型模式。在適配器模式中,我們通過增加一個新的適配器類來解決接口不兼容的問題,使得原本沒有任何關系的類可以協同工作。
根據適配器類與適配者類的關系不同,適配器模式可分為對象適配器和類適配器兩種,在對象適配器模式中,適配器與適配者之間是關聯關系;在類適配器模式中,適配器與適配者之間是繼承(或實現)關系。
這里使用了ActionAdapter與PhysicAction 和MoveToAction關聯,從而更加方便的調用SSAction接口的方法。
2. 物理運動與運動學(變換)運動
物理運動包括物體的碰撞以及物體的重力影響,重力影響可以通過給物體添加一個逐漸均勻變大的速度實現。而物體的碰撞以及運動學變換可以通過給對象添加unity內置的DigidBody實現,添加之后,對象就會擁有與真實情況相同的物理特性,包括與物理碰撞之后的反應,以及可以對物體施加力的作用進行加速。
5. 代碼
UnitySingleton類 給每個需要單實例化的類繼承,包括SceneController、DiskProductor、ScoreRecorder讓其可以單實例話,同時可以靜態被其他類調用。
public class UnitySingleton<T> : MonoBehaviour where T : Component {//用于單例實例化protected static T _instance;public static T Instance() {if (_instance == null) { _instance = FindObjectOfType(typeof(T)) as T;if (_instance == null) {GameObject obj = new GameObject();obj.name = typeof(T).ToString();_instance = obj.AddComponent<T>();}}return _instance;}
}
SceneCotnroller 場景總控制類,調用各個接口以及創建、添加所需要的對象。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[System.Serializable]public class SceneController : UnitySingleton<SceneController>{public static int roundNum = 10; //回合數量public static int trialNumber = 10; //每個Round有多少個trialpublic float[] level = new float[roundNum]; //記錄每個round出現的時間間隔,每個round的記錄難度public float random; //時間間隔隨機部分的范圍private float time; //用于計時private float timeInterval; //記錄時間間隔[SerializeField] private int round; //round記錄第幾個回合[SerializeField] private int trial; //count記錄第幾個trialpublic bool gameStart;public ActionAdapter action; //動作管理對象void Awake() {_instance = this;for (int i = 0; i < roundNum; i++) { //初始化每個round的難度,round值越大,時間間隔越小,難度越高level [i] = 2f - 0.1f * roundNum;}time = 0; timeInterval = 0; round = 0; trial = 0;gameStart = false; //游戲初始狀態為等待random = 0.1f; //飛碟時間隨機浮動范圍action = gameObject.AddComponent<ActionAdapter> () as ActionAdapter;gameObject.AddComponent<UserGUI> (); //添加用戶界面DiskProductor.Instance(); //初始化disk對象創建工廠ScoreRecorder.Instance(); //初始化計分器}void Update() {if (gameStart) { //判斷游戲是否已經開始time += Time.deltaTime;if (time < timeInterval) //時間沒到返回return; else { //時間到創建disk,并且計算得到下一次創建的時間間隔trial ++;CreateDisk (Random.Range(1, round + 1 / 2));time -= timeInterval;timeInterval = level [round] + Random.Range (-random, random);if (trial < trialNumber)return; trial = 0; //一個回合結束if (round < 9)round++;}}}void CreateDisk(int num) {//生成隨機位置,調用disk工廠創建diskfloat py = Random.Range (0, 4);for (int i = 0; i < num; i++) { //隨機創建多個飛碟Vector3 pos = new Vector3 (10f, py + i * 2, 0); //為了開始不碰撞,均勻分配disk的位置Vector3 v = new Vector3 (-10f, Random.Range (-0.2f, 0.2f), 0);int kind = Random.Range (0, 3); //隨機選擇三種飛碟的一種//創建disk,并且通過adapter給disk創建運動對象Disk tem = DiskProductor.Instance ().Create (pos, v, 5f, kind);action.moveDisk (tem.gameObject, tem.velocity * (tem.kind + 1), 50);}}public void Reset() { //重置函數time = 0; timeInterval = 0; round = 0; trial = 0;DiskProductor.Instance ().Reset ();ScoreRecorder.Instance ().Reset ();}public int GetRoundIndex() { //獲得回合數return round;}
}
Disk 每個飛碟對象的腳本類,存儲每個了飛碟的信息,以及返回對象池、運動的方法。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Disk : MonoBehaviour {private float timeLeave; //記錄每個disk剩余飛行的時間public Vector3 velocity; //每個飛碟的基礎速度,disk的速度由基礎速度與種類決定public GameObject nextDisk; //記錄下一個空閑的飛碟public int poolIndex; //記錄該飛碟對象在對象池中的位置public ClickGUI clickgui; //每個飛碟的鼠標點擊響應腳本public int kind; //記錄每個飛碟對象的類型public Rigidbody rigid;bool enableEmit = true;void Awake() {timeLeave = 0;/**創建、設置飛碟腳本 */clickgui = this.gameObject.AddComponent(typeof(ClickGUI)) as ClickGUI;rigid = this.gameObject.AddComponent<Rigidbody> ();clickgui.setDisk(this);}public void init(Vector3 _position, Vector3 _velocity, float _lifeTime) {this.transform.position = _position;timeLeave = _lifeTime;velocity = _velocity;}void Update() {timeLeave -= Time.deltaTime;if (timeLeave < 0 || gameObject.transform.position.y < -5 || gameObject.transform.position.x < -10) //時間到了,返回到對象池ReturnToPool();}public void ReturnToPool() {gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;DiskProductor.Instance().Return(poolIndex, kind);}
}
public class ScoreRecorder : UnitySingleton<ScoreRecorder>
{public int score; //分數void Start () {score = 0;}//記錄分數public void AddPoint(int point) {score += point;}public void Reset() {score = 0;}
}
ClickGUI 與上次作業類似,給每一個飛碟對象使用。不同的是點擊后分數增加、調用對象的返回對象池函數。
public class ClickGUI : MonoBehaviour {// Use this for initializationDisk disk;public void setDisk(Disk disk){this.disk = disk;}void OnMouseDown(){ScoreRecorder.Instance ().AddPoint (disk.kind + 1);disk.ReturnToPool ();}
}
UserGUI 用戶界面,包括游戲重啟、游戲開始,分數、回合顯示。
public class UserGUI : MonoBehaviour{private GUIStyle MyStyle;private GUIStyle MyButtonStyle;void Start() {MyStyle = new GUIStyle ();MyStyle.fontSize = 20;MyStyle.normal.textColor = new Color (255f, 0, 0);MyButtonStyle = new GUIStyle ("button");MyButtonStyle.fontSize = 30;}void OnGUI() {//回合顯示GUI.Label (new Rect (10, 10, 100, 20), "Round:" + (SceneController.Instance ().GetRoundIndex () + 1), MyStyle);//分數顯示GUI.Label (new Rect (10, 40, 100, 20), "Score:" + (ScoreRecorder.Instance().score), MyStyle);if (SceneController.Instance ().gameStart) {//重啟if (GUI.Button (new Rect (Screen.width / 2 - 75, 20, 150, 50), "Restart", MyButtonStyle)) {SceneController.Instance ().Reset ();SceneController.Instance ().gameStart = false;}} else {//游戲開始if (GUI.Button (new Rect (Screen.width / 2 - 75, 20, 150, 50), "Start", MyButtonStyle)) {SceneController.Instance ().gameStart = true;}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSMoveToAction : SSAction //移動
{public Vector3 dest; //移動到的目的地public float speed; //移動速度public bool enableEmit = true;public Vector3 force;private SSMoveToAction() { }public static SSMoveToAction GetSSAction(Vector3 force, float speed) {SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();//創建實例action.force = force;action.speed = speed;return action;}public override void Update() {}public override void FixedUpdate() { //給物體添加力的時候需要使用FixedUpdate函數if(!this.destroy) { if(enableEmit) { //給物體添加一個力,從而給物體一個初速度gameobject.GetComponent<Rigidbody>().AddForce(force, ForceMode.Impulse);enableEmit = false;}this.destroy = true; //添加完力就進入回收隊列this.callback.SSActionEvent(this); }}public override void Start() {//移動過程無動作}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PhysicAction : SSAction { float acceleration; //重力加速度private PhysicAction() { }public static PhysicAction GetPhysicAction() {PhysicAction action = ScriptableObject.CreateInstance<PhysicAction>();//創建實例return action;}public override void Start () {acceleration = 9.8f;}public override void Update () {if (gameobject.activeSelf) { //物體運動期間,每隔一個時間單位,物體的速度會加上一個agameobject.GetComponent<Rigidbody> ().velocity += Vector3.down * acceleration * Time.deltaTime;} else { //disk返回后回收該動作對象this.destroy = true;this.callback.SSActionEvent(this); }}public override void FixedUpdate() {}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ActionAdapter : SSActionManager{private SSMoveToAction movedisk;private PhysicAction physic;public SceneController sceneController;public void Start(){sceneController = SceneController.Instance();sceneController.action = this;}public void moveDisk(GameObject disk, Vector3 dest, float speed) {movedisk = SSMoveToAction.GetSSAction (dest, speed); //獲得被是配的對象this.RunAction (disk, movedisk, this); //調用被是配對象的函數physic = PhysicAction.GetPhysicAction ();this.RunAction (disk, physic, this);}
}
游戲圖片以及視頻、代碼地址。
視頻地址:https://www.bilibili.com/video/av70686629/
或者:hw6.mov
代碼地址:https://github.com/ouzj5/3dgame/tree/master/hw6
總結
以上是生活随笔 為你收集整理的Unity3d--改进飞碟游戏 作业6 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。