SPE__HaiKuo
本帖最后由 SPE__HaiKuo 于 2015-7-1 13:18 编辑

前言:
Gui这个万年坑脱了好久,最近有空余时间也重新研究了,困难重重啊,和几位仙贝也讨论了好久,1.8真是变化太大了,让人无时无刻想着我*他Forge!我*他Mojang!我*他Notch!看着论坛的Gui教程就只要当风(过时)的教程了,这里就分享一下自己的经验吧。
本篇先介绍一些基础的备用知识,做一个基本的界面出来,请各位刚学Java的小白点击右上角,毕竟下面的内容直接代码轰炸可能会很难理解



正篇:
这里示例做一个方块,取名为TestGui,因为测试的时候用的是小组在开发的Mod我也懒得单独提取出来了,主类为infstudio.exoticpower.ExoticPower
如果要做一个Gui将会有以下几个文件:BlockTestGui、GuiTestGui、ContainerTestGui、TileEntityTestGui、GuiHandler、GuiID(可有可无)
因为Gui制作非常复杂,传统主类可能做着做着就晕了,所以我们新建一个类proxy,里面创建CommonProxy和ClientProxy

主类ExoticPower代码:
  1. package infstudio.exoticpower;

  2. import infstudio.exoticpower.proxy.CommonProxy;
  3. import net.minecraftforge.fml.common.Mod;
  4. import net.minecraftforge.fml.common.Mod.EventHandler;
  5. import net.minecraftforge.fml.common.Mod.Instance;
  6. import net.minecraftforge.fml.common.SidedProxy;
  7. import net.minecraftforge.fml.common.event.FMLInitializationEvent;
  8. import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
  9. import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

  10. @Mod(modid = "ExoticPower", name="ExoticPower" ,version= "1.0.0")
  11. public class ExoticPower {

  12.         @SidedProxy(clientSide = "infstudio.exoticpower.proxy.ClientProxy", serverSide = "infstudio.exoticpower.proxy.CommonProxy")
  13.         public static CommonProxy proxy;

  14.         @Instance("ExoticPower")
  15.         public static ExoticPower instance;
  16.         
  17.         @EventHandler
  18.         public void preInit(FMLPreInitializationEvent event) {
  19.                 proxy.preInit(event);
  20.         }

  21.         @EventHandler
  22.         public void init(FMLInitializationEvent event) {
  23.                 proxy.init(event);
  24.         }

  25.         @EventHandler
  26.         public void postInit(FMLPostInitializationEvent event) {
  27.             proxy.postInit(event);
  28.         }
  29.    
  30. }
复制代码

注意:@Instance里的内容必须与modid一致,否则制作Gui会崩溃

CommonProxy代码:
  1. package infstudio.exoticpower.proxy;

  2. import net.minecraftforge.fml.common.event.FMLInitializationEvent;
  3. import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
  4. import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

  5. public class CommonProxy {

  6.         public void preInit(FMLPreInitializationEvent event) {
  7.             
  8.         }
  9.          
  10.         public void init(FMLInitializationEvent event) {
  11.                 //注册方块、物品、Gui等
  12.         }
  13.          
  14.         public void postInit(FMLPostInitializationEvent event) {
  15.             
  16.         }
  17.         
  18. }
复制代码


ClientProxy代码:
  1. package infstudio.exoticpower.proxy;

  2. import net.minecraftforge.fml.common.event.FMLInitializationEvent;
  3. import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
  4. import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;

  5. public class ClientProxy extends CommonProxy {

  6.         public void preInit(FMLPreInitializationEvent event) {
  7.         
  8.         }

  9.         public void init(FMLInitializationEvent event) {
  10.                 super.init(event);
  11.                 为物品和方块添加材质
  12.         }

  13.         public void postInit(FMLPostInitializationEvent event) {
  14.         
  15.         }
  16.    
  17. }
复制代码

准备好这些基础后我们在创建block包并在包下创建BlockTestGui.java继承BlockContainer
  1. package infstudio.exoticpower.block;

  2. import net.minecraft.block.BlockContainer;

  3. public class BlockTestGui extends BlockContainer {

  4.         protected BlockTestGui() {
  5.                 super(Material.rock);
  6.         }
  7.         
  8. }
复制代码

