1. 程式人生 > 實用技巧 >Unity3d實現滑鼠打飛碟(Hit UFO)遊戲

Unity3d實現滑鼠打飛碟(Hit UFO)遊戲

要求

1、編寫一個簡單的滑鼠打飛碟(Hit UFO)遊戲

  • 遊戲內容要求:
    1. 遊戲有 n 個 round,每個 round 都包括10 次 trial;
    2. 每個 trial 的飛碟的色彩、大小、發射位置、速度、角度、同時出現的個數都可能不同。它們由該 round 的 ruler 控制;
    3. 每個 trial 的飛碟有隨機性,總體難度隨 round 上升;
    4. 滑鼠點中得分,得分規則按色彩、大小、速度不同計算,規則可自由設定。
  • 遊戲的要求:
    • 使用帶快取的工廠模式管理不同飛碟的生產與回收,該工廠必須是場景單例項的!具體實現見參考資源 Singleton 模板類
    • 近可能使用前面 MVC 結構實現人機互動與遊戲模型分離

如果你的使用工廠有疑問,參考:彈藥和敵人:減少,重用和再利用;參考:Unity物件池(Object Pooling)理解與簡單應用程式碼質量較低,比較凌亂

具體程式碼請參考我的gitee

https://gitee.com/woodx9/unity-3D-homework/tree/master/HItUFO

執行效果圖

完整圖(上面沒有把分數GUI錄入)

因為熟練運用了上次牧師與魔鬼的框架,所以僅僅用一天時間就把打飛碟做出來了

設計:

1. 飛碟自身會旋轉,加上附加的圖片有漂亮的星星,所以有風火輪的既視感

2. 飛碟的總數量是20個,打死它們後,飛碟會重生

3. 當滑鼠打掉飛碟後,飛碟會往下掉,而且玩家會獲得加分,分數為飛碟到攝像頭的距離

4. 飛碟的執行軌跡,它們的軌跡一定會經過,Z為50,25, 10,5的垂直與Z平面的隨機點(這個隨機點大概率在攝像頭視野內)

5.隨著分數的升高,飛碟的速度會越來越快

部署:

攝像頭掛載

飛碟掛載

程式碼淺析:

飛碟運動 程式碼在CCActionManager.cs

public void UFOToDestination(int num)
    {
        GameObject obj = sceneController.goList[num];
        obj.transform.position = new Vector3(Random.Range(-1 * 100 / 2, 100 / 2), Random.Range(-1 * 100 / 2, 100 / 2), 100);
        CCSequenceAction css = CCSequenceAction.GetSSAction(1, 0, new List<SSAction> {shakeTheDestination(50), shakeTheDestination(25), shakeTheDestination(10), shakeTheDestination(5)});
        //改變 goList_usedAndFree[i] = 1;
        sceneController.goList_usedAndFree[num] = 1;
        this.RunAction(obj, css, this);
    }

    public CCMoveToAction shakeTheDestination(int positionZ)
    {
        return CCMoveToAction.GetSSAction(new Vector3(Random.Range(-1 * positionZ/2 , positionZ/2), Random.Range(-1* positionZ/2, positionZ/2), positionZ), SSDirector.getInstance().GetCreditCount() / 300 + 10); 
    }

輸入num是指定飛碟的序號,然後會給飛碟指定一連串隨機的目的地

// UFO墜落
    public void UFODrop(int num)
    {
        GameObject obj = sceneController.goList[num];
        CCMoveToAction ccma = CCMoveToAction.GetSSAction(new Vector3(obj.transform.position.x, -100, obj.transform.position.z), 50);
        this.RunAction(obj, ccma, this);
    }

如果飛碟被點選,會給飛碟指定向下掉的運動

//隱藏UFO
    public void hideUFO(int num)
    {
        GameObject go = sceneController.goList[num]; 
        go.transform.position = new Vector3(0, 0, -5);
    }

