我的创作纪念日

作者分享了自己学习C++编程,专注于我的世界模组开发的经历,特别提到了1.12~1.19版本Forge模组的全过程,已创建4个个人模组,包括生化危机系列和MC鹅鸭杀等。此外,作者还成功考研至东华大学计算机专业,平衡创作与学习,形成良性循环。文章展示了Boss门德斯的代码实现,展示了一个复杂的游戏AI机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

机缘

C++编程学习、我的世界模组开发

收获

  1. 掌握了1.12~1.19全部版本的forge模组开发流程,目前已经拥有4个个人模组:

1.生化危机8&4

2.生化危机枪械

3.MC鹅鸭杀

4.1.12.2掉落物光束

  1. 获得了1333名粉丝的关注
  2. 成功考研上岸:22东华大学计算机专硕854考研上岸实录

日常

  1. 平时有时间会选择创作,记录一路以来的模组开发经验。
  2. 劳逸结合地写代码,看文献,形成一种正向反馈和良性循环。

成就

  1. MC模组生化危机4重制版Boss门德斯代码:
该Boss可以拿起周围的方块对玩家发起攻击,也可以将玩家吸入空中进行攻击。
public class EntityChief3 extends Monster implements IAnimatable {
    private AnimationFactory factory = new AnimationFactory(this);
    private int timer;
    private static final EntityDataAccessor<Integer> STATE = SynchedEntityData.defineId(EntityChief3.class, EntityDataSerializers.INT);
//    private static final EntityDataAccessor<Integer> REGENERATION = SynchedEntityData.defineId(EntityChief3.class,
//            EntityDataSerializers.INT);

    private final ServerBossEvent bossInfo = (ServerBossEvent)(new ServerBossEvent(this.getDisplayName(), BossEvent.BossBarColor.PURPLE, BossEvent.BossBarOverlay.PROGRESS)).setDarkenScreen(true);


//    public EntityChief3(PlayMessages.SpawnEntity packet, Level world) {
//        this(EntityInit.CHIEF3.get(), world);
//    }

    public EntityChief3(EntityType<EntityChief3> type, Level world) {
        super(type, world);
        xpReward = 100;
        setPersistenceRequired();
        this.timer=0;
        //this.setItemSlot(EquipmentSlot.MAINHAND,);
    }