创建gui.inventory包并在包下创建GuiTestGui.java继承GuiContainer
  1. package infstudio.exoticpower.gui.inventory;

  2. import infstudio.exoticpower.inventory.ContainerTestGui;
  3. import infstudio.exoticpower.tileentity.TileEntityTestGui;
  4. import net.minecraft.client.gui.inventory.GuiContainer;
  5. import net.minecraft.client.renderer.GlStateManager;
  6. import net.minecraft.client.resources.I18n;
  7. import net.minecraft.entity.player.InventoryPlayer;
  8. import net.minecraft.inventory.Container;
  9. import net.minecraft.tileentity.TileEntityFurnace;
  10. import net.minecraft.util.ResourceLocation;
  11. import net.minecraft.util.StatCollector;

  12. public class GuiTestGui extends GuiContainer {

  13.         private TileEntityTestGui tile;
  14.         
  15.         public GuiTestGui(InventoryPlayer playerInv, TileEntityTestGui tileEntity) {
  16.                 super(new ContainerTestGui(playerInv, tileEntity));
  17.                 // TODO Auto-generated constructor stub
  18.                 this.tile = tileEntity;
  19.                 this.doesGuiPauseGame();
  20.         }

  21.         @Override
  22.         protected void drawGuiContainerForegroundLayer(int par1, int par2) {
  23.                 String s = StatCollector.translateToLocal("TitleTestGui");    //设置Gui标题
  24.                 this.fontRendererObj.drawString(s, this.xSize / 2 - this.fontRendererObj.getStringWidth(s) / 2, 6, 4210752);
  25.                 this.fontRendererObj.drawString(I18n.format("container.inventory", new Object[0]), 8, this.ySize - 96 + 2, 4210752);
  26.         }
  27.         
  28.         @Override
  29.         protected void drawGuiContainerBackgroundLayer(float var1, int var2, int var3) {
  30.                 // TODO Auto-generated method stub
  31.                 GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
  32.                 this.mc.getTextureManager().bindTexture(new ResourceLocation("exoticpower", "textures/gui/container/testgui.png"));
  33.                 //gui贴图存储地址
  34.                 int k = (this.width - this.xSize) / 2;
  35.                 int l = (this.height - this.ySize) / 2;
  36.                 this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize);
  37.         }
  38.         
  39. }
复制代码

这里就提供给大家一张图(其实就是当风的图):

创建tileentity包并在包下创建TileEntityTestGui.java继承TileEntity实现IUpdatePlayerListBox和IInventory
  1. package infstudio.exoticpower.tileentity;

  2. import net.minecraft.entity.player.EntityPlayer;
  3. import net.minecraft.inventory.IInventory;
  4. import net.minecraft.item.ItemStack;
  5. import net.minecraft.server.gui.IUpdatePlayerListBox;
  6. import net.minecraft.tileentity.TileEntity;
  7. import net.minecraft.util.IChatComponent;

  8. public class TileEntityTestGui extends TileEntity implements IUpdatePlayerListBox, IInventory{

  9.         private ItemStack tstack[] = new ItemStack[3];    //数量与Gui中库存(槽)个数有关
  10.         
  11.         public void update() {
  12.                 //此方法必须加
  13.         }

  14.         @Override
  15.         public String getName() {
  16.                 // TODO Auto-generated method stub
  17.                 return null;
  18.         }

  19.         @Override
  20.         public boolean hasCustomName() {
  21.                 // TODO Auto-generated method stub
  22.                 return false;
  23.         }

  24.         @Override
  25.         public IChatComponent getDisplayName() {
  26.                 // TODO Auto-generated method stub
  27.                 return null;
  28.         }

  29.         @Override
  30.         public int getSizeInventory() {
  31.                 // TODO Auto-generated method stub
  32.                 return tstack.length;
  33.         }    //获得最大库存

  34.         @Override
  35.         public ItemStack getStackInSlot(int index) {
  36.                 // TODO Auto-generated method stub
  37.                 return tstack[index];
  38.         }    //获得库存中的物品栈

  39.         @Override
  40.         public ItemStack decrStackSize(int index, int count) {
  41.                 if (this.tstack[index] != null)
  42.                 {
  43.                             ItemStack itemstack;

  44.                             if (this.tstack[index].stackSize <= count)
  45.                             {
  46.                                 itemstack = this.tstack[index];
  47.                                 this.tstack[index] = null;
  48.                                 return itemstack;
  49.                             }
  50.                             else
  51.                             {
  52.                                 itemstack = this.tstack[index].splitStack(count);

  53.                                 if (this.tstack[index].stackSize == 0)
  54.                                 {
  55.                                             this.tstack[index] = null;
  56.                                 }

  57.                                 return itemstack;
  58.                             }
  59.                 }
  60.                 else
  61.                        {
  62.                             return null;
  63.                 }
  64.         }    //复制原版熔炉代码

  65.         @Override
  66.         public ItemStack getStackInSlotOnClosing(int index) {
  67.                 // TODO Auto-generated method stub
  68.                 return null;
  69.         }    //关闭Gui时触发的事件

  70.         @Override
  71.         public void setInventorySlotContents(int index, ItemStack stack) {
  72.                 // TODO Auto-generated method stub
  73.                 this.tstack[index] = stack;
  74.                 if (stack != null && stack.stackSize > this.getInventoryStackLimit())
  75.                 {
  76.                             stack.stackSize = this.getInventoryStackLimit();
  77.                 }
  78.         }    //复制原版熔炉代码

  79.         @Override
  80.         public int getInventoryStackLimit() {
  81.                 // TODO Auto-generated method stub
  82.                 return 64;
  83.         }    //单个物品栈最大容量

  84.         @Override
  85.         public boolean isUseableByPlayer(EntityPlayer player) {
  86.                 // TODO Auto-generated method stub
  87.                 return true;
  88.         }    //是否任何人都能使用Gui

  89.         @Override
  90.         public void openInventory(EntityPlayer player) {
  91.                 // TODO Auto-generated method stub
  92.                
  93.         }

  94.         @Override
  95.         public void closeInventory(EntityPlayer player) {
  96.                 // TODO Auto-generated method stub
  97.                
  98.         }

  99.         @Override
  100.         public boolean isItemValidForSlot(int index, ItemStack stack) {
  101.                 // TODO Auto-generated method stub
  102.                 return false;
  103.         }

  104.         @Override
  105.         public int getField(int id) {
  106.                 // TODO Auto-generated method stub
  107.                 return 0;
  108.         }

  109.         @Override
  110.         public void setField(int id, int value) {
  111.                 // TODO Auto-generated method stub
  112.                
  113.         }

  114.         @Override
  115.         public int getFieldCount() {
  116.                 // TODO Auto-generated method stub
  117.                 return 0;
  118.         }

  119.         @Override
  120.         public void clear() {
  121.                 // TODO Auto-generated method stub
  122.                
  123.         }
  124.         
  125. }
