工程理解
本游戲為通過鍵盤上的W、A、S、D鍵控制小球的運動軌跡來對固定位置上的小方塊進(jìn)行碰撞,以此來進(jìn)行加分計數(shù)的。
其中主要對象為小球和自轉(zhuǎn)的小方塊;在小球上,我們添加剛體和碰撞盒組件。剛體用于模擬真實的物理運動,碰撞盒子則用于與后面的方塊進(jìn)行碰撞檢測。
效果展示


核心代碼
一、移動功能
用unity自帶的Input.GetAxis("")函數(shù),Horizontal代表鍵盤的左右鍵(A和D鍵);Vertical代表鍵盤的上下鍵(W和S鍵)。然后用AddForce給予小球一個外力使其按照相應(yīng)的方向動起來。
//通過鍵盤控制小球移動
private void FixedUpdate()
{
var moveHorizontal = Input.GetAxis("Horizontal"); //水平方向
var moveVertical = Input.GetAxis("Vertical");//垂直方向
var movement = new Vector3(moveHorizontal, 0, moveVertical);
//Vector3三維向量
m_Rigidbody.AddForce(movement * Speed);
//Speed 為速度 通過movement和Speed來控制小球的方向和速度
}
二、計數(shù)功能
定義了一個m_Count變量來計數(shù)小球碰到方塊的個數(shù);
并通過
GameObject.Destroy(other.gameObject);語句,來對已經(jīng)計數(shù)的方塊進(jìn)行銷毀處理;(我們給方塊修改標(biāo)簽”Tag”,如果小球碰撞的物體標(biāo)簽是方塊的標(biāo)簽名,我們則銷毀此方塊并讓分?jǐn)?shù)加一)調(diào)用
SetCountText();函數(shù),將計數(shù)傳給UI進(jìn)行顯示。
//計數(shù)功能
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Pick Up"))
{
GameObject.Destroy(other.gameObject);//銷毀已記數(shù)方塊
m_Count++;//計數(shù)
SetCountText();//調(diào)用函數(shù),將個數(shù)傳給UI進(jìn)行顯示
}
}
三、UI顯示功能
將計數(shù)功能所記的數(shù)目傳遞過來,通過
CountText.text = m_Count.ToString();//計數(shù)UI顯示語句,將所計數(shù)目通過UI顯示,其中CountText.text為UI計數(shù)的變量。當(dāng)所有小方塊都被碰撞到時,即m_Count >= 8(我這里給的小方塊個數(shù)為8個),輸出游戲成功信息,并儲存在WinText.text中。
private void SetCountText()
{
CountText.text = m_Count.ToString();//計數(shù)UI顯示
if (m_Count >= 8)
{
WinText.text = "You Win!";//成功提示
}
}



改進(jìn)——框架
由于,假設(shè)將小方塊個數(shù)改為10個,則:
顯示得分的UI是寫在一起的,當(dāng)修改相對應(yīng)的限制條件時,會受到牽連
判定輸贏的邏輯也會受到牽連
顯示輸贏結(jié)算UI邏輯也在一起,也會受到牽連
所以利用框架進(jìn)行改進(jìn)
在框架中,
Player:負(fù)責(zé)接收玩家輸入并響應(yīng)角色移動;當(dāng)碰撞到小方塊時,通知Game Mode
Game Mode:對全局的游戲規(guī)則、玩法、計分等內(nèi)容進(jìn)行處理;在Player控制器通知Game Mode碰撞到小方塊后,Game Mode進(jìn)行對應(yīng)的計分和輸贏判斷等操作
小方塊:在游戲啟動時把自己的存在告知Game Mode;這樣一來,Game Mode就完全直到當(dāng)前場上有多少個小方塊,就可以動態(tài)的根據(jù)場上方塊數(shù)量來判斷輸贏,而不會在代碼中寫死邏輯了。
相關(guān)代碼:
PickupComponent:
public class PickupComponent : MonoBehaviour
{
// Start is called before the first frame update
private void Start()
{
//把自己注冊到GameMode
GameMode.Instance.RegisterPickUp(this);
}
}
PlayerController控制器:
public class PlayerController : MonoBehaviour
{
public float Speed;
private Rigidbody m_Rigidbody;
private void Start()
{
m_Rigidbody = this.GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
var moveHorizontal = Input.GetAxis("Horizontal");
var moveVertical = Input.GetAxis("Vertical");
var movement = new Vector3(moveHorizontal, 0, moveVertical);
m_Rigidbody.AddForce(movement * Speed);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Pick Up"))
{
var pickupComponent = other.gameObject.GetComponent<PickupComponent>();
if (pickupComponent == null)
{
Debug.LogError("有一個Tag是Pickup的GameObject,卻沒有掛載Pickup相關(guān)組件");
}
GameMode.Instance.PlayerEnterPickup(pickupComponent);
}
}
}
GameMode,統(tǒng)一管理游戲的玩法、得分判定、輸贏結(jié)果等內(nèi)容的類:
public class GameMode : MonoBehaviour
{
public static GameMode Instance { get; private set; }
[Header("計分Text")]
public Text CountText;
[Header("顯示W(wǎng)in的文本")]
public Text WinText;
private readonly List<PickupComponent> m_Pickups = new List<PickupComponent>();
private int _count;
private int m_Count
{
get => _count;
set
{
_count = value;
if (CountText != null)
{
CountText.text = value.ToString();
}
}
}
private void Awake()
{
if (Instance == null)
Instance = this;
}
public void RegisterPickUp(PickupComponent pickup)
{
m_Pickups.Add(pickup);
}
public void PlayerEnterPickup(PickupComponent pickup)
{
m_Pickups.Remove(pickup);
GameObject.Destroy(pickup.gameObject);
m_Count++;
if (m_Pickups.Count <= 0)
{
WinText.text = "You Win!";
}
}
private void Start()
{
WinText.text = string.Empty;
m_Count = 0;
}
private void Update()
{
if (m_Pickups.Count > 0)
{
var rotateValue = new Vector3(15, 30, 45) * Time.deltaTime;
foreach (var pickup in m_Pickups)
{
pickup.transform.Rotate(rotateValue);
}
}
}
}