    @Override protected void registerGoals() {
        this.goalSelector.addGoal(4, new FloatGoal(this));
        this.goalSelector.addGoal(5, new RandomLookAroundGoal(this));
        this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 1.2));
        super.registerGoals();
        this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.2, false) {
            @Override
            protected double getAttackReachSqr(@NotNull LivingEntity entity) {
                return 0;
            }
        });
        this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
        this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, false, false));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, false, false));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false, false));
    }

    @Override protected void defineSynchedData() {
        super.defineSynchedData();
        this.getEntityData().define(STATE, 0);
        //this.getEntityData().define(REGENERATION, AquamiraeConfig.Common.corneliaRegenerationAbility.get());
    }

    @Override public void addAdditionalSaveData(@NotNull CompoundTag tag) {
        super.addAdditionalSaveData(tag);
        CompoundTag data = new CompoundTag();
        data.putInt("Attack", this.getEntityData().get(STATE));
        //data.putInt("Regeneration", this.getEntityData().get(REGENERATION));
        tag.put("CorneliaData", data);
    }

    @Override
    public void readAdditionalSaveData(@NotNull CompoundTag tag) {
        super.readAdditionalSaveData(tag);
//        CompoundTag data = (CompoundTag) tag.get("CorneliaData");
//        if (data == null) return;
        this.getEntityData().set(STATE, tag.getInt("Attack"));
        //this.getEntityData().set(REGENERATION, data.getInt("Regeneration"));
    }

    @Override
    public AnimationFactory getFactory() {
        return this.factory;
    }

    public void setAttackingState(int time) {
        this.entityData.set(STATE, time);
    }


    @Override
    public void baseTick() {

        //if (this.getHealth() < this.getMaxHealth() * 0.3 && this.getEntityData().get(REGENERATION) > 0 && !this.hasEffect(MobEffects.LEVITATION)) this.rage();
        if (this.getHealth() <= this.getMaxHealth() * 0.1 && !this.hasEffect(MobEffects.WEAKNESS)) this.heal(0.5F*random.nextFloat());

        if (this.getTarget() != null) {
            this.timer=(this.timer+1)%120;
            final LivingEntity target = this.getTarget();
            final double distance = this.distanceToSqr(target);
            this.lookControl.setLookAt(target);
            this.yBodyRot = this.yHeadRot;

            if (this.entityData.get(STATE) == 1) {
//                if ((distance < 3 || this.hasEffect(MobEffects.LEVITATION))) ANIMATIONS.play("attack", Math.random() < 0.5 ? 40 : 20);
//                else if (distance < 25 && random.nextInt(100) == 1) ANIMATIONS.play("attack", Math.random() < 0.5 ? 40 : 20);
//                else
                if (distance < 600 && random.nextInt(200) == 1) this.timer=-5;
            }
            if (this.entityData.get(STATE) == 1 && this.timer==25) {
                target.setDeltaMovement(new Vec3(target.getX(), target.getY(), target.getZ())
                        .vectorTo(new Vec3(this.getX(), this.getY() + 0.5F, this.getZ())).scale(0.25F));
                if (target instanceof Player player) player.hurtMarked = true;
            }
            if (this.entityData.get(STATE) == 1 && (this.timer == 8 || this.timer == 35))
                this.setDeltaMovement(new Vec3(this.getX(), this.getY(), this.getZ())
                        .vectorTo(new Vec3(target.getX(), target.getY() + 0.1F, target.getZ())).scale(0.2F));



            if (this.entityData.get(STATE) == 1 && distance < 12) this.doHurtTarget(target);
            if( this.timer==45) this.setAttackingState(2);
            if ((this.timer == 8+45 || this.timer==28+45))
            {
                this.addEffect(new MobEffectInstance(MobEffects.LEVITATION,40,1,false,false));
                this.rage();
            }

            if(this.entityData.get(STATE) == 1 && this.timer == 108)
            {
                this.timer=-10;
            }
//            if(this.entityData.get(STATE) == 2 && this.timer == 30)
//            {
//                this.timer=-10;
//            }

            if (this.isUnderWater() && !this.hasEffect(MobEffects.LEVITATION)) this.setDeltaMovement(new Vec3(this.getX(), this.getY(), this.getZ())
                    .vectorTo(new Vec3(target.getX(), target.getY(), target.getZ())).scale(0.04F));
            else if (this.isInWater() && !this.hasEffect(MobEffects.LEVITATION)) this.setDeltaMovement(new Vec3(this.getX(), this.getY(), this.getZ())
                    .vectorTo(new Vec3(target.getX(), target.getY(), target.getZ())).scale(0.04F).add(0F, 0.08F, 0F));
            System.out.println(this.getEntityData().get(STATE) +" "+this.timer);
        }
        else{
            this.timer--;
            if(this.timer<0) this.timer=0;
        }

//        ANIMATIONS.playSound("attack", 40, "aquamirae:entity.captain_cornelia.attack_1", SoundSource.HOSTILE, 2F, 1F);
//        ANIMATIONS.playSound("attack", 20, "aquamirae:entity.captain_cornelia.attack_2", SoundSource.HOSTILE, 2F, 1F);

        if (this.timer>10)
            this.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 5, 3, false, false));

        if (this.hasEffect(MobEffects.LEVITATION) && !this.getLevel().isClientSide()) {
            final Vec3 center = new Vec3(this.getX(), this.getY(), this.getZ());
            List<LivingEntity> list = this.getLevel().getEntitiesOfClass(LivingEntity.class, new AABB(center, center).inflate(10), e -> true).stream()
                    .sorted(Comparator.comparingDouble(ent -> ent.distanceToSqr(center))).toList();
            final MobEffectInstance LEVITATION = this.getEffect(MobEffects.LEVITATION);
            final int DURATION = LEVITATION == null ? 0 : LEVITATION.getDuration();
            list.forEach(entity -> {
                if (entity instanceof Player player && (player.isCreative() || player.isSpectator())) return;
                if (entity.getMaxHealth() <= 100) {
                    if (DURATION > 1) {
                        final double radius = 5;
                        final Vec3 orbit = new Vec3(center.x + Math.cos(entity.tickCount * -0.1F) * radius, center.y,
                                center.z + Math.sin(entity.tickCount * -0.1F) * radius);
                        entity.setDeltaMovement(new Vec3(entity.getX(), entity.getY(), entity.getZ()).vectorTo(orbit).scale(0.2F));
                        if (entity instanceof Player _player) _player.hurtMarked = true;
                    } else if (DURATION == 1) {
                        entity.setDeltaMovement(new Vec3(this.getX(), this.getY(), this.getZ())
                                .vectorTo(new Vec3(entity.getX(), entity.getY(), entity.getZ())).scale(0.2F));
                        if (entity instanceof Player _player) _player.hurtMarked = true;
                    }
                }
            });

            this.getPersistentData().putDouble("Par1", this.getPersistentData().getDouble("Par1") + 1);
            if (this.getLevel() instanceof ServerLevel server && this.getPersistentData().getDouble("Par1") > 1) {
                this.getPersistentData().putDouble("Par1", 0);
                server.sendParticles(ParticleInit.MUCUS_PARTICLE.get(), this.getX(), this.getY() - 0.2, this.getZ(), 1,
                        0.3, 0.1, 0.3, 0.1);
            }
            if (this.isInWater()) this.setDeltaMovement(new Vec3(0F, 0.4F, 0F));
        }
        this.getPersistentData().putDouble("Par2", this.getPersistentData().getDouble("Par2") + 1);
        if (this.getLevel() instanceof ServerLevel server && this.getPersistentData().getDouble("Par2") > 9) {
            this.getPersistentData().putDouble("Par2", 0);
            server.sendParticles(ParticleInit.FLAME_PARTICLE.get(), this.getX(), this.getY() + 1.7, this.getZ(), 1,
                    0.15, 0.1, 0.15, 0.1);
        }
        //
        final Vec3 center = this.position();
        List<Player> players = this.getLevel().getEntitiesOfClass(Player.class, new AABB(center, center).inflate(32), e -> true).stream()
                .sorted(Comparator.comparingDouble(ent -> ent.distanceToSqr(center))).toList();
        //players.forEach(player -> { if (player.getLevel().isClientSide()) AquamiraeAmbient.playCorneliaMusic(player); });
        super.baseTick();
    }

    public void rage() {
        //this.getEntityData().set(REGENERATION, this.getEntityData().get(REGENERATION) - 1);
        //this.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 200, 0, false, false));
        this.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 3, false, false));
        this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 20, 0, false, false));
        this.getDeltaMovement().add(0,1+random.nextDouble(),0);
        if (this.level instanceof ServerLevel serverLevel) {
            final BlockPos pos = new BlockPos(this.getX(), this.getY(), this.getZ());
            LightningBolt entityToSpawn = new LightningBolt(EntityType.LIGHTNING_BOLT, serverLevel);
            entityToSpawn.moveTo(Vec3.atBottomCenterOf(pos));
            entityToSpawn.setVisualOnly(true);
            serverLevel.addFreshEntity(entityToSpawn);
            serverLevel.playSound(null, pos, SoundEvents.FIREWORK_ROCKET_LARGE_BLAST, SoundSource.HOSTILE, 3, 1);
            serverLevel.playSound(null, pos, SoundEvents.FIREWORK_ROCKET_LARGE_BLAST, SoundSource.HOSTILE, 4, 1);
//            for(int i=0;i<3;i++)
//            {
                FireEntity enderBomb = new FireEntity(EntityInit.FIREENTITY.get(), this.level);
                enderBomb.setPos(this.position());
                int k=this.random.nextInt(3);
                if(k==0)
                    enderBomb.setBlock(Blocks.BIRCH_PLANKS.defaultBlockState());
                else if(k==1)
                    enderBomb.setBlock(Blocks.FIRE.defaultBlockState());
                else
                    enderBomb.setBlock(Blocks.STONE_BRICK_SLAB.defaultBlockState());

                enderBomb.setTarget(this.getTarget());
                enderBomb.setAttackType(0);
                this.level.addFreshEntity(enderBomb);
//            }
            //            DynamicProjectile.create(AquamiraeEntities.POISONED_CHAKRA.get(), this, this.level, null, 5, 0F, 600, 1000);
//            DynamicProjectile.create(AquamiraeEntities.POISONED_CHAKRA.get(), this, this.level, null, 5, 0.33F, 600, 1000);
//            DynamicProjectile.create(AquamiraeEntities.POISONED_CHAKRA.get(), this, this.level, null, 5, 0.66F, 600, 1000);
        }
    }

