Unity3D移動平臺簡單實現
在電子遊戲中移動平臺可謂是十分常見的,如平臺從一處至另一處的來回移動,或當需要玩家觸發機關時,平臺浮動並按一定的路線移動至目標處。本文主要是在Unity3D引擎下使用少量指令碼實現兩點之間來回移動平臺的最基本功能,是一種比較簡單且好理解的移動平臺解決方案。
涉及到的點如下:
- 平臺物件的實現
- 平臺移動路線的設定
- 處於平臺上游戲物件(如:玩家)的相對運動
建立平臺控制物件
建立一個空物件,命名為PlatformObject,保證其transform.scale為預設值(1,1,1),為其新增Box Collider元件,Is Trigger設為True,新增一個指令碼,命名為PlatformController.cs,需要提出的是,該物件不是平臺的實體,而是主要用於控制平臺實體的移動和實現相對運動。
建立平臺實體物件
使用方塊構建平臺的外形,在物件PlatformObject下新建一個cube子物件,命名為Platform,該子物件才是平臺的實體,並適當的設定cube的transform.scale屬性,調整方塊的長寬高,併為其新增一個Box Collider元件,平臺的其他屬性可自行設定。
如下:
設定父物件的Box Collider的size與子物件的scale一致,藉此來保證父物件的碰撞範圍與平臺實體的大小一致。
實現平臺控制
編輯PlatformController.cs指令碼,以下程式碼主要實現:平臺在兩點之間來回移動並在到達兩點時適當停留的功能,以及保證平臺上的其他遊戲物件相對於平臺運動的功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 來回移動平臺的控制
/// </summary>
public class PlatformController : MonoBehaviour {
[Tooltip("平臺移動的結束位置")]
public Vector3 stopPosiiton;
[Tooltip("平臺移動一次的時間")]
public float moveTime = 1f;
[Tooltip("平臺到邊界後的停留時間" )]
public float stayTime = 1f;
private bool toStop = true; // 是否朝結束位置移動
private float speed; // 移動的速度
private Vector3 startPostion; // 開始位置
internal bool on = false; // 平臺移動開關,是否允許平臺移動
void Start() {
startPostion = transform.position;
speed = Vector3.Distance(transform.position, stopPosiiton) / moveTime;
}
void Update(){
PlatformMoveOn(on);
}
/// <summary>
/// 平臺移動控制
/// </summary>
/// <param name="on">平臺移動開關</param>
void PlatformMoveOn(bool on){
if(!on){return;}
StartCoroutine(PlatformMove(stopPosiiton));
}
/// <summary>
/// 具體平臺移動控制
/// </summary>
/// <param name="stopPosiiton">停止位置</param>
/// <returns></returns>
IEnumerator PlatformMove( Vector3 stopPosiiton){
Vector3 tempPosition = transform.position;
if (toStop){
tempPosition = Vector3.MoveTowards(tempPosition, stopPosiiton, speed*Time.deltaTime);
transform.position = tempPosition;
if (transform.position == stopPosiiton){
yield return new WaitForSeconds(stayTime);
toStop = false;
}
}
else if (!toStop){
tempPosition = Vector3.MoveTowards(tempPosition, startPostion, speed*Time.deltaTime);
transform.position = tempPosition;
if (transform.position == startPostion){
yield return new WaitForSeconds(stayTime);
toStop = true;
}
}
}
// 相對運動
void OnTriggerEnter(Collider other){
other.transform.SetParent(transform);
}
void OnTriggerExit(Collider other){
other.transform.SetParent(null);
}
// 便於除錯
void OnDrawGizmosSelected() {
Gizmos.color = Color.red;
Gizmos.DrawWireCube(stopPosiiton, transform.GetChild(0).localScale);
}
}
相對運動注意點
本解決方案通過將物件Platform即平臺實體作為物件PlatformObject的子物件,並使用指令碼控制PlatformObject物件來間接控制平臺實體的移動,但是處於平臺上的其他遊戲物件相對於平臺進行移動的功能與平臺實體是無關的,可以理解為Platform物件是平臺的外形,而平臺的功能核心(移動、相對運動)是父物件PlatfomrObject。在以上指令碼中有兩個Trigger方法;
void OnTriggerEnter(Collider other){
other.transform.SetParent(transform);
}
void OnTriggerExit(Collider other){
other.transform.SetParent(null);
}
一個是當其他遊戲物件進入物件PlatformObject的碰撞體時該物件則作為PlatformObject的子物件,當該物件脫離PlatformObject的碰撞體時則將其與PlatformObject的父子關係解除。即通過設定父子關係(SetParent()
)來實現平臺上其他物件相對於平臺進行相對運動。至此,平臺移動的基本功能均已實現。
但是,需要注意的是,不能通過改變父物件的transform來改變平臺的外形,且一定要保證父物件的scale為(1,1,1),為什麼?因為,這是通過設定父子關係(SetParent()
)實現平臺上其他物件相對於平臺進行運動的關鍵,當父物件scale不是(1,1,1)時,其他物件進入平臺碰撞時,其sacle會根據父物件的scale發生相應的變化,這就導致其他物件的變形。
題外話:實際上,在進行正式開發時,應該儘量保證物件的scale為(1,1,1),而物件外形的具體大小則應該在建模時就要考慮到,Unity3D官方文件也有提到這一點importance of scale & use the right size。