攻击型生物实体 1.21 Fabric
本篇教程的视频:
本篇教程源代码
GitHub地址:TutorialMod-AttackEntity-1.21
介绍
有了前两期的教程,相信大家都已经对生物实体的创建有了一定的了解,那么本篇教程我们将为我们的生物实体添加攻击性
我们将自己编写生物实体的AI
,为其编写对应的目标,具有攻击性
生物实体攻击目标
这个攻击目标就是我们生物实体的AI
,因像前面写的那些目标一样,我们得让它知道应该攻击谁
创建TigerAttackGoal类
1 | public class TigerAttackGoal extends MeleeAttackGoal { |
这里我们继承了MeleeAttackGoal
,这个类是用于近战攻击的,其实这种攻击目标完全可参考原版的那些怪物的攻击目标,包括近战
和远程
的都可以写
接下来我们创建一些变量
1 | private final TigerEntity entity; |
这里我们创建了一个TigerEntity
的变量,这个是我们的生物实体
attackDelay
是攻击延迟,这个是根据你设置的动画来的,这里我们设置为20,单位是tick,也就是1秒。在我们的动画中,前1秒我设置了攻击的前摇,还没开始攻击,而到了第1秒这一刻才开始攻击,所以这里设置为20
ticksUntilNextAttack
是下一次攻击的时间,也就是攻击完之后剩下的时间(相当于cd,冷却时间)
shouldCountTillNextAttack
是是否应该计算下一次攻击的时间
先初始化一下entity
1 | public TigerAttackGoal(PathAwareEntity mob, double speed, boolean pauseWhenMobIdle) { |
重写start方法
1 |
|
这里我们重写了start
方法,这个方法是在开始攻击时调用的
我们在这里重置了attackDelay
和ticksUntilNextAttack
,这样就可以保证每次攻击都是在我们设置的时间内
重写stop方法
1 |
|
这里我们重写了stop
方法,这个方法是在停止攻击时调用的
我们在这里调用了entity
的attacking
方法,设置为false
,当然这个方法还没有写
重写tick方法
1 |
|
这里我们重写了tick
方法,判定是否应该计算下一次攻击的时间,如果是的话,就减少ticksUntilNextAttack
的时间
重写attack方法
这个方法可是这个类的核心,这个方法是在攻击时调用的
1 |
|
这里我们判断了一些条件
首先用isEnemyWithinDistance
方法(待会创建),判断是否有敌人在攻击范围内,如果有的话,就设置shouldCountTillNextAttack
为true
用isTimeToStartAttackAnimation
方法(待会创建),判断是否是攻击动画的时间,如果是的话,就设置entity
的attacking
为true
用isTimeToAttack
方法(待会创建),判断是否是攻击的时间,如果是的话,先让生物实体看向目标,然后调用performAttack
方法(待会创建),进行攻击
如果没有敌人在攻击范围内,就重置攻击冷却时间(待会创建),设置shouldCountTillNextAttack
为false
,设置entity
的attacking
为false
,并且重置entity
的attackAnimationTimeOut
为0
创建isEnemyWithinDistance方法
1 | private boolean isEnemyWithinDistance(LivingEntity target) { |
这个方法是判断敌人是否在攻击范围内(直线距离),这里我们设置为2.0f,两个方块的距离
创建isTimeToStartAttackAnimation方法
1 | private boolean isTimeToStartAttackAnimation() { |
这个方法是判断是否是攻击动画的时间,这里我们设置为ticksUntilNextAttack
小于等于attackDelay
的时候,就是攻击动画的时间
创建isTimeToAttack方法
1 | private boolean isTimeToAttack() { |
这个方法是判断是否是攻击的时间,这里我们设置为ticksUntilNextAttack
小于等于0
的时候,就是攻击的时间
创建performAttack方法
1 | private void performAttack(LivingEntity target) { |
这个方法是进行攻击的方法,这里我们重置攻击冷却时间,然后挥动手臂(如果有手的话),最后调用tryAttack
方法,尝试进行攻击
创建resetAttackCooldown方法
1 | private void resetAttackCooldown() { |
这个方法是重置攻击冷却时间的方法,这里我们设置为attackDelay
的两倍,也是40,因为前摇加上攻击的冷却时间正好是40tick
那么这个类就是这样,我们还得在TigerEntity
写一些东西
修改TigerEntity类
添加数据追踪器
首先我们要编写一个数据追踪器,用于追踪生物实体的攻击状态
1 | private static final TrackedData<Boolean> IS_ATTACKING = |
这里我们注册了一个IS_ATTACKING
的数据追踪器,用于追踪生物实体的攻击状态,这个是boolean
类型的
然后我们要初始化这个数据追踪器,重写initDataTracker
方法
1 |
|
我们将IS_ATTACKING
的值设置为false
,并加入到builder
中
接下来创建刚才在TigerAttackGoal
中用到的attacking
方法
1 | public void setAttacking(boolean attacking) { |
这个方法是设置生物实体的攻击状态
再接下来创建一个isAttacking
方法,这个我们等会会用到
1 | public boolean isAttacking() { |
这个就是获取生物实体的攻击状态
设置目标
我们在TigerEntity
的initGoals
方法中,添加我们的攻击目标
1 | this.targetSelector.add(1, new RevengeGoal(this)); |
这里我们添加了RevengeGoal
(复仇目标)和TigerAttackGoal
(我们刚才写的攻击目标),这个复仇目标是当生物实体受到攻击时,会攻击攻击它的生物实体
虽然说我们这里加了我们写的攻击目标,但准确来讲我们没有设置它自己会攻击的目标,这里可能你得参考参考狼主动攻击羊的代码了,在未来的教程中我们再修
设置动画
接下来我们来设置动画,同样首先是一些动画状态
1 | public static final AnimationState attackAnimation = new AnimationState(); |
这里我们创建了一个attackAnimation
的动画状态,这个是攻击动画的状态
以及一个attackAnimationTimeOut
的变量,这个是攻击动画的时间
然后我们在setupAnimation
方法中,设置攻击动画
1 | if (this.isAttacking() && attackAnimationTimeOut <= 0) { |
这里我们判断了一些条件
首先判断生物实体是否在攻击状态,以及攻击动画的时间是否小于等于0
,如果是的话,就设置attackAnimationTimeOut
为40
,也就是攻击动画的时间,然后开始攻击动画
然后判断生物实体是否不在攻击状态,如果是的话,就停止攻击动画
设置模型
接下来我们会到TigerRenderer
中设置模型
在setAngles
方法中,设置攻击动画
1 | this.updateAnimation(TigerEntity.attackAnimation, TigerAnimation.ATTACK, animationProgress, 1f); |
这样我们的攻击动画就设置好了
注册刷怪蛋
因为我们之前是用summon
来召唤生物实体的,不太方便,所以我们来注册一个刷怪蛋
1 | public static final Item TIGER_SPAWN_EGG = registerItems("tiger_spawn_egg", |
这里我们注册了一个刷怪蛋,这个刷怪蛋的实体是我们的TigerEntity
,底层颜色是0x252525
,第二层颜色是0x4D4D4D
(也就是上面的斑块颜色),这里的颜色码是16进制,按照自己的需求设置
将其加入物品栏
1 | entries.add(ModItems.TIGER_SPAWN_EGG); |
语言文件也写一下
1 | translationBuilder.add(ModItems.TIGER_SPAWN_EGG, "Tiger Spawn Egg"); |
模型文件和贴图文件是不用的,在游戏会自动生成
那么现在,我们就可以在游戏中使用刷怪蛋来召唤我们的生物实体了,并且你打它,它也会攻击你