
今日份關于2D橫板游戲中攀爬樓梯的考慮
- 引言
- 關于攀爬樓梯考慮
- 總體考慮
- 玩家站在1處
- 玩家站在2處
- 玩家通過跳躍來到3處
- 1處升至3處 和 2處降至3處
- 3處升至2處
- 3處降至1處
- 其他考慮
- 解決方案及代碼
- 影片條件
- 解決代碼(非完全代碼)
- 首先是一些設定
- 初始化
- 然后,重點來了,各類情況分析
- 最重要的幾點分析(前提時在梯子范圍內)
- 兩個檢測函式
- 考慮梯子上的受力情況
- 各類函式實作,沒什么好說的
- 最坑爹的地方來了,如何判斷在梯子范圍內和位于梯子底部
- 結束
- 下面放幾張效果圖
- 梯子底部不影響下蹲
- 底部向上攀爬
- 停留在梯子上
- 戰立在梯子頂端
- 頂部向下攀爬
引言
以前覺得2D橫板游戲制作起來很簡單,殊不知一個小小的動作就需要考慮這么多要素,通過對這個小小的2D橫版游戲的設計,我對那些開發出好玩炫酷兼顧打擊手感,不停琢磨提高游戲的性能及優化的開發者們的敬意油然而生啊!!!
關于攀爬樓梯考慮

總體考慮
- 玩家在梯子上將不能左右移動,不能跳躍
- 增加梯子上的停留影片,保證在梯子上停留時不會出現原地攀爬的情況
玩家站在1處
- 按下s鍵,仍應播放下蹲動作,而不是攀爬下降動作,無豎直方向受力
- 按下w鍵,播放攀爬上升動作,受力向上
玩家站在2處
- 按下w鍵,不播放攀爬上升影片,無豎直方向受力
- 按下s鍵, 播放攀爬下降影片,受力向下
玩家通過跳躍來到3處
- 按下w鍵,播放攀爬上升影片,受力向上
- 按下s鍵,播放攀爬下降影片,受力向下
1處升至3處 和 2處降至3處
- 暫時沒想到有什么可考慮的
3處升至2處
- 停止播放攀爬上升影片,播放站立影片
- 不影響跳躍(檢測盒子檢測到的不再是地面)
- 下蹲無效
- 到達橋的頂點后,橋上是可以站立的
3處降至1處
- 停止播放攀爬下降影片,播放站立影片
- 不影響跳躍(檢測盒子檢測到再次變成地面)
- 不影響下蹲
其他考慮
- 到達梯子什么地方可以攀爬,如果太寬,可能會出現沒有借助梯子而是懸空攀爬的情況
- 被攻擊就會掉落
解決方案及代碼
情況極其復雜,經過今天一整天的除錯,我才成功得完成我對于攀爬的各種需求,
影片條件

