iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0

在一些遊戲裡我們會希望讓某個物件可以移動,讓物件可以在環境中走動、跳躍。但如何實現該功能就是這邊要探討的,我們將會實現一個物件能夠自由的移動,以第一人稱的方式進行,我們也會學如何設定真實的重力,透過簡單的公式來實現,並且偵測該物件是否可以進行跳躍(是否在地面上)。今天會學習到非常多! 就讓我開始介紹。

場景建置

  1. 首先新增一個 PlayerVision 空白物件,並且新增一個 Character Controller。內部參數先調整好。

  2. 接著在Child 部分新增一個 Capsule後並且將其Collider刪除,注意到這邊要注意參數設定。

  3. 接下來就將我們的 Main Camera 設定到我們的PlayerPersonLook 的子物件上。

結果如下:

  1. 並且新增一個滑鼠控制的腳本MouseLook.cs 綁定在 Main Camera 上面。

滑鼠控制視角

  1. 我們執行時將該滑鼠的座標隱藏,若想顯示就按下 esc 滑鼠的箭頭就會出現。
Cursor.lockState = CursorLockMode.Locked;
  1. 首先撰寫該視角隨滑鼠改變的程式碼。 之前控制Camera 的涵義類似這邊就先不再說明。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseLook : MonoBehaviour
{

     public float mouseSensitive = 100f;
    public Transform playerBody;
    float xRotation = 0f;

    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
    }

    void Update()
    {
        // get the mouse move and mul the mouseSensitive
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitive * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitive * Time.deltaTime;
        
        // rotate pitch is x axis in unity
        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);              
        // The rotation of the transform relative to the transform rotation of the parent.
        transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
        
        // rotate  yaw is y axis in unity 
        playerBody.Rotate(Vector3.up * mouseX);

        
    }
   
}
  1. 撰寫完成後回到 Unity 將需要的物件拉入到 MouseLook 中,注意到該 PlayerBody 為 PlayerVision。

  2. 接下來就可以實現視角隨著滑鼠移動。

物件的移動

  1. 接著我們在 FirstPlayerPerson 撰寫一個新的文本,命名為PlayerMovement.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;
    public float speed = 12f;

    private void Update() {
        // get the w,a,s,d from the keyboard, Horizontal is a,d. Vertical is w,s
        float moveX = Input.GetAxis("Horizontal");
        float moveY = Input.GetAxis("Vertical");

        // get the new position from the movement axis
        Vector3 move = transform.right * moveX + transform.forward * moveY;

        // use controller to control the movement
        controller.Move(move * speed * Time.deltaTime);
    }
}
  1. 接下來就將Unity 中的設定放入,接下來把 Character Controller 中的 Step offset 設定成 0.7

  2. 採用重力的方式。所以需要新增程式碼來控制,我們知道說重力使該物件向下的力道為 deltaHeight += (-gravity) * deltaT^2,且移動為 Y軸方向,所以我們這邊新增一個公式。

Vector3 velocity;
public float gravity = -9.81f;

velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;
    public float speed = 12f;
    
    Vector3 velocity;
    public float gravity = -9.81f;

    private void Update() {
        // get the w,a,s,d from the keyboard, Horizontal is a,d. Vertical is w,s
        float moveX = Input.GetAxis("Horizontal");
        float moveY = Input.GetAxis("Vertical");

        // get the new position from the movement axis
        Vector3 move = transform.right * moveX + transform.forward * moveY;

        // use controller to control the movement
        controller.Move(move * speed * Time.deltaTime);


        // count the gravity, height -= gravity * t^2, and set to the y axis.
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}

這邊說明一下 Vertical, Horizontal 本身就是該鍵盤上 w,a,s,d 這邊我們會知道每個方向都是一個 數值,也就是正負關係,會回傳 1 或 -1。 接下來取得該數值後就可以乘上我們Vector 方向,Vector3.forward 向前向後,Vector3.right 向左向右。

float moveX = Input.GetAxis("Horizontal");
float moveY = Input.GetAxis("Vertical");

Vector3 move = transform.right * moveX + transform.forward * moveY;
  1. 回到場景後就可以開始移動物件。

