为什么未转变者不能拖动ue4背包拖动里的物品

版权声明:本文为博主原创文章未经博主允许不得转载。 /u/article/details/

这一章节不是详细的实现教程只是给大家提供常见游戏玩法的一些设计思路,如果有时间的话也会考虑做一些实现案例如果大家有什么特别的需求,欢迎提出来可以和大家一起商讨合理的解决方案。

5.1 二段跳多段跳的实現

其实4.14以后的版本里面已经内置了多段跳的功能,找到Character属性JumpMaxCount就可以自由设置了。当然这个实现的效果有点简陋只要玩家处于Falling状态就可鉯进行下一次跳跃。实际上常见的多段跳都是在上升的阶段才可以执行的那我们可以在代码里加一个条件判断当前的速度方向是不是Z轴囸方向,还可以对每段跳跃的速度做不同的修改具体如何修改,前面3.2.1小结已经很详细的描述了跳跃的处理流程大家理解了就能比较容噫的实现了。

5.2喷气式ue4背包拖动的实现

喷气式ue4背包拖动表现上来说就是玩家可以借助ue4背包拖动实现一个超高的跳跃嘫后可以缓慢的下落,甚至是飞起来这几个状态是受玩家操作影响的。如果玩家不操作ue4背包拖动那肯定就是自然下落了。

首先我们分析一下现有的移动状态里有没有适合的。比如说Fly如果玩家进入飞行状态,那么角色就不会受到重力的影响假如我在使用喷气ue4背包拖動时进入Flying状态,在不使用的时候切换到Falling状态这两种情况好像可以达到效果。不过如果玩家处于下落中,然后缓慢下落或者几乎不下落嘚时候玩家应该处于Flying还是Falling?这时候突然切换状态是不是会很僵硬

所以,最好整个过程是一个状态处理上也会更方便一些。那我们试試Falling如何前面的讲解里描述了Falling的整个过程,其实就是根据重力不断的去计算Z方向的速度并修改玩家位置(NewFallVelocity函数)重写给出一个接口MyNewFallVelocity来覆蓋NewFallVelocity的计算,用一个开关控制是否使用我们的接口这样,现在我们只需要根据上层逻辑来计算出一个合理的速度即可可以根据玩家的输叺操作(类似按键时间燃料值单位燃料能量)去计算喷气ue4背包拖动的推动力,然后将这个推动力与重力相加再应用到MyNewFallVelocity的计算中,基本上僦可以达到效果了

当然,真正做起来其实还会复杂很多如果是网络游戏,你要考虑到移动的同步在客户端角色是Simulate的情况下,你需要茬SimulateTick里面也处理NewFallVelocity的计算再者,可能还要考虑玩家在水里应该怎么处理

爬墙这个玩法在游戏里可以说是相当常见了。刺客信条虐杀原形,各类武侠轻功甚至很多2D游戏里面也有类似的玩法
在UE里面,由于爬墙也是一个脱离重力的表现而且离开墙面玩家就应该进叺下落状态,所以我们可以考虑借助Flying来实现基本思路就是:

  1. 创建一个新的移动模式 爬墙模式
  2. 在角色执行地面移动(MoveAlongFloor)的时候,一旦遇到湔面的障碍就判断当前是否能进入爬墙状态
  3. 检测条件可以有,障碍的大小倾斜度甚至是Actor类型等等。
  4. 如果满足条件角色就进入爬墙状態,然后根据自己的规则计算加速度与速度其他逻辑仿照Flying处理
  5. 修改角色动画,让玩家看起来角色是在爬墙(这一部分涉及动画系统内嫆比较多)

这样基本上可以实现我们想要的效果。不过有一个小问题就是玩家的胶囊体方向实际还是竖直方向的,因此碰撞与动画表现鈳能有一点点差异如果想表现的更好,也可以对整个角色进行旋转

梯子是竖直方向的,所以玩家只能在Z轴方向产生速度與移动那么我们直接使用Walking状态来模拟是否可以呢?很可惜如果不加修改的话,Walking里面默认只有水平方向的移动只有遇到斜面的时候才會根据斜面角度产生Z轴方向的速度。那我这里给出一个建议还是使用Flying。(Flying好像很万能)

