Unity笔记-29-ARPG游戏项目-03-攀爬系统

需求说明

当人物靠近墙壁时,并且对着墙壁执行移动按键时,此时会从普通状态进入到爬墙状态,这是一个进入攀爬的初始化状态,进入攀爬状态后,WASD控制攀爬方向而不能控制人物移动,跳跃键提供攀跳而不能控制人物普通跳跃;按下X会立刻退出攀爬状态,半空中则会直接坠落;当人物攀爬到墙顶,会播放攀顶动画,应用根运动,攀爬到墙顶,并推出攀爬状态;

特别强调:攀爬状态下,无法移动和跳跃;

不同的攀爬环境

这张图中,我们可以看到至少三种攀爬环境:竖直;弧形;倾斜;

人物需要能够在这些不同的环境下攀爬并且能平滑过渡与环境的变化

第一步:上墙

我们首先需要实现人物从普通状态进入攀爬初始状态,简单来说就是先能够攀在墙上,简称上墙

那么这里我们就需要通过射线检测的方式去检测面前是否有墙,检测到了还需要判断人物是否持续向这个方向移动,否则容易让角色以靠近墙就进入上墙,很多之后只是路过,否则会很影响体验。这个检测在每次上墙的短暂时间里只检测一次,不能多次检测否则会一直初始化,导致一直上墙,就导致BUG了。

注:我这里的墙体检测是写在移动脚本组件里的

    /// <summary>/// 墙壁检测-判断是否进入攀爬状态/// </summary>private void WallProcess(){if (climbTest.canClimb) return;Vector3 rayDir = moveDirection.magnitude > 0.1 ? moveDirection : transform.forward;if (!Physics.Raycast(transform.position + wallRayHeightOffset * Vector3.up, rayDir,out wallHit,wallRayLength, environmentLayerMask)){isExistWall = false;isCheckWall = false;wallDelayCounter = wallDelayTime;return;}else{isExistWall = true;}//如果检测到墙壁并且当前还未检测过墙壁if (isExistWall && !isCheckWall) {isCheckWall = true;}if (isCheckWall)//如果检测到墙壁了{if (wallDelayCounter < 0){jumpTest.canJump = false;canMove = false;rigidbody.useGravity = false;rigidbody.isKinematic = true;climbTest.wallHit = wallHit;climbTest.InitClimb();climbTest.canClimb = true;}else{wallDelayCounter -= Time.deltaTime;}}}

首先判断是否能够攀爬,则直接返回;因为正常情况下是不能攀爬的,这个值为false,如果能攀爬就说明已经进入了攀爬状态,不需要检测上墙过程了;

然后以移动方向作为射线检测的方向,这里还要注意,由于一般人物模型的坐标点在脚底,因此这里需要添加一点高度上的偏移,否则容易检测到地板,导致上墙上在了地板上,那就闹出笑话来了;这里还需要使用wallRayLength限定墙体检测距离,不可能距离墙很远也能上墙吧;如果检测到了则将isExistWall置为true,否则将一系列参数重置;这里说明一下wallDelayCounter这是一个计时器,判断玩家是否持续向这个方向移动,因为如果朝向更改就不会检测到了,就能避免玩家不小心往墙体移动就导致上墙,但实际上并不想上墙;

在判断如果isExistWall并且!isCheckWall则将isCheckWall置为true。这里貌似有点多余,阅者可以自己适当删减。

如果isCheckWalltrue,则判断已经检测到墙壁了,此时开始计时器的倒计时,判断玩家是否持续朝这个方向移动,如果计时器小于0,则表示上墙判定成功,则执行上墙操作:首先将跳跃和移动的允许执行改为不允许,并将重力关闭,

将检测到的墙体对象传给攀爬脚本组件,并执行攀爬脚本的初始化方法,并将canClimb置为true

到这里,上墙的准备工作:墙体检测算是完成了。

接下来初始化上墙位置

    /// <summary>/// 初始化上墙位置/// </summary>/// <param name="hit"></param>public void InitClimb(){onWall = false;targetPos = wallHit.point + wallHit.normal * wallOffset-GameConst.WALL_CHECK_ORIGION_OFFSET*Vector3.up;//Debug.Log(targetPos);ani.CrossFade(GameConst.IDLETOCLIMB_STATE, 0.2f);ani.SetFloat(GameConst.CLIMB_PARAM_IDLETOCLIMB, 1, 0.5f, Time.deltaTime);}

