1 角色受傷彈開
想法:角色如果碰撞到敵人,就會顯示受傷動畫,且受傷後會向和敵人碰撞的相反方向彈開。
動畫轉移:
- idle->hurt:injured爲true
- hurt->idle:injured爲false,ground爲true
- jump->hurt:injured爲true
- run->hurt:injured爲true
OnTriggerEnter2D 和OnCollisionEnter2D介紹
作用:都是碰撞/接觸到會自動觸發的函數
區別:
- OnTriggerEnter2D:取消物理碰撞,在觸發時執行。
- OnCollisionEnter2D:造成物理碰撞,在碰撞時執行。
使用條件:
- OnTriggerEnter2D:雙方都有碰撞體,運動一方必須是剛體,至少一方勾選Trigger觸發器。
- OnCollisionEnter2D:雙方都有碰撞體,運動一方必須是剛體,雙方都不可勾選Trigger觸發器。
這裏使用OnCollisionEnter2D,因爲角色碰撞到敵人受傷,需要造成物理碰撞。
Tag和Layer的介紹
作用:都是對GameObject進行分類
區別:
- Tag:是字符串。用於定義一類事物,如子彈、敵人之類的,方便查找遊戲物件,以及在觸碰時判斷遊戲物件。
- Layer:是個32位的值,最多隻有32個Layer。和物理系統有關,讓 Camera 指定哪些物件要被畫出來、讓 Light 指定哪些物件要被照明、讓物理射線確認哪些物件要被偵測到。
這次的和敵人碰撞屬於觸碰時判斷遊戲物件,所以採用了Tag來判斷觸碰的對象是不是敵人。
爲之前設置Crab敵人的Tag設置爲Enemy。
受傷彈開
思路:受傷彈開,要朝着碰撞的相反方向彈開。
方向切換代碼:
void Flip()
{
face = (face == 1) ? -1 : 1;//在牆上跳出的話,動畫要和原來相反
transform.localScale = new Vector2(face, 1);//切換方向
}
判斷碰撞方向,選擇動畫是否反轉:
void AccordingDirectionFlip(Collision2D collision)//根據敵人方向,安排玩家轉向
{
if (collision != null)//如果玩家出現視野中
{
int direction;
if (collision.transform.position.x < transform.position.x)
{
direction = -1;//玩家在敵人的左邊
}
else
{
direction = 1;//玩家在敵人的右邊
}
if (direction != face)//表示玩家朝向和敵人相對方位不一致
{
//Debug.Log(direction);
Flip();
}
}
}
受傷反彈:
void Hurt(Collision2D collision)//受傷代碼入口
{
onHurt = true;
AccordingDirectionFlip(collision);
rig.velocity = new Vector2(face * moveForce * Time.deltaTime, jumpForce * Time.deltaTime);//反彈
}
在OnCollisionEnter2D裏面添加觸發的內容:
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
Hurt(collision);
}
}
遊戲效果:
關於動畫切換的代碼可以在文章末尾總代碼中查看,因爲牽扯到之前的代碼有點多,思路主要是添加了一個Bool類型OnHurt來判斷是否在受傷狀態。
2 入門UI顯示血量
想法:角色受傷後會扣除一定的血量,然後這些血量用UI Text在畫面中顯示。
設置UI顯示血量:
新建UI畫布Canvas
在新建的Canvas下新建兩個Text,一個Text用來標識血量,另一個Text用來顯示血量數值,分別命名爲Hp、HpNumber。
修改Text的內容、大小、顏色,到合適遊戲的情況。
把UI Text的顯示固定在左上角,先把錨點固定在左上角(下圖被紅色圓圈圈起來的),因爲在畫面上拖動的UI Text的位置都是相對於錨點。把下圖的Rect Transform方框裏面選擇固定在左上角,然後拖動之前的建立好的Text到左上角。
用代碼修改血量:
需要的頭文件
using UnityEngine.UI;
需要的變量
private Text HpNumberText;
private float HP;//角色血量
初始化的時候獲取"HpNumber"的UI Text
HpNumberText= GameObject.Find("HpNumber").GetComponent<Text>();//獲取ui對於的text
HP=100f;//初始角色血量
在OnCollisionEnter2D裏面進行血量顯示的修改
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
HP -= 25f;//碰到一次敵人減去25血量
HpNumberText.text = HP.ToString();
Hurt(collision);
}
}
3 總代碼
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
private Rigidbody2D rig;//剛體
private Animator Anim;//角色的Animator
[Header("Layers")]
public LayerMask groundLayer;//用來開啓layer
[Space]
[Header("Speed")]
[SerializeField] private float moveSpeed=360f;//移動速度
private float climbSpeed=100f;//爬行速度
[Space]
[Header("Force")]
private float moveForce=150f;//移動力
private float jumpForce=575f;//跳躍力
[Space]
[Header("Frequency")]
private int jumpMax=2;//跳躍次數的上線
private int jumpNum=0;//當前跳躍的次數
[Space]
[Header("Booleans")]
[SerializeField] private bool falling = false;//用來標記是否是下落狀態
[SerializeField] private bool onWall;//是否在牆上
[SerializeField] private bool onJumping;//是否正在跳躍中
[SerializeField] private bool onGround;//是否正在地上
[SerializeField] private bool onHurt;//是否受傷
[Space]
[Header("Collision")]
private float collisionRadius = 0.15f;//碰撞半徑
public Vector2 bottomOffset, rightOffset, leftOffset;//下左右相對於角色中心的二維向量
private Collider2D coll;//角色的碰撞器
[Space]
[Header("UI")]
private Text HpNumberText;
[Space]
private float face;//記錄角色朝向
private float HP;//角色血量
//初始化
void Start()
{
rig = GetComponent<Rigidbody2D>();//獲取主角剛體組件
Anim = GetComponent<Animator>();//獲取主角動畫組件
coll = GetComponent<Collider2D>();//獲取角色碰撞器
HpNumberText= GameObject.Find("HpNumber").GetComponent<Text>();//獲取ui對於的text
groundLayer = 1 << 8;//開啓Ground的layer層,Ground在layer8
onWall = false;//初始不在牆上
onJumping = false;//初始不正在跳躍
onGround = true;//初始在地上
face = 1;//初始朝向向右邊
moveSpeed = 360f;//移動速度
HP = 100f;
bottomOffset = new Vector2(0,-1.6f);
rightOffset = new Vector2(0.61f,-1.3f);
leftOffset = new Vector2(-0.72f,-1.3f);
onHurt = false;
}
//固定的時間間隔執行,不受遊戲幀率的影響
void FixedUpdate()
{
Movement();
changeAnimator();
}
//控制移動
void Movement()
{
Debug.Log("sfjalsf");
//當按下你設置的建則返回一個有加速度的值,從1或者-1 過渡到0
//得到正數對應正半軸,負數對應負半軸的方向
float moveMultiple = Input.GetAxis("Horizontal");
//當按下你設置好的鍵盤就會返回1和-1這兩個值
float faceDirection = Input.GetAxisRaw("Horizontal");
//獲取縱軸
float verticalMove = Input.GetAxis("Vertical");
if (onGround)//在地上
{
move(moveMultiple, faceDirection);//左右移動
if (touchWall())//是否可爬牆,碰到牆
{
if (verticalMove>0)//是否有爬牆的行爲,按向上鍵
{
onGround = false;
onWall = true;
Climb(verticalMove);
}
}
if (Input.GetButtonDown("Jump"))
{
onGround = false;
onJumping = true;
Jump();
}
}
else if (onJumping)//在空中跳躍
{
if (touchWall())//可以爬牆
{
onJumping = false;//關閉現在狀態
onWall = true;//開啓下一個狀態
Climb(verticalMove);//爬行
jumpNum = 0;//跳躍次數清零
}
else if (Input.GetButtonDown("Jump"))//二段跳
{
Jump();
}
}
else if (onWall)//在牆上
{
if(Input.GetButtonDown("Jump"))
{
onWall = false;
onJumping = true;
Flip();
Jump();
}
else if (touchWall())//如果碰到牆,就說明還在爬
{
Climb(verticalMove);
}
else//如果說爬到了末端,就可以有跳躍行爲,不然的話難爬到地面
{
onWall = false;
onJumping = true;
Jump();
}
}
}
void Flip()//翻轉
{
face = (face == 1) ? -1 : 1;//在牆上跳出的話,動畫要和原來相反
transform.localScale = new Vector2(face, 1);
}
bool isGround()//判斷是否碰地
{
return Physics2D.OverlapCircle((Vector2)transform.position + bottomOffset, collisionRadius, groundLayer);//判斷是否碰到地面
}
bool touchWall()//判斷是否碰到牆
{
return Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, collisionRadius, groundLayer)
|| Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, collisionRadius, groundLayer);
}
void move(float moveMultiple,float faceDirection)//移動代碼
{
//角色左右移動
if (moveMultiple != 0)
{
//velocity表示速度,Vector表示向量
rig.velocity = new Vector2(moveMultiple * moveSpeed * Time.deltaTime, rig.velocity.y);//輸入x,y向量,數值*方向
}
//角色朝向修改
if (faceDirection != 0)
{
//Scale,代表縮放,Localscale代表的是當前物體相對於父物體的縮放,通過正負不修改大小來實現左右朝向修改
transform.localScale = new Vector2(faceDirection, 1);
face = faceDirection;//face參數的獲取,在每次按下左右按鍵的時候獲取
}
}
void Jump()//跳躍代碼
{
if(jumpNum < jumpMax)
{
rig.velocity = new Vector2(face*moveForce*Time.deltaTime, jumpForce * Time.deltaTime);
jumpNum++;
}
}
void Hurt(Collision2D collision)//受傷
{
onHurt = true;
AccordingDirectionFlip(collision);
rig.velocity = new Vector2(face * moveForce * Time.deltaTime, jumpForce * Time.deltaTime);
}
void AccordingDirectionFlip(Collision2D collision)//根據敵人方向,安排玩家轉向
{
if (collision != null)//如果玩家出現視野中
{
int direction;
if (collision.transform.position.x < transform.position.x)
{
direction = -1;//玩家在敵人的左邊
}
else
{
direction = 1;//玩家在敵人的右邊
}
if (direction != face)//表示方向不一致
{
//Debug.Log(direction);
Flip();
}
}
}
void Climb(float verticalMove)//爬牆代碼
{
rig.velocity = new Vector2(rig.velocity.x,climbSpeed * verticalMove* Time.deltaTime);//輸入x,y向量,數值*方向
}
void changeAnimator()//動畫切換
{
if (onGround)
{
Anim.SetFloat("speed", Mathf.Abs(rig.velocity.x));//速度是向量
if (onHurt)
{
Anim.SetBool("injured", true);
//Anim.SetBool("ground", false);
onGround = false;
}
}
if (onWall)//如果在牆上
{
Anim.SetBool("wall", true);
if (Anim.GetBool("ground") == false)
{
Anim.SetBool("ground", true);
}
}
else
{
Anim.SetBool("wall", false);
}
if (onJumping)
{
if (onHurt)
{
Anim.SetBool("injured", true);
jumpNum = 0;//當前跳躍次數清零
falling = false;
onJumping = false;
}
else if (Anim.GetBool("ground"))
{
falling = false;
Anim.SetBool("ground", false);
}
else
{
if (falling&&isGround())
{
Anim.SetBool("ground", true);
jumpNum = 0;//落地的話,當前跳躍次數清零
falling = false;
onJumping = false;
onGround = true;
}
else if(rig.velocity.y < 0)
{
falling = true;
}
}
}
if (onHurt)
{
if (falling && isGround())
{
Anim.SetBool("injured", false);
Anim.SetBool("ground", true);
falling = false;
onGround = true;
onHurt = false;
}
else if (rig.velocity.y < 0)
{
falling = true;
}
}
}
void OnDrawGizmos()//繪製輔助線
{
Gizmos.color = Color.red;//輔助線顏色
//繪製圓形輔助線
Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, collisionRadius);
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
HP -= 25f;//碰到一次敵人減去25血量
HpNumberText.text = HP.ToString();
Hurt(collision);
}
}
}