細 |
(解説の追加) |
||
12行目: | 12行目: | ||
<source lang = "java"> | <source lang = "java"> | ||
package yourpackage; | package yourpackage; | ||
+ | //ClientProxyのみ必要だが、拡張性も考えCommonProxyも用意。GUI等追加するなら、IGuiHandlerを実装のこと。 | ||
public class CommonProxy { | public class CommonProxy { | ||
26行目: | 27行目: | ||
public class ClientProxy extends CommonProxy { | public class ClientProxy extends CommonProxy { | ||
//キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名 | //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名 | ||
− | public static KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName"); | + | public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName"); |
@Override | @Override | ||
public void registerClientInfo() { | public void registerClientInfo() { | ||
57行目: | 58行目: | ||
//キーが押されたかどうかを保存する変数 | //キーが押されたかどうかを保存する変数 | ||
public static boolean pressSampleKey = false; | public static boolean pressSampleKey = false; | ||
+ | //キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。 | ||
@SubscribeEvent | @SubscribeEvent | ||
public void KeyHandlingEvent(KeyInputEvent event) { | public void KeyHandlingEvent(KeyInputEvent event) { | ||
71行目: | 73行目: | ||
} | } | ||
if (pressSampleKey) { | if (pressSampleKey) { | ||
− | // | + | //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述 |
− | pressSampleKey = false; | + | pressSampleKey = false;//呼ばれ続けるため、ここでクリア |
} | } | ||
} | } | ||
125行目: | 127行目: | ||
</source> | </source> | ||
==解説== | ==解説== | ||
− | + | ===ClientProxy=== | |
+ | <source lang = "java"> | ||
+ | package yourpackage.client; | ||
+ | import yourpackage.CommonProxy; | ||
+ | import net.minecraft.client.settings.KeyBinding; | ||
+ | import cpw.mods.fml.client.registry.ClientRegistry; | ||
+ | public class ClientProxy extends CommonProxy { | ||
+ | //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名 | ||
+ | public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName"); | ||
+ | @Override | ||
+ | public void registerClientInfo() { | ||
+ | ClientRegistry.registerKeyBinding(sampleKey); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | KeyBindingは1.6からインスタンス生成時の引数に“カテゴリー名”が追加されている。<br> | ||
+ | キーのローカライズはlangファイル利用。<br> | ||
+ | KeyBindingクラスとClientRegistryクラスはクライアント側のみなので、Proxyで分ける必要がある。 | ||
+ | ===KeyInputEvent=== | ||
+ | <source lang = "java"> | ||
+ | //キーが押されたかどうかを保存する変数 | ||
+ | public static boolean pressSampleKey = false; | ||
+ | //キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。 | ||
+ | @SubscribeEvent | ||
+ | public void KeyHandlingEvent(KeyInputEvent event) { | ||
+ | while (ClientProxy.sampleKey.isPressed()) { | ||
+ | pressSampleKey = true;//クライアント側のみの変更。 | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | 1.7より追加されたイベント。いづれかのキーが押された時に、呼ばれる。<br> | ||
+ | どのキーが押されたかはeventに保存されていないので、用意しているKeyBinding変数のメソッドを利用する必要が有る。<br> | ||
+ | isPressedメソッドはキーが“押された回数”が0以上の時にtrueになるが、呼ばれた際に、押された回数を1減らす。 | ||
+ | チャタリング等の防止のため、while文で押された回数が0になるまで呼んでいる。 | ||
+ | このため、同じキーの登録被りが起こった場合確実にどちらかは動作しなくなる。 | ||
+ | 中途半端に動作するよりは良いので、この方法をとっている。<br> | ||
+ | このイベントはクライアント側のみであるので、サーバーにキー判定を伝えるにはパケットを送る必要が有る。 | ||
+ | ===KeyHandlingPacket=== | ||
+ | <source lang = "java"> | ||
+ | package yourpackage; | ||
+ | |||
+ | import io.netty.buffer.ByteBuf; | ||
+ | import io.netty.channel.ChannelHandlerContext; | ||
+ | import net.minecraft.entity.player.EntityPlayer; | ||
+ | |||
+ | //クライアント側でキー入力によって変化したboolean変数をサーバー側に伝達するパケット。AbstractPacketを継承 | ||
+ | public class KeyHandlingPacket extends AbstractPacket | ||
+ | { | ||
+ | //保持しておくboolean型変数 | ||
+ | boolean pressSampleKey; | ||
+ | |||
+ | //引数を持つコンストラクタを追加する場合は、空のコンストラクタを用意してくれとのこと。 | ||
+ | public KeyHandlingPacket() { | ||
+ | } | ||
+ | |||
+ | //パケット生成を簡略化するために、boolean型変数を引数に取るコンストラクタを追加。 | ||
+ | public KeyHandlingPacket(boolean ver1) { | ||
+ | pressSampleKey = ver1; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { | ||
+ | //ByteBufに変数を代入。基本的にsetメソッドではなく、writeメソッドを使う。 | ||
+ | buffer.writeBoolean(pressSampleKey); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { | ||
+ | //ByteBufから変数を取得。こちらもgetメソッドではなく、readメソッドを使う。 | ||
+ | pressSampleKey = buffer.readBoolean(); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void handleClientSide(EntityPlayer player) { | ||
+ | //今回はクライアントの情報をサーバーに送るので、こちらはなにもしない。 | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public void handleServerSide(EntityPlayer player) { | ||
+ | SampleKeyCore.pressSampleKey = pressSampleKey; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | キー判定を送るパケットクラス。 | ||
+ | 1つのクラスで両方向のパケットの記述が可能なため、慣れると重宝する。 | ||
+ | ここでは、pressSampleKeyの内容をサーバーに送っている。 | ||
+ | ===キー判定後の処理部分=== | ||
+ | <source lang = "java"> | ||
+ | @SubscribeEvent | ||
+ | public void LivingUpdate(LivingUpdateEvent event) { | ||
+ | if (event.entityLiving != null && event.entityLiving instanceof EntityPlayer) { | ||
+ | if (event.entityLiving.worldObj.isRemote) { | ||
+ | //ここで、クライアントでの変数の変更をサーバーに伝える。 | ||
+ | packetPipeline.sendToServer(new KeyHandlingPacket(pressSampleKey )); | ||
+ | } | ||
+ | if (pressSampleKey) { | ||
+ | //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述 | ||
+ | pressSampleKey = false;//呼ばれ続けるため、ここでクリア | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | キー判定で処理を行う方法はいくつかあるが、今回はLivingUpdateEventを利用する。<br> | ||
+ | まず、EntityPlayerから呼ばれているかを判定している。 | ||
+ | 次にisRemote変数がtrue、つまりクライアント側でパケットをサーバーに送信。 | ||
+ | 同期されるので、pressSampleKey判定はクライアントとサーバー両方で、同じ結果を得る。<br> | ||
+ | このif文内でpressSampleKeyをfalseに戻さないと、一度キーを押したら実行されっぱなしになる。<br> | ||
+ | 押しっぱなしかどうかを見たいのであれば、tick処理ループ内で、KeyBinding変数のgetIsKeyPressed()メソッドを監視し続ければよい。 |
2014年5月15日 (木) 22:05時点における版
この記事は"Minecraft Forge Universal 10.12.0.xxx~"を前提MODとしています。 |
目次
1.6におけるキーの処理
1.6までは、KeyHandlerクラスを継承して、KeyUpとKeyDownをtick単位で見ることが出来ました。 1.7では、tick処理自体がイベントになったので、キーの処理もイベントになりました。
1.7でのキーイベント追加
キーイベントの追加方法 (前提記事:1.7のパケットについて)
ソースコード
CommonProxy.java
package yourpackage; //ClientProxyのみ必要だが、拡張性も考えCommonProxyも用意。GUI等追加するなら、IGuiHandlerを実装のこと。 public class CommonProxy { public void registerClientInfo(){} }
ClientProxy.java
package yourpackage.client; import yourpackage.CommonProxy; import net.minecraft.client.settings.KeyBinding; import cpw.mods.fml.client.registry.ClientRegistry; public class ClientProxy extends CommonProxy { //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名 public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName"); @Override public void registerClientInfo() { ClientRegistry.registerKeyBinding(sampleKey); } }
SampleKeyCore.java(importは省略)
package yourpackage; @Mod(modid="KeySampleMod", name="KeySampleMod", version="1.0") public class SampleKeyCore { @SidedProxy(clientSide = "yourpackage.Client.ClientProxy", serverSide = "yourpackage.CommonProxy") public static CommonProxy proxy; //パケットハンドラー。解説は前提記事を参照のこと。 public static final PacketPipeline packetPipeline = new PacketPipeline(); @EventHandler public void load(FMLInitializationEvent event) { packetPipeline.initialise(); packetPipeline.registerPacket(KeyHandlingPacket.class);//パケットの登録 FMLCommonHandler.instance().bus().register(this);//KeyHandlingEvent用 MinecraftForge.EVENT_BUS.register(this);//LivingUpdate用 } @EventHandler public void postInit(FMLPostInitializationEvent event) { packetPipeline.postInitialise(); } //キーが押されたかどうかを保存する変数 public static boolean pressSampleKey = false; //キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。 @SubscribeEvent public void KeyHandlingEvent(KeyInputEvent event) { while (ClientProxy.sampleKey.isPressed()) { pressSampleKey = true;//クライアント側のみの変更。 } } @SubscribeEvent public void LivingUpdate(LivingUpdateEvent event) { if (event.entityLiving != null && event.entityLiving instanceof EntityPlayer) { if (event.entityLiving.worldObj.isRemote) { //ここで、クライアントでの変数の変更をサーバーに伝える。 packetPipeline.sendToServer(new KeyHandlingPacket(pressSampleKey )); } if (pressSampleKey) { //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述 pressSampleKey = false;//呼ばれ続けるため、ここでクリア } } } }
KeyHandlingPacket.java
package yourpackage; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; //クライアント側でキー入力によって変化したboolean変数をサーバー側に伝達するパケット。AbstractPacketを継承 public class KeyHandlingPacket extends AbstractPacket { //保持しておくboolean型変数 boolean pressSampleKey; //引数を持つコンストラクタを追加する場合は、空のコンストラクタを用意してくれとのこと。 public KeyHandlingPacket() { } //パケット生成を簡略化するために、boolean型変数を引数に取るコンストラクタを追加。 public KeyHandlingPacket(boolean ver1) { pressSampleKey = ver1; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { //ByteBufに変数を代入。基本的にsetメソッドではなく、writeメソッドを使う。 buffer.writeBoolean(pressSampleKey); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { //ByteBufから変数を取得。こちらもgetメソッドではなく、readメソッドを使う。 pressSampleKey = buffer.readBoolean(); } @Override public void handleClientSide(EntityPlayer player) { //今回はクライアントの情報をサーバーに送るので、こちらはなにもしない。 } @Override public void handleServerSide(EntityPlayer player) { SampleKeyCore.pressSampleKey = pressSampleKey; } }
解説
ClientProxy
package yourpackage.client; import yourpackage.CommonProxy; import net.minecraft.client.settings.KeyBinding; import cpw.mods.fml.client.registry.ClientRegistry; public class ClientProxy extends CommonProxy { //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名 public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName"); @Override public void registerClientInfo() { ClientRegistry.registerKeyBinding(sampleKey); } }
KeyBindingは1.6からインスタンス生成時の引数に“カテゴリー名”が追加されている。
キーのローカライズはlangファイル利用。
KeyBindingクラスとClientRegistryクラスはクライアント側のみなので、Proxyで分ける必要がある。
KeyInputEvent
//キーが押されたかどうかを保存する変数 public static boolean pressSampleKey = false; //キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。 @SubscribeEvent public void KeyHandlingEvent(KeyInputEvent event) { while (ClientProxy.sampleKey.isPressed()) { pressSampleKey = true;//クライアント側のみの変更。 } }
1.7より追加されたイベント。いづれかのキーが押された時に、呼ばれる。
どのキーが押されたかはeventに保存されていないので、用意しているKeyBinding変数のメソッドを利用する必要が有る。
isPressedメソッドはキーが“押された回数”が0以上の時にtrueになるが、呼ばれた際に、押された回数を1減らす。
チャタリング等の防止のため、while文で押された回数が0になるまで呼んでいる。
このため、同じキーの登録被りが起こった場合確実にどちらかは動作しなくなる。
中途半端に動作するよりは良いので、この方法をとっている。
このイベントはクライアント側のみであるので、サーバーにキー判定を伝えるにはパケットを送る必要が有る。
KeyHandlingPacket
package yourpackage; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import net.minecraft.entity.player.EntityPlayer; //クライアント側でキー入力によって変化したboolean変数をサーバー側に伝達するパケット。AbstractPacketを継承 public class KeyHandlingPacket extends AbstractPacket { //保持しておくboolean型変数 boolean pressSampleKey; //引数を持つコンストラクタを追加する場合は、空のコンストラクタを用意してくれとのこと。 public KeyHandlingPacket() { } //パケット生成を簡略化するために、boolean型変数を引数に取るコンストラクタを追加。 public KeyHandlingPacket(boolean ver1) { pressSampleKey = ver1; } @Override public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { //ByteBufに変数を代入。基本的にsetメソッドではなく、writeメソッドを使う。 buffer.writeBoolean(pressSampleKey); } @Override public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) { //ByteBufから変数を取得。こちらもgetメソッドではなく、readメソッドを使う。 pressSampleKey = buffer.readBoolean(); } @Override public void handleClientSide(EntityPlayer player) { //今回はクライアントの情報をサーバーに送るので、こちらはなにもしない。 } @Override public void handleServerSide(EntityPlayer player) { SampleKeyCore.pressSampleKey = pressSampleKey; } }
キー判定を送るパケットクラス。 1つのクラスで両方向のパケットの記述が可能なため、慣れると重宝する。 ここでは、pressSampleKeyの内容をサーバーに送っている。
キー判定後の処理部分
@SubscribeEvent public void LivingUpdate(LivingUpdateEvent event) { if (event.entityLiving != null && event.entityLiving instanceof EntityPlayer) { if (event.entityLiving.worldObj.isRemote) { //ここで、クライアントでの変数の変更をサーバーに伝える。 packetPipeline.sendToServer(new KeyHandlingPacket(pressSampleKey )); } if (pressSampleKey) { //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述 pressSampleKey = false;//呼ばれ続けるため、ここでクリア } } }
キー判定で処理を行う方法はいくつかあるが、今回はLivingUpdateEventを利用する。
まず、EntityPlayerから呼ばれているかを判定している。
次にisRemote変数がtrue、つまりクライアント側でパケットをサーバーに送信。
同期されるので、pressSampleKey判定はクライアントとサーバー両方で、同じ結果を得る。
このif文内でpressSampleKeyをfalseに戻さないと、一度キーを押したら実行されっぱなしになる。
押しっぱなしかどうかを見たいのであれば、tick処理ループ内で、KeyBinding変数のgetIsKeyPressed()メソッドを監視し続ければよい。