本文主要是介绍unity:打飞碟小游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这里写目录标题
- 游戏开发要求
- 游戏规则
- 工厂与对象池理解
- UML图
- 代码介绍
- action
- action不多做讲解,可以参考之前博客的牧师与魔鬼动作分离版的讲解
- config
- controller
- factory
- model
- view
- 创建预制&&配置ruler&&配置天空盒&&挂载脚本
- 视频演示
- 代码仓库
游戏开发要求
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
- 近可能使用前面 MVC 结构实现人机交互与游戏模型分离
- 必须使用对象池管理飞碟对象。
- 建议使用 ScriptableObject 配置不同的飞碟(方便配置修改)
- 建议使用物理引擎管理飞碟飞行路径。
使用 UML 图、伪代码辅助表达对象池的原理,对象配置方法,以及你的设计
游戏规则
- 游戏有 n 个 round,每个 round 都包括10 次 trial。
- 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制。
- 每个 trial 的飞碟有随机性,总体难度随 round 上升。
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
disk | score |
---|---|
红 | 2 |
黄 | 4 |
蓝 | 6 |
绿 | 8 |
工厂与对象池理解
工厂方法,即类一个方法能够得到一个对象实例,使用者不需要知道该实例如何构建、初始化等细节。
好处:
- 游戏对象的创建与销毁高成本,必须减少销毁次数。
- 屏蔽创建与销毁的业务逻辑,使程序易于扩展
UML图
代码介绍
代码分为下面几个模块
遵循MVC架构和cocos2d的设计思想
action
action不多做讲解,可以参考之前博客的牧师与魔鬼动作分离版的讲解
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum SSActionEventType : int { Started, Competeted }
public interface ISSActionCallback
{/// <summary>/// when an action has been excuted, call the callback function/// </summary>/// <param name="source">action has been excuted</param>/// <param name="events"></param>/// <param name="intParam"></param>/// <param name="strParam"></param>/// <param name="objectParam"></param>public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competeted,int intParam = 0,string strParam = null,GameObject objectParam = null);}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSAction : ScriptableObject
{/// <summary>/// if enable, then will call update per frame/// </summary>public bool enable = true;/// <summary>/// if destory, will be removed after a frame/// </summary>public bool destroy = false;public GameObject gameobject { get; set; }public Transform transform { get; set; }public ISSActionCallback callback { get; set; }protected SSAction() { }// Start is called before the first frame updatepublic virtual void Start(){throw new System.NotImplementedException();}// Update is called once per framepublic virtual void Update(){throw new System.NotImplementedException();}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SSActionManager : MonoBehaviour
{private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();private List<SSAction> waitingAdd = new List<SSAction> ();private List<int> waitingDelete = new List<int>();// Start is called before the first frame updateprotected void Start(){}// Update is called once per frameprotected void Update(){// add to actionsforeach(SSAction ac in waitingAdd){actions[ac.GetInstanceID()] = ac;}waitingAdd.Clear();//run actionsforeach(KeyValuePair<int, SSAction> kv in actions){SSAction ac = kv.Value;if(ac.destroy){waitingDelete.Add(ac.GetInstanceID());}else if(ac.enable){ac.Update();//call action update manually}}//delete actionsforeach(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;//add action to gameobjectaction.transform = gameobject.transform;//ser action's transformaction.callback = manager;//set action's callbackwaitingAdd.Add(action);action.Start();//not monobehavior thus call start mannually}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NPhysicalDiskAction : SSAction
{float gravity;float time;float speed;Vector3 direction;// builder, get specific actions success SSActionpublic static NPhysicalDiskAction GetSSAction(Vector3 direction, float speed){NPhysicalDiskAction action = ScriptableObject.CreateInstance<NPhysicalDiskAction>();action.gravity = 9.8f;action.time = 0;action.speed = speed;action.direction = direction;return action;}// Start is called before the first frame updatepublic override void Start(){gameobject.GetComponent<Rigidbody>().isKinematic = true;}// Update is called once per framepublic override void Update(){// disk move 运动合成,transform is the one of scriptable object,// which will be set equal to gameobject which excecutes this action. transform.Translate(Vector3.down * gravity * time * Time.deltaTime);transform.Translate(direction * speed * Time.deltaTime);time += Time.deltaTime;//Debug.Log("postion of the disk"+gameobject.name+" is "+gameobject.transform.position);// 飞碟到达屏幕底部回调Camera mainCamera = Camera.main; // 获取主摄像机float cameraHeight = mainCamera.orthographicSize * 2f; // 获取相机的视图高度// 计算相机视图的上下边界坐标float upperBoundary = mainCamera.transform.position.y + cameraHeight / 2f;float lowerBoundary = mainCamera.transform.position.y - cameraHeight / 2f;//Debug.Log("Upper Boundary: " + upperBoundary);//Debug.Log("Lower Boundary: " + lowerBoundary);if (this.transform.position.y < lowerBoundary-100 || this.transform.position.y > upperBoundary+100){// action destorythis.destroy = true;this.enable = false;// action callbackthis.callback.SSActionEvent(this);//source as this}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PhysicalDiskAction : SSAction
{private float speed;private Vector3 direction;// builderpublic static PhysicalDiskAction GetSSAction(Vector3 direction, float speed){PhysicalDiskAction ac = ScriptableObject.CreateInstance<PhysicalDiskAction>();ac.speed = speed;ac.direction = direction;return ac;}// Start is called before the first frame updatepublic override void Start(){// add clash pysical effectgameobject.GetComponent<Rigidbody>().isKinematic = false;// add init speedgameobject.GetComponent<Rigidbody>().velocity = speed * direction;}// Update is called once per framepublic override void Update(){//Debug.Log("postion of the disk"+gameobject.name+" is "+gameobject.transform.position);// 飞碟到达屏幕底部回调Camera mainCamera = Camera.main; // 获取主摄像机float cameraHeight = mainCamera.orthographicSize * 2f; // 获取相机的视图高度// 计算相机视图的上下边界坐标float upperBoundary = mainCamera.transform.position.y + cameraHeight / 2f;float lowerBoundary = mainCamera.transform.position.y - cameraHeight / 2f;//Debug.Log("Upper Boundary: " + upperBoundary);//Debug.Log("Lower Boundary: " + lowerBoundary);if (this.transform.position.y < lowerBoundary - 100 || this.transform.position.y > upperBoundary + 100){// action destorythis.destroy = true;this.enable = false;// action callbackthis.callback.SSActionEvent(this);//source as this}}
}
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;public class DiskActionManager : SSActionManager, ISSActionCallback
{public FirstController firstController;public void ShootDisk(GameObject disk, float speed, Vector3 direction,PhysiclaType type){SSAction ac;// run actionif (type== PhysiclaType.noPhysical){ac = NPhysicalDiskAction.GetSSAction(direction, speed);}else if (type == PhysiclaType.pysical){ac = PhysicalDiskAction.GetSSAction(direction, speed);}else{throw new NotImplementedException();}RunAction(disk, ac, this);}protected new void Start(){// get fisrt controllerfirstController = (FirstController)Director.GetInstance().CurrentSceneController;// set action manager as thisfirstController.actionManager = this;}// specific manager do callbackpublic void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Competeted,int intParam = 0,string strParam = null,GameObject objectParam = null){//回收飞碟//source is the class success the SSAction, in this case is obj of NphysicalDiskAction ClassSingleton<RoundController>.Instance.FreeDisk(source.gameobject);}
}
config
using System;
using UnityEngine;[CreateAssetMenu(menuName ="create ruler config")]
public class Ruler : ScriptableObject
{// 对局属性public int trailIndex;public int roundIndex;public int SumRoundNum;public int SumTrailNum;public int[] diskNumPerRound;//avg disk num per roundpublic float[] shootDeltaTimePerRound;//发射间隔// 飞碟属性public DiskFeature diskFeature;[NonSerialized]public Vector3 startPos;[NonSerialized]public Vector3 startDir;}
controller
Director 导演类,管理场记
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;public class Director : System.Object
{static Director _instance;// 关联场记实例public ISceneController CurrentSceneController { get; set; }// 获取当前的场记public static Director GetInstance(){if (_instance == null){_instance = new Director();}return _instance;}public static void ReloadCurrentScene(){int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;SceneManager.LoadScene(currentSceneIndex);}
}
ISceneController场记类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface ISceneController
{void LoadResources();
}
IUserAction定义了用户的动作
using System.Collections;
using System.Collections.Generic;
using UnityEngine;// 抽象接口,定义用户的行为
public interface IUserAction
{void Restart();
}
FirstController 第一个场记,继承ISceneController
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/* 游戏状态,0为准备进行,1为正在进行游戏,2为结束 */
public enum GameState
{Ready = 0, Playing = 1, GameOver = 2
};public class FirstController : MonoBehaviour, ISceneController
{public DiskActionManager actionManager;public RoundController roundController;public UserGUI userGUI;public GameState gameState;// ruler configpublic Ruler rulerConfig;public void LoadResources(){Director.GetInstance().CurrentSceneController = this;roundController = gameObject.AddComponent<RoundController>();Debug.Log("add roundController Component");userGUI = gameObject.AddComponent<UserGUI>();Debug.Log("add UserGUI");actionManager = gameObject.AddComponent<DiskActionManager>();Debug.Log("add DiskActionManager");gameState = (int)GameState.Ready;}public void Restart(){Director.ReloadCurrentScene();}public void JudgeResultCallBack(string result){}void Awake(){LoadResources();}void Start(){}void Update(){}public void GameOver(){gameState = GameState.GameOver;userGUI.SetGameState(GameState.GameOver);}public void SetGameMode(PhysiclaType type){roundController.phyType= type;}
}
RoundController 控制飞碟对象的运动类型为运动学运动或物理运动,并根据一定规则请求飞碟工厂生成相应的飞碟对象,控制游戏飞碟对象的发射
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;public enum PhysiclaType
{pysical,noPhysical
}public class RoundController : MonoBehaviour
{DiskActionManager actionManager;ScoreRecorder scoreRecorder;FirstController firstController;Ruler ruler;float time = 0;public PhysiclaType phyType;public void LaunchDisk(){// 使飞碟飞入位置尽可能分开,从不同位置飞入使用的数组int[] beginPosY = new int[10];float beginPosX;// shoot the disks for each trailint diskNum = ruler.diskNumPerRound[ruler.roundIndex] / ruler.SumTrailNum;diskNum += Random.Range(0, 5);// random num per trailfor (int i = 0; i < diskNum; ++i){// 获取随机数int randomNum = Random.Range(1, 4);// 飞碟速度随回合数增加而变快ruler.diskFeature.speed = randomNum * (ruler.roundIndex + 2);// 根据随机数选择飞碟颜色randomNum = Random.Range(1, 4);if (randomNum == 1){ruler.diskFeature.color = DiskFeature.colors.red;}else if (randomNum == 2){ruler.diskFeature.color = DiskFeature.colors.green;}else{ruler.diskFeature.color = DiskFeature.colors.blue;}// 重新选取随机数,并根据随机数选择飞碟的大小ruler.diskFeature.size = Random.Range(1, 4);// 重新选取随机数,并根据随机数选择飞碟飞入的方向randomNum = Random.Range(0, 2);Camera mainCamera = Camera.main;float cameraW = mainCamera.orthographicSize * 2f * Camera.main.aspect;if (randomNum == 1){ruler.startDir = new Vector3(3, 1, 0);beginPosX= mainCamera.transform.position.x - cameraW / 2f;}else{ruler.startDir = new Vector3(-3, 1, 0);beginPosX = mainCamera.transform.position.x + cameraW / 2f;}// 重新选取随机数,并使不同飞碟的飞入位置尽可能分开int iterNum = 0;do{// case if infinite iteriterNum++;if (iterNum>=100){int ii;for (ii = 0; ii < beginPosY.Length; ii++){beginPosY.SetValue(0, ii);}}randomNum = Random.Range(0, 10);} while (beginPosY[randomNum] != 0);beginPosY[randomNum] = 1;ruler.startPos = new Vector3(beginPosX, -0.2f * randomNum, 0);// 根据ruler从工厂中生成一个飞碟GameObject disk = Singleton<DiskFactory>.Instance.GetDisk(ruler);// 设置飞碟的飞行动作actionManager.ShootDisk(disk, ruler.diskFeature.speed, ruler.startDir,phyType);}}/// <summary>/// free the gameobject that loaded the action/// </summary>/// <param name="obj">obj is the one load the action</param>public void FreeDisk(GameObject disk){// call factory to free the diskSingleton<DiskFactory>.Instance.FreeDisk(disk);}// 用户点击碰撞public void Hit(Vector3 position){Camera camera = Camera.main;Ray ray = camera.ScreenPointToRay(position);RaycastHit[] hits;hits = Physics.RaycastAll(ray);for (int i = 0; i < hits.Length; i++){RaycastHit hit = hits[i];if (hit.collider.gameObject != null){// 把击中的飞碟移出屏幕,触发回调释放hit.collider.gameObject.transform.position = new Vector3(0, -6, 0);// 记录飞碟得分scoreRecorder.Record(hit.collider.gameObject.GetComponent<Disk>());// 显示当前得分UserGUI userGUI = Singleton<UserGUI>.Instance;userGUI.SetScore(scoreRecorder.GetScore());}}}// Start is called before the first frame updatevoid Start(){Debug.Log("gameobject of roundcontroller is:" + this.gameObject);actionManager = gameObject.AddComponent<DiskActionManager>();scoreRecorder = gameObject.AddComponent<ScoreRecorder>();firstController = Director.GetInstance().CurrentSceneController as FirstController;ruler = firstController.rulerConfig;gameObject.AddComponent<DiskFactory>();ruler.roundIndex= 0;ruler.trailIndex= 0;Debug.Log("ruler config:");Debug.Log(JsonUtility.ToJson(ruler));phyType = PhysiclaType.noPhysical;Debug.Log("round controller's phytype is:"+phyType);}// Update is called once per framevoid Update(){// when playingif (firstController.gameState == GameState.Playing){//update usergui round indexUpdateRoundInfo();//Debug.Log("round cont is playing update--");//Debug.Log("roundIndex" + ruler.roundIndex + "trailIndex" + ruler.trailIndex);time += Time.deltaTime;float shootDeltaTime = ruler.shootDeltaTimePerRound[ruler.roundIndex];// 发射一次飞碟(trial)if (time > shootDeltaTime){// reset timetime = 0;if (ruler.trailIndex<ruler.SumTrailNum && ruler.roundIndex<ruler.SumRoundNum){// 发射飞碟Debug.LogFormat("call LaunchDisk at round controller--at round {0} trail {1}", ruler.roundIndex, ruler.trailIndex);LaunchDisk();ruler.trailIndex++;// 回合加一,重新生成飞碟数组if (ruler.trailIndex == ruler.SumTrailNum){ruler.trailIndex = 0;ruler.roundIndex++;}}// 否则游戏结束,提示重新进行游戏else{firstController.GameOver();}}}}private void UpdateRoundInfo(){Singleton<UserGUI>.Instance.SetIndex(ruler.roundIndex, ruler.trailIndex);Singleton<UserGUI>.Instance.SetRTNum(ruler.SumRoundNum, ruler.SumTrailNum);Singleton<UserGUI>.Instance.SetPhyMode(phyType);}}
记分类根据记分规则,对被点击中的飞碟得分进行记录
using UnityEngine;public class ScoreRecorder : MonoBehaviour
{private int score;public ScoreRecorder(){ score = 0; }public ScoreRecorder(int score){ this.score = score; }public int GetScore(){return score;}// record the scorepublic void Record(Disk disk){// 飞碟大小为1得3分,大小为2得2分,大小为3得1分int diskSize = disk.diskFeature.size;switch (diskSize){case 1:score += 3;break;case 2:score += 2;break;case 3:score += 1;break;default: break;}// 速度越快分就越高score += disk.diskFeature.speed;// 颜色为红色得1分,颜色为黄色得2分,颜色为蓝色得3分DiskFeature.colors diskColor = disk.diskFeature.color;if (diskColor == DiskFeature.colors.red){score += 1;}else if (diskColor == DiskFeature.colors.yellow){score += 2;}else if (diskColor == DiskFeature.colors.blue){score += 3;}}/* 重置分数,设为0 */public void Reset(){score = 0;}// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){}
}
factory
Singleton单实例类,用来获取单实例的类的对象
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{protected static T instance;public static T Instance{get{ if (instance == null){instance = FindObjectOfType(typeof(T)) as T;if (instance == null){Debug.LogError("no instance of type " + typeof(T));}} return instance;}}// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}
}
飞碟工厂类负责飞碟对象的创建和销毁,在场景中是单实例的,且使用了对象池,实现了缓存功能。
当一个飞碟对象被创建时,会首先在对象池中寻找没有被使用的空闲飞碟对象,有的话就根据规则设置飞碟对象相应属性后直接使用,没有再创建。
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using Unity.VisualScripting.Antlr3.Runtime;
using UnityEngine;
using UnityEngine.Experimental.GlobalIllumination;public class DiskFactory : MonoBehaviour
{public GameObject diskPrefab;private List<GameObject> used;private List<GameObject> free;private int diskIndex;public GameObject GetDisk(Ruler ruler){GameObject disk;// 如果free没有空闲就创建if (free.Count==0){disk = GameObject.Instantiate(diskPrefab, Vector3.zero, Quaternion.identity);disk.name = "UFO" + diskIndex;Debug.LogFormat("factory create a disk, index is {0}",diskIndex);disk.AddComponent(typeof(Disk));diskIndex++;}else{int freeNum = free.Count;disk = free[freeNum-1];free.Remove(free[freeNum-1]);}// cacheused.Add(disk);// 初始化disk featuredisk.GetComponent<Disk>().diskFeature = ruler.diskFeature;// initial disk colorRenderer render = disk.GetComponent<Renderer>();if (ruler.diskFeature.color == DiskFeature.colors.white){render.material.color = Color.red;}else if (ruler.diskFeature.color == DiskFeature.colors.blue){render.material.color = Color.blue;}else if (ruler.diskFeature.color == DiskFeature.colors.black){render.material.color = Color.black;}else if (ruler.diskFeature.color == DiskFeature.colors.yellow){render.material.color = Color.yellow;}else if (ruler.diskFeature.color == DiskFeature.colors.green){render.material.color= Color.green;}// set disk position and scaledisk.transform.localScale = new Vector3(1f, (float)ruler.diskFeature.size, 1f);disk.transform.position = ruler.startPos;disk.SetActive(true);return disk;}public void FreeDisk(GameObject dd){foreach (GameObject d in used){if (d.GetInstanceID()==dd.GetInstanceID()){Debug.LogFormat("factory free a disk, name is {0}", d.name);d.SetActive(false);used.Remove(d);free.Add(d);break;}}}// Start is called before the first frame updatevoid Start(){diskPrefab = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/UFO"));diskPrefab.SetActive(false);Debug.Log("DiskFactory initial the diskPrefab");used = new List<GameObject>();free = new List<GameObject>();diskIndex = 0;}// Update is called once per framevoid Update(){}
}
model
飞碟的model类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Disk : MonoBehaviour
{public DiskFeature diskFeature;// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}
}
飞碟的特征类,有大小,颜色,速度等属性
public struct DiskFeature
{public enum colors{green,blue,red,purple,black,white,yellow,}public int size;public colors color;public int speed;
}
view
视图类,游戏有三种状态:就绪,游戏中,游戏结束
根据游戏状态不同显示不同的gui界面
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;struct Status
{public int score;public string tip;public int roundNum;public int trialNum;public int roundIndex;public int trialIndex;public PhysiclaType type;public GameState gameState;
}public class UserGUI : MonoBehaviour
{private Status status;private ISceneController currentSceneController;private GUIStyle playInfoStyle;// Start is called before the first frame updatevoid Start(){Init();currentSceneController = Director.GetInstance().CurrentSceneController;// set styleplayInfoStyle = new GUIStyle();playInfoStyle.normal.textColor = Color.black;playInfoStyle.fontSize= 25;}private void Init(){status.score= 0;status.tip = "";status.roundNum = 0;status.trialNum = 0;status.gameState = GameState.Ready;}// Update is called once per framevoid Update(){}private void OnGUI(){// titleGUIStyle titleStyle = new GUIStyle();titleStyle.normal.textColor = Color.red;titleStyle.fontSize = 50;GUI.Label(new Rect(Screen.width / 2 - 80, 10, 60, 100), "Hit UFO", titleStyle);// show user pageShowPage();}public void SetIndex(int roundIndex, int trailIndex){status.roundIndex = roundIndex;status.trialIndex = trailIndex;}public void SetRTNum(int roundNum, int trailNum){status.roundNum = roundNum;status.trialNum= trailNum;}public void SetGameState(GameState gameState){status.gameState = gameState;}/*set property of status*/public void SetScore(int score){status.score = score;}/*base on game status to show different user view*/private void ShowPage(){switch (status.gameState){case GameState.Ready:ShowHomePage();break;case GameState.Playing:ShowPlayingPage();break;case GameState.GameOver:ShowGameoverPage();break;}}private void ShowGameoverPage(){GUI.Label(new Rect(Screen.width / 2 - 40, 60, 60, 100), "游戏结束!", playInfoStyle);if (GUI.Button(new Rect(420, 200, 100, 60), "重新开始")){FirstController f = (FirstController)currentSceneController;// set game statusf.Restart();}}private void ShowPlayingPage(){GUI.Label(new Rect(10, 10, 60, 100), "正在游戏",playInfoStyle);GUI.Label(new Rect(Screen.width - 200, 10, 60, 100), "round:" +(status.roundIndex+1)+" trail:"+ (status.trialIndex+1), playInfoStyle);GUI.Label(new Rect(10, 40, 60, 100), "得分:"+status.score, playInfoStyle);GUI.Label(new Rect(Screen.width - 200, 35, 60, 100),"总轮数:" + status.roundNum + "\n每轮射击数:" + status.trialNum, playInfoStyle);GUI.Label(new Rect(10, 70, 60, 100),"当前模式:"+(status.type==PhysiclaType.noPhysical?"运动学模式":"物理模式"), playInfoStyle);if (Input.GetButtonDown("Fire1")){Singleton<RoundController>.Instance.Hit(Input.mousePosition);}// chose modeif (GUI.Button(new Rect(50, 450, 80, 50), "运动学模式")){FirstController f = (FirstController)currentSceneController;f.SetGameMode(PhysiclaType.noPhysical);}if (GUI.Button(new Rect(150, 450, 80, 50), "物理学模式")){FirstController f = (FirstController)currentSceneController;f.SetGameMode(PhysiclaType.pysical);}}private void ShowHomePage(){// add game modeif (GUI.Button(new Rect(Screen.width/2-50, 100, 100, 60), "开始游戏式\n(默认为运动学模式)")){FirstController f = (FirstController)currentSceneController;// set game statusf.gameState = GameState.Playing;status.gameState = GameState.Playing;}}internal void SetPhyMode(PhysiclaType phyType){status.type= phyType;}
}
创建预制&&配置ruler&&配置天空盒&&挂载脚本
飞碟的预制,需要提前制作好,并加上刚体组件Rigidbody,将Use Gravity项勾选上
配置游戏对局数据,这样就不用要修改都在代码里修改了
先创建一个config,之后配置我们的对局数据
再给camera配上一个天空盒
最后挂载firstcontroller和ruler,config脚本到一个空gameobject上
游戏就可以运行了
视频演示
unity 打飞碟小游戏
代码仓库
GitHub地址
这篇关于unity:打飞碟小游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!