隱藏UFO,當飛碟不用時,可以把它藏在攝像頭的後面

檢測點選函式 PickUpObject.cs 掛載在攝像頭上

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;

public class PickupObject : MonoBehaviour
{

	public GameObject cam;

	// Update is called once per frame
	void Update()
	{
		if (Input.GetButtonDown("Fire1"))
		{
			Vector3 mp = Input.mousePosition; //get Screen Position

			//create ray, origin is camera, and direction to mousepoint
			Camera ca;
			if (cam != null) ca = cam.GetComponent<Camera>();
			else ca = Camera.main;

			Ray ray = ca.ScreenPointToRay(Input.mousePosition);

			//Return the ray's hit
			RaycastHit hit;
			if (Physics.Raycast(ray, out hit))
			{
				//如果遊戲結束了就不能點選了
				if (SSDirector.getInstance().gameEnd) return;
				if (hit.collider.gameObject.tag.Contains("Finish"))
				{ //plane tag

				}
				GameObject parentGameObject = hit.transform.parent.gameObject;
				SSDirector ssdDirector = SSDirector.getInstance();
				// Debug.Log(parentGameObject.GetComponent<UFOController>().getNum()); 不能用這個確定UFO的index,原因未知
				// 計算得分 按距離相機位置算分數
				int credit = (int)Vector3.Distance(parentGameObject.transform.position, new Vector3(0, 1, 0));
				ssdDirector.AddCreditCount(credit);
				ssdDirector.ccam.UFODrop(ssdDirector.firstcontroller.getGameObjectIndex(parentGameObject.transform.position));
			}
		}
	}
}

如果檢測到點選,就計算得分,然後傳給SSDirector函式

然後指定UFO執行墜落函式

那麼如果UFO墜落之後,如何檢測到它墜落了並且回收呢?

在SSActionManager.cs中

foreach (int key in waitingDelete)
        {
           
            SSAction ac = actions[key];
            // 檢查是不是掉落的UFO,如果是的話Y軸高度低於-90,然後檢查actions中是否還有掉落UFO的運動,有的話就刪除它們的運動,然後把它們移動到隱藏位置
            // 如果不是掉落的UFO,則說明UFO已經到達指定位置,突圍成功,遊戲結束
            if (ac.transform.position.y < -50)
            {
                foreach (KeyValuePair<int, SSAction> kv in actions)
                {
                    SSAction t_ac = kv.Value;
                    if (t_ac != ac && ac.gameobject == t_ac.gameobject)
                    {
                        t_ac.destory = true;
                        //隱藏
                        SSDirector ssdDirector = SSDirector.getInstance();
                        ssdDirector.ccam.hideUFO(ssdDirector.firstcontroller.getGameObjectIndex(ac.transform.position));
                        ssdDirector.firstcontroller.goList_usedAndFree[ssdDirector.firstcontroller.getGameObjectIndex(ac.transform.position)] = 0;
                        

                    }
                }
            }
            //到達了最終位置
            else if (ac.transform.position.z <= 10)
            {
                //code 
                SSDirector ssdDirector = SSDirector.getInstance();
                ssdDirector.gameEnd = true;
            }

            actions.Remove(key);
            Destroy(ac);
        }

當檢測到飛碟墜落後,它還有一個運動還在執行,即原先設定的運動軌跡,因此要找到並刪除它。

如果有飛碟到了最終的位置,則通知SSDirector,結束遊戲

在FirstController.cs中,有一個變數

public List<int> goList_usedAndFree; //0代表飛碟空閒,1代表飛碟忙碌

這樣就可以檢測,飛碟是否在忙碌,如果不忙碌的話,就可以重生

// Update is called once per frame
    void Update()
    {
        for (int i = 0; i < goList_usedAndFree.Count; ++i)
        {
            if (goList_usedAndFree[i] == 0)
            {
                SSDirector.getInstance().ccam.UFOToDestination(i);
            }
        }
    }