- 198
- 1
- 24
Сделал кое-как зомби с использованием модельки игрока (чтобы можно было наделать таких зомбей в разных вариантах с использованием скинов игроков), но не могу разобраться, как управлять анимацией. В частности, нужно, чтобы зомби вытягивал вперёд руки, направляясь к жертве, и опускал их, бесцельно бродя по миру. В текущем варианте он вообще руки не использует.
Класс моба:
package com.madalchemist.betterzombies.zombies;
import com.madalchemist.betterzombies.ai.ModdedZombieAttackGoal;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.model.ModelHelper;
import net.minecraft.entity.CreatureAttribute;
import net.minecraft.entity.EntitySize;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.Pose;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.ai.goal.*;
import net.minecraft.entity.merchant.villager.AbstractVillagerEntity;
import net.minecraft.entity.monster.MonsterEntity;
import net.minecraft.entity.monster.ZombifiedPiglinEntity;
import net.minecraft.entity.passive.IronGolemEntity;
import net.minecraft.entity.passive.TurtleEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.pathfinding.GroundPathNavigator;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class BasicZombie extends MonsterEntity {
public BasicZombie(EntityType<? extends BasicZombie> zombie, World world) {
super(zombie, world);
}
public static AttributeModifierMap.MutableAttribute createAttributes() {
return MonsterEntity.createMonsterAttributes()
.add(Attributes.FOLLOW_RANGE, 35.0D)
.add(Attributes.MOVEMENT_SPEED, 0.3D)
.add(Attributes.ATTACK_DAMAGE, 1.0D)
.add(Attributes.ARMOR, 2.0D)
.add(Attributes.SPAWN_REINFORCEMENTS_CHANCE);
}
protected SoundEvent getAmbientSound() {
return SoundEvents.ZOMBIE_AMBIENT;
}
protected SoundEvent getHurtSound(DamageSource p_184601_1_) {
return SoundEvents.ZOMBIE_HURT;
}
protected SoundEvent getDeathSound() {
return SoundEvents.ZOMBIE_DEATH;
}
protected SoundEvent getStepSound() {
return SoundEvents.ZOMBIE_STEP;
}
protected void playStepSound(BlockPos p_180429_1_, BlockState p_180429_2_) {
this.playSound(this.getStepSound(), 0.15F, 1.0F);
}
protected void registerGoals() {
//this.goalSelector.addGoal(8, new RandomWalkingGoal(this, 0.1D));
this.goalSelector.addGoal(8, new LookAtGoal(this, PlayerEntity.class, 8.0F));
this.goalSelector.addGoal(8, new LookRandomlyGoal(this));
this.goalSelector.addGoal(2, new ModdedZombieAttackGoal(this, 1.0D, false));
this.goalSelector.addGoal(6, new MoveThroughVillageGoal(this, 1.0D, true, 4, this::canBreakDoors));
this.goalSelector.addGoal(5, new MoveTowardsTargetGoal(this, 1, 1.0f));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, PlayerEntity.class, true));
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractVillagerEntity.class, false));
this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolemEntity.class, true));
this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, TurtleEntity.class, 10, true, false, TurtleEntity.BABY_ON_LAND_SELECTOR));
}
@Override
public void aiStep() {
super.aiStep();
}
public boolean canBreakDoors(){
return true;
}
@Override
protected int getExperienceReward(@Nonnull PlayerEntity player) {
return 2;
}
@Override
public boolean canBreatheUnderwater() {
return true;
}
@Override
@Nonnull
public ResourceLocation getDefaultLootTable() {
return super.getDefaultLootTable();
}
@Override
protected float getStandingEyeHeight(@Nonnull Pose pose, @Nonnull EntitySize size) {
return 0.9F;
}
public CreatureAttribute getMobType() {
return CreatureAttribute.UNDEAD;
}
}
Класс рендера моба:
package com.madalchemist.betterzombies.zombies;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.client.renderer.entity.layers.BipedArmorLayer;
import net.minecraft.client.renderer.entity.layers.HeldItemLayer;
import net.minecraft.client.renderer.entity.model.BipedModel;
import net.minecraft.client.renderer.entity.model.PlayerModel;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nonnull;
@OnlyIn(Dist.CLIENT)
public class BasicZombieRenderer extends MobRenderer<BasicZombie, PlayerModel<BasicZombie>> {
public BasicZombieRenderer(EntityRendererManager renderManager) {
super(renderManager, new PlayerModel<BasicZombie>(0, true), 0.5F);
this.addLayer(new BipedArmorLayer<>(this, new BipedModel(0.5F), new BipedModel(1.0F)));
this.addLayer(new HeldItemLayer<>(this));
}
@Override
@Nonnull
public ResourceLocation getTextureLocation(@Nonnull BasicZombie zombie) {
return this.getTexture("zombie_steve");
}
private ResourceLocation getTexture(String fileName) {
return new ResourceLocation("betterzombies", "textures/entity/zombie/" + fileName + ".png");
}
}
ИИ задача атаки:
package com.madalchemist.betterzombies.ai;
import net.minecraft.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.entity.monster.MonsterEntity;
import net.minecraft.entity.monster.ZombieEntity;
public class ModdedZombieAttackGoal extends MeleeAttackGoal {
private final MonsterEntity zombie;
private int raiseArmTicks;
public ModdedZombieAttackGoal(MonsterEntity p_i46803_1_, double p_i46803_2_, boolean p_i46803_4_) {
super(p_i46803_1_, p_i46803_2_, p_i46803_4_);
this.zombie = p_i46803_1_;
}
public void start() {
super.start();
this.raiseArmTicks = 0;
}
public void stop() {
super.stop();
this.zombie.setAggressive(false);
}
public void tick() {
super.tick();
++this.raiseArmTicks;
if (this.raiseArmTicks >= 5 && this.getTicksUntilNextAttack() < this.getAttackInterval() / 2) {
this.zombie.setAggressive(true);
} else {
this.zombie.setAggressive(false);
}
}
}