Advanced Programming: Unity Game Dev Course(2)-Combat System

Advanced Programming: Unity Game Dev Course(2)-Combat System_第1张图片

 

1.Creating the Combat Module

主要介绍:

战斗框架和具体实现

 

具体实现:

该教程的战斗框架。

Attack仅定义包含一个int名为Damage和一个bool名为IsCritical的类。

AttackDefinition定义攻击所需数值比如范围暴击几率等,并返回Attack类型方法计算确定最终damage和iscritical,类似ItemDefinition_SO,player和enemy通用。

IAttackable为接口,内含一个方法,表示所有使用该接口的类在被攻击时做些什么,比如生命值减少,播放被攻击动画和音效等等。此教程里是发送Log显示攻击对象名称和攻击值。player和enemy通用。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第2张图片

 

 

Scripts文件夹下新建文件夹Monobehaviours和ScriptableObjects,新建脚本Attack,作用是定义Attack类的type,这个type包含一个int Damage,一个bool IsCritical。这两个值只能在类内定义,类外只读。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第3张图片

 

然后打开在Beginner Programming: Unity Game Dev Course(5)- Creating a Character Stat System教程里提到的CharacterStat脚本修改,获得character当前的基础damage和抗性。注意Character在教程里player和enemy共用。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第4张图片

 

接下来在ScriptableObjects文件夹下新建脚本AttackDefinition,它继承自ScriptableObject。该脚本定义Attack行为需要的基本数值,包含了一个通过基本数值计算最终damage,并传出上面定义的Attack类型的damage和isCritical。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第5张图片

 

然后在项目里新建AttackDefinition,并命名为DemoAttack作为Player的Attack类型,在此处先不挂载,我们继续写脚本。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第6张图片

 

新建脚本IAttackable脚本,它是一个接口,用于之后测试并显示Attack的对象名称及具体数值。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第7张图片

 

Monobehaviours文件夹下新建脚本AttackedDebug,此例用来被攻击后显示Log。比如生命值减少,播放被攻击叫声,动画之类都可以写在此处。同样player和enemy都可共用。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第8张图片

 

场景里新建一个Cube作为被攻击测试对象,挂上Rigidbody,Layer选择Clickable,挂上刚写的脚本AttackedDebug

Advanced Programming: Unity Game Dev Course(2)-Combat System_第9张图片

 

然后打开之前教程Beginner Programming: Unity Game Dev Course(4)- Swords and Shovels Character Controller and AI写的MouseManager脚本修改,为了改变攻击时的光标样式,以及把点击对象传递到攻击者。

先新建Unity事件

Advanced Programming: Unity Game Dev Course(2)-Combat System_第10张图片

 

然后定义事件

Advanced Programming: Unity Game Dev Course(2)-Combat System_第11张图片

 

修改点击方法

Advanced Programming: Unity Game Dev Course(2)-Combat System_第12张图片

 

然后修改同教程里的HeroController脚本,用来计算攻击值并触发被攻击者身上的OnAttack方法,这个方法是一系列被攻击后的逻辑,此例只显示log。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第13张图片

 

回到Unity,在MouseManager上触发HeroController上新写的方法

Advanced Programming: Unity Game Dev Course(2)-Combat System_第14张图片

 

然后把之前建的AttackDefinition拖入Hero

Advanced Programming: Unity Game Dev Course(2)-Combat System_第15张图片

 

build后点击Cube即可显示。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第16张图片

 

2.Weapons

主要介绍:

装备武器和使用武器

具体实现:

1.装备武器

ScriptableObjects文件夹下新建脚本Weapon,它继承自AttackDefinition。作用为包含weapon的prefab和对AttackDefinition中的攻击行为扩写,比如添加判定距离方向等。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第17张图片

 

注意红框中的IsFacingTarget方法,这没有在该类中具体实现,它是一个扩展方法,接下来我们来写它的实现。新建脚本名为ExtensionMethods

Advanced Programming: Unity Game Dev Course(2)-Combat System_第18张图片

 

教程中扩展方法的解释

Advanced Programming: Unity Game Dev Course(2)-Combat System_第19张图片

 

