2021-9-4 爆肝一整天,关于2D横板游戏中攀爬楼梯的考虑
Posted giegie界清流
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-9-4 爆肝一整天,关于2D横板游戏中攀爬楼梯的考虑相关的知识,希望对你有一定的参考价值。
今日份关于2D横板游戏中攀爬楼梯的考虑
引言
以前觉得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;
}
}
}
希望有知道为什么的小伙伴不吝赐教,留言交流!
结束
经过一天的调试,总算大功告成
下面放几张效果图
梯子底部不影响下蹲
底部向上攀爬
停留在梯子上
战立在梯子顶端
顶部向下攀爬
大家有什么更好的想法可以和我交流交流哦!
以上是关于2021-9-4 爆肝一整天,关于2D横板游戏中攀爬楼梯的考虑的主要内容,如果未能解决你的问题,请参考以下文章
☀️ 爆肝整整一个周末写一款类似 皇室战争 的 即时战斗类 游戏Demo!两万多字游戏制作过程+解析!建议收藏学习
100个 Unity实用技能| 关于触发器互相检测的必要前提条件配置