Minecraft1.12.2でMod作製 Entity

こちらはPCゲーム「Minecraft」のMod作製の解説記事です。

Minecraft.1.12.2、

Forge-1.12.2-14.23.2.2611での解説になります。








Mineccraftの世界に存在する動物やモンスターなどのMob。これらに加え弓から放たれた矢、ブレイズの火球などがEntityに含まれます。

ここでは「Entity」クラスに含まれる生物に関するクラス「EntityLivingBase」の型階層やEntityを作製する際に使う可能性の高い処理などのEntityの作製に関する情報を載せています。この記事を書いている私自身が元々はJavaを勉強したことが無い状態からMod作製を始めたので、説明内容などはプロのプログラマーの人が見たら「既に知っている」事や「当たり前」の事などもあると思います。この記事は私の様にJavaに初めて触れる人や、これからMod作製に挑戦したい人やMod作製の初心者の人の為に書いているものなので、専門用語を使う時と使わない時があります。また、記載内容に誤りや私自身の理解が誤っている可能性がある事をご了承ください。

記事の内容は徐々に追加していく予定です。

EntityLivingBase

型階層

EntityLivingBaseからの型階層。eclipseでは型階層は対象のクラスを指定して右クリックで表示されるメニューから「型階層を開く」もしくはクラスを指定した状態で「F4」キーを押す事で確認出来る。eclipseで簡単に確認できるので、クラス継承などの確認だけであればeclipseの方が早いかも知れない。

EntityLivingBaseの型階層

EntityLivingBase EntityArmorStand
EntityLiving
EntityPlayer

EntityLivingBaseは上の表のように3つに分かれ、生物に関するメソッドや変数などが記載されている。アーマースタンドは体力も無く、生物とは言えないかもしれないが、内部的にはEntityLivingBaseの型階層に含まれる。これはアーマースタンドがプレイヤーと同様に鎧などの装備品に関わる「handInventory」と「armorArray」を実装しているからである。それ以外はプレイヤーかプレイヤー以外の生物かで2つのクラスに分かれる。

EntityLivingの型階層

EntityLiving EntityAmbientCreature EntityBat
EntityCreature
EntityDragon
EntityFlying EntityGhast
EntitySlime EntityMagmaCube
EntityWaterMob EntitySquid

EntityLivingからは上の表にように分かれる。EntityFlyingにはガストのみが含まれ、ブレイズなどはEntityCreatureの先のEntityMob(敵対的な生物)に含まれる。スライムも敵対的な生物ではあるが他のMobと実装している内容が違うので分かれている。スライム、ガスト、シュルカー、エンダードラゴンはインターフェースの「IMob」を実装している為、「これらを含む敵対的な生物」を取得する時は「IMob」を使用すると良い。
例:if文
if (this.getAttackTarget instanceof IMob)

ほとんどの生物はEntityLivingの先のEntityCreatureに含まれるので、型階層から探す場合はEntityCreatureから探すと良い。

EntityCreatureの型階層

EntityCreature EntityAgeable
EntityGolem
EntityMob

EntityCreatureからは上の3つに分かれる。EntityAgeableからは動物と村人に、EntityGolemからはアイアンゴーレムとスノーゴーレムとシュルカー、EntityMobからは殆どの敵対的な生物に分かれる。

EntityAgeable ➡ EntityAnimalの型階層

EntityAnimal AbstractHorse
EntityChicken
EntityCow
EntityPig
EntityPolarBear
EntityRabbit
EntitySheep
EntityTameable

EntityAnimalからは上の表のように分かれる。EntityTameableには馬、ロバ、ラバ、ラマを除く「手懐け可能な動物」のオオカミ、ヤマネコ(ネコ)、オウムが含まれる。

よく使用されるメソッド

Entityを右クリックした時

public boolean processInteract(EntityPlayer player, EnumHand hand)

EntityLivingクラスのprocessInitialInteract内で呼び出される。processInitialInteractはEntityを右クリックした際の処理で、Entityクラスで実装されているが処理内容はfalseを返すのみで実際にはEntityLiving内でオーバーライドされ処理内容が実装されている。初めにEntityへのリードの付け外しの処理を実行するかの判定が行われ、それが行われなかった場合に、processInteractの処理が実行される。processInitialInteractはfinalの修飾子が付いているのでオーバーライドが出来ない。その為、「プレイヤーがリードを持っている」状態か、「Entityにリードが付いている」状態を条件とする処理は実装できない事になる。

