3D遊戲:五、與遊戲世界互動
編寫一個簡單的滑鼠打飛碟(Hit UFO)遊戲
遊戲內容要求:
- 遊戲有 n 個 round,每個 round 都包括10 次 trial;
- 每個 trial 的飛碟的色彩、大小、發射位置、速度、角度、同時出現的個數都可能不同。它們由該 round 的 ruler 控制;
- 每個 trial 的飛碟有隨機性,總體難度隨 round 上升;
- 滑鼠點中得分,得分規則按色彩、大小、速度不同計算,規則可自由設定。
遊戲的要求:
- 使用帶快取的工廠模式管理不同飛碟的生產與回收,該工廠必須是場景單例項的!具體實現見參考資源 Singleton 模板類
- 儘可能使用前面 MVC 結構實現人機互動與遊戲模型分離
UML:
虛擬碼:
getDisk(ruler)
BEGIN
IF (free list has disk) THEN
a_disk = remove one from list
ELSE
a_disk = clone from Prefabs
ENDIF
Set DiskData of a_disk with the ruler
Add a_disk to used list
Return a_disk
END
FreeDisk(disk)
BEGIN
Find disk in used list
IF (not found) THEN THROW exception
Move disk from used to free list
END
程式碼實現:
- DiskData:包括射擊飛碟的得分、飛碟顏色、初始的位置、大小。
public class DiskData : MonoBehaviour{
public int score = 1;
public Color color = Color.white;
public Vector3 direction;
public Vector3 scale = new Vector3( 1 ,0.25f, 1);
}
- 飛碟管理員DiskFactory:負責接收SSDirector的請求,使用模板模式根據預製和規則製作飛碟、回收飛碟。
維護兩個List,分別儲存正在使用的飛碟和空閒的飛碟:
public GameObject disk_prefab = null; //飛碟預製體
private List<DiskData> used = new List<DiskData>(); //正在被使用的飛碟列表
private List<DiskData> free = new List<DiskData>(); //空閒的飛碟列表
GetDisk:根據規則在空閒列表中選擇飛碟,若空閒列表中沒有要選擇的飛碟,則重新例項化飛碟。
public GameObject GetDisk(int round){
int choice = 0;
int scope1 = 1, scope2 = 4, scope3 = 7; //隨機的範圍
float start_y = -10f; //剛例項化時的飛碟的豎直位置
string name;
disk_prefab = null;
//根據回合,隨機選擇要飛出的飛碟
if (round == 1) choice = Random.Range(0, scope1);
else if(round == 2) choice = Random.Range(0, scope2);
else choice = Random.Range(0, scope3);
//將要選擇的飛碟的name
if(choice <= scope1) name = "disk1";
else if(choice <= scope2 && choice > scope1) name = "disk2";
else name = "disk3";
//尋找相同name的空閒飛碟
for(int i=0;i<free.Count;i++) if(free[i].name == name){
disk_prefab = free[i].gameObject;
free.Remove(free[i]);
break;
}
//如果空閒列表中沒有,則重新例項化飛碟
if(disk_prefab == null){
if (name == "disk1") disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk1"), new Vector3(0, start_y, 0), Quaternion.identity);
else if (name == "disk2") disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk2"), new Vector3(0, start_y, 0), Quaternion.identity);
else disk_prefab = Instantiate(Resources.Load<GameObject>("Prefabs/disk3"), new Vector3(0, start_y, 0), Quaternion.identity);
//給新例項化的飛碟賦予其他屬性
float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;
disk_prefab.GetComponent<Renderer>().material.color = disk_prefab.GetComponent<DiskData>().color;
disk_prefab.GetComponent<DiskData>().direction = new Vector3(ran_x, start_y, 0);
disk_prefab.transform.localScale = disk_prefab.GetComponent<DiskData>().scale;
}
//新增到使用列表中
used.Add(disk_prefab.GetComponent<DiskData>());
return disk_prefab;
}
FreeDisk:回收飛碟。
public void FreeDisk(GameObject disk){
for(int i = 0;i < used.Count; i++) if (disk.GetInstanceID() == used[i].gameObject.GetInstanceID()){
used[i].gameObject.SetActive(false);
free.Add(used[i]);
used.Remove(used[i]);
break;
}
}
- Singleton.cs
ublic 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;
}
}
}
- 記分員ScoreRecorder:start初始化分數為0,每擊落一個飛碟加上對應的分數,重新開始時重置分數。
public class ScoreRecorder : MonoBehaviour{
public int score; //分數
void Start (){
score = 0;
}
//記錄分數
public void Record(GameObject disk){
int temp = disk.GetComponent<DiskData>().score;
score = temp + score;
}
//重置分數
public void Reset(){
score = 0;
}
}
- FlyDisk:丟擲飛碟,繼承SSAction實現。
public static UFOFlyAction GetSSAction(Vector3 direction, float angle, float power){
//初始化物體將要運動的初速度向量
UFOFlyAction action = CreateInstance<UFOFlyAction>();
if (direction.x == -1) action.start_vector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;
else action.start_vector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;
return action;
}
public override void Update(){
//計算物體的向下的速度,v=at
time += Time.fixedDeltaTime;
gravity_vector.y = gravity * time;
//位移模擬
transform.position += (start_vector + gravity_vector) * Time.fixedDeltaTime;
current_angle.z = Mathf.Atan((start_vector.y + gravity_vector.y) / start_vector.x) * Mathf.Rad2Deg;
transform.eulerAngles = current_angle;
//如果物體y座標小於-10,動作就做完了
if (this.transform.position.y < -10){
this.destroy = true;
this.callback.SSActionEvent(this);
}
}
執行結果:
擊中爆炸效果:
生命值為0時,遊戲結束:
相關文章
- 與遊戲世界互動-作業與練習(5)遊戲
- 設計的藝術(二):遊戲與遊戲性與互動藝術遊戲
- “遊戲中的遊戲世界”——遊戲副本的起源與發展史遊戲
- 3D遊戲的照明設計理論(四):如何在遊戲引擎中照亮遊戲世界3D遊戲引擎
- 談遊戲世界互動設計帶來的「意外之喜」遊戲
- 【遊戲互動】手遊適配設計遊戲
- cocos creator 視訊互動遊戲遊戲
- 遊戲UX互動框架規範遊戲UX框架
- 敘事:遊戲中角色與劇情的互動遊戲
- 遊戲與遊戲引擎遊戲引擎
- 3D遊戲-作業三-空間與運動3D遊戲
- 沉浸式互動讓遊戲更加迷人遊戲
- “直播+遊戲”語音房互動玩法遊戲
- 007 Web Assembly康威遊戲新增互動Web遊戲
- 3D遊戲程式設計與設計4——遊戲物件與圖形基礎3D遊戲程式設計物件
- 悠遊世界合成遊戲系統技術開發解析/合成遊戲/小遊戲遊戲
- 從業者談互動式故事遊戲的五個核心內容遊戲
- 遊戲論·現實的媒介:MOBA遊戲與一個世界的症狀遊戲
- 遊戲文件與遊戲設計遊戲設計
- 《淡夜未央》:互動敘事遊戲如何提升玩家參與感和互動性?遊戲
- 結構:遊戲核心玩法互動之“骨”遊戲
- 互動內容的遊戲化“升級”遊戲
- 互動答題小遊戲怎麼做?遊戲
- 淺談遊戲中的互動敘事遊戲
- 探究藍海市場—First part:互動遊戲遊戲
- 悠遊世界/遊戲/系統技術開發/悠遊世界養成遊戲開發解析遊戲開發
- 遊戲成就係統簡述及互動劇遊戲如何設計成就係統遊戲
- 遊戲中的叢林法則 | 互動遊戲展即將在京開幕遊戲
- 多益網路唐憶魯:推動遊戲與新科技、文化融合 用遊戲點亮世界遊戲
- 出海遊戲與“外來”遊戲,如何立足遊戲市場遊戲
- 遊戲裡的中土世界遊戲
- 如何建立遊戲世界觀遊戲
- 驅動遊戲世界運轉的“心跳”:遊戲迴圈及實時模擬遊戲
- 幽冥世界鏈遊/闖關/系統開發/合成卡牌遊戲/幽冥世界遊戲玩法遊戲
- AI打遊戲-伍(遊戲,啟動!)AI遊戲
- 遊戲互動機制探究:是什麼影響了遊戲的流暢度?遊戲
- 微信互動小遊戲:有創意的抽獎小遊戲怎麼做?遊戲
- Phaser遊戲框架與HTML Dom元素之間的通訊互動遊戲框架HTML