MOD製作チュートリアル > カスタムモデルつきブロックの追加

特殊な形のブロックを追加する。
今回は、アルミ製の金床を追加する。
(……としたいのだが、金床のGUIに関しては、実装していない。悪しからず。)

この内容はとても難解なものを含んでいるうえ、汎用性に乏しい。
そのため、更に汎用性の高いものを作る場合は、net.minecraft.client.rendererのRenderBlocksを参照。

AluminiumMod

AluminiumMod.java

+ 長いので囲みます
package aluminiummod.common;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
 
/**
*
* @author Akasata Nahama & Tom Kate & YOU!!
*
*/
@Mod(modid = "AluminiumMod", name = "Aluminium Mod")
public class AluminiumMod {
 
	//追加するブロックの定義
	/*public static Block * ;*/
	public static Block AnvilAluminium;
 
	//レンダーIDの取得
	public static int RenderID;
 
	@EventHandler
	public void perInit(FMLPreInitializationEvent event) {
 
		/*ブロックの実装。詳細割愛。*/
		AnvilAluminium = new AnvilAluminium();
 
		AnvilAluminium.setCreativeTab(CreativeTabs.tabBlock);
 
		AnvilAluminium.setBlockName("blockAluminium");
 
		AnvilAluminium.setBlockTextureName("aluminiummod:aluminium_anvil");
 
		GameRegistry.registerBlock(AnvilAluminium, "AnvilAluminium");
 
 
	}
 
	@EventHandler
	public void init (FMLInitializationEvent event) {
		/*FMLCommonHandler.instance().getSide() で、クライアントサイドでのみの動作としている。*/
		if(FMLCommonHandler.instance().getSide() == Side.CLIENT)
		{
			/*レンダーIDの設定。
			 * RenderingRegistry.getNextAvailableRenderId() で、未使用のレンダーIDを取得する。*/
			this.RenderID = RenderingRegistry.getNextAvailableRenderId();
 
			/*ブロックのレンダラ―を設定する。
			 *RenderingRegistry.registerBlockHandler(ISimpleBlockRenderingHandler); */
			RenderingRegistry.registerBlockHandler(new RenderAnvilAluminium());
 
		}
	}
 
 
 

AnvilAluminium.java

+ 長いので囲みます
package aluminiummod.common;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.world.IBlockAccess;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
 
public class AnvilAluminium extends Block{
 
	public AnvilAluminium() {
		super(Material.rock);
	}
 
		/**レンダーIDを返す。**/
		@Override
		public int getRenderType()
		{
			return AluminiumMod.RenderID;
		}
 
		/**ブロックが透けるか否かを返す。**/
	    @SideOnly(Side.CLIENT)
	    public boolean shouldSideBeRendered(IBlockAccess p_149646_1_, int p_149646_2_, int p_149646_3_, int p_149646_4_, int p_149646_5_)
	    {
	        return true;
	    }
 
	    /**通常のブロックでないかを返す。*/
	    public boolean renderAsNormalBlock()
	    {
	        return false;
	    }
 
	    /**ブロックが透明か否かを返す。*/
	    public boolean isOpaqueCube()
	    {
	        return false;
	    }
 

RenderAnvilAluminium.java

+ 長いので囲みます
package aluminiummod.common;
 
import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.world.IBlockAccess;
 
import org.lwjgl.opengl.GL11;
 
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
 
public class RenderAnvilAluminium implements ISimpleBlockRenderingHandler
{
	/**インベントリ内でブロックをレンダリングするメソッド。もしshouldRender3DInInventoryがfalseなら空でもいいかも。**/
	@Override
	public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer)
	{
		if (modelId == this.getRenderId())
		{
			float f = 0;
			f = this.renderAlumiAnvil(block, renderer, metadata, f, 0.75F, 0.25F, 0.75F ,false);
			f = this.renderAlumiAnvil(block, renderer, metadata, f, 0.5F, 0.0625F, 0.625F ,false);
			f = this.renderAlumiAnvil(block, renderer, metadata, f, 0.25F, 0.3125F, 0.5F ,false);
			this.renderAlumiAnvil(block, renderer, metadata, f, 0.625F, 0.375F, 1.0F ,false);
 
 
 
		}
	}
 