- 很明顯,我將跳躍與下落分開,然后又將向上攀爬,向下攀爬,停止攀爬分開,
- 本來連線還是較為簡單的,因為將轉換狀態時間設定為0,為通過不斷除錯,發現多條連線盡管不需要轉換時間,但如果沒有直接連通的線,仍會出現許多不合常理的bug,例如到梯子頂部仍無法結束攀爬影片的情況,因此,經過不斷除錯,我增加了很多連線,
解決代碼(非完全代碼)
自己動手敲一敲哦,就會發現這其中還是很消耗腦細胞的,
首先是一些設定
[Header("地面檢測盒子的高度")]
public float BoxHeight = 0.2f;
[Header("地面檢測層")]
public LayerMask groundMask;
[Header("橋檢測層")]
public LayerMask bridgeMask;
[Header("攀爬速度")]
public float ClimbSpeed = 10.0f;
private bool isOnLadder = false; // 是否在梯子上
private bool isClimb = false; // 是否正在攀爬
[HideInInspector]
public bool bridgeBottom = false; // 是否在梯子底
[HideInInspector]
public bool bridgeTop = false; // 是否在梯子頂
private Animator _animator;
private Rigidbody2D _rigidbody2D;
private Collider2D _collider2D;
private Collider2D BridgeCollider;
private Vector2 playersize; // 玩家大小
private Vector2 boxsize; // 檢測盒子尺寸
// 所有狀態引數的id定義
#region
private int id_run;
private int id_jump;
private int id_fall;
private int id_climbup;
private int id_climbdown;
private int id_onladder;
private int id_bridgebottom;
private int id_bridgetop;
private int id_crouch;
private int id_hurt;
#endregion
初始化
void Awake()
{
_animator = GetComponent<Animator>();
_rigidbody2D = GetComponent<Rigidbody2D>();
_collider2D = GetComponent<Collider2D>();
playersize = GetComponent<SpriteRenderer>().bounds.size;
boxsize = new Vector2(playersize.x * 0.3f, BoxHeight); // 設定檢測盒的大小
healthscontroller = GameObject.FindGameObjectWithTag("healths").GetComponent<HealthsController>();
BridgeCollider = GameObject.FindGameObjectWithTag("bridgetop").GetComponent<Collider2D>();
// 所有狀態引數轉為其id,提高性能
#region
id_run = Animator.StringToHash("run");
id_jump = Animator.StringToHash("jump");
id_fall = Animator.StringToHash("fall");
id_climbup = Animator.StringToHash("climbup");
id_climbdown = Animator.StringToHash("climbdown");
id_onladder = Animator.StringToHash("onladder");
id_bridgebottom = Animator.StringToHash("bridgebottom");
id_bridgetop = Animator.StringToHash("bridgetop");
id_crouch = Animator.StringToHash("crouch");
id_hurt = Animator.StringToHash("hurt");
#endregion
}
然后,重點來了,各類情況分析
// Update is called once per frame
void Update()
{
// 判斷是否到達梯子頂
#region
if (bridgeTop)
{
isClimb = false;
_animator.SetBool(id_bridgetop, true);
}
else
{
_animator.SetBool(id_bridgetop, false);
}
#endregion
// 判斷是否到達梯子底
#region
if (bridgeBottom)
{
isClimb = false;
_animator.SetBool(id_bridgebottom, true);
}
else
{
_animator.SetBool(id_bridgebottom, false);
}
#endregion
}
private void FixedUpdate()
{
// 判斷在地面上則下落停止
if (IsOnGround())
{
StopFall();
_animator.SetBool(id_climbdown, false);
_animator.SetBool(id_bridgebottom, true);
}
// 判斷在梯子頂部
if (IsOnBridge())
{
StopFall();
bridgeTop = true;
BridgeCollider.isTrigger = false; // 空氣墻是否有碰撞
_animator.SetBool(id_climbup, false);
_animator.SetBool(id_crouch, false);
}
else
{
bridgeTop = false;
}
最重要的幾點分析(前提時在梯子范圍內)
- 在梯子底部按下w鍵,執行向上攀爬
- 在梯子頂部按下s鍵,執行向下攀爬
- 不在梯子頂部按下w鍵,執行向上攀爬
- 不在梯子底部按下s鍵,執行向下攀爬
- 按下w或者s鍵后抬起,執行停止攀爬
// 攀爬樓梯相關
if (isOnLadder)
{
_animator.SetBool(id_onladder, true);
1.if (Input.GetButton("Climb") && bridgeBottom)
{
ClimbUp();
}
2.else if(Input.GetButton("Crouch") && bridgeTop)
{
BridgeCollider.isTrigger = true;
ClimbDown();
}
3.else if (Input.GetButton("Climb") && !bridgeTop)
{
ClimbUp();
}
4.else if (Input.GetButton("Crouch") && !bridgeBottom)
{
ClimbDown();
}
5.if (Input.GetButtonUp("Climb") || Input.GetButtonUp("Crouch"))
{
StopClimb();
}
}
else
{
_animator.SetBool(id_onladder, false);
BridgeCollider.isTrigger = true;
}
}
兩個檢測函式
// 利用檢測盒子檢測人物是否在地面上
private bool IsOnGround()
{
Vector2 boxcenter = (Vector2)transform.position + (Vector2.down * playersize.y * 0.5f);
return Physics2D.OverlapBox(boxcenter, boxsize, 0, groundMask);
}
// 利用檢測盒子檢測人物是否在梯子頂部
private bool IsOnBridge()
{
Vector2 boxcenter = (Vector2)transform.position + (Vector2.down * playersize.y * 0.5f);
return Physics2D.OverlapBox(boxcenter, boxsize, 0, bridgeMask);
}
考慮梯子上的受力情況
在梯子上停留的話應該是不動的,因此,要將重力倍數設定為0
/// <summary>
/// 改變上升下落重力大小的函式,可以讓人物沒有飄飄的感覺,提升玩家體驗
/// </summary>
private void BetterJump()
{
if (_rigidbody2D.velocity.y > 0 && !isClimb)
{
_rigidbody2D.gravityScale = JumpUpGravity;
}
else if (_rigidbody2D.velocity.y < 0 && !isClimb)
{
_rigidbody2D.gravityScale = FallGravity;
_animator.SetBool(id_jump, false);
_animator.SetBool(id_fall, true);
}
else if (isOnLadder && !bridgeTop && !bridgeBottom &&isClimb)
{
_rigidbody2D.gravityScale = 0f; // 重力設為0
}
else
{
_rigidbody2D.gravityScale = 1.0f;
}
}
各類函式實作,沒什么好說的
// 控制攀爬上升受力及影片
private void ClimbUp()
{
isClimb = true;
_animator.SetBool(id_climbup, isClimb);
_animator.SetBool(id_climbdown, false);
_rigidbody2D.velocity = new Vector2(0, ClimbSpeed);
}
// 控制攀爬下降受力及影片
private void ClimbDown()
{
isClimb = true;
_animator.SetBool(id_climbup, false);
_animator.SetBool(id_climbdown, isClimb);
_rigidbody2D.velocity = new Vector2(0, -ClimbSpeed);
}
// 停止攀爬
private void StopClimb()
{
_animator.SetBool(id_climbup, false);
_animator.SetBool(id_climbdown, false);
_rigidbody2D.velocity = new Vector2(0, 0); // 防止莫名緩慢下落
}
最坑爹的地方來了,如何判斷在梯子范圍內和位于梯子底部
坑爹并不是說它有多難想到,而是本來我覺得主角控制器上的代碼已經夠多了,所以我就這段代碼掛載到和主角發生觸發事件的物體上,結果爬了半天爬不上去,一直很鬼畜的停在最底端,播放攀爬影片,但就是上不去,我除錯了很久都沒效果,后來才發現在梯子底部時,一按向上攀爬,系統自動判定,主角離開了碰撞物體,這點我也很不明白是為什么!!!
// 檢測是否在梯子上和梯子底部
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "bridge")
{
isOnLadder = true;
}
if(collision.tag == "bridgebottom")
{
bridgeBottom = true;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.tag == "bridge")
{
isOnLadder = false;
}
if (collision.tag == "bridgebottom")
{
bridgeBottom = false;
}
}
}
希望有知道為什么的小伙伴不吝賜教,留言交流!
結束
經過一天的除錯,總算大功告成
下面放幾張效果圖
梯子底部不影響下蹲

底部向上攀爬

停留在梯子上

戰立在梯子頂端

頂部向下攀爬

大家有什么更好的想法可以和我交流交流哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297661.html
標籤:其他
上一篇:極為簡單滴迷宮游戲c++
