UE4第三人称射击游戏总结二

三,实现人物的射击功能

当前存在的bug:人物向左走或向前走速度是0.7,但是如果前和左一起按,速度变为1.0了,个人感觉是向量叠加了,以后再弄


1,为射击添加子弹

创建一个蓝图类继承actor,添加一个球体,再添加ProjectileMovement模拟子弹痕迹


在输入中添加鼠标左键的按键取名Fire,在playercontroller中添加蓝图,按下鼠标左键就生成一个实例Bullet(子弹),生成的位置定在了人物的身边


这样位置是不对的,它是在人物旁的一个点不变然后生成,应该是根据人物移动的坐标,应该加一个3维的偏移坐标,并且人物旋转时这个坐标也是旋转的因此,这样连


效果如图:


调整好偏移向量的值,让它偏移到枪口位置,在bullet类中projectileMovement中将initial Speed和Max Speed设为2000,将Velocity的x轴设为1000,效果如下:

2,添加武器

接下来给人物添加武器,在人物骨骼里面找到右手位置右键add socket命名为myWeapon,右键添加枪的mesh


调整好枪在手上的位置,创建一个蓝图类命名为myWeaponBase,里面添加skeletal mesh组件名为myWeapon,把mesh选择为枪的mesh,右键该文件,选择创建子类蓝图


将子类蓝图命名为myWeapon,在3p_PlayerCharacter中这样定义,事件开始就spawn生成一个actor蓝图类,类名就是那个基类,最右边的mesh为角色的mesh,因为目标为枪这个类,parent为人物

这样就自动生成枪了


3,发射子弹生成特效

在子弹蓝图里,添加组件--->ParticleSystem放在子弹下面,生成一个子弹就自动生成一个特效,在特效的pariticle属性中Template选择想要的特效,调整特效的缩放等特性,调整ProjectileMovement的Projectile属性里的Projectile Gravity Scale属性为0,让子弹没有重力,初始速度为2000


4,为子弹添加自定义对象通道和踪迹通道

在project settings---->collision中定义Object Channels和Trace Channels为Weapon Channels和Weapon Trace,个人理解是负责自定义的发出的射线通道。


在preset设置


在myWeaponBase事件图表中定义两个custom Event名为Weapon Fire 和Stop Fire 

在3p_PlayerCharacter中定义两个custom Event也同样命名,当触发playerCharacter中的自定义事件时候就自动触发枪的基类中的自定义函数,



在3P_PlayerController中原来我们点了鼠标左键就生成一个子弹,现在我们将生成子弹的的过程放到枪的Fire Weapon中,将鼠标左键按下和抬起调用3p_PlayerCharacter中的两个事件,这两个事件又会调用枪基类里面开枪,停止两个函数

为什么在playerController里面鼠标左键按键不直接调用枪类里面的Fire Weapon事件呢?因为在playcontroller里面没有枪的引用,在PlayerCharacter里一进游戏就实例化一个枪,可以取得引用,因此先从playController先调用了PlayerCharacter里面的事件,再调用枪类里面的事件


接下来在枪类里面添加射线踪迹,注意的是这个踪迹是从镜头作为起点而不是枪口,终点为镜头向前多少米,因此要在枪类拿到相机引用,我们需要从playerCharacter中拿。

在枪的基类中创建函数CalculateShootInfo(计算射击后的位置函数)和SetCamera(获取相机引用)函数,在setCamera函数中要输入的值为相机组件,在右侧输入值加入Camera Component相机组件

设置为一个引用变量


因为要拿到人物后面的相机,在3p_PlayerCharacter中,拿到相机的引用传入set camera方法,且set camera的目标是my weapon Base


在Calculate Shoot Info函数中通过LineTraceByChannel方法来画出一条射线,具体做法是在枪基类中的calculateShootInfo函数中,取得相机组件,射线的起点是相机世界位置,终点是相机向前100米,由于向前1个单位是1cm,因此要乘以10000,Trace Channels是我们在项目里设定的


进行射线检测,如果遇到碰撞体,输出一个节点(紫色),该节点输出的是一个transform,location为枪的位置,通过Get Socket Location获得,totation为碰到的物体和枪口的位置只差,取得一个向量,如果没遇到碰撞体,输出一个节点,输出的也是一个transform,location为枪位置,rotation为枪口前向很远的向量


在枪的子类事件中调用父类的事件,这里play Animation是播放一次枪射击时候的动画,该动画是枪的动画,不是角色动画,然后调用父类CalculateShootInfo函数,接着Spawn Emitter At Location调用一个枪射击的特效,也即开枪时从枪口射出的蓝色火焰(自己没加),最后调用一次射击的声音


效果如下:已经有发射射线效果了


5,子弹碰到物体自动消失

在bullet添加事件,当触碰到物体就自动销毁


对于生成子弹,在枪子类中将calculateShootInfo中位置传入,实例化一个子弹,将最上面的生成子弹的逻辑删去,这里有个bug,生成的子弹很大,在calculateShootInfo传入生成子弹的位置中make transform将scale比例缩小。


效果如下:


如果实例化出来的子弹是在人物中间生成,子弹和枪相碰了,在计算生成位置的时候,rotateVector+offset偏移+location让它生成的时候向前一点生成

6,为射击添加准星

在HUD文件夹中右键蓝图类选择HUD命名为3P_PlayerHUD,在右键用户界面---->控件蓝图命名为GamePlayWidget,双击打开,在左侧创建4个image这样命名


