1. 程式人生 > >Unity3D遊戲製作——人物移動邏輯

Unity3D遊戲製作——人物移動邏輯

Unity中移動某個遊戲物件有以下兩種方式:

·更改Transform元件的Position屬性;

·利用物理引擎(PhyX, Box2D)移動遊戲物件。

首先我們試著通過調整Transform元件的屬性實現遊戲物件的移動。在Unity的左手座標系中,+Z方向是前進,-Z方向就是後退。

Translate函式

Translate函式用於處理遊戲物件移動,函式原型如下                                                                                             

void Translate(Vector3 direction, [Space relativeTo]);

Vector3(x, y, z)是unity提供的用於儲存三維座標值和向量資料的結構體。當我們將向量單位乘以速度(movespeed),遊戲物件就會按照movespeed變數指定的速度移動。(這裡應該有圖片.jpg)

tr.Translate(移動方向 * 速度 * 前進/後退方向 * Time.deltaTime, 基準座標系);

Time.deltaTime表示前一幀到當前幀或非的時間,需要注意的是,Update函式內,使用Transform元件 是遊戲物件移動的邏輯必須乘以deltaTime,是遊戲物件的移動速度不受幀率的影響,而根據某個固定的速度移動。打個比方,如果沒有乘以Time.deltaTime,遊戲物件將每幀1個單位的速度移動;如果乘以Time.deltaTime,遊戲物件將以每秒1各單位的速度前進。除此之外,Translate函式的第二個引數能決定遊戲物件是以全域性座標還是區域性座標移動。

可以看到,使用Translate函式,我們可以輕鬆地實現遊戲物件的控制,但同時也發現,這樣“直來直去”的移動方式並不能很好的匹配較為複雜的地形,所以需要重力和碰撞。


Character Controller

為此,我們可以新增Character Controller元件。Character Controller不會對施加給它的作用力做出反應,也不會作用於其他的剛體。如果想讓Character Controller元件能夠作用於其他的剛體物件,可以通過指令碼[OnControllerColliderHit()函式]在與其相碰撞的物件上使用一個作用力。另外,如果想讓Character Controller受物理效果影響,那最好用剛體來代替它。


以下程式碼通過Character Controller元件實現了WSAD和空格鍵的人物移動控制。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.Utility;

public class PlayerMove : MonoBehaviour
{
    public GameObject anibody;
    public float speed = 6.0F;//移動速度
    public float jumpSpeed = 8.0F;//跳躍速度
    public float gravity = 20.0F;//重力加速度
    private Vector3 moveDirection = Vector3.zero;
    CharacterController controller;
    Quaternion ed;//四元數 方向
    public Transform camPivot;
    public Transform camDir;
    public Transform forwardstep;
    public Transform downstep;
    private Transform tr;

    private float h, v;

    private Vector3 currPos = Vector3.zero;
    private Quaternion currRot = Quaternion.identity;

    void Awake()
{
    ed = new Quaternion(0, 0, 0, 0);
    tr = GetComponent<Transform>();
   
    currPos = tr.position;
    currRot = tr.rotation;
}

    void Update()
{
    if (controller.isGrounded)//判斷人物是否在地面
    {
          moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));//獲取操作方向
          moveDirection = transform.TransformDirection(moveDirection);
          moveDirection *= speed;
          if (Input.GetKeyDown(KeyCode.Space))//跳躍
                moveDirection.y = jumpSpeed;
          moveDirection.y -= gravity * Time.deltaTime;
          controller.Move(moveDirection * Time.deltaTime);
     }
     else//跳躍狀態
     {
            moveDirection = new Vector3(Input.GetAxis("Horizontal") * speed, moveDirection.y, Input.GetAxis("Vertical") * speed);
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection.y -= gravity * Time.deltaTime;
            controller.Move(moveDirection * Time.deltaTime);
      }
}

這時我們發現,遊戲物件雖然可以移動,但其朝向始終不變而且沒有動作,就像恐怖片裡的場景(至少我覺得有點嚇人....)。關於動作我們可以先甩鍋美術,日後再說。但如果我希望角色在移動時,能始終面向前方,可以加上這樣一段程式碼:

if (Input.anyKey)
     {
            camDir = Camera.main.transform;//獲取攝像機位置資訊
            ed = camDir.rotation;//攝像機方向
            ed.x = 0;
            ed.z = 0;
            transform.rotation = Quaternion.Slerp(transform.rotation, ed, Time.deltaTime * 5.0f);//這裡用上了插值是為了使人物轉向自然過度
      }

這樣,遊戲物件的簡單控制就完成了。嗯,看起來不錯~

但使用Character Controller元件也會遇到一些小麻煩,比如說下坡的時候,isGrounded的判斷可能會出錯,這時我們可以用射線的方法檢測人物腳底與地面的距離作為另一個判斷條件,當然這個的實現就日後再說了。