//    @Override protected void dropEquipment() {
//        if (Math.random() <= 0.2F) {
//            final ItemEntity item = new ItemEntity(EntityType.ITEM, this.level);
//            item.setItem(this.getMainHandItem());
//            item.moveTo(this.position());
//            this.level.addFreshEntity(item);
//        }
//    }

    @Override
    public @NotNull MobType getMobType() {
        return MobType.WATER;
    }

    @Override public boolean removeWhenFarAway(double distanceToClosestPlayer) {
        return false;
    }

    @Override
    protected SoundEvent getAmbientSound() {
        Random ran = new Random();
        int co = ran.nextInt(3);
        if(co==0) return SoundInit.ENTITY_CHIEF_AMBIENT1.get();
        if(co==1) return SoundInit.ENTITY_CHIEF_AMBIENT2.get();
        return SoundEvents.RAVAGER_ROAR;
    }

    @Override
    protected SoundEvent getHurtSound(DamageSource source) {
        Random ran = new Random();
        int co = ran.nextInt(2);
        if(co==0) return SoundEvents.RAVAGER_HURT;
        return SoundInit.ENTITY_HESEN_HURT2.get();
    }

    @Override
    protected SoundEvent getDeathSound() {
        return SoundInit.ENTITY_CHIEF_DEATH.get();
    }

    @Override public boolean hurt(DamageSource source, float amount) {
        if (source.getDirectEntity() instanceof AbstractArrow) return false;
        if (source == DamageSource.FALL) return false;
        if (source == DamageSource.CACTUS) return false;
        if (source == DamageSource.DROWN) return false;
        if (source == DamageSource.LIGHTNING_BOLT) return false;
        if (source.isExplosion()) return false;
        if (source.getMsgId().equals("trident")) return false;
        return super.hurt(source, amount);
    }