锚点为中,位置设置一下,就会在视图中出现一个准星,在3P_PlayerHUD中将控件加入


在3P_GameMode中将HUD class选成3p_playerHUD,这样游戏里就有准星了


四,计算伤害

在bullet类里创建setDamageInfo方法,该方法设定好3个变量DamageMax,DamageMin,CuitChance(暴击),,在枪类开枪生成子弹时候调用,初始化伤害数值

在Interface文件夹里面右键蓝图--->蓝图接口命名为DamageInterface,设置输入值


打开bullet类,添加DamageInterface接口,当子弹打到物体时,输出hit actor,调用 Damage Interface接口里面的take damage方法,该方法输入5个变量



 创建一个蓝图类继承character名为BaseEnemyCharacter,设置好mesh和碰撞,在该类和3p_PlayerCharacter中分别添加Damage Interface接口,添加Take Damage事件,添加三个变量名为MaxHealth,CurrentHealth(浮点)和isDead(布尔)。

逻辑是这样的,当子弹碰撞输出hit信息,触发Damage Interface接口的Take Damage方法,将伤害的信息传进去,但是每个人,自己和敌人的类中也要添加该接口的Take Damage事件,用于触发

在子弹碰撞输出碰撞actor时如果该actor包含Take Damage接口,就调用该接口,将伤害值和子弹发起者和碰到的哪一块骨头传进去,然后在敌人和角色中都实现该接口

在BaseEnemyCharacter中写一个函数CalculateHealth,输入为DamageMin,DamageMax,CritChance和BoneName,变量为currentHealth,MaxHealth和isDead


在BaseEnemyCharacter中事件触发


效果如下


2,右键瞄准镜头的拉近

在3P_PlayerCharacter中自定义事件SetFOV,在3P_PlayController中鼠标右键按下触发一次,弹起触发一次,时间轴函数中从(0,0)点到(0.1,0.5),我们可以看到对于镜头的拉近主要是调用相机的Set Field Of View函数,点击右键镜头从67.5变到90,松开右键,从90变到67.5,最后lerp和函数绿色相连,这里忘连了


最后,将射线那条红线关闭,在LineTraceByChannel把Draw Debug Type选择none


3,如果处在找掩体动作时把准星隐藏

在HUD文件夹里GamePlayWidget,双击打开,切换到Graph,自定义一个事件,SetVisiblity将已经定义好的变量显示或隐藏



五,敌人AI

只要是AI肯定分为两个步骤,第一步是逻辑的连贯,第二步是动作的连贯,第一步指的是有哪些枚举,什么时候从站立触发到射击,什么时候触发到奔跑,将整个可能触发逻辑建立完整,第二步是每个枚举值对应的动作,当跑步状态时就调用跑步动画。


1,敌人状态的创建

新建文件夹,右键行为树命名为EnemyAI_BehaviorTree,右键黑板命名为EnemyAI_BlackBoard,右键继承AIController蓝图类命名为EnemyAI_Controller,右键蓝图-->枚举命名为CombatStatus_ENUM,打开新建3个枚举值:Guard,Patrol和Combat,再新建一个枚举类命名为CombatType_ENUM,这个枚举值是在战斗状态里面的3个可能,也即战斗中射击,战斗中找掩体,战斗中Heavy,新建3个枚举值:Assualt,Cover,Heavy

在BaseEnemyCharacter中添加组件-->pawnSensing,在AI属性中包含了该人物的听觉范围和视觉范围


在BaseEnemyCharacter添加变量CombatStatus和CombatType属性改成上面写好的那两个枚举值,点成public,加入两个事件on see pawn和on hear noise,在游戏窗口中可以看到人物的感觉范围


2,战斗状态

先想想什么时候切换为战斗状态呢?当敌人看到或听到主角时触发,还有敌人被子弹打到时候触发

on see pawn和on hear noise这两个事件中逻辑一样,如果当前敌人看到了人(也即事件产生者instigator)且战斗状态不是Combat。就把当前状态设为Combat


BaseEnemyCharacter中当敌人受伤时(触发Take Damage事件),一方面计算伤害,一方面如果当前状态不是战斗状态不是combat(一共有Guard守卫状态,Patrol巡逻状态,combat战斗状态)则设为combat


3,敌人行为树的建立

在EnemyAIController中的Event BeginPlay中调用Run Behavior Tree(调用EnemyAI_BehaviorTree),也即一开始就调用敌人的行为树

记得在BaseEnemyCharacter中的Pawn属性将AI Controller Class选择为EnemyAI_Controller

打开EnemyAI_BehaviorTree,在右侧打开黑板,创建两个枚举值CombatStatus和CombatType,在key-->Key Type--->Enum Type中选择对应的枚举,再创建一个object命名为PlayCharacter,将Base Class选择为3P_PlayerCharacter

在黑板中保存了三个变量,一个是哪个角色,其他两个是该角色的战斗状态和战斗种类


再切换到行为树,这样设定


在行为树里面选择新建服务,会在资源中多出一个文件,命名为ChangeCombatStatus_BTS。并打开这样编辑,这个逻辑主要每秒都将人物中的状态更新到黑板中


在上面的行为树的selector节点中右键,添加服务,选择ChangeCombatStatus_BTS并将属性中初始化正确,在Guard节点向下Wait5秒


  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值