概述
通过前两部分的了解,我们知道一个实体有着各种各样的属性,其中一类属性是需要频繁变动的,包括运动坐标、血量等,这一部分因为涉及到数据同步,留待以后再讲,不过,有一些属性是既定的,也就是说,在生成实体之后往往就不会变动了。这类属性有两类是特殊的,分别为实体的碰撞箱和声音,剩下的固有属性我们归结到一类,因为它们的指定方式是通用的。
我们知道,不管是动物还是怪物,都会在世界上大量生成,也就是说,生物是可以自然生成在世界上的,这一部分在讲解生物的固有属性的同时,也会讲解如何把实体生物在世界上自然生成。
实体的碰撞箱
如果之前有过游戏开发经验的开发者,可能会很容易地理解实体的碰撞箱这一概念,和其他游戏中的碰撞箱类似,实体的碰撞箱是一个长宽高既定的非常简单的长方体。我们通过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,无上界,默认为20followRange
表示生物的最大跟踪半径,最小为0,最大2048,默认为32knockbackResistance
表示生物的击退抗性,最小为0,最大为1,默认为0movementSpeed
表示生物的移速,最小为0,无上界,默认为0.7
除此之外,还有一种属性同样位于类SharedMonsterAttributes
中,不过只用于怪物,也十分常用:
attackDamage
表示生物的攻击能力,最小为0,无上界,默认为2
还有两种针对部分生物的专用属性,分别是:
horseJumpStrength
位于EntityHorse
类中,表示马的弹跳力,最小为0,最大为2,默认为0.7reinforcementChance
位于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 |