質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • C#

    7119questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity

    4004questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

###Unityで一度ぶつかったオブジェクトに対してはダメージ判定を行わないよにするにはどうすればいいのでしょうか?

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,036

donafudo

score 38

お世話になります。

現在unity3Dで敵の当たり判定の処理を作っている最中なのですが
攻撃モーション中に武器にTriggerで当たり判定を行うのオブジェクトを生成して
そのオブジェクトの範囲に入ったらダメージ処理を行うようにしています。
その際に一度当たった後にアニメーションの動きなどでまた当たる、
同じ敵キャラクターの別のコライダーに当たる(頭や胴体など複数の判定を設定している)
などで2回以上の判定が発生してしまうことを直したいです。

敵の攻撃できるコライダーすべてにEnemy_DamageChildをつけて
DamageManagerで一括管理したいです

もっと良いやり方がありましたら教えて頂きたいです。よろしくお願いします。

発生している問題・エラーメッセージ

2度当たり判定が発生する

該当のソースコード

攻撃を当てられるコライダー

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy_DamageChild : MonoBehaviour {

    public GameObject ParentObj;//ダメージマネージャーが入っているオブジェクト

    Enemy_DamageManager Edm;

    void Start () {
        Edm = ParentObj.GetComponent<Enemy_DamageManager> ();

    }

    //攻撃がヒットした際に呼ばれる
    public void AttackHitCol(GameObject HitAttack,int Damagenum){

        Edm.EnemyHPSystem (HitAttack,gameObject,Damagenum);

    }


}

当たり判定をまとめる

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections.Generic;
public class Enemy_DamageManager : MonoBehaviour {
    public int HP

    DamagePopManager Dpm;

    void Start () {
    //ダメージ表示用のキャンバス
        Dpm = GameObject.Find ("DamagePopCanvas").GetComponent<DamagePopManager> ();

    }

    public void EnemyHPSystem(GameObject hitobj,GameObject HitCol,int Damagenum){

        //ココに判定を書きたい
        Damage (HitCol,Damagenum);

    }
         //ダメージ処理
    void Damage(GameObject hitCol,int Damagenum){
        //ダメージ表示
        Dpm.DamagePopUp (Damagenum.ToString (), (Vector3)hitCol.transform.position);

    }
}

試したこと

攻撃用のオブジェクトをリストで管理して
リストにすでに入っていたらダメージ処理を行わないようにしようとしたが
リストに入っていないことをどう判断すればいいかわからなかった

敵に当たった場合に攻撃用のオブジェクトを消すという手もありますが
それだと複数敵がいる場合に最初に当たった1体にしか判定が発生しないのが歯痒い

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

※僕はUnityでゲーム開発していないので、こういう処理が既に用意されてるかどうかは分かりません

リストの初期化は敵のObjectを破壊したときにできればいいってことでしょうかね。

ちょっと動くか確認していませんが、大体はこんな感じです。

private readonly List<int> hitIdList = new List<int>();

public void EnemyHPSystem(GameObject hitobj,GameObject HitCol,int Damagenum){
    // 1. オブジェクトのIDを取得します(GameObjectのリストにすると参照関係が怖いからね)
    var instanceId = hitObj.GetInstanceId();
    // 2. オブジェクトのIDがリストに含まれていないか確認、含まれていれば処理終了
    if (hitIdList.Contains(instanceId)) return;
    // 3. オブジェクトのIDをリストに追加して処理に進む
    hitIdList.Add(instanceId);

    Damage (HitCol,Damagenum);

}

これで2回同じ処理が行われないようにできます。
非同期で処理が行われていて多重に呼ばれてしまう場合はロックを実装しても同じような効果が得られます。

補足ですが、要素の有無を判定するだけの場合はHashSetクラスを使います。
HashSetクラスは、要素として値を持つかどうかを判定することだけに長けたクラスです。
Listとコード自体は一緒ですが、要素の検索を素早く行えます。

private readonly HashSet<int> hitIdSet = new HashSet<int>();

public void EnemyHPSystem(GameObject hitobj,GameObject HitCol,int Damagenum){
    var instanceId = hitObj.GetInstanceId();
    if (hitIdSet.Contains(instanceId)) return;
    hitIdSet.Add(instanceId);

    Damage (HitCol,Damagenum);

}

追記

こういう処理は沢山書くと思うので、専用のクラスを書いてラップしておくとすっきりします。
処理の修正が必要な場合でも一括で修正できるようになります。
※名前は適当!

public class ProcessGuard
{
    private readonly HashSet<int> hitIdSet = new HashSet<int>();

    public bool PassOnce(GameObject obj)
    {
        var instanceId = obj.GetInstanceId();
        if (hitIdSet.Contains(instanceId)) return false;
        hitIdSet.Add(instanceId);
        return true;
    }
}

//...

private readonly ProcessGuard hitIdGuard = new ProcessGuard();

public void EnemyHPSystem(GameObject hitobj,GameObject HitCol,int Damagenum){
    if (!hitIdGuard.PassOnce(hitobj)) return;

    Damage (HitCol,Damagenum);
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/23 21:41

    今やってみたところ見事にできました!
    完璧な回答ありがとうございます、これで少し前に進みそうです
    その他の実装方法も参考にさせていただきます。
    本当にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    7119questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity

    4004questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • トップ
  • C#に関する質問
  • ###Unityで一度ぶつかったオブジェクトに対してはダメージ判定を行わないよにするにはどうすればいいのでしょうか?