processInteractの処理の流れは、継承先のクラスでの(右クリックした時の)処理内容の判定を行ってから、処理が行われずに最後までいった時には継承元のprocessInteractが実行される。以下はEntityWolf(オオカミ)クラス内の「processInteract」。

    public boolean processInteract(EntityPlayer player, EnumHand hand)
    {
        ItemStack itemstack = player.getHeldItem(hand);

        if (this.isTamed())
        {
            if (!itemstack.isEmpty())
            {
                if (itemstack.getItem() instanceof ItemFood)
                {
                    ItemFood itemfood = (ItemFood)itemstack.getItem();

                    if (itemfood.isWolfsFavoriteMeat() && ((Float)this.dataManager.get(DATA_HEALTH_ID)).floatValue() < 20.0F)
                    {
                        if (!player.capabilities.isCreativeMode)
                        {
                            itemstack.shrink(1);
                        }

                        this.heal((float)itemfood.getHealAmount(itemstack));
                        return true;
                    }
                }
                else if (itemstack.getItem() == Items.DYE)
                {
                    EnumDyeColor enumdyecolor = EnumDyeColor.byDyeDamage(itemstack.getMetadata());

                    if (enumdyecolor != this.getCollarColor())
                    {
                        this.setCollarColor(enumdyecolor);

                        if (!player.capabilities.isCreativeMode)
                        {
                            itemstack.shrink(1);
                        }

                        return true;
                    }
                }
            }

            if (this.isOwner(player) && !this.world.isRemote && !this.isBreedingItem(itemstack))
            {
                this.aiSit.setSitting(!this.isSitting());
                this.isJumping = false;
                this.navigator.clearPath();
                this.setAttackTarget((EntityLivingBase)null);
            }
        }
        else if (itemstack.getItem() == Items.BONE && !this.isAngry())
        {
            if (!player.capabilities.isCreativeMode)
            {
                itemstack.shrink(1);
            }

            if (!this.world.isRemote)
            {
                if (this.rand.nextInt(3) == 0 && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(this, player))
                {
                    this.setTamedBy(player);
                    this.navigator.clearPath();
                    this.setAttackTarget((EntityLivingBase)null);
                    this.aiSit.setSitting(true);
                    this.setHealth(20.0F);
                    this.playTameEffect(true);
                    this.world.setEntityState(this, (byte)7);
                }
                else
                {
                    this.playTameEffect(false);
                    this.world.setEntityState(this, (byte)6);
                }
            }

            return true;
        }

        return super.processInteract(player, hand);
    }

上のコードの最後にある「return super.processInteract(player, hand);」で継承元(親クラス)のprocessInteractを呼び出している。このコード(EntityWolfの)をコピーして間の処理内容を自分の作りたい処理に書き換えれば、右クリックした時の処理が実装または変更が出来る。

    public boolean processInteract(EntityPlayer player, EnumHand hand)
    {

    	//ここに処理内容を記述
    	//処理が実行される場合はreturn true;を記述

        return super.processInteract(player, hand);
    }
public boolean processInteract(EntityPlayer player, EnumHand hand)
{
    if (super.processInteract(player, hand))
    {
        return true;
    }

    //ここに処理内容を記述
    //処理が実行される場合はreturn true;を記述

    return false;
}

processInteractは戻り値がboolanなので、当然ながらtrueかfalseを返す必要がある。オリジナルで作った処理が実行された後にreturn (true)を記述しておかないと、「継承先の処理を優先する場合」は継承元(親クラス)の処理も実行されてしまい、「継承元の処理を優先する場合」はプレイヤーが手にアイテムを持っていた場合は、そのアイテムを右クリックで使用した際の処理も実行されてしまう。

EntityWolfクラスのprocessInteractの
ItemStack itemstack = player.getHeldItem(hand);
ここに記載されている引数handは「プレイヤーが手に持っているアイテム」なので、どちらの手に持っているかは関係しない。なので、持っている手を指定したい場合は・・・
player.getHeldItemMainhand();メインハンド
player.getHeldItemOffhand();オフハンド
に変更すれば良い。

MineCraft 目次に戻る