一、游戲內容要求:
- 游戲有 n 個 round,每個 round 都包括10 次 trial;
- 每個 trial 的飛碟的色彩、大小、發射位置、速度、角度、同時出現的個數都可能不同。它們由該 round 的 ruler 控制;
- 每個 trial 的飛碟有隨機性,總體難度隨 round 上升;
- 鼠標點中得分,得分規則按色彩、大小、速度不同計算,規則可自由設定。
二、游戲的要求:
- 使用帶緩存的工廠模式管理不同飛碟的生產與回收,該工廠必須是場景單實例的!
- 使用 MVC 結構實現人機交互與游戲模型分離
三、游戲的實現
之前的幾個博客已經構建好了一個較為完整的MVC框架,這里可以套用之前的框架。看上面的UML圖就能了解到
游戲結構和上一個游戲基本沒有不同,僅僅添加了一個飛碟工廠!!!
其實不加這個也可以實現這一個游戲,但是為什么要加上這個飛碟工廠呢?
這是因為加上對象的構建和銷毀都是很耗資源的,這個工廠能夠讓我們有效的利用已經構造好的游戲對象來實現資源的重利用,從而減少資源開銷
那么,先看看這個工廠是如何實現的:
using System.Collections.Generic;
using UnityEngine;
public class DiskFactory : MonoBehaviour {
public List<GameObject> used =
new List<GameObject>();
public List<GameObject>
free =
new List<GameObject>();
void Start () { }
public void GenDisk(){GameObject disk;
if(
free.Count ==
0){disk = Instantiate<GameObject>(Resources.Load<GameObject>(
"Prefabs/Disk"), Vector3.zero, Quaternion.identity);}
else{disk =
free[
0];
free.RemoveAt(
0);}
float x = Random.Range(-
10.0f,
10.0f);disk.transform.position =
new Vector3(x,
0,
0);disk.transform.Rotate(
new Vector3(x <
0? -x*
9 : x*
9,
0,
0));
float r = Random.Range(
0f,
1f);
float g = Random.Range(
0f,
1f);
float b = Random.Range(
0f,
1f);Color color =
new Color(r, g, b);disk.transform.GetComponent<Renderer>().material.color = color;used.Add(disk);}
public void RecycleDisk(GameObject obj){obj.transform.position = Vector3.zero;
free.Add(obj);}
}
這里的used和free分別表示已經在使用的和未被利用的飛碟對象,如果free的列表為空,而我們有需要它,這時才創建新的對象,不然,就用之前的。好了,這就是飛碟工廠,然后我們看場景控制器如何利用這個工廠。
using UnityEngine;
using UnityEngine.SceneManagement;
public class FirstSceneController : MonoBehaviour, IUserAction, ISceneController{
public CCActionManager actionManager;
public GameObject disk;
protected DiskFactory df;
public int flag =
0;
private float interval =
3;
public int score =
0;
public static int times =
0;
private void Awake(){SSDirector director = SSDirector.getInstance();director.setFPS(
60);director.currentSceneController =
this;
this.gameObject.AddComponent<DiskFactory>();
this.gameObject.AddComponent<CCActionManager>();
this.gameObject.AddComponent<UserGUI>();df = Singleton<DiskFactory>.Instance;}
private void Start(){}
public void GenGameObjects (){}
public void Restart(){SceneManager.LoadScene(
"1");}
public void Pause (){actionManager.Pause();}
public void Update(){
if (times <
30 && flag ==
0){
if (interval <=
0){interval = Random.Range(
3,
5);times++;df.GenDisk();}interval -= Time.deltaTime;}}
}
場景控制器是需要重寫的一個類,因為它是游戲對象生成的,顯然之前的場景控制器在這里完全用不上當然由于之前MVC架構的分離作用,這里也僅需要改Awake,Update,GenGameObject這三個函數和各種變量。
然后動作管理器是需要重寫動作的,而動作在這里需要的改動較小,只需要改MoveToAction就行了,不過為了更好的控制飛碟,這里的動作將變成一個列表,這是為了能夠同時控制多個飛碟在游戲中飛行。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCActionManager : SSActionManager, ISSActionCallback {
public FirstSceneController sceneController;
public List<CCMoveToAction> seq =
new List<CCMoveToAction>();
public UserClickAction userClickAction;
public DiskFactory disks;
protected new void Start(){sceneController = (FirstSceneController)SSDirector.getInstance().currentSceneController;sceneController.actionManager =
this;disks = Singleton<DiskFactory>.Instance;}
protected new void Update(){
if(disks.used.Count >
0){GameObject disk = disks.used[
0];
float x = Random.Range(-
10,
10);CCMoveToAction moveToAction = CCMoveToAction.GetSSAction(
new Vector3(x,
12,
0),
3 * (Mathf.CeilToInt(FirstSceneController.times /
10) +
1) * Time.deltaTime);seq.Add(moveToAction);
this.RunAction(disk, moveToAction,
this);disks.used.RemoveAt(
0);}
if (Input.GetMouseButtonDown(
0) && sceneController.flag ==
0){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hitGameObject;
if (Physics.Raycast(ray,
out hitGameObject)){GameObject gameObject = hitGameObject.collider.gameObject;
if (gameObject.tag ==
"disk"){
foreach(
var k
in seq){
if (k.gameObject == gameObject)k.transform.position = k.target;}userClickAction = UserClickAction.GetSSAction();
this.RunAction(gameObject, userClickAction,
this);}}}
base.Update();}
public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed,
int intParam =
0,
string strParam =
null, Object objParam =
null){disks.RecycleDisk(source.gameObject);seq.Remove(source
as CCMoveToAction);source.destory =
true;
if (FirstSceneController.times >=
30)sceneController.flag =
1;}
public void CheckEvent(SSAction source, SSActionEventType events = SSActionEventType.Completed,
int intParam =
0,
string strParam =
null, Object objParam =
null){}
public void Pause(){
if(sceneController.flag ==
0){
foreach (
var k
in seq){k.enable =
false;}sceneController.flag =
2;}
else if(sceneController.flag ==
2){
foreach (
var k
in seq){k.enable =
true;}sceneController.flag =
0;}}
}
這里需要改動的也只有那幾個函數:Update,SSActionEvent,Pause函數,另外幾個類的改動更小,基本就改了一兩行代碼,在這里就不說了。如果對那些改動感興趣的話,可以去文章末尾的鏈接看看。
下面說說用戶GUI:
using UnityEnginepublic class UserGUI : MonoBehaviour {private FirstSceneController actionprivate GUIStyle fontstyle1 = new GUIStyle()// Use this for initializationvoid Start () {action = SSDirector
.getInstance()
.currentSceneController as FirstSceneControllerfontstyle1
.fontSize =
50}// Update is called once per frameprivate void OnGUI(){if (GUI
.Button(new Rect(
0,
80,
80,
60),
"RESTART")){action
.Restart()}if (GUI
.Button(new Rect(
0,
160,
80,
60),
"Pause")){action
.Pause()}if (action
.flag ==
0){fontstyle1
.normal.textColor = Color
.greenGUI
.Label(new Rect(Screen
.width /
2 -
150,
0,
300,
100),
"Score: " +action
.score +
", Round: " + (Mathf
.CeilToInt(FirstSceneController
.times /
10) +
1), fontstyle1)}else if (action
.flag ==
1){fontstyle1
.normal.textColor = Color
.redGUI
.Label(new Rect(Screen
.width /
2 -
150,
0,
300,
100),
"Your score is : " + action
.score, fontstyle1)}else{fontstyle1
.normal.textColor = Color
.greenGUI
.Label(new Rect(Screen
.width /
2 -
150,
0,
300,
100),
"Score: " +action
.score +
", Round: " + (Mathf
.CeilToInt(FirstSceneController
.times /
10) +
1), fontstyle1)fontstyle1
.normal.textColor = Color
.redGUI
.Label(new Rect(Screen
.width /
2 -
150, Screen
.height/
2-
50,
300,
100),
"Pause!", fontstyle1)}}
}
這本身就是一個很簡單的類,應該不難看懂,因此僅貼上代碼。游戲效果圖如下(沒下什么資源,所以界面有點難看)
更多更詳細的內容請戳:github
總結
以上是生活随笔為你收集整理的游戏开发之Unity学习(五)——鼠标打飞碟(Hit UFO)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。