【Unity3D】实现横版2D游戏角色二段跳、蹬墙跳、扶墙下滑

目录

一、二段跳、蹬墙跳 

二、扶墙下滑


一、二段跳、蹬墙跳

GitHub - prime31/CharacterController2D

下载工程后直接打开demo场景:DemoScene(Unity 2019.4.0f1项目环境)

Player物体上的CharacterController2D,Mask添加Wall层(自定义墙体层)

将场景里其中一个障碍物设置为Wall层 Wall标签 并拉伸为墙体高度

Player物体上的Demo Scene脚本控制玩家移动 二段跳 蹬墙跳

蹬墙跳要调整好Jump On Wall H Force 横向力 和 Jump On Wall V Force 纵向力 数值才能表现正常,其中 V Force 是在 1的基础上的增量值,这里的力并非物理力实际是速度增量倍率。

跳跃对Y轴速度影响是用公式:根号2gh
代码则是:Mathf.Sqrt(2f * jumpHeight * -gravity),加速度是重力反方向,跳跃高度固定,则计算出了速度增量,之后用它乘以(1+V Force)得出的一个对Y轴速度影响的增量。

上例子中速度增量根号2gh是8.48,因此每次蹬墙跳Y速度增量是8.48*1.335=11.32
代码默认有重力对Y轴速度影响:_velocity.y += gravity * Time.deltaTime; 即每秒Y轴速度会减去重力加速度(墙上为-24,地面为-25)若帧数是30,则每帧会减少0.8。具体可以将_velocity参数公开查看变化,实际蹬墙跳会离开墙体,重力加速度为-25,可自行调整这些参数来达到理想效果

修改部分代码:

    private float rawGravity;private int jumpLevel;//跳跃阶段 1段跳 2段跳private int dir; //朝向 -1左 1右public LayerMask jumpOnWallMask = 0;//墙体Layer层遮罩private bool isHoldWall; //是否在墙上public float jumpOnWallHForce = 1; //墙上跳跃横向力度public float jumpOnWallVForce = 2; //墙上跳跃纵向力度public float gravityOnWall = -24f;void Awake(){//... ...rawGravity = gravity;}void Update(){if (_controller.isGrounded){gravity = rawGravity;_velocity.y = 0;jumpLevel = 0;}//朝着dir方向发射长度为(碰撞体宽度+自身皮肤厚度)的射线RaycastHit2D hit = Physics2D.Linecast(playerBottomTrans.position, playerBottomTrans.position + new Vector3(dir * (Mathf.Abs(transform.localScale.x) * _controller.boxCollider.size.x / 2f + _controller.skinWidth), 0, 0), jumpOnWallMask);if (hit && hit.collider.tag == "Wall"){isHoldWall = true;gravity = gravityOnWall; //可调整由rawGravity随着时间降低到gravityOnWall}else{isHoldWall = false;gravity = rawGravity;}if ( Input.GetKey( KeyCode.RightArrow ) ){//... ...dir = 1;}else if( Input.GetKey( KeyCode.LeftArrow ) ){//... ...dir = -1;}else { //... ...}//原点击UpArrow代码删除,改为如下//点击向上if (Input.GetKeyDown(KeyCode.UpArrow)){//未在墙上if (!isHoldWall){//在地面起跳 (1级跳)if (_controller.isGrounded){jumpLevel = 1;_velocity.y = Mathf.Sqrt(2f * jumpHeight * -gravity);_animator.Play(Animator.StringToHash("Jump"));}else{//1级跳途中,再次起跳(2级跳)if(jumpLevel == 1){jumpLevel = 2;_velocity.y = Mathf.Sqrt(2f * jumpHeight * -gravity);_animator.Play("Jump");}}}else{//墙上可连续起跳,若想限制只能2段跳,则要类似上面代码写法//在墙上_velocity.x += -dir * jumpOnWallHForce;//仅在墙上会受到重力因此想再次起跳上升 必须比重力还要大的力 1+jumpOnWallForce//若在墙体上且在地面上,则不要加这个jumpOnWallVForce力,否则贴墙就起跳会让你飞起来!_velocity.y += Mathf.Sqrt(2f * jumpHeight * -gravity) * (1 + (_controller.isGrounded ? 0 : jumpOnWallVForce));_animator.Play("Jump");}}}

