@KAISEI_sky (快 青)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【Minecraft Bedrock版】ダメージエリアの攻撃対象を除外する方法

統合版Minecraftのダメージエリアで攻撃対象を設定によって除外したい

Minecraft Bedrock Editionで、@minecraft/serverを使用して範囲攻撃を実装しています。

現在は、攻撃したエンティティの周囲6ブロック以内にいるエンティティへダメージを与える処理を作っています。

しかし、攻撃対象の除外条件を柔軟に設定できるようにしたいです。

実現したいこと

以下のような設定を切り替えられるようにしたいです。

① 自分だけ除外

  • 自分 → ダメージなし
  • 他のプレイヤー → ダメージあり
  • モブ → ダメージあり

② 自分とプレイヤーを除外

  • 自分 → ダメージなし
  • 他のプレイヤー → ダメージなし
  • モブ → ダメージあり

③ 特定のエンティティだけ除外

例えばゾンビとスケルトンを除外する場合、

  • 自分 → ダメージなし
  • ゾンビ → ダメージなし
  • スケルトン → ダメージなし
  • クリーパー → ダメージあり
  • プレイヤー → ダメージあり

としたいです。

④ 特定のプレイヤーだけ除外

例えば、

PlayerA
PlayerB

だけを除外して、それ以外のプレイヤーにはダメージを与えたいです。


現在使用しているコード

import { world, system, EntityDamageCause } from "@minecraft/server";

const isAttackBlocked = (attacker, target) => {
    if (!attacker || !target) return false;

    if (target.id === attacker.id) return true;

    return false;
};

function applyAreaDamage(attacker, primaryTarget, centerLocation) {
    const targets = attacker.dimension.getEntities({
        location: centerLocation,
        maxDistance: 6
    });

    for (const target of targets) {

        // 攻撃者本人・メインターゲットは除外
        if (
            target.id === attacker.id ||
            target.id === primaryTarget.id
        ) continue;

        // エンティティが有効か確認
        try {
            if (!target.isValid) continue;
        } catch {
            continue;
        }

        // 追加フィルター
        if (isAttackBlocked(attacker, target)) continue;

        // ダメージ適用
        try {
            target.applyDamage(2, {
                cause: EntityDamageCause.entityAttack,
                damagingEntity: attacker
            });
        } catch (_) {}
    }
}

world.afterEvents.entityHitEntity.subscribe((event) => {
    const attacker = event.damagingEntity;
    const hitEntity = event.hitEntity;

    if (attacker.typeId !== "minecraft:player") return;

    const inv = attacker.getComponent("minecraft:inventory");
    if (!inv?.container) return;

    const item = inv.container.getItem(attacker.selectedSlotIndex);

    if (!item || item.typeId !== "ameno:custom_sword") return;

    // 叩いたエンティティの位置を中心に範囲攻撃
    applyAreaDamage(
        attacker,
        hitEntity,
        hitEntity.location
    );
});

world.afterEvents.itemCompleteUse.subscribe((event) => {
    const { source, itemStack } = event;

    if (itemStack?.typeId !== "ameno:custom_sword") return;

    const { dimension, location } = source;

    const dir = source.getViewDirection();

    // 投擲物を生成
    const proj = dimension.spawnEntity(
        "ameno:sonic_bullet",
        {
            x: location.x + dir.x * 2,
            y: location.y + 1.5,
            z: location.z + dir.z * 2
        }
    );

    // 速度を付与
    proj.applyImpulse({
        x: dir.x * 2,
        y: dir.y * 2,
        z: dir.z * 2
    });

    source.sendMessage("§e投擲武器を発射しました!");
});

現在困っていること

現在のコードでは、applyDamage()を使用していますが、場合によっては誰にもダメージが入らない状態になります。

また、

try {
    target.applyDamage(2, {
        cause: EntityDamageCause.entityAttack,
        damagingEntity: attacker
    });
} catch (_) {}

としているため、エラーが発生しても表示されません。

そのため、原因を確認するために、

try {
    target.applyDamage(2, {
        cause: EntityDamageCause.entityAttack,
        damagingEntity: attacker
    });
} catch (error) {
    console.warn(`applyDamage failed: ${error}`);
}

のようにした方がよいのかも気になっています。

実現したい設定方法

例えば以下のような設定を用意して、