对该扩展方法内Vector3.Dot的说明,即二者向量夹角小于45°判定为面向。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第20张图片

 

写好Weapon后我们在项目里新建Weapon数据命名为SwordAttack

Advanced Programming: Unity Game Dev Course(2)-Combat System_第21张图片

 

之前我们任何Item都是ItemPickUp类型,现在为武器单独写了类,我们把之前与武器相关的地方类型都改变一下。

ItemPickUp_SO脚本

Advanced Programming: Unity Game Dev Course(2)-Combat System_第22张图片

 

CharacterStat_SO 脚本,加上.weaponPreb

Advanced Programming: Unity Game Dev Course(2)-Combat System_第23张图片

 

CharacterStats脚本

Advanced Programming: Unity Game Dev Course(2)-Combat System_第24张图片

 

然后修改之前ItemPickUp_SO类的Sword

Advanced Programming: Unity Game Dev Course(2)-Combat System_第25张图片

 

点击运行游戏,可以看到开箱捡起剑后摁1可以顺利装备了。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第26张图片

 

Advanced Programming: Unity Game Dev Course(2)-Combat System_第27张图片

 

但我们刚才只写了weapon形式并把其他脚本里相关武器的类型都改了过来,使其顺利执行一起写好的换上装备。写的执行攻击并没有触发,下面我们来让weapon进行攻击。

 

2.使用武器攻击

打开player身上的AnimatorController,拖入攻击动画,并设置转换,转换条件为trigger,名为Attack。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第28张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第29张图片

 

注意攻击动画上已设置了一个Event名为Hit

Advanced Programming: Unity Game Dev Course(2)-Combat System_第30张图片

 

打开HeroController脚本来实现攻击,逻辑是这样 点击对象接近对象 → 直到攻击距离内播放攻击动画 →触发动画Event执行攻击逻辑

Advanced Programming: Unity Game Dev Course(2)-Combat System_第31张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第32张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第33张图片

 

 

3.给攻击增加击退敌人效果,并添加新的weapon

Monobehaviours文件夹下新建脚本AttackedForce,使用IAttackable接口,这意味着重写OnAttack方法,并在攻击时触发。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第34张图片

 

把脚本挂在Cube上,运行游戏就看到攻击cube会击退它

Advanced Programming: Unity Game Dev Course(2)-Combat System_第35张图片

 

接下来添加一个新的weapon,新建一个空对象命名为Pole,添加Rigidbody组件,勾选isKinematic。下面新建一个圆柱体Cylinder子对象。

然后把该新建的weapon拖入prefab文件夹。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第36张图片

 

新建weapon数据类型命名为PoleAttack并拖入Prefab

Advanced Programming: Unity Game Dev Course(2)-Combat System_第37张图片

 

再把生成该武器的ItemPickUp_SO数据类型,为了方便复制一下Sword,改名为Pole,并拖入PoleAttack

Advanced Programming: Unity Game Dev Course(2)-Combat System_第38张图片

 

然后把场景里箱子将要掉落的物体换成该ItemPickUp_SO Pole

Advanced Programming: Unity Game Dev Course(2)-Combat System_第39张图片

 

运行游戏,打开箱子后就可以捡到一根水管子了。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第40张图片

 

3.Making Combat Interesting

主要介绍:

添加各种战斗效果,使enemy和player相互攻击

 

具体实现:

1.添加战斗跳字

Hierechy下新建空对象命名为ScrollingText,添加TextMesh组件,该组件的作用是在worldspace里显示text。其CharacterSize用来设置该对象大小。

 

然后在Monobehaviours文件夹下新建脚本ScrollingText,并挂在ScrollingText对象上,然后把该对象存为Prefab并在场景中删除。(记得设置Duration和Speed值)

Advanced Programming: Unity Game Dev Course(2)-Combat System_第41张图片

 

Advanced Programming: Unity Game Dev Course(2)-Combat System_第42张图片

 

ScrollingText脚本,里面包含了本对象在一定时间内向上飘,设定本TextMesh的内容和颜色 3个方法。还是和以前一样,该脚本类似于_SO写具体方法实现,然后再有对应脚本引用这些方法并触发。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第43张图片

 

