Related Posts Plugin for WordPress, Blogger...

2-1 Using Gizmos To Visualise Code

本章使用Unity提供的Gizmos工具來視覺化Code,比方說我們要製作一個點擊敵人後,人物會移動敵人前幾公尺的距離,好讓玩家可以放出範圍技之類的功能。撰寫這項功能時,我們可以用Gizmos工具輔助我們從視覺化看出效果如何,如下圖這樣。


我們使用兩個變數walkMoveStopRadius、attackMoveStopRadius,分別控制人物移動的停止點與點擊敵人的停止點,如上圖標示人物在敵人(紅色球球)前一段距離停下來,紅色虛線框繪製出停止的範圍,可以想像成發動範圍技的適合範圍。

以下完整程式碼跟註解。


using System;
using UnityEngine;
using UnityStandardAssets.Characters.ThirdPerson;

[RequireComponent(typeof (ThirdPersonCharacter))]
public class PlayerMovement : MonoBehaviour
{
 [SerializeField] float walkMoveStopRadius = 0.2f;
 [SerializeField] float attackMoveStopRadius = 5f;

 ThirdPersonCharacter theThirdPersonCharacter;   // A reference to the ThirdPersonCharacter on the object
    CameraRaycaster cameraRaycaster;
 Vector3 currentDestination, clickPoint;
        
 bool isInDircetMode = false;

    private void Start()
    {
        cameraRaycaster = Camera.main.GetComponent();
        theThirdPersonCharacter = GetComponent();
        currentDestination = transform.position;
    }

    // Fixed update is called in sync with physics
    private void FixedUpdate()
    {
  if(Input.GetKeyDown(KeyCode.G)){
   //切換GamePad Mode
   isInDircetMode = !isInDircetMode;
   //解決Gamepad模式切換時,人物角色會自動回到上一個滑鼠點擊位置的Bug
   currentDestination = transform.position;
  }

  if (isInDircetMode) {
   ProcessDirectMovement ();
  } else {
   ProcessMouseMovement ();
  }

    }

 private void ProcessDirectMovement(){
  // read inputs
  float h = Input.GetAxis("Horizontal");
  float v = Input.GetAxis("Vertical");

  // calculate camera relative direction to move:
  Vector3 cameraForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
  Vector3 movement = v*cameraForward + h*Camera.main.transform.right;

  theThirdPersonCharacter.Move(movement, false, false);
 }

 private void ProcessMouseMovement(){
  if (Input.GetMouseButton(0))
  {
   //print("Cursor raycast hit" + cameraRaycaster.currentLayerHit);
   clickPoint = cameraRaycaster.hit.point;
   switch (cameraRaycaster.currentLayerHit) {
   case Layer.Walkable:
    //取得滑鼠點擊到的物件的位置
    currentDestination = ShortDestination (clickPoint, walkMoveStopRadius);
    break;
   case Layer.Enemy:
    currentDestination = ShortDestination (clickPoint, attackMoveStopRadius);
    print ("Not moving to enemy.");
    break;
   default:
    print ("Unexpected layer found.");
    break;
   }
  }
  WalkToDestination ();
 }

 private void WalkToDestination(){
  //將點擊到的物件位置減去自己的位置,取得相減後的向量
  Vector3 playerToClickPoint = currentDestination - transform.position;
  //計算該向量的距離,若距離太短,就不要移動了(可避免人物角色原地移動)
  if (playerToClickPoint.magnitude >= 0) { //TODO  設為0導致原本角色原地移動的Bug又出現了
   //告知ThirdPersonCharacter物件依向量移動,後面兩個false分別為蹲下和跳躍
   theThirdPersonCharacter.Move(playerToClickPoint, false, false);
  } else {
   theThirdPersonCharacter.Move(Vector3.zero, false, false);
  }
 }

 Vector3 ShortDestination(Vector3 destination, float shortening){
  //將滑鼠點擊的位置減去自己所在的位置後,normalized取得單位向量,保持向量方向不變長度為1後
  //再乘以shortening亦即要縮短幾倍的乘量,故reductionVector會變為移動至該位置方向且縮短指定倍率的Vector
  Vector3 reductionVector = (destination - transform.position).normalized * shortening;
  //將滑鼠點擊位置減去reductionVector,就會得到一個縮短距離後的Vector
  return destination - reductionVector;
 }

 void OnDrawGizmos(){
  //繪製移動路徑
  Gizmos.color = Color.black;
  Gizmos.DrawLine (transform.position, clickPoint);
  Gizmos.DrawSphere (currentDestination, 0.15f);
  Gizmos.DrawSphere (clickPoint, 0.1f);

  //繪製攻擊範圍
  Gizmos.color = new Color(255f, 0f, 0f, 0.5f);
  Gizmos.DrawWireSphere (transform.position, attackMoveStopRadius);
 }
}


留言