自动射击(warframe自动射击)

有一个充要条件:

枪的z轴和第一人称相机的z轴平行。这样不管经过多远,枪的正前方和第一人称相机正前方的落点的距离保持不变,而这个偏差在很远处是可以忽略不计的。

还有一个检验方法:在第一人称截个图,沿枪管画出一条直线,看是否经过屏幕中心。

1526af50f3e0600b93a0bc39990f3a75.png

改变仰角

方案1:使用目标物

人物建立一个TargetAxis,TargetAxis前方很远处建一个target,相机Follow人物根节点,LookAt target,鼠标改变TargetAxis的仰角。

这个方案需要多建两个物体,切换控制的人物需要把这两个物体迁移或新建。

随人物站、蹲、趴改变高度

方案1:TPP相机挂animator,用动画改变shoulder Offset

需要注意的问题:

不持枪状态改变仰角

方案1:只改变相机仰角

问题:由于不改变人物头部的仰角,相机仰视可能拍到人物头内部。

274dc52acd94489bb42776bece6978d4.png

方案2:改变人物头的仰角,带动FPP相机

改变人物头的仰角还有几种方案:

1.LootAtConstraint看向目标物,可以防抖,但是跑步时人物头动作僵硬;

2.RotationConstraint约束到人物根节点,但是x轴旋转加一个Offset,不需要目标物,也可以防抖,也僵硬;

024d32b5d448490d8e1e363830d4dea6.gif

3.animator.SetBoneLocalRotation(),不需要目标物,应该有防抖的写法,但是我还没研究出来;

总结下来,目标物方案需要手动建立、指定目标物,比较麻烦,但是控制一个TargetAxis就能控制TPP相机、FPP相机、人物头的旋转,使用很方便。

不用目标物,FPP相机、TPP相机、头部不能用LookAt和LookAtConstraint,TPP相机跟随人物根节点,不会晃动,可以用transform.localEulerAngle,为了让人物在视野里,灵敏度还要调;FPP相机跟随人物头,需要防抖,使用RotationContraint约束到人物根节点;

feab4327876a252474603272915b80c3.png

实现方法1:人物趴下的时候用代码把刚体的x轴旋转约束解除

d437ad8739363fcfa8f08c0e73b3fd84.png

11c1c4ca38c0a671c505fdec2d2e8b2b.png

刚开始做的时候没发现这个方法因为忘了在人物趴下时把碰撞体平放,导致碰撞体翻倒。于是研究出了下面复杂的方法。

实现方法2:在OnCollisionStay()里获得人物和地面的碰撞,得到碰撞点的法向,然后用SetFromToRotation()旋转。

453b472c624350d963d1958e44f0095b.png

这个方法的问题:趴下的时候人物很容易不停晃。

动画和代码的比较

游戏里大部分参数都既可以用代码控制也可以用动画控制。二者的特点不同。

动画:时间控制精确,逻辑死板;

代码:逻辑灵活,时间控制困难,只有第一帧和每一帧执行的生命周期函数,其他时机都要写计时器代码控制。

比如写一个人物定时眨眼的效果,二者都能控制模型skinned mesh renderer的blendShapes,动画需要打4个关键帧,极简单;代码需要一个计时器变量,在Update()判断到没到该眨眼的帧,用Mathf.Lerp()写过渡效果……

代码方案

我一开始的射击功能就是靠代码、计时器变量写的。

31f77090e3a14b71bf645475d5fde042.png

而枪的射速是固定的,用动画实现应该会更简单。

动画方案

枪上挂Animator。

枪的动画状态机

firing为true时进入Recoil,Recoil通过hasExitTime退出,另外通过hasAmmo判断是跳转到Idle还是HoldOpen(空仓挂机),换弹后hasAmmo=true,进入Idle。

41f999e30a00425cb87ec383df6d207b.png2fe7a03dba4540aeb98d0323697ef26a.png

枪的射击动画

Fire()在第一帧执行,一共有几帧取决于枪的射速,枪一秒射击n发,动画一秒60帧,动画长度就是60/n。动画有回膛就做回膛,无事可做就加个无关紧要的属性,比如Scale保持不变。

20642de7e99c4fca9c67df59819467a8.png

如果想加一个小的后座,加给MeshRenderer所在的物体,不要加给根节点,否则开枪的时候枪会跑到世界的那个位置。换句话说枪的实体别做根节点。

