MinecratにEntityを追加してみる その1【1.7.10】

#はじめに
実はアイデアがなくてマトモに書いたことがなかったんですよね。
あと思いついても使うかどうかすら微妙だったので途中まで書いて
破棄したコードも今までたくさんありました。んで、最近無駄なModを
作るのがマイブームなので、その過程でできたとあるコードをこちらで解説したいと思います。
自分はしっくりこなかったので、破棄するのももったいないし、
せっかく最近Qiitaを始めたので書くか！ということで書いていきます。

11/09追記
この記事で作ったEntityを使ってそれっぽいModを作りました。興味のある方は[こちらをチェック！](https://forum.civa.jp/viewtopic.php?t=152#p548)

#開発環境 ᕕ( ᐛ )ᕗ
- Windows 10
- Minecraft 1.7.10
- MinecraftForge 1.7.10 #1614
- IntelliJ IDEA 2019.1.3

#作っていきましょう！
##とりあえずModとして読み込ませる

```java

package mangalam.mineplus.common;

@Mod(modid = Reference.MOD_ID, name = Reference.MOD_NAME, version = Reference.MOD_VERSION)
public class MinePlus {

    @SidedProxy(clientSide = Reference.CLIENT_PROXY, serverSide = Reference.COMMON_PROXY)
    public static CommonProxy proxy;

    @Mod.Instance
    public static MinePlus instance;

    @Mod.EventHandler
    public void PreInit(FMLPreInitializationEvent event)
    {
        proxy.registerRenders();
    }
}
```

```java

package mangalam.mineplus.common;

public class CommonProxy {

    public void registerRenders()
    {}
}
```
本当は他にもいろいろ書いてますが、簡略化させていただきます。
とりあえずこれがベースになります。Moddingをやったことある人なら誰でもできますね。
ここには載せていませんが、ClientProxyも必要です。内容はCommonProxyを継承して中身を丸コピで構いません。

- **MinePlus** : Modのベースクラスです。
- **CommonProxy** : サーバーサイドで処理したいことを書きます。今回は使いません。
- **ClientProxy** : クライアントサイドで処理したいことを書きます。Entityのレンダリングに使います。


##無機能なEntityを作る
なんでもそうですが、まずはある程度コンセプトなどを考えておきましょう。スムーズに書けると思います。
今回は以下のコンセプトで作っていきます。

 - エンダーパールのように投げられる
 - 落下地点のブロックが土か草ブロックなら、耕す(耕地ブロックに置き換える)
 
要は使い捨てワイヤレスクワですね。何でもかんでもワイヤレスにするのはどうなのかというのはさておき、書いていきます。

```java

package mangalam.mineplus.entity;

public class EntityPlow extends EntityThrowable {

    public EntityPlow(World world)
    {
        super(world);
    }

    public EntityPlow(World world, EntityLivingBase living)
    {
        super(world, living);
    }

    @SideOnly(Side.CLIENT)
    public EntityPlow(World world, double x, double y, double z)
    {
        super(world, x, y, z);
    }

    @Override
    protected void onImpact(MovingObjectPosition mop)
    {
    
    }
}
```

これだけで、一応はEntityとして完成です。コンストラクタが3つありますが、今回は2つめしか使いません。
ですがいろんな方のコードを拝見すると、大体この3つは最低限書いてあるので書いておいて損はないでしょう。
親クラスは投げられるEntityとしてある程度機能が既に備わっている**EntityThrowable**を使います。

- public EntityPlow(World world) : コンストラクタ 親クラスが要求してくるので必須
- public EntityPlow(World world, EntityLivingBase living) : プレイヤーが投げる時にこいつを呼びたいので書いとく
- public EntityPlow(World world, double x, double y, double z) : まぁ...保険ですね！

次にこいつをEntityとしてMinecraftに登録します。PreInitのタイミングで登録します。
好きなタイミングで登録できますが、事前初期化処理の時が一番いいと思います。

```java

    @Mod.EventHandler
    public void PreInit(FMLPreInitializationEvent event)
    {
        EntityRegistry.registerModEntity(EntityPlow.class, "plow", 0, MinePlus.instance, 30, 10, true);
        proxy.registerRenders();
    }
```
registerModEntityメソッドについて解説します。EntityRegistry内では以下のようになっています。

***public static void registerModEntity(Class<? extends Entity> entityClass, String entityName, int id, Object mod, int trackingRange, int updateFrequency, boolean sendsVelocityUpdates)***

>EntityをMinecraftに登録するためのメソッド
- **Class<? extends Entity> entityClass** : Entityのクラス
- **String entityName** : Entityを登録する時の名前。
- **int id** : EntityのID Mod内での判別にのみ使われるので、分かるものでOK
- **Object mod** : Modのインスタンス
- **int trackingRange** : MOBの探知範囲
- **int updateFrequency** : 更新頻度(tick)
- **boolean sendsVelocityUpdates** : 速度情報の有無

この辺はEntityの動いて欲しい挙動を元に自分で微調整してあげるといいです。
登録はしましたが、これでは実際にできているのかよくわからないので、このEntityを投げられるアイテムも作っておきます。

##Entityを投げられるアイテムを作る
アイテムを登録する処理については割愛させていただきます。

```java

package mangalam.mineplus.item;

public class ItemTestPlow extends MineItem {

    public ItemTestPlow(String name)
    {
        super(name);
        this.setMaxStackSize(16);
    }

    public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player)
    {
        if(player.capabilities.isCreativeMode)
        {
            world.playSoundAtEntity(player, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));

            if(!world.isRemote)
            {
                world.spawnEntityInWorld(new EntityPlow(world, player));
            }

            return itemStack;
        }
        else
        {
            --itemStack.stackSize;
            world.playSoundAtEntity(player, "random.bow", 0.5F, 0.4F / (itemRand.nextFloat() * 0.4F + 0.8F));

            if(!world.isRemote)
            {
                world.spawnEntityInWorld(new EntityPlow(world, player));
            }

            return itemStack;
        }
    }
}
```
エンダーパールのソースを流用しました。スタックサイズや名前とかは自分で好きにいじってください。以下内容の解説です。

***public ItemStack onItemRightClick(ItemStack itemStack, World world, EntityPlayer player)***

>アイテムを右クリックした際に呼ばれるメソッド
- **ItemStack itemStack** : 使ったアイテムスタック
- **World world** : ワールド
- **EntityPlayer player** : 使ったプレイヤー

***world.spawnEntityInWorld(new EntityPlow(world, player));***
==>
***public boolean spawnEntityInWorld(Entity p_72838_1_)***

>ワールドにEntityを生成するメソッド
- **Entity p_72838_1_** : 生成するEntity

先程Entityのクラスで作った2つ目のコンストラクタを使うのはこのためです。こうしないと、
スロワーの情報が取得できないため、ワールド内でアイテムを使った時に上手くEntityが生成されません。

##プレイしてみる
とりあえずEntityを投げられるようになったのでプレイしてチェックしてみます。
<img width="700" alt="throwtest" src="https://media.giphy.com/media/JSeq97JcjOwtVm2BO8/giphy.gif">
微妙に見にくいですが、右クリックした際に白いブロックが出ているのがわかると思います。
というわけで、Entityとしては完成です！

#長くなりそうなので次回に続く！
ちゃんと解説しようとすると思った以上に長くなりそうなので、続きは別の記事に分けたいと思います。
次回は肝心な中身を記述していこうと思います。 それでは！

9/23追記
次はここやで！٩(  ᐛ)و [**MinecratにEntityを追加してみる その2【1.7.10】**](https://qiita.com/Onmitsu600/items/3e5e6b201b7cad9dca8a)