//    @Override public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor world, @NotNull DifficultyInstance difficulty, @NotNull MobSpawnType reason, @Nullable SpawnGroupData livingdata, @Nullable CompoundTag tag) {
//        if (this.getLevel() instanceof ServerLevel serverLevel) serverLevel.playSound(null, new BlockPos(this.getX(), this.getY(), this.getZ()),
//                AquamiraeSounds.ENTITY_CAPTAIN_CORNELIA_HORN.get(), SoundSource.HOSTILE, 3, 1);
//        this.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 120, 0, false, false));
//        AquamiraeMod.loadFromConfig(this, Attributes.MOVEMENT_SPEED, AquamiraeConfig.Common.corneliaMovementSpeed.get());
//        AquamiraeMod.loadFromConfig(this, Attributes.MAX_HEALTH, AquamiraeConfig.Common.corneliaMaxHealth.get());
//        AquamiraeMod.loadFromConfig(this, Attributes.ARMOR, AquamiraeConfig.Common.corneliaArmor.get());
//        AquamiraeMod.loadFromConfig(this, Attributes.STATE_DAMAGE, AquamiraeConfig.Common.corneliaAttackDamage.get());
//        AquamiraeMod.loadFromConfig(this, Attributes.FOLLOW_RANGE, AquamiraeConfig.Common.corneliaFollowRange.get());
//        AquamiraeMod.loadFromConfig(this, Attributes.STATE_KNOCKBACK, AquamiraeConfig.Common.corneliaAttackKnockback.get());
//        AquamiraeMod.loadFromConfig(this, Attributes.KNOCKBACK_RESISTANCE, AquamiraeConfig.Common.corneliaKnockbackResistance.get());
//        return super.finalizeSpawn(world, difficulty, reason, livingdata, tag);
//    }

    @Override public boolean canChangeDimensions() {
        return false;
    }

    @Override public void startSeenByPlayer(@NotNull ServerPlayer player) {
        super.startSeenByPlayer(player);
        this.bossInfo.addPlayer(player);
    }

    @Override public void stopSeenByPlayer(@NotNull ServerPlayer player) {
        super.stopSeenByPlayer(player);
        this.bossInfo.removePlayer(player);
    }

    @Override public void customServerAiStep() {
        super.customServerAiStep();

        this.fallDistance=0;

        if(this.timer<45)
            this.setAttackingState(1);
        else
            this.setAttackingState(2);

        this.bossInfo.setProgress(this.getHealth() / this.getMaxHealth());
    }

    public static AttributeSupplier.@NotNull Builder prepareAttributes() {
        return Monster.createMobAttributes()
                .add(Attributes.MOVEMENT_SPEED, 0.3D)
                .add(Attributes.MAX_HEALTH, 150D)
                .add(Attributes.ARMOR, 6D)
                .add(Attributes.ATTACK_DAMAGE, 4)
                .add(Attributes.FOLLOW_RANGE, 50)
                .add(Attributes.KNOCKBACK_RESISTANCE, 1)
                .add(Attributes.ATTACK_KNOCKBACK, 2);
    }

    private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
        if (event.isMoving()) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.walk", true));
            return PlayState.CONTINUE;
        }
