Densyakunのブログ

高校生プログラマの雑なブログです。ゲームを開発しています。

【Spigot】Bukkitプラグインの作り方講座 第3回 – エンティティ、瞬間移動、ダメージ、ベクトル操作

こんにちは、電車君です。

前回はコマンドの追加や、Bukkitプラグインの基本であるイベントシステムと、その活用例について解説しました。

 

前回のコメントにて今回の話題を募集したところ、

エンティティに関するものが多かったため、

今回はEventシステムを使って、エンティティを制御します。

 

今回やること

  • エンティティの種類について
  • エンティティが受けるダメージを制御する
  • エンティティを瞬間移動させる
  • エンティティにダメージを与える
  • エンティティをスポーンさせる
  • エンティティを乗り物に乗らせる
  • エンティティのベクトルを操作して、移動させる

などなど...

 

 

 

 

エンティティの種類について

 

エンティティには種類があり、用途やバージョンによって使い方が異なる場合があるため、注意が必要です。

エンティティは全て、Entityインターフェース(org.bukkit.entity.Entity)とそれを継承したインターフェースです。

 

また、Entityインターフェースを継承したLivingEntityインターフェースと言うものがあります。

これは、エンティティのうち、生き物が持っているインターフェースです。

つまり、LivingEntityにはダメージを与えることが出来ます

俗に言う「モブ」などはLivingEntityに当たります。

弓矢の矢や、爆発中のTNT、落下中のブロック(砂、砂利、金床等)はLivingEntityではありません。

 

また、LivingEntityインターフェースを継承したHumanEntityインターフェースと言うものがあります。

つまり、人の形をしているエンティティということですが、

実はHumanEntityインターフェースを継承しているのはPlayerインターフェースのみです。(MC1.12時点)

 

他にもコマンドを送信するプレイヤーが継承し、サーバーコンソール用でもあるCommandSenderや、

インベントリを持っているエンティティやブロック(チェスト等)が継承しているInventoryHolder、

弓矢の矢や卵、雪玉などの投げるものが継承しているProjectileなど色々なものがありますが、

これらについては今後別の回で解説していきます。

 

Entityについて詳しくはspigot公式によるjavadocがありますので、ご覧下さい:https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/Entity.html

 

 

 

エンティティのダメージを制御する

 

@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
	double damage = e.getDamage();
	e.setDamage(damage * 2);
}

いきなりコードです。

 

 

上のコードではEntityDamageEventを使用しています。

EntityDamageEventはエンティティがダメージを受けた時に発動するイベントです。

上のコードではエンティティが受けるダメージを二倍にしています。

 

ダメージを受けるエンティティを取得するには、e.getEntity()Entityインターフェースを返します。

ダメージが関係していますが、返すのはLivingEntityインターフェースではないので注意して下さい。

 

エンティティの種類を取得するには、

Entity entity = e.getEntity();
EntityType type = entity.getType();

又は、e.getEntityType()EntityType型を返します。

 

 

当然ですがこのイベントでダメージを受けるエンティティはプレイヤーも含まれます。

先程のコードではプレイヤーも二倍のダメージを受けてしまいます。

プレイヤーを除外するには以下のようなコードになります。

@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
	double damage = e.getDamage();
	EntityType type = e.getEntityType();
	if (type != EntityType.PLAYER) {
		e.setDamage(damage * 2);
	}
}

 

また前回同様、多くのイベントでイベントのキャンセルをすることが出来ます。

これを使用してプレイヤーが攻撃を受けないようにする事もできます。

if (type == EntityType.PLAYER) {
	e.setCancelled(true);
}

 

このイベントは攻撃する側がどんなものであっても発動します。

攻撃する側をエンティティに限定したい場合は、EntityDamageByEntityEventを使うと良いです。

逆にエンティティ以外に限定したい場合は、EntityDamageByBlockEventを使います。

 

EntityDamageEventで、攻撃するものが何なのか調べたい場合は、e.getCause()を使用します。

 

EntityDamageByEntityEventの場合は、e.getDamager()を使って攻撃したエンティティを取得できます。

 

EntityDamageByBlockEntityではサボテンに刺された時や、奈落に落ちた時などに発生します。

サボテンの場合など、e.getDamager()でブロックを取得できますが、

奈落などの場合は対象のブロックがない場合があるので注意が必要です。

 

 

 

エンティティにダメージを与える

 

Entity entity = e.getEntity();
if (entity instanceof LivingEntity) {
	double damage = 1.0;
((LivingEntity) entity).damage(damage); }

エンティティにダメージを与えるには、LivingEntityにキャストする必要があります。

LivingEntity.damage(double damage)でダメージを与えることが出来ます。

LivingEntity.damage(double damage, Entity damager)でダメージを与えるエンティティを指定することも出来ます。

 

 

 

エンティティを瞬間移動させる

 

エンティティを瞬間移動させるには、

entity.teleport(entity)
entity.teleport(location)

を使います。

引数にEntity型を入れる場合は、そのエンティティの場所に、

Location型(org.bukkit.Location)を入れる場合は、その場所に瞬間移動します。

 

エンティティの座標を取得するには、entity.getLocation()を使います。

 

@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
	Entity entity = e.getEntity();
	Location loc = entity.getLocation();
	loc.setY(loc.getY() + 3);
	entity.teleport(loc);
}

上の例では、getY()で取得したY座標に3を足して、loc.setY(y)でY座標を設定しています。

つまり、エンティティがダメージを受けると、3ブロック上に瞬間移動します。

f:id:Densyakun:20180212202115g:plain

瞬間移動なので、木に埋まったりしてしまいます。 

 

 

 

ベクトルを操作して、移動させる

 

最後に、ベクトルを操作して、移動させます。

ベクトルは、数学では「大きさと向きを持った量」とされています。

 

 

平面で例えると、

原点から点[vx,vy]まで矢印が伸びているとします。

この矢印をベクトルと言います。

この時、原点から点までのvx量とvy量がベクトルの持つ大きさです。

そしてこの量によって向きが決まるわけです。

 

ベクトルは3Dでも使われており、 x,y,z で構成されています。

xは横方向、yは縦方向、zは前後方向の量です。

ベクトルがよくわからない人はこちら: ベクトル解析 - [物理のかぎしっぽ]

 

@EventHandler
public void onEntityDamage(EntityDamageEvent e) {
	Entity entity = e.getEntity();Entity entity = e.getEntity();
entity.setVelocity(new Vector(0f, 2f, 0f)); }

上の例ではダメージを受けたエンティティがトンでいきます。

ベクトル量の調整がちょっと難しかったりします。(1だとなかなか飛びません。10だと果てしなくトンでいきます)

f:id:Densyakun:20180213011025p:plain

f:id:Densyakun:20180213011030p:plain

 

 

 


今回はここまでとなります。

他にも出来ることは山ほどあるので、色々試してみて下さい。

何か質問があればコメントでどうぞ。

次回については未定ということで、次回の話題をコメントで募集します。

 

お楽しみに!