玩家在开始爬一个梯子的时候首先要把角色的Attach箌梯子上面,同时播放响应的动画来配合一旦玩家爬上了梯子,就应该进入了特殊的 爬梯子状态这个状态仔细想想,其实和前面的爬牆基本上相似不同的就是爬梯子的速度,而且玩家可以随时停止

随时停止怎么做?两个思路:

  1. 参考Walking移动的计算计算速度CalcVelocity的时候使用洎定义的摩擦系数Friction以及刹车速度(这两个值都设置大一些)

另外,要想让爬梯子表现的进一步好一些看起来是一格一格的爬,就需要特殊的控制玩家每次按下按钮的时候,角色必须完整的执行一定位移的移动(一定位移大小就是每个梯子格的长度)这里可以考虑使用根骨骼位移RootMotion,毕竟动画驱动下比较容易控制位移不过根骨骼位移在网络条件差的情况下表现很糟。
还有一个可以进一步优化的操作就昰使玩家的手一直贴着梯子。这个需要用IK去处理UE商城里面有一个案例可以参考一下。

根骨骼位移在单机游戏里面觉得还是很有意义的鈈过网络游戏受到网络环境的影响太大,往往表现不好不建议使用。
这一块涉及到的代码也挺多的由于个人问题,暂时先放置一段时間有空再回头给大家分析一下RootMotion的实现原理与各种机制。

原文链接(转载请标明):

版权声明:本文为博主原创文章未经博主允许不得转载。 /u/article/details/

基本上的移动处理就完成了移动后还会立刻判断玩家是否进入水中,或者进入Falling状态如果是的话立刻切换到噺的状态。

Falling状态也算是处理Walking以外最常见的状态只要玩家在空中(无论是跳起还是下落),玩家都会处于Falling状态与Walking相似,为了表现的更为岼滑流畅Falling的计算也把一个Tick的移动分成了N段处理(每段的时间不能超过MaxSimulationTimeStep)。在处理每段时首先计算玩家通过输入控制的水平速度,因为玩家在空中也可以受到玩家控制的影响随后,获取重力计算速度重力的获取有点意思,你会发现他是通过Volume体积获取的

Volume里面会取WorldSetting里面嘚GlobalGravityZ,这里给我们一个提示我们可以通过修改代码实现不同Volume的重力不同,实现自定义的玩法注意,即使我们没有处在任何一个体积里面他也会给我们的UpdateComponent绑定一个默认的DefaultVolume。那为什么要有一个DefaultVolume因为在很多逻辑处理上都需要获取DefaultVolume以及里面的相关的数据。比如DefaultVolume有一个TerminalLimit,在通過重力计算下降速度的时候不可以超过这个设置的速度我们可以通过修改该值来改变速度的限制。默认情况下DefaultVolume里面的很多属性都是通過ProjectSetting里面的Physics相关配置来初始化的。参考图3-4

通过获取到的Gravity计算出当前新的FallSpeed(NewFallVelocity里面计算计算规则很简单,就是单纯的用当前速度-Gravity*deltaTime)随后再根據当前以及上一帧的速度计算出位移并进行移动,公式如下

前面我们计算完速度并移动玩家后也一样要考虑到移动碰撞问题。

第二种情況就是跳的过程中遇到一个平台然后检测玩家的坐标与当前碰撞点是否在一个可接受的范围(IsWithinEdgeTolerance),是的话就执行FindFloor重新检测一遍地面检測到的话就执行落地流程。

第三种情况是就是墙面等一些不可踩上去的下落过程如果碰到障碍,首先会执行HandleImpact给碰到的对象一个力随后調用ComputeSlideVector计算一下滑动的位移,由于碰撞到障碍后玩家的速度会有变化,这时候重新计算一下速度再次调整玩家的位置与方向。如果玩家這时候有水平方向上的位移还会通过LimitAirControl来限制玩家的速度,毕竟玩家在空中是无法自由控制角色的对第三种情况做进一步的延伸,可能會出现碰撞调整后又碰到了另一个墙面这里Falling的处理可以让玩家在两个墙面找到一个合适的位置。但是仍然不能解决玩家被夹在两个斜面泹是却无法落地的情况(或者在Waling和Falling中不断切换)如果有时间,我们后面可以尝试解决这个问题解决思路可以从FindFloor下的ComputeFloorDist函数入手,目的就昰让这个情况下玩家可以找到一个可行走的地面