接着在Monobehaviours文件夹新建脚本AttackedScrollingText脚本,使用IAttackable接口,用来调用之前写的方法。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第44张图片

 

挂到被攻击对象Cube上,并选择颜色。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第45张图片

 

运行游戏后就可看到攻击一次字网上飘一次了。

 

2.实现Cube被攻击后减血及死亡后销毁

新建CharacterStats_SO数据型对象,命名为Block,代表这个被攻击方块的各项CharacterStats

Advanced Programming: Unity Game Dev Course(2)-Combat System_第46张图片

 

然后修改CharacterStat脚本,即生成一个新的CharacterStats_SO模板的实例。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第47张图片

 

新建脚本IDestructable,该脚本表示对象死亡后的一系列执行的接口

Advanced Programming: Unity Game Dev Course(2)-Combat System_第48张图片

 

Monobehaviours文件夹下新建脚本AttackedDamage,用来实现Cube受到攻击后减少声明值,并在生命值为0后触发所有IDestructable接口

Advanced Programming: Unity Game Dev Course(2)-Combat System_第49张图片

 

再实现接口的具体语句,即摧毁对象,Monobehaviours文件夹下新建脚本DestructedDestroyObject

Advanced Programming: Unity Game Dev Course(2)-Combat System_第50张图片

 

把这两个脚本都挂在Cube上,并把之前的属于Cube的CharacterStats_SO对象Block拖入

Advanced Programming: Unity Game Dev Course(2)-Combat System_第51张图片

 

运行游戏可以看到Cube被砍几刀后销毁。

 

3.实现Enemy攻击Player

现在我们来给哥布林添加攻击性,把哥布林的Layer选为Enemy,添加Collider,然后把四个攻击相关的脚本挂上,TextMesh Prefab也填入。然后记得点击Apply使所有哥布林有同样的设置,Layer改变时会提示改变包括子对象,还是仅改变此对象。选择改变此对象就好。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第52张图片

 

MouseManager里添加Enemy Layer使鼠标点击哥布林时能转换光标样式。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第53张图片

 

运行游戏,可以看到哥布林也能攻击player且跳字了。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第54张图片

 

4.给哥布林添加一个布娃娃效果

布娃娃Ragdoll效果就像被砍死了后啊的一声掉下楼的效果。之前我们已经写了生命值低于0后销毁使用IDestructable接口,之后我们再写销毁了同时生成个布娃娃给布娃娃一个力并在N秒后消失,通过这种方式呈现布娃娃效果。

首先我们找到哥布林的模型(注意不是Prefab),复制哥布林的模型命名为BatGoblin_for_Ragdoll记得把新模型的Optimaze Game Object关掉。这个选项的作用是优化游戏对象的骨骼层级提高性能,但我们之后需要拖拽骨骼层级设置Ragdoll,所以新的模型不需要这个优化。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第55张图片

 

把新模型拖到场景命名为BatGoblinRagdoll,在Hierachy里添加Ragdoll,拖入对应骨骼后点击Creat生成。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第56张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第57张图片

 

Monobehaviours文件夹下新建脚本Ragdoll,用来确定脊柱骨骼,给脊柱添加一个力,并在n秒后摧毁。它的触发由普通哥布林prefab触发,即哥布林死了生成ragdoll哥布林,然后触发其添加力的方法。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第58张图片

 

把脚本挂到Rogdoll哥布林上,拖入脊骨骨骼,填好时间,点击Apply后存成prefab,然后把此对象在场景中删除。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第59张图片

 

Monobehaviours文件夹下新建脚本DestructableRagdoll,用来触发生成ragdoll并调用添加力方法。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第60张图片

 

拖入场景里普通哥布林身上,把ragdoll哥布林的prefab填入。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第61张图片

 

运行游戏后可看到效果。

 

4.Finalizing Systems

主要介绍:

使哥布林Enemy能够释放魔法飞弹攻击player并且player可死亡,aoe型攻击

 

具体实现:

1.添加释放魔法和魔法飞弹

Monobehaviours文件夹下新建Projectile脚本用来代表飞弹这一子弹对象本身。它包含了飞弹自己的移动和在适当情况下销毁,以及最关键的,传递释放者和飞弹打到的对象这两个参数,所以它包含一个委托Action。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第62张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第63张图片

 