这里引入onWall表示玩家此时是否在墙体上,上墙初始化不算在墙上,因此置为false,并将墙体位置通过墙面法线向量计算偏移后的到适当的上墙位置targetPos即可,随后就是动画设置,这里阅者自己完成;

获得上墙位置后,需要对人物位置进行设置

    private void SetBodyPosition(){if (Vector3.Distance(transform.position, targetPos) < 0.01f){onWall = true;transform.position = targetPos;return;}Vector3 lerpTargetPos = Vector3.MoveTowards(transform.position, targetPos, 0.2f);transform.position = lerpTargetPos;}

首先判断如果人物位置已经接近墙体位置,则将onWall置为true,并直接将位置赋值,再返回;否则则通过lerp的方式将玩家移动到目标位置

Update

    private void Update(){if (Input.GetButtonDown(GameConst.EXITCLIMB_BUTTON) && canClimb){ExitClimb();}if (canClimb){inputDelta = new Vector2(Input.GetAxis(GameConst.HORIZONTAL_AXIS), Input.GetAxis(GameConst.VERTICAL_AXIS));if (!onWall){SetBodyPosition();}else{ClimbUpToLand();HopHandler();MoveHandler();FixBody();}}}

这里首先判断是否按下X推出攀爬按键并且当前正在攀爬,如果成立则推出攀爬,如果不在攀爬状态,按下X是无效的。

在判断是否进入攀爬状态,如果进入,则通过虚拟轴获取移动的二维方向向量;

在判断时候以及完成上墙初始化,如果没有完成onWallfalse,会继续设置初始化位置,如果完成则执行else里的语句。

第二步:爬起来