const damageSettings = {
    // 自分自身を除外するか
    excludeSelf: true,

    // プレイヤー全員を除外するか
    excludePlayers: false,

    // 特定のエンティティを除外
    excludedEntityTypes: [
        // "minecraft:zombie",
        // "minecraft:skeleton"
    ],

    // 特定のプレイヤーを除外
    excludedPlayerNames: [
        // "PlayerA",
        // "PlayerB"
    ]
};

この設定を変更するだけで攻撃対象を変更できるようにしたいです。

例えば、

excludeSelf: true

なら自分だけ除外。

excludeSelf: true,
excludePlayers: true

なら自分とプレイヤー全員を除外。

excludedEntityTypes: [
    "minecraft:zombie",
    "minecraft:skeleton"
]

ならゾンビとスケルトンだけ除外。

というようにしたいです。

特定のプレイヤーについて

特定のプレイヤーだけを除外する場合、

target.id
target.name
target.nameTag

のどれを使用するのが適切なのかも知りたいです。

例えば、

excludedPlayerNames: [
    "PlayerA",
    "PlayerB"
]

と設定した場合に、

PlayerA → ダメージなし
PlayerB → ダメージなし
その他のプレイヤー → ダメージあり
モブ → ダメージあり

としたいです。

質問

  1. 攻撃者自身、プレイヤー、特定のモブなどを設定によって除外するには、どのような実装が適切でしょうか?

  2. プレイヤー判定にはtarget.typeId === "minecraft:player"を使用して問題ないでしょうか?

  3. 特定のモブを除外する場合はtarget.typeIdを使用する方法で問題ないでしょうか?

  4. 特定のプレイヤーを除外する場合はidnamenameTagのどれを使用するのがおすすめでしょうか?

  5. 現在のコードでダメージが入らなくなる原因として考えられる点はありますでしょうか?

  6. 今後、別の攻撃にも使い回せるような汎用的な除外処理にするには、どのようなコードにすればよいでしょうか?

Minecraft Bedrock Editionのアドオン開発に詳しい方、ご教授いただけると助かります。

0 likes

1Answer

この手の物には詳しくありませんので憶測での回答になります。正確性は不明ですが一応公式ドキュメントは軽く見ました。なので鵜呑みにしないように。

攻撃者自身、プレイヤー、特定のモブなどを設定によって除外するには、どのような実装が適切でしょうか?

オリジナルコマンドを作成するべきでは?
今の現状だとソースレベルでの変更が必要になります。

プレイヤー判定にはtarget.typeId === "minecraft:player"を使用して問題ないでしょうか?

公式ドキュメントもそんな感じなので問題は無いかと思われます。
enumっぽい物も無いですし、リソースパックからの影響も受けるので文字列の判定が合理的と判断されたのではないかと思われます。

特定のプレイヤーを除外する場合はid、name、nameTagのどれを使用するのがおすすめでしょうか?

役割が違います。

  • id はユニークIDの事かと思われます。全てのエンティティは確かUUIDを持っているので個々のダメージ量などを保持できているのです。
  • namePlayerから継承されているとあるので、プレイヤー名のことを指すのかと思われます。
  • nameTagはおそらく「名札」のことですね。別名を付けられるので本名を汚染することはありません。

現在のコードでダメージが入らなくなる原因として考えられる点はありますでしょうか?

パット見た感じで疑問に思った点は

  • beforeEventsではなくafterEventsが扱われている。「after」という意味がそのまんまならダメージが通った後のイベント処理になる可能性があるわけですから、「無効化したい(before)」と「ダメージ量調整(after)」で用途が変わるはずです。
  • if (attacker.typeId !== "minecraft:player") return;だと完全にプレイヤーを除外していますが、コレは本当に合っているのですか?「他のプレイヤー → ダメージあり」とかかれていますが。

今後、別の攻撃にも使い回せるような汎用的な除外処理にするには、どのようなコードにすればよいでしょうか?

設定を内部コードに留めるのでは無く、設定ファイルを外部から読み出せるのであればそう言った機構が有れば良いかと。

1Like

Comments

  1. @KAISEI_sky

    Questioner

    ご返信ありがとうございます。

    そもそもコード自体理解出来てない部分もあり
    自分でも何回か作り直してみたりAI(Claude)に頼ってみたのですが、この部分だけがどうしても上手くいかず諦めてました
    そもそもイベント処理に問題があり、before処理すら知らずにafter処理でのみ無理やり作っていました。(無知ですいません💦)

    この内容を基にまたアドオン作成に力を入れて行きます( * ॑꒳ ॑*)
    改めてご返信ありがとうございました!

Your answer might help someone💌