进入和退出射击状态的动画过渡要特别注意设置短,接近突变。

89419c3e3a1c460a974195a3df0a4ad7.png

射击控制代码

人物脚本声明一个bool pullTrigger,玩家按下左键,判断人物准备好射击后,把pullTrigger=true,把枪动画状态机的参数bool firing=true;

09fa8e87ec4c4b4cae4666c99ec5e470.png

 

半自动射击的实现

1.如果使用旧输入系统,使用GetMouseButtonDown(),全自动使用GetMouseButton()

2.如果使用PlayerInput,相当于只有GetMouseButton,可以定义一个bool fireReg用来记录上一帧有没有按下左键,在执行射击后把fireReg=triggerPulled,射击判断写成triggerPulled&&!fireReg。

这样写有一个特性,就是如果玩家按鼠标的速度比枪的射速还快,在射击冷却前松开再按下鼠标,也不会射击。之所以不叫bug,因为如果玩家手速快过了全自动的射速,就允许枪的射速超过全自动射速,这是不合理的。第一种方法就是这样,只要手速够快,半自动可以比全自动还快。

三连点射(Burst)实现

先总结三连点射需要处理的所有情况:

1.按一下鼠标,发射三发;

2.一直按着鼠标,发射三发;

3.剩余子弹不到三发,按一下鼠标,发射完;

如果不考虑3,就可以做一个触发三次Fire()动画事件的AnimationClip。要考虑3,则可以:

6f49ad75eea7401ca33ce6ae9b369367.png

第一次发射后根据是不是Burst选择到Idle还是下一个射击状态,每次发射根据还有没有子弹判断是到下一个发射状态还是Hold Open,最后一次发射到Idle或Hold Open。

总之充分利用动画状态机的逻辑功能,可以使代码简化。

枪当前的自动方式我是用枚举表示的:

720d213b63364ceea9fb3f5b6aa0b98d.png

有些枪只有半自动,将来可能还要做3发点射,还需要一个变量记录枪支持哪些自动方式。我试了用多选枚举实现。先定义一个枚举:

2214a4891cd24275a933710a00cc399e.png

再用外挂脚本改成多选:

2cd48115ce8a4607a8194a972493fd60.pngaad9fe2ed9f2491fa37d825cde1673a0.png

看起来好像不错:

3212a6000ad34beb90821bc4bfdfc30a.png

但是我在预制体里修改自动方式,却记录不下来,退出进去又变成Nothing;在场景里修改,开始运行又变成Nothing。

在外挂脚本OnInspectorGUI()里打印一下,发现是鼠标一进入监视器面板就执行OnInspectorGUI(),但是也不应该改变我设置的值。

27a4902426964bfdbb06f3876986d9cd.png

在外挂脚本里加一句赋值成Semi,又变成运行时自动变成Semi。

30d9a2cd27604285bade5ebc7a9aa206.png

这个方案失败了,我决定用多个bool hasXXX记录这个信息,和多选枚举的本质是一样的,只是把各个位拆出来。

e11c7ca53ac049dda572bf7404ba139f.png5ad059a80f6843789cb3a94fa0da5f77.png

切换自动方式的代码非常麻烦:

 
 

要实现击中不同部位造成不同伤害需要由中枪触发器实现。

b18cae637e114b9bb86c02965ddb65d1.png

中枪触发器的形状参数不全需要手调,有很多可以用代码自动设置,如四肢触发器的height可以用子骨骼的localPosition.y,center的y值是height的一半,x和z是0,radius需要手调。躯干可以找Hips的三级子节点Neck和Hips的高度差作为height,radius也是手调,头的radius也是手调。

e0cb33e957a247418538013b6d82a7c0.png

或者直接用Unity内置的Ragdoll生成器。

e8fc0141ef564c158ee0d8226741d856.png2d1ab609ca3c4705a00374445329fcff.png

这样写射击射线检测的时候需要把人物的碰撞体排除,把身体触发器包括,人物根节点和骨骼节点需要在不同层。

瞄准相机配置

在枪上挂一个记录瞄准相机位置的节点。步枪瞄准和手枪瞄准的方案不太一样。

手枪瞄准

手枪的瞄准相机不能做手枪的子物体,因为手枪射击要上跳,瞄准相机做手枪的子物体就和手枪一起上跳。人物的眼睛是不会随手枪上跳的。手枪的瞄准相机需要跟随枪的位置,不跟随枪的旋转。实现这个功能有几种方案:

  • 父物体为空,使用Cinemachine,瞄准相机Follow枪的瞄准节点,LookAt设置目标物