复制代码

创建inventory包并在包下创建ContainerTestGui.java
  1. package infstudio.exoticpower.inventory;

  2. import infstudio.exoticpower.tileentity.TileEntityTestGui;
  3. import net.minecraft.entity.player.EntityPlayer;
  4. import net.minecraft.entity.player.InventoryPlayer;
  5. import net.minecraft.inventory.Container;
  6. import net.minecraft.inventory.Slot;

  7. public class ContainerTestGui extends Container{

  8.         private TileEntityTestGui tile;
  9.         
  10.         public ContainerTestGui(InventoryPlayer par1InventoryPlayer, TileEntityTestGui tileEntity) {
  11.                 this.tile = tileEntity;
  12.                 this.addSlotToContainer(new Slot(tileEntity, 0, 49, 19));
  13.                 this.addSlotToContainer(new Slot(tileEntity, 1, 112, 19));
  14.                 this.addSlotToContainer(new Slot(tileEntity, 2, 80, 54));    //设置物品栏的槽
  15.                 int var3;
  16.                 for (var3 = 0; var3 < 3; ++var3)
  17.                 {
  18.                             for (int var4 = 0; var4 < 9; ++var4)
  19.                             {
  20.                                 this.addSlotToContainer(new Slot(par1InventoryPlayer, var4 + var3 * 9 + 9, 8 + var4 * 18, 84 + var3 * 18));
  21.                             }
  22.                 }

  23.                 for (var3 = 0; var3 < 9; ++var3)
  24.                 {
  25.                             this.addSlotToContainer(new Slot(par1InventoryPlayer, var3, 8 + var3 * 18, 142));
  26.                 }    //设置Gui的槽
  27.                 //第一个参数是IInventory,第二个参数是ID,对应第一个参数,即取得第一个参数对应ID的内容,第三个参数是显示的X坐标,第四个是参数是显示的Y坐标
  28.         }
  29.         
  30.         @Override
  31.         public boolean canInteractWith(EntityPlayer playerIn) {
  32.                 // TODO Auto-generated method stub
  33.                 return true;
  34.                 //能否打开Gui
  35.         }

  36. }
复制代码

在主类创建GuiID类,存取Gui的ID
  1. package infstudio.exoticpower;

  2. public class GuiID {

  3.         public static final int GUI_TG = 0;
  4.         
  5. }
复制代码

这时我们再在BlockTestGui增加createNewTileEntity和onBlockActivated方法
  1. @Override
  2.         public TileEntity createNewTileEntity(World worldIn, int meta) {
  3.                 return new TileEntityTestGui();
  4.         }
  5.         
  6.         @Override
  7.         public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumFacing side, float hitX, float hitY, float hitZ)
  8.         {
  9.                 ItemStack stack = playerIn.inventory.mainInventory[playerIn.inventory.currentItem];
  10.                 playerIn.openGui(ExoticPower.instance, GuiID.GUI_TG, worldIn, pos.getX(), pos.getY(), pos.getZ());
  11.         return true;
  12.         }
