Minecraft Forge 模組開發(fā)實戰(zhàn) — 游戲規(guī)則可控的二段跳(一)二段跳部分

第一天 準備開發(fā)環(huán)境
首先你需要一個MDK,這里使用forge-1.19.4-45.1.0,把它解壓到一個文件夾
然后你需要一個IntelliJ(Community免費版即可),

打開build.gradle所在的文件夾,然后等待構(gòu)建。
構(gòu)建就不用多說了,遇到的問題也五花八門
至少我現(xiàn)在還不懂所有錯誤的解決方法,我自己構(gòu)建是一帆風(fēng)順的,但幫別人構(gòu)建總會出各種各樣的錯誤
構(gòu)建一般需要一個小時,也有可能十幾分鐘
listLibraries可能會運行好久...我這一步運行了半小時
展開這個

,然后找到src/main/java/com.example.example/ExampleMod打開看看
如果沒有紅字報錯就說明構(gòu)建好了
建議大家給IntelliJ裝中文插件和Minecraft Development插件,裝的方法網(wǎng)上都有教程,這里就不細說了


第二天 配置開發(fā)環(huán)境
首先創(chuàng)建一個主類,把com.example.examplemod給刪了
然后創(chuàng)建一個自己的包,一般用域名倒寫+模組id
軟件包的名字一般是全小寫+下劃線


如果沒有域名的話可以直接com.什么什么.模組id
以下目錄僅作參考

然后給Main類加兩個注解
@Mod("你的modid")
@Mod.EventBusSubscriber

鼠標懸停到Mod上點擊導(dǎo)入類
import net.minecraftforge.fml.common.Mod;

然后是mods.toml文件



注意:只能用純英文
mods.toml文件包含的是模組的一些相關(guān)信息
比如名稱、作者、描述之類的
顯示到模組列表中

寫好之后,可以啟動游戲試試了
第一次啟動可能需要安裝minecraft
會下載一些資源
從屏幕右上角也可以運行/調(diào)試

但是第一次是要從右邊gradle里運行/調(diào)試的,然后會自動生成配置文件,之后就可以從右上角了
注意:Forge并不支持在游戲運行的時候修改代碼,修改代碼后必須重啟游戲才能應(yīng)用,但是有種很神奇的方式可以大大提高調(diào)試效率:斷點調(diào)試

這樣就啟動好了
調(diào)一下語言,然后打開模組列表看看吧

可以關(guān)掉游戲了,我們來寫個事件處理器吧
在Main類里創(chuàng)建一個
@SubscribeEvent
public static void onKey(InputEvent.Key event) { }
注意SubscribeEvent注解需要導(dǎo)入?import net.minecraftforge.eventbus.api.SubscribeEvent;
InputEvent類需要導(dǎo)入?import net.minecraftforge.client.event.InputEvent;
Minecraft mc = Minecraft.getInstance();可以獲取客戶端實例
要知道按鍵事件是只有客戶端會觸發(fā)的
mc.player就是獲取客戶端玩家
如果玩家是null說明沒有進入世界,為了防止NullPointerException(空指針錯誤)必須做個判斷

玩家沒有進入世界怎么按按鍵
在主頁面按啊
Minecraft mc = Minecraft.getInstance();可以寫在任何地方,只要是能調(diào)用到的地方就行

這樣也行
event.getAction()獲取你的操作:按下/彈起
event.getKey()獲取按下的鍵
event.getAction()的返回值有三種:按下、彈起、重復(fù)(都是int類型的常量,所以如果不顧代碼可讀性的話可以直接換成數(shù)字)
InputConstants.PRESS
InputConstants.RELEASE
InputConstants.REPEAT
重復(fù)?
比如你按住a,然后會發(fā)現(xiàn),你會一直輸入a,第一次是按下,后面的都是重復(fù)了
重復(fù)的觸發(fā)延時和觸發(fā)間隔都是可以在系統(tǒng)設(shè)置里調(diào)的
if (event.getAction() == InputConstants.PRESS) {
這個樣子就可以判斷是不是按下
檢查按鍵有兩種方式
第一種方式是檢測按下的是不是空格鍵
if (event.getKey() == GLFW.GLFW_KEY_SPACE)
GLFW.GLFW_KEY_SPACE也是int常量
第二種方法是檢測按下的是不是跳躍鍵
mc.options獲取客戶端設(shè)置,類型是net.minecraft.client.Options
mc.options.keyJump.getKey().getValue()返回跳躍鍵的按鍵碼
if (event.getKey() == mc.options.keyJump.getKey().getValue())
這種方式可以應(yīng)對修改按鍵設(shè)置的情況
mc.options.keyJump是net.minecraft.client.KeyMapping類型(按鍵映射)


然后寫讓玩家跳起來
跳躍是客戶端的操作
mc.player其實是一個net.minecraft.client.player.LocalPlayer對象
我們通過調(diào)用這個對象的方法來讓玩家起跳
mc.player.jumpFromGround();
就是這么簡單,無論是不是踩在地上都可以起跳
jumpFromGround是默認你在地上了
是不是還要加限定條件才能成為二段跳,而不是無限跳
確實,這樣就是無限段跳(外掛模組),你進別人世界玩的時候可以裝個無限跳,但進服務(wù)器就得小心了

這是我無限跳的代碼,大家可以運行游戲嘗試一下
接下來我們要寫個跳躍計數(shù)器
這個計數(shù)器不能寫成方法變量,要寫成類變量

注意必須是靜態(tài)的(static)
方法變量是什么

然后每跳一次就把它+1

然后要做的是在玩家落地的時候把計數(shù)器清零,我們再寫一個處理器用來檢測落地
LivingFallEvent在任何生物落地的時候都會觸發(fā)
需要檢測觸發(fā)事件的是不是客戶端玩家
@SubscribeEvent
? ? public static void onFall(LivingFallEvent event) {
? ? ? ? if (event.getEntity() instanceof LocalPlayer player) {
? ? ? ? ? ? if (player == mc.player) {
? ? ? ? ? ? ? ? jumpCount = 0;
? ? ? ? ? ? }
? ? ? ? }
? ? }

event.getEntity()獲取觸發(fā)事件的實體
instanceof關(guān)鍵字判斷對象是否屬于某個類
if (event.getEntity() instanceof LocalPlayer player) {
是
if (event.getEntity() instanceof LocalPlayer) {
? ? LocalPlayer player = (LocalPlayer) event.getEntity();
的簡寫
event.getEntity();
得到的是一個Entity(實體)對象
玩家也是實體
LocalPlayer(本地玩家)類是從Entity類繼承下來的
因此LocalPlayer類是Entity類的子類
和C++一樣,在確保event.getEntity()獲取到的一定是一個LocalPlayer對象或者是LocalPlayer的子類的對象的時候,可以通過(LocalPlayer) event.getEntity()來把它轉(zhuǎn)換成LocalPlayer對象(如果不是LocalPlayer對象的話會拋異常)
而event.getEntity() instanceof LocalPlayer就能確保event.getEntity()獲取到的一定是一個LocalPlayer對象或者是LocalPlayer的子類的對象

但是這種寫法難免有些復(fù)雜,因此就產(chǎn)生了模式變量這種東西


現(xiàn)在二段跳的功能已經(jīng)實現(xiàn)了,大家可以運行游戲嘗試一下