前一篇教程已经把GUI基础的部分构建完成了,这一篇教程将会告诉你如何为方块添加自己的行为。
TileEntity是方块运行的后台,方块的进阶功能都在这里实现,包括GUI,要能使TileEntity与GUI互动需要引入IInventory接口。引入之后会多出很多的接口方法,我们先不管。我们做的修复台需要放置物品,而承载物品的数据就在TileEntity中,新建一个长度为3的ItemStack的数组,表示要存储3个物品,或者说有3个物品栏。
private ItemStack stack[] = new ItemStack[3];
然后要让GUI读取到TileEntity中的物品就通过IInventory的接口来实现,重写decrStackSize(从物品栏取出物品)、getStackInSlot(取得对应索引的ItemStack)、getSizeInventory(取得ItemStack数组长度)、getInventoryStackLimit(单个物品最大数量限制)、setInventorySlotContents(根据索引存放ItemStack)这几个接口函数。decrStackSize因为机制比较复杂,直接复制熔炉的就好,这里提供的方式是很久很久以前一直用到现在都没有失效的方法。
@Override
public ItemStack decrStackSize(int par1, int par2) {
// TODO Auto-generated method stub
if (this.stack[par1] != null) {
ItemStack var3;
if (this.stack[par1].stackSize <= par2) {
var3 = this.stack[par1];
this.stack[par1] = null;
return var3;
} else {
var3 = this.stack[par1].splitStack(par2);
if (this.stack[par1].stackSize == 0) {
this.stack[par1] = null;
}
return var3;
}
} else {
return null;
}
}
@Override
public ItemStack getStackInSlot(int var1) {
// TODO Auto-generated method stub
return stack[var1];
}
@Override
public int getSizeInventory() {
// TODO Auto-generated method stub
return stack.length;
}
@Override
public int getInventoryStackLimit() {
// TODO Auto-generated method stub
return 64;
}
@Override
public void setInventorySlotContents(int var1, ItemStack var2) {
// TODO Auto-generated method stub
stack[var1] = var2;
}
然后是修改Container,这里需要用到一个叫槽位(Slot)的东西,Slot是提供给物品放置在GUI上的一个容器,同时也能实现一些基本的存取功能,工作台的合成就是基于此,使得工作台可以在不运算TileEntity的基础上实现合成物品的逻辑。不过还没深入了解,只是稍微提一下这个东西。这里修改的地方是描绘槽位,先描绘TileEntity的那3个槽,然后是玩家的背包和快捷栏,玩家的背包同样也是引入IInventory来实现GUI存取的功能。addSlotToContainer的参数为:第一个参数是IInventory,第二个参数是IInventory的索引,即取得第一个参数对应索引的内容,第三个参数是显示的X坐标,第四个是参数是显示的Y坐标。
tile = par2TileEntityRepairTable;
this.addSlotToContainer(new Slot(par2TileEntityRepairTable, 0, 49, 19));
this.addSlotToContainer(new Slot(par2TileEntityRepairTable, 1, 112, 19));
this.addSlotToContainer(new Slot(par2TileEntityRepairTable, 2, 80, 54));
int var3;
for (var3 = 0; var3 < 3; ++var3)
{
for (int var4 = 0; var4 < 9; ++var4)
{
this.addSlotToContainer(new Slot(par1InventoryPlayer, var4 + var3 * 9 + 9, 8 + var4 * 18, 84 + var3 * 18));
}
}
for (var3 = 0; var3 < 9; ++var3)
{
this.addSlotToContainer(new Slot(par1InventoryPlayer, var3, 8 + var3 * 18, 142));
}
接下来是修改TileEntity的运行方式,为TileEntity增加两个参数,这两个参数是储存燃料值的。
public int tableBurnTime = 0;
public int maxBurnTime = 0;
然后重写NBT存取方法,NBT是存储数据的标签,会在一定的时候读取和存储数据。在这里是将ItemStack的数组和燃料值储存到NBT中,防止在退出游戏时数据丢失。
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readFromNBT(par1NBTTagCompound);
NBTTagList var2 = par1NBTTagCompound.getTagList("Items", 10);
this.stack = new ItemStack[this.getSizeInventory()];
for (int var3 = 0; var3 < var2.tagCount(); ++var3)
{
NBTTagCompound var4 = (NBTTagCompound)var2.getCompoundTagAt(var3);
byte var5 = var4.getByte("Slot");
if (var5 >= 0 && var5 < this.stack.length)
{
this.stack[var5] = ItemStack.loadItemStackFromNBT(var4);
}
}
this.tableBurnTime = par1NBTTagCompound.getShort("tableBurnTime");
this.maxBurnTime = par1NBTTagCompound.getShort("maxBurnTime");
}
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeToNBT(par1NBTTagCompound);
par1NBTTagCompound.setShort("tableBurnTime", (short)this.tableBurnTime);
par1NBTTagCompound.setShort("maxBurnTime", (short)this.maxBurnTime);
NBTTagList var2 = new NBTTagList();
for (int var3 = 0; var3 < this.stack.length; ++var3)
{
if (this.stack[var3] != null)
{
NBTTagCompound var4 = new NBTTagCompound();
var4.setByte("Slot", (byte)var3);
this.stack[var3].writeToNBT(var4);
var2.appendTag(var4);
}
}
par1NBTTagCompound.setTag("Items", var2);
}
然后是添加读取燃料值的相关方法,复制熔炉的即可
public static int getItemBurnTime(ItemStack p_145952_0_)
{
if (p_145952_0_ == null)
{
return 0;
}
else
{
Item item = p_145952_0_.getItem();
if (item instanceof ItemBlock && Block.getBlockFromItem(item) != Blocks.air)
{
Block block = Block.getBlockFromItem(item);
if (block == Blocks.wooden_slab)
{
return 150;
}
if (block.getMaterial() == Material.wood)
{
return 300;
}
if (block == Blocks.coal_block)
{
return 16000;
}
}
if (item instanceof ItemTool && ((ItemTool)item).getToolMaterialName().equals("WOOD")) return 200;
if (item instanceof ItemSword && ((ItemSword)item).getToolMaterialName().equals("WOOD")) return 200;
if (item instanceof ItemHoe && ((ItemHoe)item).getToolMaterialName().equals("WOOD")) return 200;
if (item == Items.stick) return 100;
if (item == Items.coal) return 1600;
if (item == Items.lava_bucket) return 20000;
if (item == Item.getItemFromBlock(Blocks.sapling)) return 100;
if (item == Items.blaze_rod) return 2400;
return GameRegistry.getFuelValue(p_145952_0_);
}
}
最后就是这个方块的主要功能——修复,重写updateEntity,平时主要就是修改这里就行了。
@Override
public void updateEntity() {
super.updateEntity();
//System.out.println("Hello GUI");
if(!this.worldObj.isRemote)
// 判断燃烧时间
if (tableBurnTime > 0) {
// 取得修复的物品
ItemStack repairItem = getStackInSlot(0);
// 取得修复好的物品
ItemStack outputItem = getStackInSlot(1);
// 确定开始修复的条件之一:修复物品槽不为空,已修复物品槽为空
if (repairItem != null && outputItem == null) {
// 判断被修复的物品是否为工具或武器
if (repairItem.getItem() == Items.iron_sword || repairItem.getItem() == Items.stone_sword ||
repairItem.getItem() == Items.golden_sword || repairItem.getItem() == Items.diamond_sword ||
repairItem.getItem() instanceof ItemArmor) {
//System.out.println("can repair");
// 判断物品是否要修理
if (repairItem.getItemDamage() > 0) {
// 修复物品
repairItem.setItemDamage(repairItem.getItemDamage() - 1);
} else {
setInventorySlotContents(1, repairItem);
setInventorySlotContents(0, null);
}
}
}
// 减少燃烧时间
tableBurnTime -= 1;
} else // 没有燃料的情况下
{
// 如果有被修复的物品
if (getStackInSlot(0) != null) {
// 取得燃料槽的物品
ItemStack burnItem = getStackInSlot(2);
// 取得物品的燃烧值
int getBurnTime = getItemBurnTime(burnItem);
// 判断物品是否能燃烧
if (getBurnTime > 0) {
maxBurnTime = getBurnTime;
tableBurnTime = getBurnTime;
// 如果燃烧物品为岩浆桶
if (burnItem.getItem() == Items.lava_bucket) {
// 取得空桶
setInventorySlotContents(2, new ItemStack(Items.bucket,
1));
} else {
// 其他物品就减少
if (burnItem.stackSize - 1 > 0) {
burnItem.stackSize--;
setInventorySlotContents(2, burnItem);
} else {
setInventorySlotContents(2, null);
}
}
}
}
}
}
然后你就可以看到一把受损的武器在这个路子填充燃料之后就开始修复了,修复完成后悔移动到右边的槽。
第二章就是这些内容。附上本章节源码:http://pan.baidu.com/s/1gd93dWR
求解:为什么一按Shift取下物品时就闪退??
因为还没有添加Shift处理,第三篇教程会有Shift处理的说明