1 創建敵人
按照之前創建Player角色的方法,一樣創建出敵人,併爲角色添加剛體、碰撞、動畫。具體可以參考我之前的unity2D學習(4)(5),具體的細節就不放在這裏了。
素材包裏面有三種敵人(crab、jumper、octopus),我選擇crab來做示範動畫狀態轉移。把Animation新建在Asserts->Animation->Enemies->Crab裏面,其它類型的敵人以此類推。
參數判斷:
- Walk->Idie:speed小於0.01f
- Idie->Walk:speed大於0.01f
2 爲敵人設置簡單ai
我的想法:如果Player角色出現在某一範圍內,敵人就會朝玩家走去碰撞,然後走到邊緣就會停下來。因爲我後面想寫一個玩家碰到敵人就會受傷的效果,所以我希望敵人會主動去碰撞玩家。
思路:
- 敵人判斷Player是否是在敵人的某個範圍內:可以用Physics2D.OverlapCircle,來判斷角色的碰撞體是否在圓形範圍裏面,然後根據Player在敵人左邊還是右邊來改變方向。
利用Physics2D.OverlapCircle判斷玩家是否進入視野,和上一章unity2D學習(9)中判斷碰牆的方法一樣。
但是這次有點不同就是,如果用Collider2D類型來獲取Physics2D.OverlapCircle就可以得到碰撞對象Collider2D,上一章裏面使用Bool類型來獲取得到就是“是否碰撞到”。還有需要爲Player玩家設置一個Layer層來做判斷用。
Collider2D isPlayerView()//判斷玩家是否進入了視野
{
return Physics2D.OverlapCircle((Vector2)transform.position, collisionRadius,playerLayer);//判斷是否碰到玩家
}
利用獲取的Collider2D類型來判斷敵人在玩家的那個方向。但是要注意敵人的動畫的朝向初始是朝向左邊的和主角不一樣。敵人初始的橫向向量雖然是正,但是動畫的朝向起始對應的是左邊。
void AccordingDirectionFlip(Collider2D playerColl)//根據玩家是否出現在視野中,安排敵人轉向
{
if (playerColl != null)//如果玩家出現視野中
{
int direction;
if (playerColl.transform.position.x < transform.position.x)
{
direction = -1;//玩家在敵人的左邊
}
else
{
direction = 1;//玩家在敵人的右邊
}
if (direction != face)//表示方向不一致
{
//Debug.Log(direction);
Flip();
}
}
}
void Flip()//翻轉角色方向
{
face = (face == 1) ? -1 : 1;
transform.localScale = new Vector2(face*(-1), 1);//乘-1是因爲初始動畫朝向是朝着左邊的,但是初始座標卻是1,是相反的
}
- 敵人跟隨Player會走到邊緣,需要停下:用射線Physics2D.Raycast來判斷是否走到了邊緣。
Physics2D.Raycast介紹
作用:檢查對撞機是否落在射線上。
public static RaycastHit2D Raycast(Vector2 origin, Vector2 direction, float distance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, float minDepth = -Mathf.Infinity, float maxDepth = Mathf.Infinity);
origin | 二維空間中射線起源的點 |
direction | 表示射線方向的向量 |
distance | 投射射線的最大距離 |
layerMask | 檢測的特定Layer的對象 |
minDepth | z軸大於或等於此值的對象 |
maxDepth | z軸小於或等於此值的對象 |
設置Physics2D.Raycast的射線方向的向量爲45°(斜着向下),然後檢測的特殊Layer層爲之前創建的Ground的Layer(之前TileMap的Layer層),然後起始源點爲敵人自己的座標。
涉及到的變量
Vector2 down = new Vector2(0, -1);//控制射線角度的向量
private float radialLength = 1.5f;//射線的長度
beg = transform.position;//射線起點,這個要每帖更新
核心代碼
bool isBorder()//判斷是否已經抵達邊境
{
//也可以採用Debug的方式可視化射線
//Debug.DrawLine(beg, beg + (new Vector2(face, 0) + down) * radialLength, Color.red);
if (!Physics2D.Raycast(beg,new Vector2(face,0)+down, radialLength, LayerMask.GetMask("Ground")))//抵達邊境
{
return true;
}
return false;
}
這種方法射線和圈不好調整,爲了方便調整參數,繪製輔助線來可視化。(具體代碼看文章的末尾)
3 總代碼
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnamyController : MonoBehaviour {
private Rigidbody2D rig;//剛體
private Animator Anim;//動畫
[Header("Layers")]
public LayerMask playerLayer;//用來開啓layer
[Space]
[Header("Collision")]
private Collider2D coll;//碰撞器
[SerializeField] private float collisionRadius = 5f;//檢測碰撞半徑
Vector2 beg;//射線起點
Vector2 down = new Vector2(0, -1);//控制射線角度的向量
[SerializeField] private float radialLength = 1.1f;//射線的長度
[Space]
[Header("Speed")]
private float moveSpeed = 100f;//移動速度
[SerializeField] private float face;//朝向
void Start () {
rig = GetComponent<Rigidbody2D>();//獲取剛體組件
Anim = GetComponent<Animator>();//獲取動畫組件
coll = GetComponent<Collider2D>();//獲取碰撞器
face = -1;//初始朝向是負的,和角色不同的地方,face-1代表朝向左邊
playerLayer = 1 << 9;//把玩家Layer放在Layer9
}
void FixedUpdate()
{
beg = transform.position;
Collider2D playerColl = isPlayerView();
if (isBorder())//是否到邊緣
{
Debug.Log("hello");
rig.velocity = new Vector2(0,0);
AccordingDirectionFlip(playerColl);
}
else //不到邊緣就可以移動
{
AccordingDirectionFlip(playerColl);
Move();
}
}
void AccordingDirectionFlip(Collider2D playerColl)//根據玩家是否出現在視野中,安排敵人轉向
{
if (playerColl != null)//如果玩家出現視野中
{
int direction;
if (playerColl.transform.position.x < transform.position.x)
{
direction = -1;//玩家在敵人的左邊
}
else
{
direction = 1;//玩家在敵人的右邊
}
if (direction != face)//表示方向不一致
{
//Debug.Log(direction);
Flip();
}
}
}
void Flip()//翻轉角色方向
{
face = (face == 1) ? -1 : 1;
transform.localScale = new Vector2(face*(-1), 1);//乘-1是因爲初始動畫朝向是朝着左邊的,但是初始座標卻是1,是相反的
}
bool isBorder()//判斷是否已經抵達邊境
{
//也可以採用Debug的方式可視化射線
//Debug.DrawLine(beg, beg + (new Vector2(face, 0) + down) * radialLength, Color.red);
if (!Physics2D.Raycast(beg,new Vector2(face,0)+down, radialLength, LayerMask.GetMask("Ground")))//抵達邊境
{
return true;
}
return false;
}
Collider2D isPlayerView()//判斷玩家是否進入了視野
{
return Physics2D.OverlapCircle((Vector2)transform.position, collisionRadius,playerLayer);//判斷是否碰到地面
}
void Move()//左右移動
{
rig.velocity = new Vector2(face*moveSpeed * Time.deltaTime, rig.velocity.y);//輸入x,y向量,數值*方向
}
void ChangeAnimator()//動畫狀態轉換
{
Anim.SetFloat("speed", Mathf.Abs(rig.velocity.x));//速度是向量
}
void OnDrawGizmos()//繪製輔助線
{
Gizmos.color = Color.red;//輔助線顏色
Gizmos.DrawWireSphere((Vector2)transform.position, collisionRadius);//繪製射線
Gizmos.DrawLine((Vector2)transform.position, (Vector2)transform.position+(new Vector2(face, 0) + down)*radialLength);//繪製圓形
}
}