复制代码

再创建util包和GuiHandler类继承IGuiHandler类
  1. package infstudio.exoticpower.util;

  2. import infstudio.exoticpower.gui.inventory.GuiTestGui;
  3. import infstudio.exoticpower.inventory.ContainerTestGui;
  4. import infstudio.exoticpower.tileentity.TileEntityTestGui;
  5. import infstudio.exoticpower.GuiID;
  6. import net.minecraft.entity.player.EntityPlayer;
  7. import net.minecraft.util.BlockPos;
  8. import net.minecraft.world.World;
  9. import net.minecraftforge.fml.common.network.IGuiHandler;

  10. public class GuiHandler implements IGuiHandler{

  11.         @Override
  12.         public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
  13.                 // TODO Auto-generated method stub
  14.                 BlockPos bp = new BlockPos(x, y, z);
  15.                 switch(ID)
  16.                 {
  17.                 case GuiID.GUI_TG:
  18.                         return new ContainerTestGui(player.inventory, (TileEntityTestGui)world.getTileEntity(bp));
  19.                 }
  20.                 return null;
  21.         }

  22.         @Override
  23.         public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
  24.                 // TODO Auto-generated method stub
  25.                 BlockPos bp = new BlockPos(x, y, z);
  26.                 switch(ID)
  27.                 {
  28.                 case GuiID.GUI_TG:
  29.                         return new GuiTestGui(player.inventory, (TileEntityTestGui) world.getTileEntity(bp));
  30.                 }
  31.                 return null;
  32.         }

  33. }
复制代码

至此基础已经准备就绪,最后再在CommonProxy注册

  1.         public static Block testgui = new BlockTestGui();

  2.         public void init(FMLInitializationEvent event) {
  3.                     GameRegistry.registerBlock(testgui, "testgui");
  4.                 GameRegistry.registerTileEntity(TileEntityTestGui.class, "TileEntityTestGui");
  5.                 NetworkRegistry.INSTANCE.registerGuiHandler(ExoticPower.instance, new GuiHandler());
  6.         }
复制代码

所有准备已经就绪,现在打开游戏试试吧!




后序:
不过这个Gui现在什么用都没有,我们要通过更改TileEntity来创建他的功能,具体操作下一个Part会讲,有兴趣的可以先看看当风过时的教程,其实Gui就是不断魔改熔炉等带Gui的方块,只要理解了每个方法的含义就能轻而易举地创造出属于自己的Gui_(:з」∠)_
*如果有什么好的意见可以提出来哦qwq
*小唠叨:为何格式那么奇怪啊!调了好久啊!
*求人气求金粒_(:з」∠)_

来自群组: InfinityStudio

hhttll
真.前排围观大触

Fighter
學java學到一半就想放棄了......這麼多內容學不完啊{:10_524:}

qq1223332009
大力出奇迹{:10_501:}

咕噜and呼噜
然而我至今都做不了一个方块 下面的问题没人回答

侠客
群里来支持

御殇城c
我看看,感觉代码号难==

渡邉みなみ
这个gui看上去就是烧制嘛....

mcjava
然而ExoticPower快点开发出来!
支持,这是中国第一张的1.8gui教程,不错不错

黑暗空间
mcjava 发表于 2015-7-1 21:35
然而ExoticPower快点开发出来!
支持,这是中国第一张的1.8gui教程,不错不错 ...

Java代码死记中

Causeway

也是醉了

拘束
字好少...感觉代码要比字多得多...

tzdgreyd
求教,我每次一右击我的新方块就shutting down internal server了。。
我是按照Anvil来改的,就是没有对应的entity了。

就算是跳过这些,直接在onBlockActivated方法里
Minecraft.getMinecraft().displayGuiScreen(new GuiExchange(player.inventory, w, x, y, z));
这样的话也是闪退。(我的Gui是GuiExchange)

而相反的,如果直接
Minecraft.getMinecraft().displayGuiScreen(new GuiRepair(player.inventory, w, x, y, z));
的话至少能看到页面(虽然会鬼畜)。。

是我的Gui里面出错了吗?(可是我自我感觉还是没有改掉Anvil的关键东西的。。)

跪求解答。。

wsd81377
哎呦不错哦

liach
exoticpower,被这个mod惊呆了

mjmj1996
MC的GUI一直无力吐槽.....(要是能用Swing 该多好OTZ)

harry_01
支持一下,写了那么大篇幅。不过我已经被楼主的代码绕晕了。

a970695276
这样的方法能用在1.7.10么 =。= 找不到1.7.10的gui教程哎

a970695276
请问一下 在1.7.10中 blockpos 这个类是用什么代替的?