概述

通过前两部分的了解,我们知道一个实体有着各种各样的属性,其中一类属性是需要频繁变动的,包括运动坐标、血量等,这一部分因为涉及到数据同步,留待以后再讲,不过,有一些属性是既定的,也就是说,在生成实体之后往往就不会变动了。这类属性有两类是特殊的,分别为实体的碰撞箱和声音,剩下的固有属性我们归结到一类,因为它们的指定方式是通用的。

我们知道,不管是动物还是怪物,都会在世界上大量生成,也就是说,生物是可以自然生成在世界上的,这一部分在讲解生物的固有属性的同时,也会讲解如何把实体生物在世界上自然生成。

实体的碰撞箱

如果之前有过游戏开发经验的开发者,可能会很容易地理解实体的碰撞箱这一概念,和其他游戏中的碰撞箱类似,实体的碰撞箱是一个长宽高既定的非常简单的长方体。我们通过setSize方法,来为实体指定碰撞箱,很明显,目前的黄金鸡的碰撞箱过小,不太和它的身材符合,所以我们在构造方法中指定其碰撞箱:

src/main/java/com/github/ustc_zzzz/fmltutor/entity/EntityGoldenChicken.java(部分):

    public EntityGoldenChicken(World worldIn)
    {
        super(worldIn);
        this.setSize(1.2F, 1.8F);
    }

setSize方法的第一个参数指定了这个实体的长宽,第二个参数指定了这个实体的高。

声音

很明显,EntityLiving类提供了四个用于获取声音的方法,覆写掉它们就可以替换对应的声音了:

  • getLivingSound表示生物存活的时候发出的声音
  • getHurtSound表示生物受伤的时候发出的声音
  • getDeathSound表示生物死亡的时候发出的声音
  • getFallSoundString表示生物坠落的时候发出的声音,该方法传入一个整数值表示伤害点数

上面四个方法需要返回一个字符串,该字符串表示的就是声音,在前面的部分中我们已经提到了如何自定义声音。

除此之外,我们还可以调用playSound方法手动发出声音,第一个参数作为一个字符串和上面的一样表示声音,第二个参数表示声音的大小,第三个参数表示声音的音调。

生物的固有属性

一般来说,Minecraft提供的实体生物的其他固有属性一共有四种,它们都是IAttribute类的子类,位于类SharedMonsterAttributes中:

  • maxHealth表示生物的最大血量,最小为0,无上界,默认为20
  • followRange表示生物的最大跟踪半径,最小为0,最大2048,默认为32
  • knockbackResistance表示生物的击退抗性,最小为0,最大为1,默认为0
  • movementSpeed表示生物的移速,最小为0,无上界,默认为0.7

除此之外,还有一种属性同样位于类SharedMonsterAttributes中,不过只用于怪物,也十分常用:

  • attackDamage表示生物的攻击能力,最小为0,无上界,默认为2

还有两种针对部分生物的专用属性,分别是:

  • horseJumpStrength位于EntityHorse类中,表示马的弹跳力,最小为0,最大为2,默认为0.7
  • reinforcementChance位于EntityZombie类中,表示僵尸在被攻击时增加支援的可能性,最小为0,最大为1,默认为0

增加属性带来的一个显而易见的好处,就是可以通过自定义(如命令方块)的方式生成不同属性的同种生物。那么,如何在实体生物生成的时候定义它的属性呢?

我们需要覆写掉实体生物的applyEntityAttributes方法:

src/main/java/com/github/ustc_zzzz/fmltutor/entity/EntityGoldenChicken.java(部分):

    @Override
    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();

        this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(8.0D);
        this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.5D);
    }

首先我们通过getEntityAttribute方法获取一个实体对应的属性,然后我们通过setBaseValue方法来设置其值。

那么如何添加新的属性呢?我们其实可以如法炮制,新创造一个IAttribute类的子类,这里我们添加一个有趣的属性,就是黄金鸡的翅膀振速:

src/main/java/com/github/ustc_zzzz/fmltutor/entity/EntityGoldenChicken.java(部分):

    public static final IAttribute wingSpeed = new RangedAttribute(null, "fmltutor.GoldenChicken.wingSpeed", 1.5D, 0.0D,
            4.0D).setDescription("Wing Speed").setShouldWatch(true);

我们注意到,Minecraft提供的IAttribute类的子类中,只有一个RangedAttribute是可以直接初始化的,所以我们理所当然地初始化了这个类:

  • 第一个参数经推测可能表示父属性,不过在所有上述的属性中,这个值都被设置成空,所以这里我们也只传入一个null
  • 第二个参数表示这个属性的名称,这里我们如法炮制一个名称就好了
  • 第三个参数表示这个属性的默认值,需要传入一个双精度浮点数
  • 第四个参数表示这个属性的最小值,同样需要双精度浮点数
  • 第五个参数表示这个属性的最大值,同样需要双精度浮点数

这里的属性名称,Minecraft同时为其在语言文件中提供了记录,这里暂时没有发现它的作用,不过我们还是选择加上更好:

src/main/resources/assets/fmltutor/lang/en_US.lang(部分):

attribute.name.fmltutor.GoldenChicken.wingSpeed=Wing Speed