也就是瞄准相机的旋转由目标物决定。还可以加一点damping看起来更真实,但是Composer不要加Vertical Damping,否则上抬的时候相机可能穿到枪身里。

39a25ed163f74ca2a5441941bb1e1f62.png

  • 父物体为头,使用Cinemachine,瞄准相机Follow枪的瞄准节点,LookAt不设置

也就是瞄准相机的旋转由头决定。

步枪瞄准

步枪射击时因为托腮,人物眼睛随枪上跳,瞄准相机就可以直接挂在瞄准位置。

其他方案,总之位置可以用Follow、PositionConstraint、ParentConstraint或父子级约束,旋转可以用LookAt、RotationConstraint、ParentConstraint或父子级约束。

瞄准镜

我直接参考了这两篇文章:

【unity小技巧】使用三种方式实现瞄准瞄具放大变焦效果_unity放大镜效果-CSDN博客

【unity小技巧】实现FPS武器的瞄准放大效果(UGUI实现反向遮罩,全屏遮挡,局部镂空效果)_unity 开镜-CSDN博客

第二篇文章的效果:挺不错,能满足要求。

65677fa69bcb401e9e404edce6620856.png

第一篇文章方案三,相机输出到贴图,贴图再应用到瞄准镜后端,实现局部放大的效果:

材质配置:Base 自动射击 Map颜色选黑,贴图给Emission Map,颜色选白色。

0a6c67c2c1fc4606b519e19cc982c067.png

效果:

1007f67a08e04c71a6e3eced52c8ab28.png

可惜我的人物头发和瞄准镜后端穿模了,没法用。

1679ea132ac8409e8897cef0da1d456d.png

有射线检测方案和发射弹头实体的方案。

射线检测方案

比较简单,弹道只能是直线,没有弹头火光效果。

 

发射弹头实体方案

能模拟抛物线弹道,有子弹火光。但是击中检测不能用碰撞检测,因为子弹每帧飞过几米到几十米,大概率穿过物体。只能用一个Vector3记录上一帧的位置,使用Physics.Linecast()做连线检测。这样击中检测的轨迹其实是拟合抛物线的折线。但是勉强能用了。

发射代码:

 

弹头脚本:

 
 

射击游戏动作系统的特点:

  • 很难不用分层和AvatarMask;
  • 有些动作需要生动性,有些动作需要精确性(主要是瞄准);
  • 人和随身物品的交互关系较复杂,武器在不同的动作跟随不同节点,有些动作受多个节点影响;

我想让人物移动的同时人物端枪瞄准前方。所以我加了一个Arm层,移动放在Base层,希望走路时上半身稳定。

?AvatarMask覆盖上半身

问题:如果走路动画Hips的旋转是摇晃的,那么AvatarMask覆盖的上半身也会跟着摇晃。

59a3328ee40b4b45ab5724471fc6a8fd.gif

AvatarMask覆盖双臂

问题:走路时Chest朝向和静止时不一样,导致走路时双臂的方向歪。

静止时Chest的朝向:

9e5449f13dcd48b1a1bd159f2d80b528.png

前进时Chest的朝向:

aa831a2007d4432aa323f19ade95be51.png

效果:

f73236a991df44f8a871754a0354c5e1.gif

AvatarMask覆盖双臂和根节点

又会导致腿走路的方向歪。

7e141c517abc4b88ab8f799890f319c6.gif

解决方法

给Spine加Rotation Constraint,由一个指向瞄准方向的物体约束它。先预览人物静止端枪的动画,再点Rotation Constraint的Is activated,组件会计算出当前Spine相对约束物体的旋转偏移,再Lock。

3932beda67c74084b34a24a3c1cf8ba2.png

但是想在开始跑步时腰从约束状态平滑过渡到动画状态,这个约束平滑把权重降到0,腰也没有播放动画,而是局部旋转不变。AnimationRigging的Multi Rotation Constraint可以通过权重平滑变化到0平滑过渡到动画状态。这是AnimationRigging约束很重要的一个优势:

ba8bae34afbf424aa7aefcff90c38705.gif

