日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【游戏开发】unity教程4 打飞碟小游戏

發(fā)布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【游戏开发】unity教程4 打飞碟小游戏 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

github傳送門:https://github.com/dongzizhu/unity3DLearning/tree/master/hw4/Disk

視頻傳送門:https://space.bilibili.com/472759319

打飛碟小游戲

這次的代碼架構(gòu)同樣采用了MVC模式,與之前的牧師與魔鬼基本相同,這里就不重復(fù)敘述了,感興趣的可以看上上篇博文。

這里主要還是介紹一下firstController的變化以及新應(yīng)用的工廠模式和真正負(fù)責(zé)飛碟移動的Emit類。

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using MyGame; using UnityEngine.SceneManagement;public class FirstController : MonoBehaviour, ISceneController, IUserAction {public ActionManager MyActionManager { get; set; }public DiskFactory factory { get; set; }public RecordController scoreRecorder;public UserGUI user; void Awake() {Director diretor = Director.getInstance();diretor.sceneCtrl = this; }// Use this for initializationvoid Start() {Begin();}// Update is called once per framevoid Update () {}public void Begin() {MyActionManager = gameObject.AddComponent<ActionManager>() as ActionManager;scoreRecorder = gameObject.AddComponent<RecordController>();user = gameObject.AddComponent<UserGUI>();user.Begin();}public void Hit(DiskController diskCtrl) { // 0=playing 1=lose 2=win 3=cooling if (user.game == 0) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)) {//hit.collider.gameObject.SetActive(false);Debug.Log("Hit");factory.freeDisk(hit.collider.gameObject);hit.collider.gameObject.GetComponent<DiskController>().hit = true;scoreRecorder.add(hit.collider.gameObject.GetComponent<DiskController>());}}}public void PlayDisk() {MyActionManager.playDisk(user.round);}public void Restart() {SceneManager.LoadScene("scene");}public int Check() {return 0;} }

FirstController同樣是負(fù)責(zé)著所有其他的controller和userGUI,這都和之前相同;新加入的DiskFactory我們一會兒再介紹。這里主要講一下Hit函數(shù)。所謂ScreenPointToRay就是從Camera出發(fā)連接到鼠標(biāo)點(diǎn)擊位置的一條射線,然后如果射線經(jīng)過了我們目標(biāo)的GameObject,就算是擊中了。當(dāng)一個飛碟被擊中時,我們首先將這個Object的Active設(shè)為False,從而將擊中的消息傳回給Action;然后FreeDisk是將這個實(shí)例從放到free列表中等待下一次調(diào)用(其實(shí)在FreeDisk中我們已經(jīng)有了設(shè)置Active的操作,這里將其注釋在這里是為了提醒我們它的重要性)。不知道free列表是什么東西沒關(guān)系,我們繼續(xù)看DiskFactory的代碼。

using System.Collections; using System.Collections.Generic; using UnityEngine; using MyGame;public class DiskFactory : MonoBehaviour {private static DiskFactory _instance;public FirstController sceneControler { get; set; }GameObject diskPrefab;public DiskController diskData;public List<GameObject> used;public List<GameObject> free;// Use this for initializationpublic static DiskFactory getInstance() {return _instance;}private void Awake() {if (_instance == null) {_instance = Singleton<DiskFactory>.Instance;_instance.used = new List<GameObject>();_instance.free = new List<GameObject>();diskPrefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk"), new Vector3(40, 0, 0), Quaternion.identity);}}public void Start() {sceneControler = (FirstController)Director.getInstance().sceneCtrl;sceneControler.factory = _instance; }public GameObject getDisk(int round) { // 0=playing 1=lose 2=win 3=coolingif (sceneControler.scoreRecorder.Score >= round * 4) {if (sceneControler.user.round < 3) {sceneControler.user.round++;sceneControler.user.num = 0;sceneControler.scoreRecorder.Score = 0;}else {sceneControler.user.game = 2; // 贏了return null;}}else {if (sceneControler.user.num >= 10) {sceneControler.user.game = 1; // 輸了return null;} }GameObject newDisk;RoundController diskOfCurrentRound = new RoundController(sceneControler.user.round); if (free.Count == 0) {// if no free disk, then create a new disknewDisk = GameObject.Instantiate(diskPrefab) as GameObject;newDisk.AddComponent<ClickGUI>();diskData = newDisk.AddComponent<DiskController>();}else {// else let the first free disk be the newDisknewDisk = free[0];free.Remove(free[0]);newDisk.SetActive(true);}diskData = newDisk.GetComponent<DiskController>();diskData.color = diskOfCurrentRound.color;//Debug.Log(diskData);newDisk.transform.localScale = diskOfCurrentRound.scale * diskPrefab.transform.localScale;newDisk.GetComponent<Renderer>().material.color = diskData.color;used.Add(newDisk);return newDisk;}public void freeDisk(GameObject disk1) {used.Remove(disk1);disk1.SetActive(false);free.Add(disk1);return;}public void Restart() {used.Clear();free.Clear();} }

這就是所謂的工廠模式了。當(dāng)游戲?qū)ο蟮膭?chuàng)建與銷毀成本較高,且游戲涉及大量游戲?qū)ο蟮膭?chuàng)建與銷毀時,必須考慮減少銷毀次數(shù),比如這次的打飛碟游戲,或者像其他類型的射擊游戲,其中子彈或者中彈對象的創(chuàng)建與銷毀是很頻繁的。工廠模式將已經(jīng)創(chuàng)建好正在使用的實(shí)例存在一個used列表中,然后當(dāng)使用完成(被擊中)就將其放在free列表中,等待下一次調(diào)用;當(dāng)我們需要一個新的實(shí)例的時候,首先檢查free列表,當(dāng)其中沒有限制的實(shí)例時我們才創(chuàng)建一個新的。getDisk和freeDisk就實(shí)現(xiàn)了上面所敘述的邏輯,是核心的代碼。