这里通过动画根动作实现,逻辑十分简单,直接上代码,仅供参考,需要阅者自己完成

    public void MoveHandler(){if (inputDelta != Vector2.zero){//count = 1;ani.SetFloat(GameConst.CLIMB_PARAM_HORIZONTAL, inputDelta.x);ani.SetFloat(GameConst.CLIMB_PARAM_VERTICAL, inputDelta.y);}else{ani.SetFloat(GameConst.CLIMB_PARAM_HORIZONTAL, 0);ani.SetFloat(GameConst.CLIMB_PARAM_VERTICAL, 0);}}public void HopHandler(){if (Input.GetButtonDown(GameConst.JUMP_BUTTON)&inputDelta.magnitude>0.4f){ani.CrossFade(GameConst.CLIMBHOP_STATE,0f);}}

第三步:位置与旋转修正

这一步最为重要,因为,人物在攀爬过程中,如果没有位置和旋转的不断修正,是会导致穿模的,这对于玩家来说是难以接受的。

因此这里需要详细的说明,老规矩先上代码,再讲解

    private void FixBody(){//世界坐标转局部坐标localHelperPos = transform.InverseTransformPoint(climbHelper.position);//头部世界坐标headPos = transform.TransformPoint(localHelperPos.x, localHelperPos.y, 0);//计算固定位置RaycastHit hit;if (Physics.SphereCast(new Ray(headPos, transform.forward), 0.1f, out hit,fixedCheckLength, environmentLayerMask)){//位置修正Vector3 temp = transform.position - climbHelper.position;if (Vector3.Distance(transform.position, hit.point + temp) > 0.01f){transform.position = hit.point + temp;}//Yaw轴修正Vector3 normal_Yaw = Vector3.ProjectOnPlane(hit.normal, upAxis);Vector3 forward_Yaw = Vector3.ProjectOnPlane(transform.forward, upAxis);float angle_Yaw = 180 - Vector3.Angle(normal_Yaw, forward_Yaw);Vector3 cross_Yaw = Vector3.Cross(normal_Yaw, forward_Yaw);if (cross_Yaw.y < 0) angle_Yaw = -angle_Yaw;transform.rotation = Quaternion.AngleAxis(angle_Yaw, transform.up) * transform.rotation;//Pitch轴修正Vector3 normal_Pitch = Vector3.ProjectOnPlane(hit.normal, transform.right);Vector3 forward_Pitch = Vector3.ProjectOnPlane(transform.forward, transform.right);float angle_Pitch = 180 - Vector3.Angle(normal_Pitch, forward_Pitch);Vector3 cross_Pitch = Vector3.Cross(normal_Pitch, forward_Pitch);if (Vector3.Angle(transform.right, cross_Pitch)>90) angle_Pitch = -angle_Pitch;//Debug.Log(angle_Pitch);if (angle_Pitch < -45){ExitClimb();return;}Quaternion relative = Quaternion.AngleAxis(angle_Pitch, transform.right) * transform.rotation;transform.rotation = Quaternion.Lerp(transform.rotation,relative,fixTime);}}

首先我们需要一个空对象,这个对象事先创建好作为人物的子级跟随人物移动,将他的位置放在人物模型的前方,作为攀爬位置修正的辅助位置,人物需要与墙体保持一段恒定的距离以防止穿模,这个恒定距离就是事先设定好的辅助位置到固定直线距离(不是坐标的直线距离)的固定直线位置,图解如下:

当然只是修正位置还不够,攀爬时,人物朝向必须与墙面垂直,人物纵向朝向必须与墙面平行,因此,这里就需要两个自由度上的角度修正

思路都是一样的:

射线检测墙体,通过墙体的法向向量与人物朝向的夹角修正即可,左右通过叉乘判断,注意获取夹角时,需要先将想来那个投影在对应的面上,确保获得的夹角时正确的,可以用Debug确定,注意一点,在pitch轴修正的时候角度的正负需要通过判断叉乘向量和人物的右方是否一致,而不是简单的大于0或者小于0,Yaw轴由于重力方向不会变化,因此左右判断通过大于0或小于0判断即可,这是二者的细微不同之处,修正完方向后,叠加四元数后lerp给角色的rotation即可。pitch轴注意一个,当墙体负倾斜过大时,人物应当直接掉落而非能够继续攀爬;

第四部:攀爬到墙顶

添加一个辅助检测位置,将这个位置放在头顶上方,检测是否有墙体,如果头顶已经检测不到墙体了,则执行攀到墙顶的操作,值得注意的是:注意射线检测距离,设置的近一点,防止由于地形倾斜导致检测到地面,其余较为简单不再赘述

    public void ClimbUpToLand(){Vector3 rayDir = moveTest.moveDirection.magnitude > 0.2f ?moveTest.moveDirection:transform.forward;//Vector3 rayDir = transform.forward;if(!Physics.SphereCast(new Ray(climbUpHelper.position, rayDir),0.1f,upCheckLength,environmentLayerMask)){canClimb = false;ani.CrossFade(GameConst.CLIMBTOUP_STATE, 0f);Invoke("ExitClimb", ani.GetCurrentAnimatorStateInfo(1).length);}}

最后,其实还有IK动画的设置,这就交给阅者自己完成了,这个相对前面的会简单些。

当然,这样的攀爬系统仍然不够完善,阅者自己完成它吧!

最后补充各类参数的定义

    [Header("是否能够攀爬")]public bool canClimb;[Header("是否在墙上")]public bool onWall;[Header("地形层")]public LayerMask environmentLayerMask;[Header("贴墙位置偏移")][Range(0,1)]public float wallOffset;[Header("辅助坐标-贴墙")]public Transform climbHelper;[Header("辅助坐标-墙顶")]public Transform climbUpHelper;[Header("修正过渡时间")][Range(0,0.5f)]public float fixTime;[Header("墙顶持续检测范围")][Range(0, 2)]public float upCheckLength;[Header("修正持续检测范围")][Range(0, 2)]public float fixedCheckLength;private Animator ani;//动画组件private Rigidbody rigidbody;//刚体组件[HideInInspector]public RaycastHit wallHit;//墙体检测点private Vector3 upAxis;//Yaw轴private Vector2 inputDelta;//攀爬二维输入量private JumpTest jumpTest;//跳跃组件private MoveTest moveTest;//移动组件private Vector3 targetPos;//贴墙初始目标位置private Vector3 localHelperPos;//临时存储位置private Vector3 headPos;//头部位置

Unity笔记-29-ARPG游戏项目-03-攀爬系统相关推荐

  1. ue4——攀爬系统的实现与总结

    攀爬系统概述 运用场景 在许多动作类游戏中,攀爬系统作为动作系统的一部分为游戏提供了更多的玩法.如"跑酷系统"."躲避系统"."轻功系统". ...

  2. 【UE·GamePlay篇】攀爬系统系列教程(二)——相邻墙壁飞跃、墙角拐弯、回头反向跳

    这一篇的内容对应视频教程: UE4 Climb System - Tutorial - Part 3 - Side Jumps & Corner Detection UE4 Climb Sys ...

  3. Unity3D ARPG C# Scripting 學習筆記-1 ( 基本移动, 攀爬动作 )

    Udemy 仿刺客教条游戏的课程学习笔记 Learn & Build Unity 3D Mobile Assassin Creed Game Clone 2023 ​ 0. 基本动作对应动画设 ...

  4. 藤本植物和攀爬植物模型包 Globe Plants – Bundle 23 – Vines and Creepers 03 (3D Models)

    藤本植物和攀爬植物模型包 Globe Plants – Bundle 23 – Vines and Creepers 03 (3D Models) 全球植物–第23束–藤本植物和攀缘植物03 (3D模 ...

  5. Unity手游之路十自动寻路Navmesh之跳跃,攀爬,斜坡

    转载 Unity手游之路<十>自动寻路Navmesh之跳跃,攀爬,斜坡 分类: unity2013-12-27 00:50 6545人阅读 评论(5) 收藏 举报 unity3dNavme ...

  6. Unity手游:自动寻路Navmesh 跳跃 攀爬 斜坡

    原地址:http://dong2008hong.blog.163.com/blog/static/46968827201403114644210/ 步骤 1.在场景中摆放各种模型,包括地板,斜坡,山体 ...

  7. 【Unity3D日常开发】自动寻路系统Navigation实现人物上楼梯、走斜坡、攀爬、跳跃

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 QQ群:1040082875 参考文章:列表 Unity3D深入浅出 - 导航网格自动寻路(Navigat ...

  8. 【Unity3D】自动寻路系统Navigation实现人物上楼梯、走斜坡、攀爬、跳跃

    @toc 参考文章:列表 Unity3D深入浅出 - 导航网格自动寻路(Navigation Mesh) unity3D--自带寻路Navmesh入门教程(二) Unity3D自动寻路系统Naviga ...

  9. 攀爬网怎么取消_桂林旅游学院宿舍条件怎么样

    大学就是我们的第二个家,高考填报志愿时,桂林旅游学院宿舍条件怎么样.好不好是广大同学和家长朋友们十分关心的问题,为了方便大家查询,大学生必备网已经为大家整理好了桂林旅游学院宿舍条件和宿舍图片,供大家参 ...

  10. python爬取b站评论_学习笔记(1):写了个python爬取B站视频评论的程序

    学习笔记(1):写了个python爬取B站视频评论的程序 import requests import json import os table='fZodR9XQDSUm21yCkr6zBqiveY ...

最新文章

  1. 判断两个图片的特征向量_响应式布局提高篇 图片正确的打开方式
  2. Nature Methods:宏基因组物种组成分析工具MetaPhlAn2
  3. 基于Matlab的声波信号处理,基于声卡和Matlab平台的语音信号增强处理系统
  4. 曙光与包头签署云计算中心战略合作协议
  5. 1625 宝石项链 大视野评测
  6. P3369-[模板]普通平衡树【有旋Treap】
  7. Android中文API(136) —— Bitmap
  8. 2021年00后生活方式洞察报告
  9. C++ 中的数学计算函数
  10. windows下安装python的包管理工具pip,scikit-learn
  11. Vivado封装自定义IP
  12. 模式识别与机器学习第六章有监督学习方法
  13. 解决Win10系统下运行unity游戏闪退报错问题 包含 人类一败涂地 波西亚时光等
  14. 以计算机网络为中介的人际传播,人际传播在传媒中的运用
  15. 【Dataset】GoEmotions: A Dataset of Fine-Grained Emotions
  16. 程序员的圣诞礼物:计算机寓言之夏
  17. 实话谈扶贫第一篇——教育扶贫
  18. Flask入门教程—超详细
  19. GDT陶瓷气体放电管的材质介绍
  20. Jmeter介绍与使用

热门文章

  1. WordPress | QQ互联授权登录
  2. PowerBI动态M查询参数
  3. 作为审稿人,你什么情况下会选择拒稿?
  4. Windows与Linux之间的文件互传
  5. 高项笔记1.信息化和信息系统
  6. MySOL(狂殴26K字只为博君一赞)
  7. Keil出现“File has been changed outside the editor, reload?”提示
  8. 中国六大最忙和六大最懒城市
  9. 图解:什么是拓扑排序?
  10. 各个国家的人有什么特点?