石橋を叩いて壊すページ

一定時間おきに花火を打ち上げたりする

引き続きボスモンスタープラグインを作りながら思ったことを色々書く…
つもりだったけど、ちょっと趣向を変えてみた。

花火を打ち上げるには

手に花火を持ってクリックしたとき、花火が打ち上げられるプログラムは以下のように書く。

/**
 * プレイヤーが右クリックしたとき呼び出される
 * 
 * @param e
 */
@EventHandler
public void onPlayerInteractEvent(PlayerInteractEvent e) {

	if (e.getPlayer().getItemInHand().getType().equals(Material.FIREWORK)) {

		Firework firework = e.getPlayer().getWorld()
				.spawn(e.getPlayer().getLocation(), Firework.class);

		FireworkMeta meta = firework.getFireworkMeta();

		Builder effect = FireworkEffect.builder();

		effect.with(FireworkEffect.Type.BALL_LARGE);
		effect.withColor(Color.YELLOW);
		effect.withFade(Color.RED);
		effect.flicker(true);
		effect.trail(true);

		meta.addEffect(effect.build());

		meta.setPower(1);

		firework.setFireworkMeta(meta);
	}

}

マインクラフトでは、キャラクター・モンスター・トロッコ・花火といったゲーム世界上で動くものをエンティティと呼んでいる。
getWorld().spawn(…)のところで、花火エンティティをプレイヤーの位置に生成している。
一度生成すれば、あとは自動的に打ちあがるので、花火が移動する処理とかは不要である。

生成した花火エンティティは、初期状態では発射されても爆発しない。
ゲーム内で、花火玉を詰めずに紙と火薬だけで作った花火と同じような物体が発射される。
花火を花火らしく爆発させるには、爆発の色や効果と言ったものを発射後に設定してやる必要がある。

花火の設定情報はFireworkMetaクラスのオブジェクトで管理されるので、まずはFireworkMetaオブジェクトを用意しないといけない。
FireworkEffect.builder()メソッドで、FireworkEffect.Builderクラスのオブジェクトを作成しよう。

次に、このオブジェクトに色々な設定を入れていく。
ちなみに花火の設定についてはMinecraft Wikiの花火のページも合わせて参照されたい。
定数の種類や効果などは詳しく紹介しないので、かわりにBukkitのAPIでFireworkEffectなどのクラスの説明を読んでほしい。

effect.with(FireworkEffect.Type.BALL_LARGE);で、大きな花火が撃ちあがる。他にCREEPERやBURSTといったタイプもある。
デフォルトでは小さい花火が撃ちあがる。

effect.withColor(Color.YELLOW);で、花火の色を黄色に決めている。
今回は単色だが、複数色を使いたい場合はカンマで複数の色をつなげてもよい。
たとえばeffect.withColor(Color.YELLOW,Color.RED);のようにすれば、黄色と赤の花火になる。
デフォルトでは爆発しない。

effect.withFade(Color.RED);は、打ち上げ後の余韻の色を赤にしている。
こちらも複数色を使用することができる。デフォルトでは余韻なし。

effect.flicker(true)は、爆発後に光が明滅し、パチパチという音を立てる。ゲーム内で花火製作時にダイヤモンドを入れたのと同じ効果がある。
effect.trail(true);は、爆発の光が尾を引くようになる。こちらはグロウストーンダストを入れたのと同じ効果がある。

meta.setPower(1);は、花火が撃ちあがる高さの段階を指定する。
数値が大きいほど花火は高く飛び上がって爆発する。
デフォルトではゼロが指定されている。

ただしここで注意がある。花火が撃ちあがる高さは、0から4の範囲で指定すること。
環境によるのかもしれないが、高さ5以上を設定した花火を打ち上げると、打ち上げた数に比例して
マインクラフトのクライアントに負荷がかかりはじめ、最終的にフリーズしてしまう。理由はわからないがバグっぽい気がする。
万一フリーズした場合は、クライアントを強制終了するかBukkitサーバーを再起動するとよい。


発射高さの比較のため、同じ発射点(Y=4)から、高さを変えて複数の花火を発射した例。
高さゼロ(黄色の花火)でおよそY=8まで、1(オレンジの花火)でY=14まで、
以後同様に2(赤)で28、3(紫)で45、4(青)で64、5(水色)で85まで飛び上がって爆発した。
ただし高さ5の花火はほとんどが水平に画面外まで飛んだため、視界内で爆発したのは10発に1発くらい。
ちなみに撮影後にゲームがフリーズした。高さ4までの花火なら5分連続で打ち上げてもフリーズしなかった。

