最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

又談工作臺類型的設(shè)計方法(1.12.2FML)

2019-07-26 18:10 作者:祿存天璣  | 我要投稿

再次強烈譴責(zé)專欄沒法貼代碼塊的功能

前往TIS論壇,感受更好的 Markdown?渲染體驗:https://forum.tis.world/topic/137/又談工作臺類型的設(shè)計方法-1-12-2FML

最近也有需求,需要設(shè)計一個類似原版工作臺的方塊“注魔臺”,支持在消耗一些素材的情況下合成一些物品。在參考了?異形龍蝦?的專欄 CV3031327 和他的一些代碼了以后,表示完全搞不懂。后來轉(zhuǎn)而在鐵砧的代碼里尋得了解決方案。

這篇文章雖然較長,實際信息量應(yīng)該對了解 Java 的人來說并不大;對深諳 Forge 的各種操作的 Modder 來說更是小菜一碟。部分代碼自己還未完全吃透,發(fā)在這里權(quán)當(dāng)拋磚引玉了。

因為工作臺合成這個東西太龐雜了,不知道怎么看起,決定對需求重新抽象:

  • 方塊本身不保存界面中的東西,退出界面后剩余物品自動返回背包

  • 輸入物品,輸出欄位顯示另一個物品,但只有把輸出的物品拿走的時候,才會消耗輸入的物品

  • 有一定的配方 根據(jù)這些抽象結(jié)果,鐵砧比工作臺看起來更加貼近要求。那么接下來對鐵砧的代碼進(jìn)行研究,抽取有用的部分用在自己的模組里。

鐵砧主要由三個類組成:

  • BlockAnvil 負(fù)責(zé)方塊本體各種屬性(如透明底,碰撞箱)的配置,

  • ContainerRepair是負(fù)責(zé)對界面中物品的儲存和邏輯判斷,

  • GuiRepair負(fù)責(zé)對客戶端的 GUI 進(jìn)行渲染。

首先從方塊類看起。BlockAnvil重寫了onBlockActivated方法,對玩家右鍵的操作進(jìn)行響應(yīng):

/** * Called when the block is right clicked by a player. */?

public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {

? ?if (!worldIn.isRemote) {

? ? ? ?playerIn.displayGui(new BlockAnvil.Anvil(worldIn, pos));

? ?}

? ?return true;?

}

這里使用了一個額外的類Anvil來顯示 GUI ,但是在實際的 mod 編寫中,應(yīng)該使用 forge 給我們提供的方法openGui()而不是displayGui(),另外,GUI 應(yīng)該被注冊好了,具體注冊方法別處都有,恕不贅述。

方塊部分就是這樣,很簡單,不涉及任何 TileEntity(方塊實體)。接下來看邏輯的重中之重ContainerRepair。在類的初始化方法中,可以看到初始化了兩個欄位:一個二格的輸入和一個一格的輸出,對應(yīng)鐵砧的輸入輸出:

this.outputSlot = new InventoryCraftResult();?

this.inputSlots = new InventoryBasic("Repair", true, 2) {

? ?public void markDirty() {

? ? ? ?super.markDirty();

? ? ? ?ContainerRepair.this.onCraftMatrixChanged(this);

? ?}

};

這里使用匿名類的方法,重寫了輸入欄位的markDirty(),讓它調(diào)用onCraftMatrixChanged()方法。markDirty()方法會在欄位發(fā)生任何變化的時候調(diào)用,提醒游戲保存一下。

那么接著看onCraftMatrixChanged()這個方法,它也被重寫了。如果輸入欄位被改變,就調(diào)用一個更新輸出欄位的方法:

public void onCraftMatrixChanged(IInventory inventoryIn) {

? ?super.onCraftMatrixChanged(inventoryIn);

? ?if (inventoryIn == this.inputSlots) {

? ? ? ?this.updateRepairOutput();

? ?}?

}

簡而言之,通過重寫方法,所有輸入欄位的變化都會更新輸出欄位

這樣一來具體的實現(xiàn)就變得很簡單了,另外寫一個類,用HashMap統(tǒng)一管理配方,要獲得輸出就直接從里面查詢。記得用ItemStack.areItemsEqual()而不是雙等于進(jìn)行比較。獲取到的產(chǎn)物要用copy()來防止引用問題,修改到不該修改的東西。

將欄位加入容器的過程,Minecraft原本的是:

this.addSlotToContainer(new Slot(this.inputSlots, 0, 27, 47));

this.addSlotToContainer(new Slot(this.inputSlots, 1, 76, 47));?

this.addSlotToContainer(new Slot(this.outputSlot, 2, 134, 47){/**一些重寫代碼**/});

