第一天 准备开发环境
首先你需要一个MDK,这里使用forge-1.19.4-45.1.0,把它解压到一个文件夹
然后你需要一个IntelliJ(Community免费版即可),
打开build.gradle所在的文件夹,然后等待构建。
构建就不用多说了,遇到的问题也五花八门
至少我现在还不懂所有错误的解决方法,我自己构建是一帆风顺的,但帮别人构建总会出各种各样的错误
构建一般需要一个小时,也有可能十几分钟
listLibraries可能会运行好久...我这一步运行了半小时
展开这个
,然后找到src/main/java/com.example.example/ExampleMod打开看看
如果没有红字报错就说明构建好了
建议大家给IntelliJ装中文插件和Minecraft Development插件,装的方法网上都有教程,这里就不细说了
第二天 配置开发环境
首先创建一个主类
把com.example.examplemod给删了
然后创建一个自己的包,一般用域名倒写+模组id
软件包的名字一般是全小写+下划线
如果没有域名的话可以直接com.什么什么.模组id
以下目录仅作参考
然后给Main类加两个注解
@Mod("你的modid")
@Mod.EventBusSubscriber
鼠标悬停到Mod上点击导入类
import net.minecraftforge.fml.common.Mod;
然后是mods.toml文件
注意:只能用纯英文
mods.toml文件包含的是模组的一些相关信息
比如名称、作者、描述之类的
显示到模组列表中
启动游戏
写好之后,可以启动游戏试试了
第一次启动可能需要安装minecraft
会下载一些资源
从屏幕右上角也可以运行/调试
但是第一次是要从右边gradle里运行/调试的,然后会自动生成配置文件,之后就可以从右上角了
注意:Forge并不支持在游戏运行的时候修改代码,修改代码后必须重启游戏才能应用,但是有种很神奇的方式可以大大提高调试效率:断点调试
这样就启动好了
调一下语言,然后打开模组列表看看吧
可以关掉游戏了,我们来写个事件处理器吧
在Main类里创建一个
@SubscribeEvent
public static void onKey(InputEvent.Key event) { }
注意SubscribeEvent注解需要导入
import net.minecraftforge.eventbus.api.SubscribeEvent;
InputEvent类需要导入
import net.minecraftforge.client.event.InputEvent;
Minecraft mc = Minecraft.getInstance();
可以获取客户端实例
要知道按键事件是只有客户端会触发的
mc.player就是获取客户端玩家
如果玩家是null说明没有进入世界,为了防止NullPointerException(空指针错误)必须做个判断
玩家没有进入世界怎么按按键
在主页面按啊
Minecraft mc = Minecraft.getInstance();可以写在任何地方,只要是能调用到的地方就行
这样也行
event.getAction()获取你的操作:按下/弹起
event.getKey()获取按下的键
event.getAction()的返回值有三种:按下、弹起、重复(都是int类型的常量,所以如果不顾代码可读性的话可以直接换成数字)
-
InputConstants.PRESS
-
InputConstants.RELEASE
-
InputConstants.REPEAT
重复?
比如你按住a,然后会发现,你会一直输入a,第一次是按下,后面的都是重复了
重复的触发延时和触发间隔都是可以在系统设置里调的
if (event.getAction() == InputConstants.PRESS) {
这个样子就可以判断是不是按下
检查按键有两种方式
第一种方式是检测按下的是不是空格键
if (event.getKey() == GLFW.GLFW_KEY_SPACE)
GLFW.GLFW_KEY_SPACE也是int常量
第二种方法是检测按下的是不是跳跃键
mc.options获取客户端设置,类型是net.minecraft.client.Options
mc.options.keyJump.getKey().getValue()返回跳跃键的按键码
if (event.getKey() == mc.options.keyJump.getKey().getValue())
这种方式可以应对修改按键设置的情况
mc.options.keyJump是net.minecraft.client.KeyMapping类型(按键映射)
然后写让玩家跳起来
跳跃是客户端的操作
mc.player其实是一个net.minecraft.client.player.LocalPlayer对象
我们通过调用这个对象的方法来让玩家起跳
mc.player.jumpFromGround();
就是这么简单,无论是不是踩在地上都可以起跳
jumpFromGround是默认你在地上了
是不是还要加限定条件才能成为二段跳,而不是无限跳
确实,这样就是无限段跳(外挂模组),你进别人世界玩的时候可以装个无限跳,但进服务器就得小心了
这是我无限跳的代码,大家可以运行游戏尝试一下
接下来我们要写个跳跃计数器
这个计数器不能写成方法变量,要写成类变量
注意必须是静态的(static)
方法变量是什么
然后每跳一次就把它+1
然后要做的是在玩家落地的时候把计数器清零,我们再写一个处理器用来检测落地
LivingFallEvent在任何生物落地的时候都会触发
需要检测触发事件的是不是客户端玩家
@SubscribeEvent
public static void onFall(LivingFallEvent event) {
if (event.getEntity() instanceof LocalPlayer player) {
if (player == mc.player) {
jumpCount = 0;
}
}
}
event.getEntity()获取触发事件的实体
instanceof关键字判断对象是否属于某个类
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()来把它转换成LocalPlayer对象(如果不是LocalPlayer对象的话会抛异常)
而event.getEntity() instanceof LocalPlayer就能确保event.getEntity()获取到的一定是一个LocalPlayer对象或者是LocalPlayer的子类的对象
但是这种写法难免有些复杂,因此就产生了模式变量这种东西
现在二段跳的功能已经实现了,大家可以运行游戏尝试一下