src/main/resources/assets/fmltutor/lang/zh_CN.lang(部分):

attribute.name.fmltutor.GoldenChicken.wingSpeed=翅膀振速

setDescription方法用于描述这个属性,不过暂时没有发现它的作用,而且和语言文件的功能也有一些类似,不过同理,我们还是选择加上更好。

setShouldWatch方法用于设定这个属性是否需要服务端向客户端数据同步,如果该数据永远都不需要同步,那么就可以考虑不调用这一方法,否则,还是加上的好。

现在我们添加了一个新的固有属性,那么我们怎么在实体中注册它呢:

src/main/java/com/github/ustc_zzzz/fmltutor/entity/EntityGoldenChicken.java(部分):

    @Override
    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();

        this.getAttributeMap().registerAttribute(EntityGoldenChicken.wingSpeed);

        this.getEntityAttribute(EntityGoldenChicken.wingSpeed).setBaseValue(1 + this.rand.nextDouble());
        this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(8.0D);
        this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.5D);
    }

我们先通过getAttributeMap方法,再通过registerAttribute方法,注册了这个固有属性。

现在还剩最后一个问题,也就是,如何取出这个固有属性呢?其实也很简单,我们通过调用getAttributeValue方法获取,这里给出了一个示例:

src/main/java/com/github/ustc_zzzz/fmltutor/client/entity/model/ModelGoldenChicken.java(部分):

    protected float getWingSpeed(Entity entity, float rotateFloat)
    {
        return (float) (((EntityGoldenChicken) entity).getEntityAttribute(EntityGoldenChicken.wingSpeed)
                .getAttributeValue() * rotateFloat);
    }

src/main/java/com/github/ustc_zzzz/fmltutor/client/entity/model/ModelGoldenChicken.java(部分):

    @Override
    public void setRotationAngles(float limbSwing, float limbSwingAmount, float rotateFloat, float rotateYaw,
            float rotatePitch, float scale, Entity entity)
    {
        this.head.rotateAngleX = rotatePitch / (180F / (float) Math.PI);
        this.head.rotateAngleY = rotateYaw / (180F / (float) Math.PI);
        this.bill.rotateAngleX = this.head.rotateAngleX;
        this.bill.rotateAngleY = this.head.rotateAngleY;
        this.chin.rotateAngleX = this.head.rotateAngleX;
        this.chin.rotateAngleY = this.head.rotateAngleY;
        this.body.rotateAngleX = (float) (Math.PI / 2.0D);
        this.rightLeg.rotateAngleX = MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbSwingAmount;
        this.leftLeg.rotateAngleX = -MathHelper.cos(limbSwing * 0.6662F) * 1.4F * limbSwingAmount;
        this.rightWing.rotateAngleZ = this.getWingSpeed(entity, rotateFloat);
        this.leftWing.rotateAngleZ = -this.getWingSpeed(entity, rotateFloat);
    }

自然生成

Forge提供了一个非常简单的注册实体生物生成的方法,我们简单包装下,拿过来用就是了:

src/main/java/com/github/ustc_zzzz/fmltutor/entity/EntityLoader.java(部分):

    private static void registerEntitySpawn(Class<? extends Entity> entityClass, int spawnWeight, int min,
            int max, EnumCreatureType typeOfCreature, BiomeGenBase... biomes)
    {
        if (EntityLiving.class.isAssignableFrom(entityClass))
        {
            Class<? extends EntityLiving> entityLivingClass = entityClass.asSubclass(EntityLiving.class);
            EntityRegistry.addSpawn(entityLivingClass, spawnWeight, min, max, typeOfCreature, biomes);
        }
    }

src/main/java/com/github/ustc_zzzz/fmltutor/entity/EntityLoader.java(部分):

    public EntityLoader()
    {
        registerEntity(EntityGoldenChicken.class, "GoldenChicken", 80, 3, true);
        registerEntityEgg(EntityGoldenChicken.class, 0xffff66, 0x660000);
        registerEntitySpawn(EntityGoldenChicken.class, 8, 2, 4, EnumCreatureType.CREATURE, BiomeGenBase.plains,
                BiomeGenBase.desert);
    }
  • 第一个参数和之前的相同,需要传入这个实体对应的class实例
  • 第二个参数表示生物的生成权重,这个值越大,优先生成该生物的机率越高
  • 第三个参数表示一次性生成的最少生物数量
  • 第四个参数表示一次性生成的最多生物数量
  • 第五个参数表示这个实体生物的生成类型,有MONSTER(刷怪),CREATURE(动物),AMBIENT(飞行生物)和WATER_CREATURE(水生动物)四种
  • 第六个参数往后就是表示可以生成的生物群系了,BiomeGenBase类中提供了原版的所有生物群系

这里给出一个部分Minecraft原版的生物生成权重、一次性生成的最小数量和最大数量表,以帮助大家确定对应参数的数量级:

生物 生成权重 最小数量 最大数量
12 4 4
10 3 3
10 4 4
8 4 4
蜘蛛 100 4 4
僵尸 100 4 4
骷髅 100 4 4
史莱姆 100 4 4
末影人 10 1 4
女巫 5 1 1
鱿鱼 10 4 4
蝙蝠 10 8 8

results matching ""

    No results matching ""