//        Random ran = new Random();
//        int co = ran.nextInt(30);
//        if(co==1) {
//        	event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.dimi.idle2", true));
//            return PlayState.CONTINUE;
//        }

        event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.idle", true));
        return PlayState.CONTINUE;
    }

    private <E extends IAnimatable> PlayState predicate1(AnimationEvent<E> event) {
//        if (this.timer>55 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
//            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.idle", true));
//            return PlayState.CONTINUE;
//        }

        if (this.entityData.get(STATE)==1 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
            int k=this.random.nextInt(10);
            if(k<5)
            {
                event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.attack", true));
                return PlayState.CONTINUE;
            }
//            else if(k<7){
//                event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.idle", true));
//                return PlayState.CONTINUE;
//            }
            else{
                if(this.getTarget()!=null)
                {
                    LivingEntity livingentity = this.getTarget();
                    double d00 = livingentity.getX() - this.getX();
                    double d10 = livingentity.getZ() - this.getZ();
                    double d20 = Math.max(d00 * d00 + d10 * d10, 0.001D);
                    if(livingentity instanceof IronGolem) livingentity.hurt(DamageSource.CACTUS,(livingentity.getMaxHealth()+livingentity.getArmorValue())*0.25f);
                    livingentity.push(d00 / d20 * 4.0D, 0.4D, d10 / d20 * 4.0D);
                }
                event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.attack2", false));
                return PlayState.CONTINUE;
            }
        }

        if (this.entityData.get(STATE) == 3 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.chief2.idle", false));
            return PlayState.CONTINUE;
        }
        return PlayState.CONTINUE;
    }


    @Override
    public void registerControllers(AnimationData data) {
        data.addAnimationController(new AnimationController(this, "controller",
                0, this::predicate));
        data.addAnimationController(new AnimationController(this, "controller1",
                0, this::predicate1));
    }

}


憧憬

研究生顺利毕业、找到大厂工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jay_fearless

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值