YuHang’s Blog

Unreal自由镜头需求总结

细数做自由镜头时采用的方案已经遇到的坑

Unreal自由镜头

整理一下最近做的自由镜头的一系列实现方案,总结一下知识点和遇到的坑

镜头控制

方案一:camera Location/Rotation设置

这是我的第一个想法,通过直接摆放相机来获得向玩家展示的画面,这种做法可以实现但不是很明智,因为Location的坐标计算其实是SpringArm已经做了的事情,这样做会做多余计算,而且每帧都做比较耗。

方案二:SpringArm Location/Rotation设置

SpringArm是一个玩家与摄像机中间的一个连接体,像是一个有弹性的杆,一边连着character一边连着camera。这里需要注意的是镜头控制中的各个Actor的朝向问题:现有这么几个actor: character,Controller, SpringArm, Camera. character的朝向是Controller赋予的,但是需要注意:Controller并不一定将所有的方向都赋予Character。在无需pitch/roll的场合,为了网络性能考虑可能不会传出无用参数给Character(坑了好久。。。)
回到SpringArm,目前理解它的作用主要有两个:1.设置镜头location. 2.做镜头移动延时。想象开始说的那个弹性杆,一端绑在Character上,一端绑住镜头,当人物移动的时候,相机会随之移动。而SparingArm的弹性决定了它什么时候会到达既定的位置(Lag)。在默认的情况下,它是与两个绑定在一起的,当然你也可以选择解绑其中的任何部分。开始因为不知道项目里绑定了SpringArm所以用camera做贼心累。。。

输入控制

输入控制为了实现一个功能:当按住按钮并滑动的时候可以自由移动视角,当手指松开的时候镜头会恢复到正常的状态。
最开始的想法是当button pressed的时候开始记录手指位置,move的时候持续采集并开始计算镜头移动角度,relase的时候停止记录位置并返回相应的值。问题在于系统对于点击事件的责任链中,当button被点击的时候会处理并消化事件,也就是说,这时候屏幕失去了获取ThouchState的能力。以此为背景。

方案一:hover release

这种方案的初衷是做一个假的按钮,根据事件触发的先后顺序绕过button的press事件,实现流程为:在hover的时候将Button设置为collapsed,这样Button就从屏幕上消失了,而且也没有碰撞事件的触发。这时候继续触发FreeCamera的Start事件并开始捕捉手指坐标,因为Button已经不再了,所以touch事件就可以直接让屏幕处理。
这种方式在PC上实现了一版,可以达到预期的目标,但是有两个问题:
1.对手机来说hover事件是没有意义的,所以触发机制还不一定。因为错过了打包,这个事件还没有验证。
2.用户在点击之后图标会消失,第一会有一些突兀,第二没有了图标之后就开始位置来做参照,可能会影响精细的操作

方案二:HUD

HUD是一套提供了画画接口的类库,它可以直接画在在显示屏幕上,作为玩家的提示信息(血量,准星等)。同时,他也提供了HitBox,通过使用HitBox,我们可以自定义click/relase事件。因为HUD考虑到覆盖其他控件的问题,所以在HitBox中允许玩家定义Hitbox在处理事件之后将事件下放。通过这种方式我们可以达到开始的需求。

设置最后一个参数为false,设置允许事件下传

1
2
3
AddHitBox(FVector2D(Canvas->ClipX/2 - FreeCameraIcon.UL + 200, Canvas->ClipY - FreeCameraIcon.VL - 25),
FVector2D(74, 74),
HIT_FREECAMERA, false);

HUD是一种并不优雅的解决方案。

  1. 适配问题很难解决,要写一个复杂的算法根据不同机型安排不同的位置
  2. 维护起来比较麻烦,每次都要自己去算一下位置,然后在C++里写了编译之后在看情况。
  3. 每帧都要去画图形,对于按钮来说不划算。

    在这个方案作完之后又遇到了一个致命的缺陷:HitBox中不支持多指的操作,所以当你正在触碰屏幕的其他区域的时候,这时候触碰HitBox区域捕捉到的是第一个手指的位置,这也意味着没有办法在跑步过程中使用FreeCamera,也意味着还要再想一种方法。。

方案三:image & controInput

分析一下需要什么:

  1. 一个触发机制(例如press,hover,click)
  2. 一种在触发后可以捕捉到屏幕坐标的方式(touch事件不被拦截)
  3. 一个回传的事件(我要知道什么时候release)

经历一堆波折之后我找到了image。image经常作为一种覆盖的形式表现出来,所以当然会不消化事件,然而它还提供了OnMouseDown方法可以作为触发。但还有一个问题是,只能click的时候触发一次,虽然可以设一个bool在tick里面做判断,但是并不优雅,这时候看到前辈有一手操作:写一个leveBP,在levelBP中的InputTouch中可以有Press Release moving 三个接口可以用。