78081


# 前置き

Unity を用いてオリジナルゲームを制作しています。  
プレイヤーの操作するキャラクターに足音を実装する作業を行っており、  
現在は以下のサイトを参考に、キャラクターの足が接触したオブジェクトの tag を検知して再生するクリップを切り替えるプログラムを書いています。

[Unityで効果音とBGMを付ける (1) ～足音の基本と応用～](https://acua-
piece.com/post/186042580240/game-audio-with-unity-footsteps)

* * *

# 本題

Dictionaryでtagの名前(string)と対応する番号(int)を決めて置き、if文を使って取得したtagの名前に一致するKeyがあるか調べてクリップを再生するメソッドをつくりました。

[code]

     public void RelayedTrigger(Collider other)
        {
            if(tagToIndex.ContainsKey(other.gameObject.tag))
            {
                groundIndex = tagToIndex[other.gameObject.tag];
            }
        }
    
[/code]

`tagToIndex`にtagの名前と番号を対応させたDictionaryを代入しており、  
`groundIndex`で最終的に再生するクリップを決定しています。

## 期待

実際に動作させたときには、if文中の内容が実行されてほしいのですが↓

## 結果

なぜか実行されません(elseで確認)。  
なので、取得したtag名はtagToIndexのKeyに含まれていないということなのだと思いますが、  
しかし↓

## 詳細

tagToIndexはちゃんと宣言・初期化できており(foreachで確認)、  
Key名とtag名も一致しています。

## 補足

### 追記1 : tagToIndex

`tagToIndex` ディクショナリに関連しているものを集めました。  
`listAudioClips` にオブジェクトのtagと同名の要素を格納しています。

[code]

    public class FootStepSEHandler : MonoBehaviour
    {
       [System.Serializable]
        public class AudioClips
        {
            public string groundTypeTag;
        }
    
       [SerializeField] List<AudioClips> listAudioClips = new List<AudioClips>();
    
       private Dictionary<string, int> tagToIndex = new Dictionary<string, int>();
    
       private void Awake()
       {
           for (int i = 0; i < listAudioClips.Count(); ++i)
                tagToIndex.Add(listAudioClips[i].groundTypeTag, i);
       }
    }
    
[/code]

### 追記2

どうやら足が地面に接触し、地面の`tag`を取得する前に足の親要素であるオブジェクトのコライダに判定をとられてしまい、その親のオブジェクトの`tag`を`tagToIndex`の`Key`と照らし合わせてしまっているようです。

### 追記3

レイヤーと _LeyerCollisionMatrix_ を用いてプレイヤーと足のコライダとの間で判定が  
起こらないようにしました。  
しかし、そもそも足のコライダが地面のコライダと接触していないようです。(`OnTriggerEnter()`が呼び出されていない)


CC BY-SA 4.0
2021-07-04T14:27:42.077
77971
2021-07-09T13:56:34.733
2021-07-09T13:09:09.380
43447
43447
question
c# unity3d
if文とDictionary.ContainsKey


本題に提示されているコードに不審な点は見つかりません。  
単純に tagToIndex に other.gameObject.tag のキーが存在しないことを疑うべきでしょう。

Awake() で存在確認できていても、RelayedTrigger()
実行時にそのキーが存在するとは限りません。実行前に他のコードによって変更される可能性が否定できないためです。  
なので、検証コードは RelayedTrigger() に実装して確認するのがよいと思います。

例えば、以下のようにします。

[code]

    using System;
    using System.Linq;
    
    public void RelayedTrigger(Collider other)
    {
        if (tagToIndex.ContainsKey(other.gameObject.tag))
        {
            groundIndex = tagToIndex[other.gameObject.tag];
        }
        else
        {
            // 検証用コード：見つからないときに詳細にチェックする
            string tag = other.gameObject.tag;
            bool exists = false;
            Debug.Log("Check...");
            foreach (var key in tagToIndex.Keys)
            {
                Debug.Log($"Key: {GetStringWithHex(key)}");
                if (key == tag)
                {
                    Debug.Log("** Find !! **");
                    exists = true;
                }
            }
            Debug.Log("Check done.");
            Debug.Log($"{GetStringWithHex(tag)} は" + (exists ? "見つかりました" : "見つかりませんでした"));
            Debug.Break(); // 実行を中断
        }
    }
    
    // 文字列に16新数表示を追加
    private string GetStringWithHex(string input)
    {
        return $"{input}({string.Join("-", input.ToCharArray().Select(e => Convert.ToInt32(e).ToString("X2")))})";
    }
    
[/code]


CC BY-SA 4.0
2021-07-06T11:06:06.727
78007
2021-07-07T01:04:43.177
2021-07-07T01:04:43.177
14817
14817
77971
answer


# 感謝

皆様の提案をもとに自己解決いたしました。ありがとうございます。

# 解決方法

コライダと`OnCollisionEnter()`、`OnTriggerEnter()`などの関数を使う際は、  
衝突・侵入するコライダのアタッチされたオブジェクトのどちらか一方にリジッドボディ  
コンポーネントがなければいけないようです。

判定を取得しているコライダのアタッチされたオブジェクト(プレイヤキャラクタの足)に  
リジッドボディをアタッチすることですべて解決しました。


CC BY-SA 4.0
2021-07-09T13:56:34.733
78081
2021-07-09T13:56:34.733
43447
77971
answer