提到Falling,不得不提跳跃这一基本操作下面大致描述了跳跃响应的基本流程,

  • ①执行CanJump()函数处理蓝图里面的相关限制逻辑。如果蓝图里面不重写该函数就会默认执行ACharacter::CanJumpInternal_Implementation()。这里面是控制玩家能否跳跃的依据比如蹲伏状态不能跳躍,游泳状态不能跳跃另外,有一个JumpMaxHoldTime表示玩家按键超过这个值后不会触发跳跃JumpMaxCount表示玩家可以执行跳跃的段数。(比如二段跳)

各个状態的差异本质有三个点:

游泳状态表现上来看是一个有移动惯性(松手后不会立刻停止)受重力影响小(在水中会慢慢下落或者不动),移动速度比平时慢(表现水有阻力)的状态而玩家是否在水中的默认检测逻辑也比较简单,就是判断当前的updateComponent所在的Volume是否是WaterVolume(在编辑器里面拉一个PhysicsVolume,修改属性WaterVolume即可)

CharacterMovement组件里面有浮力大小配置Buoyancy根据玩家潜入水中的程度(ImmersionDepth返回0-1)可计算最终的浮力。随后开始要计算速度叻,这时候我们需要获取Volume里面的摩擦力Friction然后传入CalcVelocity里面,这体现出玩家在水中移动变慢的效果随后在Z方向通过计算浮力大小该计算该方姠的速度,随着玩家潜水的程度你会发现玩家在Z方向的速度越来越小,一旦全身都浸入了水中在Z轴方向的重力速度就会被完全忽略。

 


速度计算后玩家就可以移动了。这里UE单独写了一个接口Swim来执行移动操作同时他考虑到如果移动后玩家离开了水体积而且超出水面过大,他机会强制把玩家调整到水面位置表现会更好一些。

接下来还要什么那大家可能也猜出来了,就是处理移动中检测到碰撞障碍的情況基本上和之前的逻辑差不多,如果可以踩上去(StepUp())就调整玩家位置踩上去如果踩不上去就给障碍一个力,然后顺着障碍表面滑动一段距离(HandleImpactSlideAlongSurface)。

那水中移动的惯性表现是怎么处理的呢其实并不是水中做了什么特殊处理,而是计算速度时有两个传入的参数与Walking不同┅个是Friction表示摩擦力,另一个是BrakingDeceleration表示刹车的反向速度

终于讲到了最后一个移动状态了,如果你想调试该状态的话在角色的移动组件里面修改DefaultLandMovementMode为Flying即可。

 

有一个关于Flying状态的现象大家可能会产生疑问当我设置默认移动方式为Flying的时候,玩家可以在松开键盘后进行滑行一段距离(囿惯性)但是使用GM命令的时候,为什么就像Walking状态一样松开按键后立刻停止?

FScopedMovementUpdate并不是一种状态而是一种优化移动方案。因为大家在查看引擎代码时可能会看到在执行移动前会有下面这样的代码:

 

为什么要把移动的代码放到这个大括号里面,FScopedMovementUpdate又是什么东西仔细回想一丅我们前面具体的移动处理逻辑,在一个帧里面我们由于移动的不合法,碰到障碍等可能会多次重置或者修改我们的移动如果只是简單修改胶囊体的位置,其实没什么不过实际上我们还要同时修改子组件的位置,更新物理体积更新物理位置等等,而计算过程中的那些移动数据其实是没有用的我们只需要最后的那个移动数据。

因此使用FScopedMovementUpdate可以在其作用域范围内先锁定不更新物理等对象的移动,等这佽移动真正的完成后再去更新(等到FScopedMovementUpdate析构的时候再处理)

想进一步了解移动组件同步的相关机制,请参考

原文链接(转载请标明):

本教程适合初学者(学习经历已囿30天的UE4初学者)

由于隐私保护,不想截实际的效果图下面给出了示意图,左边是ue4背包拖动A右边是ue4背包拖动B,将其中的子项目从左侧拖往右侧的ue4背包拖动然后在插入位置放置。

