初心者modderの備忘録

マイクラのmodを作りたくて、初めて見たのですが難しくて忘れそうなので自分用の備忘録も兼ねてブログにしようと思います

4日目 アイテムの機能の追加

今回は簡単な機能を持ったアイテムを作成しようと思います。前回作成したトマトは何の機能も持たないアイテムだったので、もう少し実用的な何かを作りたいと思います。
まずは、トマトを追加したときと同じようにアイテムを登録します。
1日目 アイテムの追加 - 初心者modderの備忘録


モンスターエッグのような効果を持ったアイテムを作りたいのでトマトエッグと名付けてクラスを作成します。
ItemTomatoEgg.java

package testmod;

import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;

public class ItemTomatoEgg extends Item
{
	public ItemTomatoEgg() {
		this.setCreativeTab(CreativeTabs.MATERIALS);
		this.setUnlocalizedName("tomato_egg");
		this.setRegistryName("tomato_egg");
	}
}


testmod.java

package testmod;

import net.minecraft.block.Block;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.ForgeRegistries;

@Mod(modid = testmod.MOD_ID, name = testmod.MOD_NAME, version = testmod.MOD_VERSION)
public class testmod {
    public static final String MOD_ID = "testmod";
    public static final String MOD_NAME = "testmod";
    public static final String MOD_VERSION = "1.0.0";
    
    public static final Item Tomato = new ItemTomato();
    public static final Item TomatoEgg = new ItemTomatoEgg();
    public static final Block Tomato_Block = new BlockTomato();
    
    @Mod.EventHandler
	public void preInit(FMLPreInitializationEvent event) {
    	ForgeRegistries.ITEMS.register(Tomato);
    	ForgeRegistries.ITEMS.register(new ItemBlock(Tomato_Block).setRegistryName("testmod", "block_tomato"));
    	ForgeRegistries.ITEMS.register(TomatoEgg);
    	
    	ForgeRegistries.BLOCKS.register(Tomato_Block);
    
    	if(event.getSide().isClient()) {
    		ModelLoader.setCustomModelResourceLocation(Tomato, 0, new ModelResourceLocation(new ResourceLocation("testmod", "tomato"), "inventory"));
    		ModelLoader.setCustomModelResourceLocation(TomatoEgg, 0, new ModelResourceLocation(new ResourceLocation("testmod", "tomato_egg"), "inventory"));
    		ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(Tomato_Block), 0, new ModelResourceLocation(new ResourceLocation("testmod", "block_tomato"), "inventory"));
    	}
    }
}

続いて、jsonファイル、テクスチャー画像、langファイルも設定してください。
テクスチャーにはこの画像を用いました。
f:id:json_fileman:20181231023113p:plain


あとは、ひたすらItemTomatoEggにコードを書き足していきます。
まず、右クリックの発動には2種類あります。クワのようにブロックにカーソルを合わせて右クリックする場合と、エンダーパールのように空中などカーソルがあっていなくても発動できる場合です。
今回は、選択したマスにモンスターをスポーンさせたいのでカーソルを合わせて使うタイプのアイテムに設定します。

クワは消費アイテムじゃないので、消費アイテムだと花火がそれに該当するようです。なので、参照ライブラリーからItemFireWork.classを開いて「Ctrl」+「F」で検索を開いて「click」で検索をかけました。すると一番上に「Called when a Block is right-clicked with this Item」とコメントされたメソッドが出てきたのでこれを参考にItemTomatoEggを編集します。

ItemTomatoEgg.java_ed1

    public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
    {
		ItemStack itemstack = player.getHeldItem(hand);
		
		System.out.println("Block is Clicked");
		
		if (!player.capabilities.isCreativeMode)
        {
            itemstack.shrink(1);
        }
        return EnumActionResult.SUCCESS;
    }

今書き足したのは、printlnでコンソールにメッセージを出力し、アイテムを1つ消費するだけの機能です。
実際に開いて、ブロックに合わせて右クリックしてみるとコンソール上にメッセージが出力されていることが確認できました。

f:id:json_fileman:20181231024729p:plain


このようにコンソール上に出力しておくことで、プログラムの動きを追えるようになるので便利だと思います。

右クリックを認識していることが確認できたので、ちゃんとした機能を実装しようと思います。

ItemTomatoEgg.java_ed2

    public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
    {
		ItemStack itemstack = player.getHeldItem(hand);
		EntityLiving living = new EntityChicken(worldIn);
		living.setPosition(pos.offset(facing).getX()+0.5,pos.offset(facing).getY(),pos.offset(facing).getZ()+0.5);
		
		if(!worldIn.isRemote)
			worldIn.spawnEntity(living);
		
		System.out.println("Block is Clicked");
		
		if (!player.capabilities.isCreativeMode)
        {
            itemstack.shrink(1);
        }
        return EnumActionResult.SUCCESS;
    }

f:id:json_fileman:20181231032429p:plain


こんな感じで動くようになりました。
今回はオリジナルのMOBがいないので、にわとりのスポーンエッグになりましたが、スポーンするエンティティをオリジナルにすれば専用のスポーンエッグにもなりますね。

ちなみに、if(!worldIn.isRemote)とsetPositionのX,Z座標の+0.5は最初は入れてなくてバグが起きました。

if(!worldIn.isRemote)を入れないとサーバー側とクライアント側とで2回実行されるためなのか、一度の使用で2羽のニワトリが生まれました。
f:id:json_fileman:20181231032850p:plain


また、getX()やgetZ()で得られる座標はint型で整数値なので、そのままだと選択しているブロックの角にスポーンするようでした。なので、となりに壁がある所でアイテムを使用すると壁に埋まって窒息してしまいました。
f:id:json_fileman:20181231033205p:plain

XとZ座標をそれぞれ+0.5することで選択したブロックの中心にスポーンするようになりました。


ちなみにほぼ同じ機能でアイテムをスポーンさせることもできます。

ItemTomatoEgg.java_ed3

public EnumActionResult onItemUse(EntityPlayer player, World worldIn, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
    {
		ItemStack itemstack = player.getHeldItem(hand);
		EntityItem item = new EntityItem(worldIn, pos.offset(facing).getX()+0.5, pos.offset(facing).getY(), pos.offset(facing).getZ()+0.5, new ItemStack(Items.BEEF, 4));

		if(!worldIn.isRemote)
			worldIn.spawnEntity(item);

		System.out.println("Block is Clicked");
		
		if (!player.capabilities.isCreativeMode)
        {
            itemstack.shrink(1);
        }
        return EnumActionResult.SUCCESS;
    }

spawnEntityの引数をEntityChickenからEntityItemに変更して、それに伴って数ヶ所変更しました。
4行目の最後のItemStackの第一引数がアイテム第二引数が個数です。



次回は、もう一つの右クリックの機能を持ったアイテムの追加をしようと思います。

最終的なItemTomatoEggのファイルをあげておきます。

ItemTomatoEgg.java(EntityChicken)
ItemTomatoEgg.java(ItemBeef)