怎樣制作一個回旋斧 2D篇
【參考視訊】
url:bilibili - 【中文字幕】在2D中重制:戰神4奎爺投擲和召回寒冰之斧的攻擊方式
這個視訊中不僅實作了回旋斧的制作,還實作了相機震動、以及一些特效效果豐富體驗。有興趣的小夥伴可以觀看這個視訊,這裡我隻實作普通的回旋斧制作。
【PS:我實作的方式與這位UP有些不同,若是有錯誤請指正】
一、打開初始資源
下載下傳位址 https://pan.baidu.com/s/1L5APoVJundN1IUDphSNUBg
提取碼:v4m2
- 打開Scenes檔案夾下的第一個場景,這個場景已經實作了部分功能(玩家移動,敵人攻擊,按空格敵人血量會減少)。
- 打開Sprites檔案夾,找到weapon斧頭,将其拖拽到Player的子物體中,并調整Position和Sorting Layer以顯示在正确的位置
二、在Scripts/01檔案夾下建立C#腳本 Weapon
(1)首先來實作物體的旋轉,在點選斧頭物體按E進行旋轉可知斧頭是圍繞Z軸進行旋轉的。簡單的旋轉隻需以下代碼即可:
public class Weapon: MonoBehaviour
{
[Header("旋轉參數")]
[SerializeField]
float rotateSpeed = 1000f; // 旋轉速度
private void Update()
{
SelfRotate();
}
void SelfRotate()
{
// 斧頭圍繞Z軸順時針旋轉
transform.Rotate(-Vector3.forward * rotateSpeed * Time.deltaTime);
}
}
(2)接下來實作滑鼠點選某個位置,斧頭會旋轉并移動到該位置。
建立兩個變量 移動速度moveSpeed , 目标位置 targetPos
[Header("移動參數")]
[SerializeField]
float moveSpeed = 10f; // 移動速度
Vector2 targetPos; // 滑鼠點選位置
private void Update()
{
SelfRotate();
Movement();
// 點選滑鼠左鍵
if (Input.GetMouseButtonDown(0))
{
targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
}
void Movement()
{
// 斧頭以一定速度移動到目标位置
transform.position = Vector2.MoveTowards(transform.position, targetPos, moveSpeed * Time.fixedDeltaTime);
}
(3)接下來實作武器到達目标點位置後,傳回人物手中。
首先聲明幾個變量, 玩家位置 playerPos, 三個bool值 isRotating 旋轉狀态, isGo 前進狀态, isBack 傳回狀态。
邏輯:
·點選滑鼠時,武器開始旋轉,斧頭移動到滑鼠點選位置(即 isGo = true)。·
·斧頭到達目标位置後,開始傳回到玩家位置playerPos(即 isGo = false,isBack = true)
Vector2 playerPos; // 玩家位置
[Header("bool參數")]
[SerializeField]
bool isRotating; // 旋轉狀态
[SerializeField]
bool isGo; // 前進狀态
[SerializeField]
bool isBack; // 傳回狀态
private void Update()
{
playerPos = transform.parent.position;
// 點選滑鼠左鍵 && 斧頭是靜止狀态
if (Input.GetMouseButtonDown(0) && !isGo && !isBack)
{
isRotating = true; // 開始旋轉
isGo = true; // 開始前進
targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (isRotating)
{
SelfRotate();
Movement();
}
}
void Movement()
{
// 如果武器到達了目标點
if (Vector2.Distance(transform.position, targetPos) < 0.01f)
{
isBack = true;
isGo = false;
}
// 如果武器傳回玩家手中
if(Vector2.Distance(transform.position, playerPos) < 0.01f)
{
isBack = false;
}
// 武器處于前進狀态 且 不是傳回狀态
if (isGo && !isBack)
{
// 斧頭以一定速度移動到目标位置
transform.position = Vector2.MoveTowards(transform.position, targetPos, moveSpeed * Time.fixedDeltaTime);
}
// 武器處于傳回狀态 且 不是前進狀态
if (isBack && !isGo)
{
// 斧頭以一定速度移動到目标位置
transform.position = Vector2.MoveTowards(transform.position, playerPos, moveSpeed * Time.fixedDeltaTime);
}
}
(4)這時候斧頭傳回玩家手中時并不會停止旋轉,但是,如果用Vector2.Distance()的方法判斷斧頭是否回到玩家的位置,然後指派isRotating = false。就會出現錯誤了!因為武器一直在玩家的位置,是以isRotating會一直會false,根本不會旋轉和移動了。
// 錯誤的方法
if (Vector2.Distance(transform.position, playerPos) < 0.01f)
{
isRotating = false;
isBack = false;
}
是以我們要添加另外的條件,因為斧頭傳回狀态中isBack是為true的,是以我們可以判斷 isBack為true 且 斧頭回到玩家位置時, 斧頭停止旋轉,傳回狀态為假,這樣這個方法就隻在 武器回到玩家手中 的時候調用了一次,而不是無限調用
// 正确的方法
if (isBack && Vector2.Distance(transform.position, playerPos) < 0.01f)
{
isRotating = false;
isBack = false;
// 傳回初始的旋轉角度
transform.rotation = Quaternion.Euler(0, 0, 0);
}
(5)兩個缺陷:
1.我們注意到,武器回到的位置是玩家中心的位置,而不是回到玩家手上
2.因為武器是玩家的子物體,是以武器會跟随玩家的移動而移動(也就是說玩家的速度會影響到武器的速度),武器和玩家同時運動就會會顯得别扭,如果玩家移動速度過快,武器甚至會反向運動。 .
有一種方法可以同時解決這兩個缺陷,就是将武器的位置替代為一個空物體,然後将武器移出Player作為一個單獨的物體,然後改變腳本中的一些參數即可
1.在Player下建立一個空物體weapon_point,并将斧頭移動到Player外作為獨立的物體
2.進入腳本修改一些代碼
删掉變量 playerPos,聲明一個公共變量Transform point,删掉Update()中對 playerPos 的指派,然後将所有的playerPos改為point.position即可
不要忘記在unity中對point進行指派
3.這樣武器确實不會跟随玩家進行移動了,但是産生了新bug,武器在玩家手中的時候也不會跟随玩家移動了。是以我定義了一個bool值,onHand,預設為true,用來判斷武器是否回到玩家手中。
在Update()方法中,當點選滑鼠左鍵時,物體會進行移動,是以此時onHand應為false
在Update()方法中,當onHand = true時,讓武器的位置一直為點的位置
在Movement()方法中,當武器回到手中時,onHand應為true
[SerializeField]
bool onHand = true; // 在手中
// 在Update中添加
private void Update()
{
// 點選滑鼠左鍵 && 斧頭是靜止狀态
if (Input.GetMouseButtonDown(0) && !isGo && !isBack)
{
onHand = false;
}
if (onHand)
transform.position = point.position;
}
void Movement()
{
// 如果武器傳回玩家手中
if (isBack && Vector2.Distance(transform.position, point.position) < 0.01f)
{
onHand = true;
}
}
【PS:這種方法隻是相對減少了一些違和感,并不能完全阻止,比如當玩家的移動速度快于斧頭的移動速度,如果斧頭傳回圖中玩家也一起移動的話,斧頭就會“追”不上玩家,是以還需合理的限制玩家和斧頭的速度】
(6)實作攻擊
隻需給敵人添加collider 2D元件,給斧頭添加collider 2D(勾選is trigger),rigidbody 2D(關掉重力)元件,然後用OntriggerEnter2D方法即可
1.在Weapon腳本中新增方法
注意:任何判斷碰撞的方法都需要雙方物體都有collider元件,且其中一個物體帶有rigidbody元件
private void OnTriggerEnter2D(Collider2D collision)
{
// 調用Enemy的腳本中的Hurt方法,參數為25
if (collision.CompareTag("Enemy"))
collision.gameObject.SendMessage("Hurt", 25);
}
别忘記給Enemy添加tag Enemy,如果沒有請點選Add Tag新增
2.打開Enemy腳本,根據寫好的參數直接定義Hurt方法
public void Hurt(int damage)
{
GetComponentInChildren<HealthBar>().hp -= damage;
}
實作效果
·完整項目百度雲
https://pan.baidu.com/s/1Kkrx8v5MRfHWNPz0RVKFtQ
提取碼:zfet
Unity版本:2019.4.3及以上
日期:2020-10-24