	/**ワールド内でブロックをレンダリングするメソッド**/
	@Override
	public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer)
	{
		if (modelId == this.getRenderId())
		{
			/*レンダリングする立方体のサイズを決めるメソッド。
			 * setRenderBounds(始点X, 始点Y, 始点Z, 終点X, 終点Y, 終点Z)*/
			renderer.setRenderBounds(0.1D, 0.0D, 0.1D, 0.9D, 0.2D, 0.9D);
			/*レンダリングするメソッド。
			 * renderStandardBlock(block, x, y, z);*/
			renderer.renderStandardBlock(block, x, y, z);
			renderer.setRenderBounds(0.25D, 0.2D, 0.25D, 0.75D, 0.3D, 0.75D);
			renderer.renderStandardBlock(block, x, y, z);
			renderer.setRenderBounds(0.3D, 0.3D, 0.2D, 0.7D, 0.6D, 0.8D);
			renderer.renderStandardBlock(block, x, y, z);
			renderer.setRenderBounds(0.2D, 0.6D, 0.0D, 0.8D, 1.0D, 1.0D);
			renderer.renderStandardBlock(block, x, y, z);
 
			return true;
		}
		return false;
	}
 
	@Override
	/**インベントリ内で3Dレンダリングするか否かを返すメソッド**/
	public boolean shouldRender3DInInventory(int modelId) {
		return true;
	}
 
	/**自身のレンダーIDを返すメソッド**/
	@Override
	public int getRenderId() {
 
		return AluminiumMod.RenderID;
	}
 
	protected float renderAlumiAnvil(Block block , RenderBlocks renderer , int metadata , float sides1 , float sides2 , float sides3  , float sides4 , boolean flg)
	{
		/**詳しい説明はカット。ここは難しいため、基本的にはshouldRender3DInInventoryをfalseにすることをお勧めする。**/
		if(flg)
		{
			float f = sides2;
			sides2 = sides4;
			sides4 =f;
		}
		sides2 /= 2.0F;
        sides4 /= 2.0F;
		renderer.setRenderBounds((double)(0.5F - sides2), (double)sides1, (double)(0.5F - sides4), (double)(0.5F + sides2), (double)(sides1 + sides3), (double)(0.5F + sides4));
          /*これより下は、ブロックを各面ごとにレンダリングしている。*/
		Tessellator tessellator = Tessellator.instance;
		GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
		tessellator.startDrawingQuads();
		tessellator.setNormal(0.0F, -1.0F, 0.0F);
		renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata));
		tessellator.draw();
		tessellator.startDrawingQuads();
		tessellator.setNormal(0.0F, 1.0F, 0.0F);
		renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 1, metadata));
		tessellator.draw();
		tessellator.startDrawingQuads();
		tessellator.setNormal(0.0F, 0.0F, -1.0F);
		renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 2, metadata));
		tessellator.draw();
		tessellator.startDrawingQuads();
		tessellator.setNormal(0.0F, 0.0F, 1.0F);
		renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 3, metadata));
		tessellator.draw();
		tessellator.startDrawingQuads();
		tessellator.setNormal(-1.0F, 0.0F, 0.0F);
		renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 4, metadata));
		tessellator.draw();
		tessellator.startDrawingQuads();
		tessellator.setNormal(1.0F, 0.0F, 0.0F);
		renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata));
		tessellator.draw();
		GL11.glTranslatef(0.5F, 0.5F, 0.5F);
		renderer.setRenderBounds(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D);
		return sides1 + sides3;
	}
 

解説

RenderAnvilAluminium

この中では、インベントリ内でのレンダリングが一番難しいはずである。
もし大変ならば、shouldRender3DInInventoryをfalseにすればインベントリにはテクスチャのみが表示されるため、作業が楽になる。

コメント