首先,如果想实现边走路边换弹,又不想做朝八个方向的边走路边换弹的动画,Layers和Avatar Mask是肯定要用的。但是有些状态要双臂和躯干叠加,有些状态又是全身动作,全身要么1.放在Base层,上半身放None,要么2.在这两层上面加一个全身层。1.导致身体层和双臂层出现了很多同名的状态,状态机的状态几乎增加了一倍。

把玩家所有的操作分成躯干-下半身动作、纯双臂动作、全身动作。

躯干-下半身动作:站立及其移动、蹲着及其移动

纯双臂动作:换弹、收枪、拔枪

全身动作:跑步、趴着及其移动(爬行)、趴下、站起、攀爬、捡东西。(爬行是全身动作,无法边爬行边换弹,就把趴着的所有动作定义为全身动作。)全身动作里又有可以叠加的,如跑步是同一个躯干&腿叠加不同的双臂,也有单纯一个动作的如趴下、攀爬。

跳跃可以是躯干&腿动作也可以是全身动作。如果定义为全身动作,且由Trigger触发,就会出现一个Trigger需要触发两层转换的情况,很容易出问题。

躯干-下半身动作只在Trunk&LowerBody层有状态;

纯双臂动作只在arm层有状态;前两类动作可以任意组合。

全身动作的几种方案:

这样有难以解决的问题:None状态同时代表趴着状态和站着无枪状态,从None到步枪站立无法知道是趴着站起来还是站着取枪,然后趴着站起来时同时做了取枪动作。看来Arm层状态合并太狠会出问题。

801e3ef0f429404b9a4b9996c8fac1d7.png

5c5c2e443d8a474b99f4b70331116cb3.png

84702f1e6c494323bfe65aab5b4ff0c8.png

Trunk&LowerBody层只考虑人物的躯干和腿有什么状态。需要的状态有noGunStanding(身体向正前方站立)、gunStanding(身体向右偏45度站立)、crouching(拿枪和不拿枪共用一个躯干&下半身姿势)、NoGun Jump、Gun Jump(允许玩家边跳边开枪、换弹);

后来我又把跳跃改成全身动作了。因为边跑边跳跃时WholeBody层进入一下None状态又到跑步状态,出现在空中跑步的情况,然后我把全身层进入跑步的条件加了一个onGround,不会在跳跃中跑步了,又遇到了新问题:跳跃是靠触发器进入的,允许边跳跃边瞄准射击意味着一个触发器同时触发两层的转换,如果稍有不同步就只能触发一层,出现异常状态。最终决定只在全身层做一个跳跃状态。

bf73c23e60c2455caa7569da90b772a3.png

arm层只考虑人物双臂有什么状态。有noGunIdle、rifleIdle、rifleReload、putAwayRifle、takeOutRifle、rifleRunning;

8eab59acbabe40e0be9637bfe9a968dd.png

WholeBody层有所有用到全身的状态。和一个不覆盖下层的None(motion)。有running、prone、goProne、getUp、climbing;

动画状态机的一个简化技巧:动作状态到空闲状态无需设置到所有空闲状态的转换,只需转换到其中一个,然后靠空闲状态中间的转换。但是空闲状态到动作状态是所有空闲状态都要设置转换。例如蹲着Crouching到捡东西PickUp,捡完后无需设置PickUp到Crouching的转换,只需有PickUp到Standing的转换,再通过控制身体高度的参数从Standing转换到Crouching。

本来想在Arm层加一个从持枪空闲Pistol Stand到射击的状态。但是遇到了问题:Pistol Stand状态脚本的OnStateExit()我写了解除瞄准,因为离开Pistol Stand进入的所有状态都不能瞄准。然后射击时就会解除瞄准。

9dcd466c70f34998bbab66481fa8a0f3.png

只能另开一层Hand放射击上跳动画。另外这里站和趴都有上跳动画,如果Hand层是Override,那么站的上跳动画就不能用于趴,但是改成Addictive,这个上跳动画可以同时用于站和趴。

e57d994db91a4996b2e00911376c588a.png

cfdca592f0734589b3bbb8a85ae51933.gif

扔掉、捡起物品需要做的可以粗分为两部分:

1.对物体的操作(改变父级、设置位置旋转);

2.播放人物动作;

二者的调用关系可以是:

1.在一个方法里执行物体操作;

2.方法里设置状态机参数,在动画事件里执行物体操作;

动画状态机的问题

动画状态机里我只想用一个整数gunStatus表示手的状态(0空手、1拿步枪、2拿手枪),但是这样出现了一些含糊不清的情况:

gunStatus从1到0可能是扔掉步枪和收起步枪都需要从自动射击1到0,为了播放正确的动画,必须

1.加另外一个参数区分两种转换

2.扔枪也要把gunStatus设0,但要在进入扔枪状态后,防止进入背枪状态

给扔枪加了Trigger PutDown,捡枪加了Trigger PickUp,捡枪时先设置PickUp,捡起的动画调用动画事件,在里面把手的状态设置为1或2。捡枪后手应该进入1还是2状态也由动画事件的方法根据枪的类型判断。

需要处理的情景/需要做的测试:

1.手里没枪,身上也没步枪时捡步枪,手枪也有类似情景

2.手里没枪,身上有步枪时换步枪

3.手里有步枪时换步枪

4.手里有步枪时捡手枪

5.

6.手里没枪,身上有步枪时扔步枪

一种逻辑简单的设计

1.步枪放到背上

2.背上的步枪放到地上,地上的步枪放到背上

3.手里的步枪放到地上,地上的步枪放到背上

4.手枪放到身上,如果身上有手枪则放到地上

6.不允许,只能扔手里的枪

这套方案保证了枪进入手里只有一种途径,就是从身上的挂载点拿;会有枪在身上和地上的位置突变。(后来发现,情况2会出现gunStatus是1但是步枪在背上的情况,必须用下面的折中设计。)

一种真实但逻辑复杂的设计

1.步枪放到手里

2.先把背上的步枪拿到手里,再手里的步枪放地上,地上的步枪放手里

3.手里的步枪放地上,地上的步枪放手里

4.把步枪收起来,把手枪放到手里,使用手枪或者换回步枪

6.不允许

我本来想做第二套方案。这套方案的情景2、4都会玩家按一个按键触发两个动作,先gunStatus=0,进入空手状态,设置PickUp,进入拾取状态后通过动画事件gunStatus=1。结果Arm层有收枪的过渡状态,Body层没有,就收到PickUp进入拾取状态,然后Arm层根据gunStatus=1做了取枪动作,原本Arm层应该也收到PickUp进入拾取状态,然后直接进入拿步枪状态的。这涉及到一个Trigger能否同时触发两层的转换,以及两层准备转换的时机不一致,一层先消耗了Trigger的情况。到这里情况的复杂有点超出我的能力,我决定做第一种方案。

复盘方案二,问题就在为了模拟真实强制

人物空手状态才能拿枪;又为了用户体验,选择一键执行两步动作,导致两层出现不同步。一二两种方案折中,又有了第三种方案

折中的设计

1.步枪放到手里

2.再手里的步枪放地上,地上的步枪放背上

3.手里的步枪放地上,地上的步枪放手里

4.把地上的手枪放到腿上

6.不允许

一个功能要播放动画且执行一些代码,这些代码可放在3个地方:

1.和播放动画的代码写在一起,在动画开始时执行;

2.放在状态脚本的OnStateEnter()或OnStateExit();

3.使用动画事件。动画事件可以精确控制方法执行的时机,但是不能传参数,需要在脚本里加字段。

以射击条件为例,不能射击的情况很多,包括人物动作没准备好(换弹、跑步、手里没枪、爬行)、枪没准备好(枪里没子弹、射击冷却没结束)。

两种思路

一个是给人物写一个方法ReadyToFire(),玩家按下射击时执行,里面检查所有可能影响射击的条件,包括没有在换弹&&没有在跑步&&手里有枪&&没有在爬行&&枪里有子弹。没有在跑步可以用Animator参数isRunning判断,换弹是触发器触发的,我只能使用animator.GetCurrentAnimatorStateInfo(1).IsName("Reload")靠名字判断,到了没有在爬行,爬行和趴着空闲的动画在一个混合树里,属于一个状态,趴着空闲时可以射击,使用状态名字判断也不行了。然后可以通过判断Animator的VerticalSpeed、HorizontalSpeed判断……

一个是给人物维护一个变量public bool readyToFire,玩家按下射击时把这个变量加入判断条件,其他地方的代码设置这个变量,可以在1.人物脚本;2.状态机脚本;3.动画事件。这样直接在站、蹲的瞄准状态的状自动射击态脚本的OnStateEnter()把这个置true,OnStateExit()里置false,前面的一大堆判断都不用做了,特别是判断状态名字的一长串。趴着的状态还是需要根据VerticalSpeed、HorizontalSpeed判断,写在状态脚本的OnStateUpdate()里。

