3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】GetComponent を使わずに低負荷でコンポーネントを取得する方法を思いついたが間違っていた話

Last updated at Posted at 2024-03-26

はじめに

この記事は GetComponent より Dictionary の方が速い前提で書きました。
しかし下記の記事で逆だと知りました。

この記事は二の鉄を踏もうとした方が検索で見つけられるように残そうと思います。
ちなみに、頻繁に GetComponent するものは上に配置すると僅かに速くなるようです。

これより先は、先頭の記事を見つける前に私が書いた記事になります。

背景

私はヴァンサバライクなゲームを作る際、OnTriggerEnter 等で衝突した Collider から目的のコンポーネントを取得するために TryGetComponent(GetComponent)を使っていました。
しかし GetComponent は重めの処理なので、弾幕や無双ゲームといった大量の物体を扱うゲームでは利用頻度を減らしたいと思いました。
そこで私は、シングルトンな Dictionary<GameObject, Component> を用意して目的のコンポーネントを追加しておけば、GameObject をキーとして目的のコンポーネントを簡単かつ低負荷で取得できると考え、それを実現する GetComponentDictionary クラスを作りました。

コード

Enter Play ModeReload Domainを無効にしても利用できます。

UniTask/UniRx がインポートされたプロジェクトで1行目/2行目をコメントアウトすると、Add() で追加されたコンポーネントの GameObject が破壊される際に自動で Remove() が呼ばれます。Component だけ破棄する際は Component の OnDestroy() に Remove() を追加し Add() の第二引数を false にしてください。

使い方

プレイヤーの弾が敵に当たり、敵がダメージを受けるといった具合の実装例です。

Enemy.cs
public class Enemy : MonoBehaviour
{
    [SerializeField] public int Hp;

    private void Start()
    {
        GetComponentDictionary<Enemy>.Add(this);
    }
    public void ReceiveDamage(int damage)
    {
        Hp -= damage;
    }
}
PlayerBullet.cs
using Generic;
using UnityEngine;

public class PlayerBullet : MonoBehaviour
{
    [SerializeField] private int damage;

    private void OnTriggerEnter(Collider other)
    {
        if (GetComponentDictionary<Enemy>.TryGetValue(other.gameObject, out var enemy))
        {
            enemy.ReceiveDamage(damage);
        }
    }
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?