但是實際情況下,設(shè)置成0,1,2會有下標(biāo)越界錯誤,不太清楚,但是都改成0就好了:

this.addSlotToContainer(new Slot(this.powderSlot, 0, 80, 53) {/**一些重寫代碼**/});?

this.addSlotToContainer(new Slot(this.inputSlot, 0, 48, 26));?

this.addSlotToContainer(new Slot(this.outputSlot, 0, 111, 26){/**一些重寫代碼**/});

接下來別忘了把玩家背包的欄位也添加進(jìn)去,這部分代碼直接抄就好:

for (int i = 0; i < 3; ++i) {

? ?for (int j = 0; j < 9; ++j) {

? ? ? ?this.addSlotToContainer(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));

? ?}

}?

for (int k = 0; k < 9; ++k) {

? ?this.addSlotToContainer(new Slot(playerInventory, k, 8 + k * 18, 142));?

}

然后在一個統(tǒng)一的方法進(jìn)行輸出欄位的更新,然后搞一個 GUI 的渲染。

接下來處理一些細(xì)節(jié),首先是輸出欄位不能放入東西,只能在創(chuàng)造模式或者等級夠的時候拿出輸出欄位的物品,拿出輸出欄位物品會減少輸入欄位的物品。這些邏輯在添加欄位的時候重寫已有的方法就好,還是拿鐵砧舉例:

this.addSlotToContainer(new Slot(this.outputSlot, 2, 134, 47) {

?? ?public boolean isItemValid(ItemStack stack) {

?? ? ? ?return false;

? ?}

? ?public boolean canTakeStack(EntityPlayer playerIn) {

? ? ? ?return (playerIn.capabilities.isCreativeMode || playerIn.experienceLevel >= ContainerRepair.this.maximumCost) && ContainerRepair.this.maximumCost > 0 && this.getHasStack();

? ?}

?? public ItemStack onTake(EntityPlayer thePlayer, ItemStack stack){

? ? ? ?if (!thePlayer.capabilities.isCreativeMode) {

? ? ? ? ? ?thePlayer.addExperienceLevel(-ContainerRepair.this.maximumCost);

? ? ? ?}

? ? ? ?//減少輸入物品可以用setInventorySlotContents()或者decrStackSize()做到

? ? ? ?//一堆復(fù)雜的東西,具體就是用玩家的rng計算鐵砧會不會壞,還有播放音效之類的。各位rng大法師可以試試操控

?? ? ? ?return stack;

?? ?}

});

如果要控制輸入欄位只能塞入特定的物品,也是重寫isItemValid方法。

在退出界面時自動把欄位的物品彈到玩家身上或地上:

public void onContainerClosed(EntityPlayer playerIn) {

? ?super.onContainerClosed(playerIn);

? ?if (!this.world.isRemote) {

? ? ? ?this.clearContainer(playerIn, this.world, this.inputSlots);

? ?}

}

玩家用SHIFT點擊的情況需要特殊處理,不過這里全部照抄鐵砧的transferStackInSlot()就好

成品展示

感謝?XeKr?做的材質(zhì)和模型,XKnb!。

我給注魔臺上面的蛋糕模型做了一個旋轉(zhuǎn)+起伏的效果,這里是需要 TileEntity 和 TileEntitySpecialRenderer?的


結(jié)

從這篇文章可以看出,大部分玩家想要做出的功能,都可以在原版中找到對應(yīng)。只要了解 Java,能閱讀代碼,就能做出不少東西。如果要做背包,那么可以參考末影箱(數(shù)據(jù)較多,要單獨存放)或者潛影盒(數(shù)據(jù)不多,可以存放在背包的NBT里)。如果要做 GUI 里面的按鈕,可以參考附魔臺或者信標(biāo)。要對周圍方塊實時監(jiān)測,信標(biāo)或者附魔臺也是不錯的例子……

又談工作臺類型的設(shè)計方法(1.12.2FML)的評論 (共 條)

分享到微博請遵守國家法律
揭阳市| 富民县| 丰城市| 虎林市| 石城县| 绥江县| 即墨市| 顺平县| 昌都县| 天台县| 合阳县| 苍南县| 湛江市| 犍为县| 会东县| 孟连| 北宁市| 凌海市| 江华| 中阳县| 宝清县| 根河市| 同江市| 淮安市| 郸城县| 龙泉市| 闸北区| 石楼县| 湘阴县| 顺昌县| 泗水县| 奉新县| 玉环县| 赤城县| 丽水市| 寿阳县| 山东省| 钦州市| 织金县| 特克斯县| 怀来县|