完整代码:

using UnityEngine;
using System.Collections;
using Prime31;public class DemoScene : MonoBehaviour
{// movement configprivate float rawGravity;public float gravity = -25f;public float runSpeed = 8f;public float groundDamping = 20f; // how fast do we change direction? higher means fasterpublic float inAirDamping = 5f;public float jumpHeight = 3f;[HideInInspector]private float normalizedHorizontalSpeed = 0;private CharacterController2D _controller;private Animator _animator;private RaycastHit2D _lastControllerColliderHit;private Vector3 _velocity;private int jumpLevel;//跳跃阶段 1段跳 2段跳private int dir; //朝向 -1左 1右public LayerMask jumpOnWallMask = 0;//墙体Layer层遮罩private bool isHoldWall; //是否在墙上public float jumpOnWallHForce = 1; //墙上跳跃横向力度public float jumpOnWallVForce = 2; //墙上跳跃纵向力度public float gravityOnWall = -24f;void Awake(){_animator = GetComponent<Animator>();_controller = GetComponent<CharacterController2D>();// listen to some events for illustration purposes_controller.onControllerCollidedEvent += onControllerCollider;_controller.onTriggerEnterEvent += onTriggerEnterEvent;_controller.onTriggerExitEvent += onTriggerExitEvent;rawGravity = gravity;}#region Event Listenersvoid onControllerCollider( RaycastHit2D hit ){// bail out on plain old ground hits cause they arent very interestingif( hit.normal.y == 1f )return;// logs any collider hits if uncommented. it gets noisy so it is commented out for the demo//Debug.Log( "flags: " + _controller.collisionState + ", hit.normal: " + hit.normal );}void onTriggerEnterEvent( Collider2D col ){Debug.Log( "onTriggerEnterEvent: " + col.gameObject.name );}void onTriggerExitEvent( Collider2D col ){Debug.Log( "onTriggerExitEvent: " + col.gameObject.name );}#endregion// the Update loop contains a very simple example of moving the character around and controlling the animationvoid Update(){if (_controller.isGrounded){gravity = rawGravity;_velocity.y = 0;jumpLevel = 0;}//朝着dir方向发射长度为(碰撞体一半宽度+自身皮肤厚度)的射线RaycastHit2D hit = Physics2D.Linecast(playerBottomTrans.position, playerBottomTrans.position + new Vector3(dir * (Mathf.Abs(transform.localScale.x) * _controller.boxCollider.size.x / 2f + _controller.skinWidth), 0, 0), jumpOnWallMask);if (hit && hit.collider.tag == "Wall"){isHoldWall = true;gravity = gravityOnWall; //可调整由rawGravity随着时间降低到gravityOnWall}else{isHoldWall = false;gravity = rawGravity;}if ( Input.GetKey( KeyCode.RightArrow ) ){normalizedHorizontalSpeed = 1;dir = 1;if( transform.localScale.x < 0f )transform.localScale = new Vector3( -transform.localScale.x, transform.localScale.y, transform.localScale.z );if( _controller.isGrounded )_animator.Play( Animator.StringToHash( "Run" ) );}else if( Input.GetKey( KeyCode.LeftArrow ) ){normalizedHorizontalSpeed = -1;dir = -1;if( transform.localScale.x > 0f )transform.localScale = new Vector3( -transform.localScale.x, transform.localScale.y, transform.localScale.z );if( _controller.isGrounded )_animator.Play( Animator.StringToHash( "Run" ) );}else{normalizedHorizontalSpeed = 0;if( _controller.isGrounded )_animator.Play( Animator.StringToHash( "Idle" ) );}//点击向上if (Input.GetKeyDown(KeyCode.UpArrow)){//未在墙上if (!isHoldWall){//在地面起跳 (1级跳)if (_controller.isGrounded){jumpLevel = 1;_velocity.y = Mathf.Sqrt(2f * jumpHeight * -gravity);_animator.Play(Animator.StringToHash("Jump"));}else{//1级跳途中,再次起跳(2级跳)if(jumpLevel == 1){jumpLevel = 2;_velocity.y = Mathf.Sqrt(2f * jumpHeight * -gravity);_animator.Play("Jump");}}}else{//墙上可连续起跳,若想限制只能2段跳,则要类似上面代码写法//在墙上_velocity.x += -dir * jumpOnWallHForce;//仅在墙上会受到重力因此想再次起跳上升 必须比重力还要大的力 1+jumpOnWallForce//若在墙体上且在地面上,则不要加这个jumpOnWallVForce力,否则贴墙就起跳会让你飞起来!_velocity.y += Mathf.Sqrt(2f * jumpHeight * -gravity) * (1 + (_controller.isGrounded ? 0 : jumpOnWallVForce));_animator.Play("Jump");}}// apply horizontal speed smoothing it. dont really do this with Lerp. Use SmoothDamp or something that provides more controlvar smoothedMovementFactor = _controller.isGrounded ? groundDamping : inAirDamping; // how fast do we change direction?_velocity.x = Mathf.Lerp( _velocity.x, normalizedHorizontalSpeed * runSpeed, Time.deltaTime * smoothedMovementFactor );// apply gravity before moving_velocity.y += gravity * Time.deltaTime;//在地面上,按住下键不松开会蓄力将起跳速度*3倍// if holding down bump up our movement amount and turn off one way platform detection for a frame.// this lets us jump down through one way platformsif( _controller.isGrounded && Input.GetKey( KeyCode.DownArrow ) ){_velocity.y *= 3f;_controller.ignoreOneWayPlatformsThisFrame = true;}_controller.move( _velocity * Time.deltaTime );// grab our current _velocity to use as a base for all calculations_velocity = _controller.velocity;}}

蹬墙跳问题:

因此你要将重力、X Force 、Y Force、JumpHeight都要调整好才能呈现出正常的蹬墙跳,目前来看仅靠简单调整Y Force是不行的,要么力度太大 要么力度太小。

二、扶墙下滑

Asset Store使用免费资源:Hero Knight - Pixel Art

		if(!_controller.isGrounded){if (isHoldWall){//必须是坠落时 if (_velocity.y < 0){//人物顶点发起射线检测到墙体 才算是完整在墙体上 播放扶墙动画RaycastHit2D hit2 = Physics2D.Linecast(playerTopTrans.position, playerTopTrans.position +new Vector3(dir * (Mathf.Abs(transform.localScale.x) * _controller.boxCollider.size.x / 2f + _controller.skinWidth), 0, 0), jumpOnWallMask);if (hit2 && hit2.collider.tag == "Wall"){_animator.Play(Animator.StringToHash("WallSlide"));}}}else{//避免影响1级跳(离地后)以及2级跳时立即切到Fall动画,代码里没有主动将jumpLevel在1级跳或2级跳结束后将jumpLevel改为0的操作,仅在蹬墙跳重置为0if (jumpLevel != 2 && jumpLevel != 1){_animator.Play(Animator.StringToHash("Fall"));}}}

蹬墙跳时进行重置jumpLevel为0状态 

Animator如上所示,Roll和Jump是无条件直接结束时回到Fall,仅适用于本案例不会在平地滚动。

可做辅助射线查看是否正常射线检测到墙体

//朝着dir方向发射长度为(碰撞体宽度+自身皮肤厚度)的射线
Debug.DrawRay(playerTopTrans.position, new Vector3(dir * (Mathf.Abs(transform.localScale.x) * _controller.boxCollider.size.x / 2 + _controller.skinWidth), 0, 0), Color.red);
Debug.DrawRay(playerBottomTrans.position, new Vector3(dir * (Mathf.Abs(transform.localScale.x) *_controller.boxCollider.size.x / 2 + _controller.skinWidth), 0, 0), Color.red);

        

skinWidth是为了让射线延伸到碰撞盒外面一点点(皮肤厚度)从而才能检测到其他物体

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9970.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA 使用 CLOCK_LOW_FANOUT 约束

使用 CLOCK_LOW_FANOUT 约束 您可以使用 CLOCK_LOW_FANOUT 约束在单个时钟区域中包含时钟缓存负载。在由全局时钟缓存直接驱动的时钟网段 上对 CLOCK_LOW_FANOUT 进行设置&#xff0c;而且全局时钟缓存扇出必须低于 2000 个负载。 注释&#xff1a; 当与其他时钟约束配合…

Excel 技巧21 - Excel中整理美化数据实例,Ctrl+T 超级表格(★★★)

本文讲Excel中如何整理美化数据的实例&#xff0c;以及CtrlT 超级表格的常用功能。 目录 1&#xff0c;Excel中整理美化数据 1-1&#xff0c;设置间隔行颜色 1-2&#xff0c;给总销量列设置数据条 1-3&#xff0c;根据总销量设置排序 1-4&#xff0c;加一个销售趋势列 2&…

Leetcode:219

1&#xff0c;题目 2&#xff0c;思路 第一种就是简单的暴力比对当时过年没细想 第二种&#xff1a; 用Map的特性key唯一&#xff0c;把数组的值作为Map的key值我们每加载一个元素都会去判断这个元素在Map里面存在与否如果存在进行第二个判断条件abs(i-j)<k,条件 符合直接…

MySQL(高级特性篇) 14 章——MySQL事务日志

事务有4种特性&#xff1a;原子性、一致性、隔离性和持久性 事务的隔离性由锁机制实现事务的原子性、一致性和持久性由事务的redo日志和undo日志来保证&#xff08;1&#xff09;REDO LOG称为重做日志&#xff0c;用来保证事务的持久性&#xff08;2&#xff09;UNDO LOG称为回…

芯片AI深度实战:进阶篇之vim内verilog实时自定义检视

本文基于Editor Integration | ast-grep&#xff0c;以及coc.nvim&#xff0c;并基于以下verilog parser(my-language.so&#xff0c;文末下载链接), 可以在vim中实时显示自定义的verilog 匹配。效果图如下&#xff1a; 需要的配置如下&#xff1a; 系列文章&#xff1a; 芯片…

C++:多继承习题5

题目内容&#xff1a; 先建立一个Point(点)类&#xff0c;包含数据成员x,y(坐标点)。以它为基类&#xff0c;派生出一个Circle(圆)类&#xff0c;增加数据成员r(半径)&#xff0c;再以Circle类为直接基类&#xff0c;派生出一个Cylinder(圆柱体)类&#xff0c;再增加数据成员h…

基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发

基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发 摘要 随着人工智能技术的不断发展&#xff0c;语音识别在会议记录、语音笔记等场景中得到了广泛应用。本文介绍了一个基于Python和阿里云百炼大模型的语音识别与文本保存工具的开发过程。该工具能够高效地识别东…

buu-pwn1_sctf_2016-好久不见29

这个也是栈溢出&#xff0c;不一样的点是&#xff0c;有replace替换&#xff0c;要输入0x3c字符&#xff08;60&#xff09;&#xff0c;Iyou 所以&#xff0c;20个I就行&#xff0c;找后面函数 输出提示信息&#xff0c;要求用户输入关于自己的信息。 使用fgets函数从标准输入…

【C语言】在Windows上为可执行文件.exe添加自定义图标

本文详细介绍了在 Windows 环境下,如何为使用 GCC 编译器编译的 C程序 添加自定义图标,从而生成带有图标的 .exe 可执行文件。通过本文的指导,读者可以了解到所需的条件以及具体的操作步骤,使生成的程序更具专业性和个性化。 目录 1. 准备条件2. 具体步骤步骤 1: 准备资源文…

分布式系统架构怎么搭建?

分布式系统架构 互联网企业的业务飞速发展&#xff0c;促使系统架构不断变化。总体来说&#xff0c;系统架构大致经历了单体应用架构—垂直应用架构—分布式架构—SOA架构—微服务架构的演变&#xff0c;很多互联网企业的系统架构已经向服务化网格&#xff08;Service Mesh&am…

阿里巴巴Qwen团队发布AI模型,可操控PC和手机

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

从 UTC 日期时间字符串获取 Unix 时间戳:C 和 C++ 中的挑战与解决方案

在编程世界里&#xff0c;从 UTC 日期时间字符串获取 Unix 时间戳&#xff0c;看似简单&#xff0c;实则暗藏玄机。你以为输入一个像 “Fri, 17 Jan 2025 06:07:07” 这样的 UTC 时间&#xff0c;然后轻松得到 1737094027&#xff08;从 1970 年 1 月 1 日 00:00:00 UTC 开始经…

ESP32-CAM实验集(WebServer)

WebServer 效果图 已连接 web端 platformio.ini ; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library stor…

DRF开发避坑指南01

在当今快速发展的Web开发领域&#xff0c;Django REST Framework&#xff08;DRF&#xff09;以其强大的功能和灵活性成为了众多开发者的首选。然而&#xff0c;错误的使用方法不仅会导致项目进度延误&#xff0c;还可能影响性能和安全性。本文将从我个人本身遇到的相关坑来给大…

qt-C++笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphicsRectItem的区别

qt-C笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphicsRectItem的区别 code review! 参考笔记 1.qt-C笔记之重写QGraphicsItem的paint方法(自定义QGraphicsItem) 文章目录 qt-C笔记之QLine、QRect、QPainterPath、和自定义QGraphicsPathItem、QGraphic…

C动态库的生成与在Python和QT中的调用方法

目录 一、动态库生成 1&#xff09;C语言生成动态库 2&#xff09;c类生成动态库 二、动态库调用 1&#xff09;Python调用DLL 2&#xff09;QT调用DLL 三、存在的一些问题 1&#xff09;python调用封装了类的DLL可能调用不成功 2&#xff09;DLL格式不匹配的问题 四、…

.NET MAUI进行UDP通信(二)

上篇文章有写过一个简单的demo&#xff0c;本次对项目进行进一步的扩展&#xff0c;添加tabbar功能。 1.修改AppShell.xaml文件&#xff0c;如下所示&#xff1a; <?xml version"1.0" encoding"UTF-8" ?> <Shellx:Class"mauiDemo.AppShel…

什么是Maxscript?为什么要学习Maxscript?

MAXScript是Autodesk 3ds Max的内置脚本语言,它是一种与3dsMax对话并使3dsMax执行某些操作的编程语言。它是一种脚本语言,这意味着您不需要编译代码即可运行。通过使用一系列基于文本的命令而不是使用UI操作,您可以完成许多使用UI操作无法完成的任务。 Maxscript是一种专有…

适配器模式

目录 一、概念 1、定义 2、涉及到的角色 二、类适配器 1、类图 2、代码示例 &#xff08;1&#xff09;水饺&#xff08;源角色&#xff09; &#xff08;2&#xff09;烹饪&#xff08;目的角色&#xff09; &#xff08;3&#xff09;食品适配器&#xff08;适配器角…

YOLO11/ultralytics:环境搭建

前言 人工智能物体识别行业应该已经饱和了吧&#xff1f;或许现在并不是一个好的入行时候。 最近看到了各种各样相关的扩展应用&#xff0c;为了理解它&#xff0c;我不得不去尝试了解一下。 我选择了git里非常受欢迎的yolo系列&#xff0c;并尝试了最新版本YOLO11或者叫它ultr…