接下来写远程魔法攻击这一行为本身,ScriptableObjects文件夹下新建Spell,它继承自AttackDefinition。记得之前的近战攻击Weapon也是继承自AttackDefinition。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第64张图片

 

我们先制作一个魔法飞弹的Prefab,场景里新建3D对象Sphere,下路拖入项目里FBX的火焰粒子效果,拖入飞弹脚本Projectile后保存到Prefab并从场景中删除。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第65张图片

 

项目内新建魔法攻击数据类型Spell命名为Fireball,填入对应数值和prefab。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第66张图片

 

新添加两个Layer如下,EnemySpell作用于player,playerSpell作用于enemy。防止自己发出的火球打到自己。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第67张图片

 

点击Physics设置管理

Advanced Programming: Unity Game Dev Course(2)-Combat System_第68张图片

 

对Layer勾选,确保两者间的对应作用关系。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第69张图片

 

Spell脚本里有飞弹发射点,一般为右手,但我们的动画都是Optimize Game Object过的,所以先把右手的transform标记出来。

点击哥布林的模型(注意是模型,不是prefab),在添加位置中找到右手。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第70张图片

 

然后点击apply

Advanced Programming: Unity Game Dev Course(2)-Combat System_第71张图片

 

找到场景里随便一个哥布林,把哥布林的模型拖入变成其子对象。然后把子对象中的右手位置对象拖入到场景的哥布林。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第72张图片

 

Advanced Programming: Unity Game Dev Course(2)-Combat System_第73张图片

 

然后把子对象哥布林的模型删除就行了。记得点击apply到prefab里。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第74张图片

 

接着我们来改写NPCController让哥布林攻击,包括近战攻击和远程攻击。红框标注的都是此次新加内容。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第75张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第76张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第77张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第78张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第79张图片

 

最后填入飞弹发射点右手和fireball数据类型就好了。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第80张图片

 

此例的精髓在于把攻击这一行为设置成了SO类型,所有的攻击,远程近战都继承自这一类型。这样做的好处是抽象了代码,减少了很多重复逻辑判断,在项目很大的情况下是必须的,不然就是无尽的判定bug。

 

2.让player也能被enemy攻击,并在health不大于0时死亡

所有有关受到攻击接收伤害的脚本AttacktedTakeDamage,它使用IAttackable接口。所有有关对象死亡并摧毁的脚本DestructedDestroyObject脚本继承自接口IDestructable。我们把这两个脚本挂到Player上。

运行游戏后发现player可以正常受到伤害,但player死亡销毁后提示bug找不到引用。原因在于enemy的NPCController一直在调用player.tranform.position,所以我们要修改NPCController让player死亡后所有哥布林回归正常。

Monobehaviours文件夹下新建脚本DestructedEvent,它使用IDestructable接口,包含一个Action用来通知NPCController。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第81张图片

 

然后修改NPCController

Advanced Programming: Unity Game Dev Course(2)-Combat System_第82张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第83张图片

Advanced Programming: Unity Game Dev Course(2)-Combat System_第84张图片

 

然后把这三个脚本都挂在player上,点击运行可看到player死亡后,哥布林回去原来的位置。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第85张图片

 

3.aoe型攻击

ScriptableObjects文件夹下新建脚本Aoe,它继承自AttackDefinition,和Weapon,Spell一样是一种攻击形式。这里只写了检测半径内敌人,播放aoe攻击效果,造成伤害并跳字。

Advanced Programming: Unity Game Dev Course(2)-Combat System_第86张图片

 

这里只是一个示例,如果想要造成击飞一圈敌人的效果,就给所有enemy挂上之前写的AttackedForce。

 

总结:

战斗框架的学习完成了,最精髓的是通过定义IAttackable接口进行所有攻击类执行,IDestructable接口进行所有死亡类执行。通过AttackDefinition抽象了所有攻击种类,通过NPCController里判定哥布林到底是远程攻击还是近战攻击来确定攻击。

 

完毕。

 

 

 

 

 

 

你可能感兴趣的:(•【完整课程】)