この項目に関する質問などをどうぞ。
  • ページ左のサイト内リンクからのリンクが間違っていると思います - 名無しさん 2015-07-08 23:19:57
    • ご指摘ありがとうございます。修正しました。 - 赤砂蛇凪浜 2015-07-09 09:55:44
  • 赤砂蛇凪浜様(そうでしょうか)、おはようございます - Dao_Za 2016-04-01 10:07:32
  • 赤砂蛇凪浜様(そうでしょうか)、おはようございます!中国のファンです。昨日夜このサイトを拝見いたしまして、即刻ファンになります~一つご質問がございますが、どうやて、ブロックのbnound大きさを設置しますでしょうか。AnvilAluminium.javaにsetBoundなどを高さ3.0のブロックに設置しましたが、上から踏んた時、画面が痙攣のようになりましたwwww。ほかのmodを読んでいましたが、onEntityCollidedWithBlockという方法でしょうか。 - Dao_Za 2016-04-01 10:12:18
    • setBlockBoundsの引数で、ブロックの大きさを設定することができます。
      また、getCollisionBoundingBoxFromPoolをオーバーライドすると衝突判定だけを設定することができます。
      衝突判定は、Yに2.0Fより大きい値を設定するとうまく反映できず、画面が荒ぶるようです。
      onEntityCollidedWithBlockは、Entityがブロックに触れているときの処理です。 - 赤砂蛇凪浜 2016-04-01 14:57:54
  • ありがとうございます。あの、手持ち時の3D形をどうやって設置しますか。現在椅子の形を作りたく、RenderAluminumファイルでのrenderInventoryBlockで設置して、どうか真ん中から広げて、例えば0.2F,0.3F,0.4Fで、0.2X0.4の柱になってしまいます。(あるいは最後のrenderAlumiAnvilのところで設置?ほかのMOD内容を見て、renderAlumiAnvilのところはみんなほぼお同じcodeですが。) - Dao_Za 2016-04-02 00:32:33
  • こんにちは。もう一点ですが、放置するときに椅子の向き方向の調整案例がございますでしょうか。 - Dao_Za 2016-04-02 12:05:08
    • 上記二つの質問ですが、いまいち意図がつかめませんでした。
      (「0.2F,0.3F,0.4F」とはどこの数値でしょうか?)
      私もあまり得意な分野ではないので、的確な返答ができないかもしれません。申し訳ありません。 - 赤砂蛇凪浜 2016-04-04 07:52:30
  • 説明不足でした申し訳ございませんでした。0.2とかは仮説の数字で無視すればOKです~あの、上の計算式で三つ数字の意味を知りたいですが:「f = this.renderAlumiAnvil(block, renderer, metadata, f, 0.75F, 0.25F, 0.75F ,false);」の中の0.75、0.25、0.75の機能はそれぞれなんでしょうかね? - Dao_Za 2016-04-05 18:49:32
    • renderAlumiAnvilは、金床のレンダリングを行うメソッドです。sides1は始点の高さ、sides2,sides3,sides4はそれぞれ立方体のx,y,z方向の長さです。この三つで立方体の大きさを表せます。 - Tom Kate 2016-04-05 21:04:45
  • こんばんは。プレイヤーの向きによってカスタムモデルの向きを変えるようなブロック(例:フェンスゲート、階段等)はどのようにして追加するのでしょうか。 - modder 2016-05-11 00:07:21
    • 返信遅くなってしまいすみません。
      バニラのフェンスゲートと同様、onBlockPlacedByで設置時のプレイヤーの向きに応じてメタデータを設定し、レンダリング時にメタデータを取得して描画する向きを決めればよいかと思います。 - 赤砂蛇凪浜 2016-05-13 17:58:12
      • ありがとうございます - modder 2016-06-03 22:27:41
  • modelは、jsonで指定するはずです。 - pppp 2017-08-30 06:55:39
    • こちらのチュートリアルは1.7.10版のものです。jsonで指定するのは1.8版以降ですので、まだチュートリアルには記載しておりません。今後1.12版の方はチュートリアル実装予定です。 - TomKate 2017-08-30 18:22:14
最終更新:2015年07月09日 19:36