最后是Emit類。

using System.Collections; using System.Collections.Generic; using UnityEngine; using MyGame;public class Emit : SSAction {public FirstController sceneControler = (FirstController)Director.getInstance().sceneCtrl;public Vector3 target; public float speed; private float distanceToTarget; float startX;float targetX;float targetY;public override void Start() {speed = sceneControler.user.round * 5;GameObject.GetComponent<DiskController>().speed = speed;startX = 6 - Random.value * 12;if (Random.value > 0.5) {targetX = 36 - Random.value * 36;targetY = 25 - Random.value * 25;}else {targetX = -36 + Random.value * 36;targetY = -25 + Random.value * 25;}this.Transform.position = new Vector3(startX, 0, 0);target = new Vector3(targetX, targetY, 30);//Debug.Log(target);distanceToTarget = Vector3.Distance(this.Transform.position, target);}public static Emit GetSSAction() {Emit action = ScriptableObject.CreateInstance<Emit>();return action;}public override void Update() {Vector3 targetPos = target;if(!GameObject.activeSelf){this.destroy = true;return;}//facing the targetGameObject.transform.LookAt(targetPos);//calculate the starting angel float angle = Mathf.Min(1, Vector3.Distance(GameObject.transform.position, targetPos) / distanceToTarget) * 45;GameObject.transform.rotation = GameObject.transform.rotation * Quaternion.Euler(Mathf.Clamp(-angle, -42, 42), 0, 0);float currentDist = Vector3.Distance(GameObject.transform.position, target);//Debug.Log("****************************");//Debug.Log(startX);//Debug.Log(target);//Debug.Log("****************************");GameObject.transform.Translate(Vector3.forward * Mathf.Min(speed * Time.deltaTime, currentDist));if (this.Transform.position == target) {sceneControler.scoreRecorder.miss();Debug.Log("here in miss!!");GameObject.SetActive(false);GameObject.transform.position = new Vector3(startX, 0, 0);sceneControler.factory.freeDisk(GameObject);this.destroy = true;this.Callback.ActionDone(this);}} }

我們在Start函數(shù)中保證了飛碟出現(xiàn)的位置和目標(biāo)方向的隨機(jī)性。然后在Update函數(shù)中首先計算移動的角度,然后根據(jù)速度給出當(dāng)前的位移,然后進(jìn)行一次判斷,如果當(dāng)前位置已經(jīng)是終點(diǎn)了,那么我們首先setActive告訴外層的actionManager之前的運(yùn)動可以取消了,然后將當(dāng)前的實(shí)例free掉。在Update函數(shù)開始返回前也需要設(shè)置一下destroy是為了在hit后也可以告訴actionManager取消當(dāng)前運(yùn)動,與后面那個并不是重復(fù)操作。

最后我們來看一眼actionControl的核心ActionMananger,其他的就不全部貼上來了。

public class ActionManager : SSActionManager {public FirstController sceneController;public DiskFactory diskFactory;public RecordController scoreRecorder;public Emit EmitDisk;public GameObject Disk;int count = 0;protected void Start() {sceneController = (FirstController)Director.getInstance().sceneCtrl;diskFactory = sceneController.factory;scoreRecorder = sceneController.scoreRecorder;sceneController.MyActionManager = this;}protected new void Update() {if (sceneController.user.round <= 3 && sceneController.user.game == 0) {count++;if (count == 60 * sceneController.user.round) {playDisk(sceneController.user.round);sceneController.user.num++;count = 0;}base.Update();}}public void playDisk(int round) {EmitDisk = Emit.GetSSAction();Disk = diskFactory.getDisk(round);this.AddAction(Disk, EmitDisk, this);Disk.GetComponent<DiskController>().action = EmitDisk;}}

Update實(shí)現(xiàn)了每60幀*round后發(fā)出一個飛碟。之所以這樣設(shè)計是因?yàn)樽詈笠惠喌娘w碟速度太快,這樣能夠適當(dāng)降低游戲難度。playDisk函數(shù)就是從工廠中獲取一個飛碟,然后和下一個應(yīng)該出現(xiàn)的飛碟的移動方向和特征一起傳給AcitionManager。

另外為了有空戰(zhàn)的感覺,我還加入了在AssetStore下載的StarField天空盒,最終的效果如下圖所示。

總結(jié)

以上是生活随笔為你收集整理的【游戏开发】unity教程4 打飞碟小游戏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。