a584d029ab732d8d865d584b20688c12.png

同理,其他动作都可以维护一个这样的变量:

d2b56f963c44771d5f8ba88e65e3ddf7.png

然后判断是否能瞄准的代码从这样:

f793027d193ef3d8c1edb3a088c47c1f.png

变成了这样:

0ae00625cf3dc31cb3a78dc927e4fc33.png83309f18fb735fec398d9266faf520e4.png

为什么维护变量比执行判断方法简单了这么多?因为它利用了动画状态机本身的逻辑,换弹、跑步两个状态本身的互斥的。后来我发现,判断射击直接放在射击状态机行为脚本的OnStateUpdate()就行了,连readyToXXX变量都省了。同理,判断能不能换弹根本不用readyToReload,只在持枪状态机行为脚本里的OnStateUpdate()监听换弹输入就行了。

并非所有不能同时做的动作都要在相应的状态脚本里把另一个动作的readyToXXX置false,有一些因为状态之间没有转换,天然不会同时进行,比如在Rifle Run状态因为没有转换,不可能到Reload状态,但是这个图是Arm层,跑步在Body层也有状态,Reload没有,换弹过程中跑步会导致Body层进入跑步状态,这时候就要在Reload状态脚本里限制一下。具体哪些地方要加限制只能一个个试。我又试了一下,跑步中按换弹,虽然没有播放换弹动画,但是播放了换弹声音,子弹数更新了,因为状态之间没有转换只阻止了播放动画,我的Reload()方法是输入触发的。还是要加限制;要么就改成动画事件触发。

d856b28db8cf18169f75d4abcd900917.png

动作条件判断的测试

射击游戏动作系统都可以做这几个测试判断系统的严谨性:

1.跑步时按换弹,是否不换弹或结束跑步后换弹;

2.换弹时按跑步,是否不会跑步;

3.瞄准状态按换弹、跑步,是否会解除瞄准;

4.换弹、跑步状态按瞄准,是否不会瞄准;

以上测试可以总结为跑步、换弹、瞄准3个动作的互斥测试。

7.趴下、站起的过程中按换弹、跑步、机瞄,是否不会做相应动作或当前动作完成后再做;

8.瞄准状态按爬行,是否会解除瞄准

9.瞄准状态扔掉手里的枪、交换枪是否会解除瞄准

10.瞄准状态把枪收起来或者换成手枪是否会解除瞄准

92bcb227b9cba134f0a96d3bdf567e16.png

写了一大堆,突然发现上面一大堆条件就是离开瞄准状态的各种途径,只需要在站、蹲瞄准状态脚本的OnStateExit()、趴瞄准状态脚本的OnStateUpdate()(水平、垂直速度比较大时)、OnStateExit()执行关闭瞄准方法即可,无需在各个输入的时候写。但是有一个例外,手枪射击的时候的上跳我是用人物的手腕上跳做的,这时候就不应该解除瞄准了。

5241ae395b7115677ed88088652f275f.png

为了解决这个问题我只好把人物手腕上跳状态删掉,单独给手枪做一个上跳,不属于人物动画状态机,射击的时候手腕不动,效果僵硬了点,但是先这样吧。

68420451de829024070782fc08ba0939.png

d5e5ddaa95e6f8d82a2179940193add1.pngb363ab94c36fba03e1a734a10b7149c0.png

对叛乱:沙漠风暴做了上面的测试,结果是

1.没换弹,跑步结束也不换

2.换弹动作被打断,进入跑步,弹匣没插,此时开枪没子弹或者只有一发,此时按换弹只插弹匣。这个处理牛逼。

bd57742116a33866cd354b8c6c01e50f.jpeg

3.会

4.换弹时不会瞄准,会打断跑步进入瞄准

7.按换弹被直接忽略,瞄准会等趴下后进入,按跑步会再站起来开始跑步

8052f9a0f5024f8c8bd8215c3ec75d9d.gif

鉴定为上下半身的状态转换时间不同,如果有一层还没有回到静止,而另一层已经回到静止,那么再开始跑步两层开始播放跑步动画的时机不同,晃动的节奏不一致。所以如果用AvatarMask拼接跑步动画,上半身应该用一个静止的。

本来想做左右斜身的动画,发现用Avatar做这两个动画极难。

