1 基本準備
在前幾篇裏面,已經搞定了基本的角色控制,已經設置好了角色不同狀態的動畫效果。
但是會發現,在進行跳躍的時候也依舊是閒置狀態下的動畫,那麼這一篇要解決的就是不同動作下的狀態切換。
2 爲不同動畫狀態切換設置參數
點擊之前在Assets->Animation->Player裏面創建的Player(Animator類型)的文件,就會看到下圖中間這個Animatior面板。這裏面會看到之前我們爲Player設置的run、idle等動畫狀態。
每個狀態可以通過右鍵點擊Make Transition來創建一個箭頭,連接其它的模塊,這裏也就是不同狀態轉移方向的設置。
然後結合之前寫的代碼,寫了左右移動和跳的控制,那麼我就連接好idle、jump和run的動畫,來配合我們之前寫的代碼。
接下來,設置動畫之間轉移需要的控制參數,通過下圖框選的地方就可以新建一個參數了。先點擊Parameters-> + ->選擇參數的類型。
新建了ground(bool)和speed(float)兩種變量。ground用來判斷角色是否在地上,speed用來記錄角色左右移動速度。
然後點擊之前創建的Transition,爲每一個Transition添加參數控制。
點擊Transition後,右邊會出來一個面板,紅色框框的地方:
Has Exit Time(是否有退出時間),這個不勾選的,勾選代表這個動畫必須播完才能下一個動畫,不勾選代表這個動畫可以被打斷;
Transition Duration(過渡的時間),設置爲0,從A動畫過渡到B動畫需要的時間,如果設勾選了Fixed Duration,那麼這個時間以秒爲單位,否則的話以A的時間爲基礎(百分比時間);
Conditions,用來添加參數判斷。
上圖的參數ground要勾選,角色一開始是在地面上,ground初始值應該是true。
參數判斷:
- idle->run:speed速度大於0.001
- run->idle:speed速度小於0.001
- run->jump:ground等於false
- jump->idle:ground等於true
- idle->jump:ground等於false
3 代碼控制參數實現動畫狀態切換
初始的代碼思路:每次更新後,更新速度,通過y軸速度來判斷是否處於跳躍狀態。
遇到的問題:
- 跳躍不能通過y軸速度不爲零來判斷,因爲上下坡也會有y軸速度的變化。在按下跳躍鍵後就讓jump動畫轉換,需要來判斷是否碰到地面落地來結束jump動畫,這也是爲什麼我要添加ground(前面動畫狀態切換的參數)。
- 如果只判斷是否碰到地面的時候需要二段跳的時候纔會有動畫轉變,大概是因爲按下跳躍按鍵後ground剛轉換爲false,又立馬檢測是否碰到地面,結果有修改爲了true。
修改後的代碼思路:每次更新後,更新速度,按下跳躍鍵後就轉變動畫,在下落狀態的時候判斷是否有沒有觸碰到地面。
介紹一下Layer:通常是邏輯用到的,用來判斷碰撞,觸發檢測的掩蓋用的。(需要用這個來判斷是否碰到了地面)Layer只有32層,官方佔了前8個(不可更改)。通常代碼裏面會用LayerMask來開啓和關閉Layer,使用方式(LayerMask mask = 1 << 你需要開啓的Layers層,LayerMask mask = 0 << 你需要關閉的Layers層)。
代碼前期工作:爲TileMap修改Layer,添加Ground的Layer,然後把TileMap的Layer修改爲Ground。
代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
private float moveSpeed;//移動速度
private float jumpForce;//跳躍力
private Rigidbody2D rig;//剛體
private Animator Anim;//角色的Animator
private Collider2D coll;//角色的碰撞器
public LayerMask ground;//用來開啓layer
private bool falling=false;//用來標記是否是下落狀態
//初始化
void Start () {
rig = GetComponent<Rigidbody2D>();//獲取主角剛體組件
Anim = GetComponent<Animator>();//獲取主角動畫組件
coll = GetComponent<Collider2D>();//獲取角色碰撞器
ground = 1<<8;//開啓Ground的layer層,Ground在layer8
jumpForce = 575f;
moveSpeed = 500f;
}
//固定的時間間隔執行,不受遊戲幀率的影響
void FixedUpdate()
{
Move();
changeAnimator();
}
//控制移動
void Move()
{
float moveMultiple = Input.GetAxis("Horizontal");
float faceDirection = Input.GetAxisRaw("Horizontal");
//角色左右移動
if (moveMultiple!=0)
{
rig.velocity = new Vector2(moveMultiple * moveSpeed * Time.deltaTime, rig.velocity.y);//輸入x,y向量,數值*方向
}
//角色朝向修改
if(faceDirection!=0)
{
transform.localScale = new Vector2(faceDirection, 1);
}
//角色跳躍
if (Input.GetButtonDown("Jump"))
{
rig.velocity = new Vector2(rig.velocity.x, jumpForce * Time.deltaTime);
Anim.SetBool("ground", false);
}
}
void changeAnimator()
{
Anim.SetFloat("speed", Mathf.Abs(rig.velocity.x));//速度是向量
if (Anim.GetBool("ground")==false&&rig.velocity.y<0)
{
falling = true;
}
else if (coll.IsTouchingLayers(ground)&&falling)
{
Anim.SetBool("ground", true);
falling = false;
}
/*if (coll.IsTouchingLayers(ground))
{
Anim.SetBool("ground", true);
Debug.Log("你碰地了!");
}
//會有一個問題,只有第二次跳纔會有動畫,
*/
/*if (Mathf.Abs(rig.velocity.y) > 0.001)
{
Anim.SetBool("ground",false);
}
else {
Anim.SetBool("ground", true);
}
//會有問題,斜坡走的時候,y軸也會發生速度的變化
*/
}
}
4 調整TileMap碰撞點
在進行爬坡測試的時候,出現了一個問題就是斜坡的瓦片碰撞點不能和瓦片重合,且凹凸不平,運行體驗不佳。
不是正方形的瓦片的話,TileMap的碰撞點自動設置可能很奇怪,直接TileMap設置碰撞器的話,可能會有凹凸不平的情況,且凹凸不平的形狀不能和瓦片完全重合。
出現這個問題可能需要回到一開始編輯圖片,在Sprite Editor裏面,左邊的紅框選擇第三個Custom Physics Shape,然後點擊需要修改碰撞點的方形塊,然後點擊Generate就可以修改碰撞點。