跳到主要内容

29攻击动画

代码

在PorcupineEntity中:

private static final TrackedData<Boolean> ATTACKING =
DataTracker.registerData(PorcupineEntity.class, TrackedDataHandlerRegistry.BOOLEAN);

public final AnimationState attackAnimationState = new AnimationState();
public int attackAnimationTimeout = 0;


private void setupAnimationStates() {
if (this.idleAnimationTimeout <= 0) {
this.idleAnimationTimeout = this.random.nextInt(40) + 80;
this.idleAnimationState.start(this.age);
} else {
--this.idleAnimationTimeout;
}

if(this.isAttacking() && attackAnimationTimeout <= 0) {
attackAnimationTimeout = 40;
attackAnimationState.start(this.age);
} else {
--this.attackAnimationTimeout;
}

if(!this.isAttacking()) {
attackAnimationState.stop();
}
}

@Override
protected void initGoals() {
this.goalSelector.add(0, new SwimGoal(this));

this.goalSelector.add(1, new PorcupineAttackGoal(this, 1D, true));


this.goalSelector.add(1, new AnimalMateGoal(this, 1.15D));
this.goalSelector.add(2, new TemptGoal(this, 1.25D, Ingredient.ofItems(Items.BEETROOT), false));

this.goalSelector.add(3, new FollowParentGoal(this, 1.15D));

this.goalSelector.add(4, new WanderAroundFarGoal(this, 1D));
this.goalSelector.add(5, new LookAtEntityGoal(this, PlayerEntity.class, 4f));
this.goalSelector.add(6, new LookAroundGoal(this));

this.targetSelector.add(1, new RevengeGoal(this));

}


@Override
public void setAttacking(boolean attacking) {
this.dataTracker.set(ATTACKING, attacking);
}

@Override
public boolean isAttacking() {
return this.dataTracker.get(ATTACKING);
}

@Override
protected void initDataTracker() {
super.initDataTracker();
this.dataTracker.startTracking(ATTACKING, false);
}

在PorcupineModel中:

@Override
public void setAngles(PorcupineEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
this.getPart().traverse().forEach(ModelPart::resetTransform);
this.setHeadAngles(netHeadYaw, headPitch);

this.animateMovement(ModAnimations.PORCUPINE_WALK, limbSwing, limbSwingAmount, 2f, 2.5f);
this.updateAnimation(entity.idleAnimationState, ModAnimations.PORCUPINE_IDLE, ageInTicks, 1f);
this.updateAnimation(entity.attackAnimationState, ModAnimations.PORCUPINE_ATTACK, ageInTicks, 1f);
}

新建一个AI类:

package net.kaupenjoe.tutorialmod.entity.ai;

import net.kaupenjoe.tutorialmod.entity.custom.PorcupineEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.entity.mob.PathAwareEntity;
import net.minecraft.util.Hand;

public class PorcupineAttackGoal extends MeleeAttackGoal {
private final PorcupineEntity entity;
private int attackDelay = 20;
private int ticksUntilNextAttack = 20;
private boolean shouldCountTillNextAttack = false;

public PorcupineAttackGoal(PathAwareEntity mob, double speed, boolean pauseWhenMobIdle) {
super(mob, speed, pauseWhenMobIdle);
entity = ((PorcupineEntity) mob);
}

@Override
public void start() {
super.start();
attackDelay = 20;
ticksUntilNextAttack = 20;
}

@Override
protected void attack(LivingEntity pEnemy) {
if (isEnemyWithinAttackDistance(pEnemy)) {
shouldCountTillNextAttack = true;

if(isTimeToStartAttackAnimation()) {
entity.setAttacking(true);
}

if(isTimeToAttack()) {
this.mob.getLookControl().lookAt(pEnemy.getX(), pEnemy.getEyeY(), pEnemy.getZ());
performAttack(pEnemy);
}
} else {
resetAttackCooldown();
shouldCountTillNextAttack = false;
entity.setAttacking(false);
entity.attackAnimationTimeout = 0;
}
}

private boolean isEnemyWithinAttackDistance(LivingEntity pEnemy) {
return this.entity.distanceTo(pEnemy) <= 2f; // TODO
}

protected void resetAttackCooldown() {
this.ticksUntilNextAttack = this.getTickCount(attackDelay * 2);
}

protected boolean isTimeToStartAttackAnimation() {
return this.ticksUntilNextAttack <= attackDelay;
}

protected boolean isTimeToAttack() {
return this.ticksUntilNextAttack <= 0;
}

protected void performAttack(LivingEntity pEnemy) {
this.resetAttackCooldown();
this.mob.swingHand(Hand.MAIN_HAND);
this.mob.tryAttack(pEnemy);
}

@Override
public void tick() {
super.tick();
if(shouldCountTillNextAttack) {
this.ticksUntilNextAttack = Math.max(this.ticksUntilNextAttack - 1, 0);
}
}

@Override
public void stop() {
entity.setAttacking(false);
super.stop();
}
}

测试

此时我们攻击豪猪,豪猪就会把我们当作攻击目标了