今日份关于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定义#regionprivate 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,提高性能#regionid_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 framevoid Update(){// 判断是否到达梯子顶#regionif (bridgeTop){isClimb = false;_animator.SetBool(id_bridgetop, true);}else{_animator.SetBool(id_bridgetop, false);}#endregion// 判断是否到达梯子底#regionif (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;}

最重要的几点分析(前提时在梯子范围内)

  1. 在梯子底部按下w键,执行向上攀爬
  2. 在梯子顶部按下s键,执行向下攀爬
  3. 不在梯子顶部按下w键,执行向上攀爬
  4. 不在梯子底部按下s键,执行向下攀爬
  5. 按下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横板游戏中攀爬楼梯的考虑相关推荐

  1. 2021-9-2 Cinemachine 不需要写代码的高级跟随摄像机 2D横板游戏应用

    Cinemachine在2D横版游戏中的使用方法简介 Cinemachine的下载及导入 Cinemachine基础 设置 简单用法的一些重要的属性(没讲到的暂时就保持默认设置,如果有补充,欢迎评论区 ...

  2. Unity游戏开发日记(一):独自开发2d横板游戏:Small man(MainMenu主界面)基本构建

    目录 一.独自开发想法 前言: 开发构想: 二.主要内容:MainMenu主界面基本构建 (一)预想功能 (二)功能实现 1.主界面UI设计 2.Option功能设计 3.TypeOption功能设计 ...

  3. Unity 3D下开发2D飞行游戏中的背景滚动

    背景滚动 有以下几点必要的: 在Canvas下创建Raw Image组件 背景图片设置为Texture 填充方式为Repeat重复填充方式 C#代码 using UnityEngine; using ...

  4. 2D动作游戏开发与实现(翻译) .

    本文为 cping1982 主持翻译,如有转载,请严格按照如下方式显示标明译文作者及出处,以示尊重! 译者:cping1982 原文:http://blog.csdn.net/cping1982/ar ...

  5. 用python写跑酷游戏脚本_用python写游戏之2D跑酷游戏(二)

    这篇文章介绍2D跑酷游戏中,添加地板资源, 给主角附加重力作用,以及添加游戏控制器和游戏场景的切换. 废话不多说,直接开始. 添加地板资源 定义地板类,继承自pygame.sprite.Sprite ...

  6. 2D动作游戏开发与实现(翻译)

    原文太长,所以将翻译与原文分成了两部分, 主要是讲2D游戏瓦片规则及不规则渲染与角色碰撞原理的. 因为单纯的2D游戏开发过于简单,所以本文尝试结合不同的2D平面游戏并将之归类,列出他们的优缺点,然后讨 ...

  7. 高二学生爆肝10个月!自学数电在《我的世界》里打造理论最快计算器,5天涨粉1万...

    金磊 梦晨 发自 凹非寺 量子位 报道 | 公众号 QbitAI 辛丑牛年(2021),<我的世界>,一高二学生因爆肝在B站火了. 他从未接触过数电,一切从零开始,仅仅是为了搞清计算器的原 ...

  8. LeCun大佬点赞转发!B站大佬爆肝6个月,目前播放量破百万!

    来源:量子位 非计算机专业.神经网络小白,爆肝六个月-- 在<我的世界>里搭建一个卷积神经网络,这是什么神操作? ‍‍ 最近,来自B站up主@辰占鳌头的作品着实火了一把. 他和朋友们合作完 ...

  9. 再也不用熬夜爆肝做汇报了!PPT生成神器ChatBCG来啦!

    来源:新智元 相信不管是学生党,还是上班族,都有为PPT汇报熬夜爆肝的经历...... 光挑选模版和样式就杀死了一堆脑细胞. 而现在,一款能一键自动生成PPT模版和文字可能成为解放生产力的神器,它就是 ...

最新文章

  1. VRRP和单臂路由的综合运用
  2. 【Timbre,Amplitude,Pitch】声音的基本属性
  3. python映射类型-python笔记-映射类型(字典)
  4. JavaScript实现浏览器菜单的一些功能
  5. Redis分布式锁---完美实现
  6. 牛客题霸 [判断二叉树是否对称] C++题解/答案
  7. [转]C#用SHA对密码加密
  8. Ubuntu 无法mount解决办法
  9. 【车辆计数】基于matlab形态学停车场车辆计数【含Matlab源码 628期】
  10. 匹配滤波器及matlab仿真
  11. 网络唤醒Wake On Lan
  12. 注册表启动项设置方法
  13. order by使用索引列排序时会失效吗?
  14. Python语言中的注释方法应用
  15. 做不大的支付宝小程序,逃不脱的付钱关系
  16. android客户端与服务器端交互 如何保持session
  17. 编制计算机程序的算法是什么,中国大学MOOC: 编制计算机程序解决问题的过程有:描述问题、算法设计、编写计算机程序和调试等,其中对算法描述不正确的是()。...
  18. 时间戳转换,在线转换时间戳
  19. 二极管正向压降测试仪适合在哪里应用?
  20. 卡梅隆大学计算机排名,2022卡梅隆大学全美排名多少(研究生院)

热门文章

  1. 数据库平滑扩容方案剖析
  2. 回收站删除数据恢复怎么操作
  3. redhat安装jdk8
  4. TopCoder提交测试
  5. nhibernate和mysql_利用NHibernate与MySQL交互
  6. 亿唐高管反思六年烧钱:转型Web2.0重提专注
  7. 【链表】C++链表反转、链表逆序打印
  8. perl 5.26安装步骤
  9. 基于Android的多功能日程表,基于android的多功能日程表系统的设计与实现.doc
  10. 救命!我的电子邮件发不到 500 英里以外! 1