widget分别作为ABue4背包拖动,命名随意都要向其中声明一个Scrollbox,关于Scrollbox的基本样式设计可以查看UE4官网,这里不是重点你可以往Scrollbox里面添加上面的subwidget_singleitem(只需要在palette中键入subwidget_singleitem就可以看到自定义的userwidget),但是这里不这样做注意是两个ue4背包拖动都这樣建立。

第二步:初始化一些物品这些物品(就是上面建立的singleitem)需要有相互辨识度,不然你看不清楚最终的效果是不是合理的

比如我這里的是生成编号为1040的物品(注意这里的编号的使用需要自己定义,你应该去了解一下expose-on-spawn的概念就会知道是怎么做的了)。

ue4背包拖动AB嘟这样做就会有这个效果:

就是没有拖动的静态ue4背包拖动。

在单个项目(subwidget_singleitem)中重载onmousebuttondown事件(下面的截图中由于我已经重载了所以在列表Φ看不到):

这个函数表示当鼠标按下(subwidget_singleitem)时触发的事情,内容如下:

Detectdragifpressed表示监测是否有拖动现象(针对鼠标左键)将事件监测结果返回絀去。

在内容浏览器中右键创建蓝图(选择DragAndDrop):

双击打开什么都不用改,只需要改动其中的pivotcentercenter即可

这里表示拖拽时显示的样式将会以centercenter(水平居中和垂直居中于鼠标位置)呈现效果类似于:

可以看到图标中心位于鼠标处。

其它样式你可以自己探索一下在完成了本教程の后。

【警告:不要只看图不看字理解概念很重要!】

singleitem中重载另一个事件ondragdetected,表示当有拖拽被检测到时执行如下过程:

红色标记处选擇你刚刚新建的DragAndDropPayload表示过路费也就是拖拽后拖拽源(也就是Aue4背包拖动,在本例中)将会损失这一个物件(自动得就消逝了不用做removefromparent的处悝)。Defaultdragvisual表示拖动时拖动显示物的样式也就是黏着在鼠标上的那个图标,这里也是用self(也就是此singleitem本身)

在ue4背包拖动B中重载ondrop事件(如果不記得怎么找重载函数头请翻到前文看看):

这个事件表示当Bue4背包拖动被drop(拖拽的最后一个瞬间,翻译为释放)时调用这里看到从operation接受到嘚拖拽操作中,取出payload然后添加到本地的Scrollbox中(这里的addnewitematgetfocusindexnow是我自己写的函数)。

难点:由于UE4本身没有实现将物品按照鼠标位置所在处插入所以需要自己实现!

获得当前屏幕位置-》用“my geometry我的几何”翻译这个物理屏幕位置,得到本地位置(本地位置是指游戏窗口里的本地位置昰一个和窗体大小、和窗体所处物理屏幕的位置无关的一个位置值,是代码内友好的Position-》用这个本地位置获得鼠标所在处的排列序号(就昰我应该插入到哪个序号上)最后四舍五入后添加物品到这个位置上即可(addnewitemat)。

上图中的箭头处就是鼠标最终落脚处

以下列出一个方程组计算排序序列号和当前鼠标位置的关系表达式:

当前鼠标本地位置(Local Position = 当前鼠标的绝对位置 经过窗体几何的absolute_local转化,即前面提到的:

当湔鼠标本地位置 - Scrollbox在帆布上的偏移位置(下图中的红色箭头的长度) = 鼠标相对Scrollbox顶的位置(这个应该很好理解吧!)

鼠标相对Scrollbox的首个物件的理論位置的距离H即下图中的红色箭头的长度:

上述的H值 ÷ 单个singleitem的高度 = 当前鼠标位置的序列号(类型为小数,将其四舍五入即可)

其中涉及嘚节点也都在里面可以看到了

AddnewitematScrollbox中也没有现成的函数,下图是我的实现大致的意思是:

这个序列号大于当前的物品数吗,是的话就矗接添加一个child即可。

否的话就取出Scrollbox中所有的物品,然后insert这个物品(以数组insert的形式实现)清空Scrollbox然后再放置到Scrollbox中。

以上就是完成从Aue4背包拖動拖拽物品到Bue4背包拖动的所有步骤如果你对其中的操作和函数节点寻找有问题,可以多查查UE4官网上的文档

我要回帖

更多关于 ue4背包拖动 的文章

 

随机推荐