使用了animator.SetBoneLocalRotation()实现,和俯仰写在一个方法里,因为一帧里好像只有最后一次animator.SetBoneLocalRotation()是最终效果,所以把改变Spine的仰角和左右倾斜写到一个Quaternion,加给Spine的旋转。

使用Mathf.Lerp()加了倾斜角度渐变。

47aca5735ec4460aa8123d3ffb204b59.png

在持枪的状态机行为脚本里调用。

5a1d68e2410b411ea8784171b16a1e31.png

枪的碰撞体用来做捡枪的检测,肯定要加,这里讨论的是非触发器碰撞体。

加了,扔枪的效果就更真实,但一个问题就是人物趴着的时候一低头枪会把人顶起来:

a20d6a4fd135cf4ba50c83ac3a9531d4.jpeg

用代码关闭碰撞体好像不错,但不难预测又可能出现趴着扔枪前枪已经和地面穿模,开启碰撞体也不能阻止枪穿到地下。要解决这个问题就要防止枪和地面穿模,可以增大趴着的最小仰角。但是如果人物趴在斜坡上这个最小仰角又不合适了。

总之给枪加碰撞体和刚体增加了一点物理效果,但是增加了游戏系统的不可控性。

武器信息栏包含武器名、自动模式、子弹数、弹匣数。

42207df201064e6fb874a260a01de726.png

哪些情况需要更新武器信息栏:

1.拿出枪;

2.收起枪(隐藏);

3.交换枪;

4.放下枪;

5.射击;

6.换弹;

7.拿起手里枪的弹匣;

8.放下手里枪的弹匣;

9.改变自动模式;

人物在动画状态机的任何状态都可能死亡,不可能给每个状态加一个到死亡状态的转换。有几个办法解决。

18834949362d44d5be0ac6cad6515f67.png66bbdbe12c6a4ae6ac65e1c9f068f506.png

注意Any State到Dead的转换不要勾选转换到自己。

播放一个状态的名字,不管有没有转移,直接跳到那个状态。

覆盖在所有层上,只有两个状态,Alive状态播放no Motion,Dead状态播放死亡。

通过检测目标人物在不在自己前面的扇区判断有没有看到其他人。问题是怎么知道要检测的目标人物有哪些?FindObjects找到所有人物脚本实例?很明显开销太大。如果有扇区触发器碰撞体,是最合适的,但是没有。只能退而求其次,先用球形触发器碰撞体,把附近的人物加到一个列表,再做扇区检测。

第一人称射击游戏一般不显示身体,这大大简化了系统的设计,比如:

1.改变瞄准仰角可以直接改变相机的仰角,双手是相机的子物体,无需改变人物腰部的旋转,而人物持枪状态腰部的俯仰是个极复杂的旋转;

2.走路是单纯的平移,没有双腿动画,移动换弹就不用把双手换弹动画叠加到身体层,也就无需用AvatarMask,甚至AnimatorController不用分身体和手臂层;

相比起来第三人称射击游戏要表现人物全身的动作,要复杂得多,但也有简单的地方:

1.人物动作要求不那么精确,比如持枪如果枪和相机z轴如果稍微不平行,第一人称看着很奇怪,第三人称就不明显;换弹动作粗糙一点,因为有身体挡住,也看不出来;

要做兼顾第一第三人称的射击游戏,是难上加难。吃鸡就是这样,比如

1.跑步第一人称和第三人称用的是两个动画,第三人称手臂更靠下,摆动更大,第一人称手臂在相机视野内,摆动更小;

这是第一人称的跑步:

2dfe202ca26b42abbb2bce387ffef374.png

同一个姿势第三人称是这样的:

05c67fecb7a24777ad420013f216244a.png6a4f07753ce241c99c41dbe0dfdad5f6.png

2.跑步时第一人称相机挂在头上,又不能随头晃动,需要加某种约束;

规则设计的两个关键问题:1.怎么赢;2.死了怎么办。

第一个问题的方案:1.消灭指定敌人(cs歼灭模式等);2.占领所有目标点(战地、叛乱沙漠风暴Checkpoint);3.摧毁指定物品(cs爆破模式);4.到达某位置(绝地求生、逃离塔科夫)。

第二个问题的方案:1.读档(使命召唤、武装突袭等,只适用于单机游戏);2.局内指定地点重生(战地、叛乱沙漠风暴等);3.下一局重生(cs、绝地求生、逃离塔科夫等)。

转载请说明出处 内容投诉内容投诉
九幽软件 » 自动射击(warframe自动射击)