確認是否接觸表面

  1. 接下來要去判定說是否完全若下,因為如果沒有確認是否落下的話在天空中是不是也就可以跳躍XDD,所以這邊就需要再設一個GroundCheck 來判定是否已經完全落在地面上。

  2. 撰寫判斷的程式碼

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

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;
    public float speed = 12f;
    
    Vector3 velocity;
    public float gravity = -9.81f;

    // ground Check
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask  groundMask;
    bool isOnGround;

    // jump setting 
    public float jumpHigh = 3f;


    private void Update() {

        // get the groundcheck to the layer mask
        isOnGround = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
        Debug.Log(isOnGround);
        if(isOnGround && velocity.y < 0)
        {
            velocity.y = -2f;
        }
        // get the w,a,s,d from the keyboard, Horizontal is a,d. Vertical is w,s
        float moveX = Input.GetAxis("Horizontal");
        float moveY = Input.GetAxis("Vertical");

        // get the new position from the movement axis
        Vector3 move = transform.right * moveX + transform.forward * moveY;

        // use controller to control the movement
        controller.Move(move * speed * Time.deltaTime);


        // count the gravity, height -= gravity * t^2, and set to the y axis.
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}
  1. 回到 Unity 把該放入地放進去。

  2. 新增 Ground Layer,先點選 Add Layer到裡面進去新增。

  3. 將環境上的所有物件、地面的 Layer 都設定成 Ground。

  4. 記得將該 GroundMask 設定好點選。

  5. 接下來就可以撰寫跳躍了! 但首先我們要去確認該GroundCheck 是否判斷正確。我們這邊新增一個 Debug.Log去顯示IsOnGround 的結果。
    注意到在地面的時候Console會顯示 True。

當我跳躍的時候就會顯示 False。

請注意若你實驗的時候一直都是False 或是有一直都是True 的話就要修正一下該 IsGroundCheck的位置。

實現跳躍

  1. 跳躍的文本設定也就確認當我在地面上以及是否按下鍵盤的 e。 這邊有個跳躍的公式,也就是我們結合 gravity來進行計算與控制。現實中跳躍的公式為 Mathf.Sqrt(height * -2f * gravity)。
if(Input.GetKeyDown("e") && isOnGround)
        {
            velocity.y = Mathf.Sqrt(jumpHigh * -2f * gravity);
        }
  1. 完整的程式碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;
    public float speed = 12f;
    
    Vector3 velocity;
    public float gravity = -9.81f;

    // ground Check
    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask  groundMask;
    bool isOnGround;

    // jump setting 
    public float jumpHigh = 3f;


    private void Update() {

        // get the groundcheck to the layer mask
        isOnGround = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
        Debug.Log(isOnGround);
        if(isOnGround && velocity.y < 0)
        {
            velocity.y = -2f;
        }
        // get the w,a,s,d from the keyboard, Horizontal is a,d. Vertical is w,s
        float moveX = Input.GetAxis("Horizontal");
        float moveY = Input.GetAxis("Vertical");

        // get the new position from the movement axis
        Vector3 move = transform.right * moveX + transform.forward * moveY;

        // use controller to control the movement
        controller.Move(move * speed * Time.deltaTime);


        // count the gravity, height -= gravity * t^2, and set to the y axis.
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);

        // jump high when you on the ground
        if(Input.GetKeyDown("e") && isOnGround)
        {
            velocity.y = Mathf.Sqrt(jumpHigh * -2f * gravity);
        }
    }
}
  1. 回到 Unity 開始執行其結果
  • 首先我們要跳到最上面,同時確認跳躍的判斷是否正常

  • 目前跳到中間可以看到在該Cube 上表現還不錯

  • 讓我們繼續往上移動

  • 最後跳躍看一下結果。 結果可以在 Console 上看到為 False

結論:

  1. 今天我們學到如何透過鍵盤與滑鼠來控制物件的移動、跳躍。同時實現基本真實環境的跳躍與重力的影響。
  2. 以下可以有效地確認某物體與該 Layer 上的距離,幫助我們更好去透過 Layer 來控制更多的物件來表現,比如在這設定一個 Ground Layer 就可以讓環境上所有的Object 都變成地面,根據與地面的距離來確認是否可以跳躍。
Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
  1. 今天也學習到 localRotation 的使用方式。幫助我們能基於Parent 實現物件的轉動。
  2. 透過 Mathf.Clamp 幫助我們限制一個範圍的數值。

上一篇
Day15: Player Field of View
下一篇
Day17: Audio Listener Setting
系列文
Unity 基本功能實作與日常紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言