(2D)小狐大冒險01-角色移動!

來自專欄 unity學習與開發總結4 人贊了文章

這次我們(其實只有我一個)來製作一個2d中小型遊戲,以提出需求,解決需求為過程,來開發遊戲。

項目需求:製作一款2d橫板闖關遊戲,要求有各種主動技能;被動技能;時效性、限次數性buff;能夠存檔。

本期要解決的內容為:人物移動(配動畫)

話不多說先放最終結果:

https://www.zhihu.com/video/1015578380581875712

首先要解決的是移動邏輯,其次再加入動畫播放邏輯。

只是沒想到在解決移動問題的時候竟然廢了那麼多時間,試了好幾種方法,最終找到一種,撞到障礙不會抖動,可以在跳躍狀態調整位置,沒有其他bug的寫法:

使用transform.Translate,將函數寫在FixedUpdate()內,

就這麼簡單....

但是fixedupdate運行間隔只有0.02秒,在裡面寫按鍵判定是很蠢的,實測有時候按鍵不會被檢測到,所以fixedupdate方法內只能留一個move方法,

private void FixedUpdate() { Move(_moveFactor); }

在move方法內,通過_moveFactor的值,來判斷角色是再往左走還是往右走或者是在原地踏步,把按鍵寫在updat里:

private void Update() { if (Input.GetKey(KeyCode.D)) { _moveFactor = 1; } if (Input.GetKey(KeyCode.A)) { _moveFactor = -1; } if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D)) { _moveFactor = 0; } }

basemove方法(順便做了貼圖旋轉,也就是轉身):

private void BaseMove(int moveFactor) { if (moveFactor == 0) { } else if (moveFactor == 1) { transform.rotation = Quaternion.Euler(0, 0, 0); transform.Translate(new Vector3(1f * moveSpeed * Time.deltaTime * moveSpeedScale, 0, 0), Space.World); } else if (moveFactor == -1) { transform.rotation = Quaternion.Euler(0, 180, 0); transform.Translate(new Vector3(-1f * moveSpeed * Time.deltaTime * moveSpeedScale, 0, 0), Space.World); } }

這樣的基本上是解決了,

但是我們策劃(我)說了,要有各種各樣的技能系統,這樣簡單的寫是沒法加入在「移動中怎麼怎麼」這樣的技能的,所以,必須繼續改。

這裡要使用委託來寫移動,關於委託等知識,請完全初學者自行去菜鳥教程等網站學習。

using System; private event Action<int> Move; void Start() { //由於是單人完成,不會犯一些簡單的錯誤,所以直接獲取,並且在使用該欄位時不加任何錯誤修正 playerRigidbody = GetComponent<Rigidbody2D>(); animator = GetComponent<Animator>(); //事件初始化,暫時先這樣寫,後面會專門的初始化類。 Jump += BaseJump; Move += BaseMove; }

然後將委託事件在fixedupdate里執行即可。

將來如果需要加入技能,只需要+=技能方法即可,上面可以看到基礎的移動和跳躍也是作為「技能」+=進事件的。當玩家觸發事件,就會執行一系列「技能」。

角色跳躍同理:

private event Action Jump; private float JumpHeight = 5; private void BaseJump() { playerRigidbody.velocity = new Vector2(0, JumpHeight); }

下面簡述一下動畫,使用animator,目前只有移動和跳躍,所以還比較簡單,

說一下我的實現思路,

moving:玩家是否在移動(-movefactor是否等於0)

velocityY:rigibody的Y軸力,用來判斷角色是在向上跳還是在下落,因為我們有兩個動畫。

inspace:是否處於浮空狀態,此值使用射線投射來進行判定。

除此之外,我使用了 Animator.StringToHash,來降低拼寫錯誤率,並提升程序效率。

下面是整個腳本的代碼:

本人英文渣,希望不要在意起名。

using System.Collections;using System.Collections.Generic;using UnityEngine;using System;public class PlayerControl : MonoBehaviour{ private Rigidbody2D playerRigidbody; private event Action Jump; private event Action<int> Move; private Animator animator; int _moveFactor = 0; //角色屬性 public float moveSpeed = 1; private float JumpHeight = 5; public float moveSpeedScale = 1.0f; //動畫哈希 int moving, velocityY, inSpace; // Use this for initialization private void Awake() { moving = Animator.StringToHash("moving"); velocityY = Animator.StringToHash("velocityY"); inSpace = Animator.StringToHash("inSpace"); } void Start() { //由於是單人完成,不會犯一些簡單的錯誤,所以直接獲取,並且在使用該欄位時不加任何錯誤修正 playerRigidbody = GetComponent<Rigidbody2D>(); animator = GetComponent<Animator>(); //事件初始化,暫時先這樣寫,後面會專門的初始化類。 Jump += BaseJump; Move += BaseMove; } private void Update() { //同步velocityY的值 animator.SetFloat(velocityY, playerRigidbody.velocity.y); //射線判斷 if (Physics2D.BoxCast(transform.position, new Vector2(0.15f, 0.1f), 0, Vector2.down, 0.2f, 1 << LayerMask.NameToLayer("Default"))/*Physics2D.Raycast(transform.position, Vector2.down, 0.2f, 1 << LayerMask.NameToLayer("Default"))*/) { animator.SetBool(inSpace, false); } else { animator.SetBool(inSpace, true); } //按鍵觸發 if (Input.GetKeyDown(KeyCode.Space)) { Jump(); } if (Input.GetKey(KeyCode.D)) { _moveFactor = 1; animator.SetBool(moving, true); } if (Input.GetKey(KeyCode.A)) { _moveFactor = -1; animator.SetBool(moving, true); } if (Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D)) { _moveFactor = 0; animator.SetBool(moving, false); } } private void BaseJump() { playerRigidbody.velocity = new Vector2(0, JumpHeight); } private void BaseMove(int moveFactor) { if (moveFactor == 0) { } else if (moveFactor == 1) { transform.rotation = Quaternion.Euler(0, 0, 0); transform.Translate(new Vector3(1f * moveSpeed * Time.deltaTime * moveSpeedScale, 0, 0), Space.World); } else if (moveFactor == -1) { transform.rotation = Quaternion.Euler(0, 180, 0); transform.Translate(new Vector3(-1f * moveSpeed * Time.deltaTime * moveSpeedScale, 0, 0), Space.World); } } private void FixedUpdate() { Move(_moveFactor); }

關於動畫控制器:

我分為了兩層,一層為base,沒改名,就是基本狀態,二層為space,浮空狀態,二層權重高於0.5可以覆蓋一層動畫,

二層默認是空動畫,空動畫不會覆蓋其他層的動畫,所以只有space為true時,才會覆蓋1層,並根據velocity的值,播放起跳或者下落的動畫,最後當space不為true時,要回到空動畫。

搞定。


推薦閱讀:
相关文章