meta.addEffect(effect.build())で上記で設定した効果を花火設定情報に入れ、
最後にfirework.setFireworkMeta(meta)で花火設定情報を実際の花火に適用している。


全く意味はないが、打ち上げた花火にfirework.setVelocity(new Vector(0.08F,0,0));のように
横向きの初速を与えてやると、上を向いたまま斜めに飛ぶ不思議な花火が作れる。

一定時間おきに処理をさせるには

花火を1秒間に1発ずつ、定期的に発射させるにはどうすればいいか?
BukkitにはBukkitRunnableという、一定時間後に処理を行ってくれるクラスがあるからこれを使う。

簡単にいうと、やるべきことは2つある。
BukkitRunnableクラスを拡張したクラスを作り、そこに花火を1発打つプログラムを書く。
そしてその拡張クラスを、1秒間に1回ずつ実行するようBukkitに依頼するという流れだ。

花火を1発打つプログラムは、以下のように書く。

class TestRunnable extends BukkitRunnable {

	/**
	 * 発射位置
	 */
	private Location loc;

	/**
	 * コンストラクタ
	 * 
	 * @param player
	 *            矢の発射の中心地点となるプレイヤー
	 */
	public TestRunnable(Location _loc) {

		loc=_loc;
		
	}

	/**
	 * タスク処理内容
	 */
	public void run() {

		Firework firework = loc.getWorld().spawn(loc, Firework.class);
		FireworkMeta meta=firework.getFireworkMeta();
		Builder effect=FireworkEffect.builder();
		effect.withColor(Color.YELLOW);
		meta.addEffect(effect.build());
		meta.setPower(1);
		firework.setFireworkMeta(meta);
	}
}

見てのとおり、BukkitRunnableクラスを拡張したクラスを作成している。
そして実際の処理は、run()メソッドの中に書いてある。
run()の中は花火を打ち上げる処理だが、既に紹介したので詳細は割愛する。

そして、花火を手に持ってクリックすると、上記クラスを1秒間に1回ずつ実行してくれるプログラムは以下のように書く。

/**
 * プレイヤーが右クリックしたとき呼び出される
 * 
 * @param e
 */
@EventHandler
public void onPlayerInteractEvent(PlayerInteractEvent e) {

	new TestRunnable(e.getPlayer().getLocation()).runTaskTimer(this, 100, 20);

}

new TestRunnable(…)のところで、BukkitRunnableの拡張クラスのオブジェクトを新規作成している。
そしてrunTaskTimer(this, 100, 20)のところで、処理を1秒間に1回実行するよう依頼している。

1番目の引数のthisはおまじないのようなものなので、あまり考えず指定していい。
2番目の引数は、最初の待機時間を0.05秒単位で指定する。
例では100を指定してあるので、100×0.05、つまり最初に5秒待った後、run()メソッドが呼ばれる。
3つ目の引数は、ループ処理中の待機時間を0.05秒単位で指定する。
例では20を指定してあるので、同様に20×0.05で、1秒に1回、run()メソッドが呼ばれる。

まとめると、runTaskTimer(this, 100, 20)で花火の打ち上げを申し込むと
まず5秒待機し、花火が打ちあがり、1秒待って、花火が打ちあがり、1秒待って…という処理になる。

ちなみに一度申し込むと、基本的には永久に止まらない。
止めたい場合は、run()メソッドの中からBukkitRunnableクラスのCancel()メソッドを呼ぶか、
runTaskTimer(…)メソッドの戻り値のBukkitTaskオブジェクトのCancel()メソッドを使う。

この説明を書く間に副産物として花火大会プラグインが完成したので、次の記事で公開した
右クリックで打ち上げ開始、左クリックでCancel()を呼ぶ処理に変更した上でソースファイルもそちらに置いてある。

いうまでもないが、あまりたくさん花火を打ち上げすると処理に負荷がかかるので、ほどほどにすること。

いつもどおり、ここまでの記事をBukkitWikiの 花火の打ち上げ一定時間おきに処理をする に書いておいた。


最初はボスモンスタープラグインの話の流れで
「一定時間おきに矢を発射するプログラム」について書くつもりだったが、
BukkitWikiに書くには話が地味すぎるので趣向を変えて派手な花火にした。
マシンガンショットは0.05秒おきに矢を発射している。
スプリンクラーショットも0.05秒おきに角度を変えて矢を発射しているだけ。
ということで、ボスモンスタープラグインも花火も
一定時間おきに処理すると言う本質は同じ。

この記事を評価

この記事にコメント

  1. ...

【この記事にコメント】
お名前:
コメント:

Menu