スポンサーリンク
Unity C#・スクリプト実装

UnityでオブジェクトをListに追加・削除する方法|クリック・接触・切り替えまで解説

Unity C#・スクリプト実装

Unityでゲームを作っていると、「クリックしたオブジェクトを後から使いたい」「拾ったアイテムを記録したい」「選択中の武器だけ表示したい」といった場面によく出会います。

ところが、いざ実装しようとすると「配列とListのどちらを使えばいいの?」「オブジェクトを消したのにListに残っている……」「Triggerが反応しないのはなぜ?」と、思わぬところで手が止まってしまうことも少なくありません。

私も最初の頃は、「とりあえずListに入れれば大丈夫かな?」と思って進めた結果、取得したアイテムが二重登録されたり、消したはずのオブジェクトの参照が残っていたりして、コンソールとにらめっこした経験があります。ゲーム開発って、派手な演出よりも、こういう地味な管理処理が意外と重要なんですよね。

アイテム取得、インベントリ、ターゲット選択、武器切り替えなど、多くのゲームシステムは「オブジェクトを集める・記録する・切り替える・削除する」という仕組みの組み合わせでできています。

このあたりをしっかり理解しておくと、新しい機能を作るたびに同じところで悩まずに済むようになります。頭の中が整理されると、「次はこれを組み合わせれば作れそう」という発想も自然と出てくるようになりますよ。


結論

Unityでオブジェクトを管理するときは、まず「数が固定か、ゲーム中に増減するか」で考えると迷いにくくなります。

武器やキャラクターのように、最初から候補が決まっているものは配列が扱いやすいです。反対に、拾ったアイテムやクリックしたターゲットのように、プレイ中に増えたり減ったりするものはListが向いています。

やりたいこと使いやすい方法
クリックしたオブジェクトを記録するRaycast+List
触れたアイテムを取得するTrigger+List
武器やキャラを切り替える配列+インデックス
特定の種類だけ判定するTag

ここで大事なのは、Listに追加しただけではシーン上のオブジェクトが消えるわけではない、という点です。Listはあくまで「あとで使うためのメモ帳」のようなものです。

見た目を消したいならSetActive(false)、完全に破棄したいならDestroy()を使います。この違いを分けて考えるだけでも、オブジェクト管理の混乱はかなり減ります。




Unityのオブジェクト管理は配列とListの使い分けが重要

Unityで複数のオブジェクトを扱うときは、最初に「このオブジェクトたちはゲーム中に増えたり減ったりするのか?」を考えると整理しやすくなります。

たとえば、キャラクター選択画面で使うキャラ候補や、切り替えたい武器の見た目が最初から決まっている場合は、配列が向いています。数が固定されているので、番号を使って順番に切り替えやすいからです。

一方で、プレイヤーが拾ったアイテム、クリックで選択したターゲット、接触したオブジェクトの記録などは、Listが使いやすいです。ゲーム中に追加したり削除したりできるので、インベントリやターゲット管理と相性が良いです。

管理したいものおすすめ理由
武器の切り替え配列候補数が固定されやすい
キャラクター選択配列登録順に切り替えやすい
拾ったアイテムListゲーム中に増減する
選択中のターゲット一覧List状況によって追加・削除される

配列は固定された候補の管理に向いている

配列は、あらかじめ「何個のオブジェクトを扱うか」が決まっているときに便利です。UnityのInspectorから複数のGameObjectを登録しておき、番号で表示を切り替えるような使い方ができます。

たとえば、剣、弓、杖の3種類を切り替えるだけなら、配列で十分です。むしろListを使うよりも、「この3つを順番に切り替える」と考えやすくなります。

Listは増えたり減ったりする管理に向いている

Listは、プレイ中に中身が変わるものを管理するときに便利です。アイテムを拾ったら追加し、使ったら削除する。敵を発見したら追加し、倒したら削除する。こうした処理はListの得意分野です。

ただし、Listは便利なぶん「何を入れて、いつ消すのか」を決めておかないと、同じオブジェクトが何度も追加されたり、消したはずの参照が残ったりします。まるでカバンの中に同じレシートが増えていくような状態ですね。

迷ったらゲーム中に増減するかで判断する

判断に迷ったら、「ゲーム中に数が変わるか?」だけを見てみましょう。

  • 数が固定されているなら配列
  • ゲーム中に追加・削除するならList
  • 種類で分けたいならTag
  • 特定のキーで探したいならDictionaryも候補

今回の主役は、クリックや接触で取得したオブジェクトを管理するListです。配列は「切り替え用」、Listは「記録・増減用」と分けて考えると、次の実装がかなり見通しやすくなります。




UnityでクリックしたオブジェクトをListに追加・削除する方法

クリックしたオブジェクトをListに入れるには、まずマウスの位置からRayを飛ばして、クリック先のGameObjectを取得します。Unityではこの処理にPhysics.Raycastを使うことが多いです。

たとえば、アイテムをクリックして取得したり、敵をクリックしてターゲットリストに入れたりする場面で使えます。クリック操作は「プレイヤーが自分で選ぶ」動きなので、インベントリや選択システムと相性が良いです。

Raycastがうまく反応しない場合は、クリック対象にColliderが付いているか確認してみてください。Colliderがないと、Rayが当たる場所を判定できません。

Raycastの基本や当たらない原因を詳しく確認したい場合は、こちらも参考になります。

Raycastでクリックしたオブジェクトを取得する

まずは、クリックしたオブジェクトを取得する基本形を作ります。管理用の空オブジェクトを作り、以下のスクリプトをアタッチしてください。

using System.Collections.Generic;
using UnityEngine;

public class ClickObjectListManager : MonoBehaviour
{
    private List<GameObject> selectedObjects = new List<GameObject>();

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit))
            {
                GameObject clickedObject = hit.collider.gameObject;
                Debug.Log("クリックしたオブジェクト: " + clickedObject.name);
            }
        }
    }
}

Input.GetMouseButtonDown(0)は、左クリックされた瞬間だけ処理を実行します。押している間ずっと反応するわけではないので、クリック1回につき1回だけ登録したい場面に向いています。

Listにクリックしたオブジェクトを追加する

クリックしたオブジェクトを取得できたら、次はListへ追加します。ただし、そのままAdd()するだけだと、同じオブジェクトを何度もクリックしたときに重複して登録されます。

重複を避けたい場合は、Contains()で「すでにListに入っているか」を確認してから追加しましょう。

using System.Collections.Generic;
using UnityEngine;

public class ClickObjectListManager : MonoBehaviour
{
    private List<GameObject> selectedObjects = new List<GameObject>();

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit))
            {
                GameObject clickedObject = hit.collider.gameObject;

                if (!selectedObjects.Contains(clickedObject))
                {
                    selectedObjects.Add(clickedObject);
                    Debug.Log("Listに追加: " + clickedObject.name);
                }
                else
                {
                    Debug.Log("すでに登録済み: " + clickedObject.name);
                }
            }
        }
    }
}

この形にしておくと、クリックした対象を安全に記録できます。アイテム取得なら「取得済みリスト」、敵選択なら「ターゲットリスト」のように使えます。

Listからオブジェクトを削除する

Listから削除するときは、用途に応じてRemove()RemoveAt()Clear()を使い分けます。

メソッド使い方向いている場面
Remove()指定したオブジェクトを削除クリック対象だけ外す
RemoveAt()指定した番号の要素を削除先頭や選択中の要素を外す
Clear()Listの中身をすべて削除リセット処理

たとえば、スペースキーでListの先頭を削除するなら、次のように書けます。

if (Input.GetKeyDown(KeyCode.Space))
{
    if (selectedObjects.Count > 0)
    {
        GameObject removedObject = selectedObjects[0];
        selectedObjects.RemoveAt(0);

        Debug.Log("Listから削除: " + removedObject.name);
    }
}

ここでselectedObjects.Count > 0を確認しているのが大切です。Listが空なのにRemoveAt(0)を実行すると、エラーになります。空の箱から1個取り出そうとしているようなものですね。

SetActiveとDestroyを使い分ける

クリックしたオブジェクトをListに追加したあと、画面上から消したい場合はSetActive(false)Destroy()を使います。

インベントリのように後から再表示する可能性があるなら、SetActive(false)が扱いやすいです。完全に不要な弾や破壊済みのオブジェクトなら、Destroy()を使う選択もあります。

if (!selectedObjects.Contains(clickedObject))
{
    selectedObjects.Add(clickedObject);

    // 一時的に非表示にする
    clickedObject.SetActive(false);
}

注意したいのは、Listから削除してもシーン上のGameObjectは自動で消えないことです。Listは参照を管理しているだけなので、「Listから外す処理」と「画面上から消す処理」は別だと考えましょう。




Unityで触れたオブジェクトをListに保存する方法

クリックではなく、「プレイヤーが触れたら自動で取得する」仕組みもゲームではよく使われます。RPGの宝箱やコイン収集、回復アイテムの取得などをイメージすると分かりやすいですね。

プレイヤーがわざわざ選択しなくても処理が進むため、テンポの良いゲーム体験を作りやすいのが特徴です。私もアクションゲームを作るときは、「これは自分で選ばせるべきか、それとも触れたら自動取得にするべきか」を最初に考えるようにしています。

Triggerでオブジェクト取得する仕組み

接触による取得では、OnTriggerEnterを使います。これは、Collider同士が「重なった瞬間」に呼び出されるイベントです。

たとえば、プレイヤーがコインに触れたらListへ追加し、取得済みとして非表示にする、といった処理が簡単に作れます。

using System.Collections.Generic;
using UnityEngine;

public class ItemCollector : MonoBehaviour
{
    private List<GameObject> collectedItems = new List<GameObject>();

    private void OnTriggerEnter(Collider other)
    {
        if (!collectedItems.Contains(other.gameObject))
        {
            collectedItems.Add(other.gameObject);

            Debug.Log("取得: " + other.gameObject.name);
        }
    }
}

otherには、接触した相手のCollider情報が入っています。そこからother.gameObjectを取得してListへ保存しています。

Triggerが動く最低条件

「コードは書いたのに反応しない……」というのは、Trigger処理で最も多い悩みのひとつです。原因の多くは、Unity側の設定不足にあります。

正常に動く例反応しない例
両方にColliderが付いているどちらかにColliderがない
対象のColliderでIs Triggerが有効Is Triggerがオフ
どちらか一方にRigidbodyがある両方ともRigidbodyなし

特に忘れやすいのがRigidbodyです。「Colliderを付けたのに動かない!」という場合は、まずRigidbodyの有無を確認してみてください。

当たり判定がうまく動かない場合は、こちらの記事も参考になります。

取得したオブジェクトをListに保存する

アイテム取得では、同じアイテムを何度も登録しないようにすることも大切です。

プレイヤーがTrigger内に留まり続けたり、複数の判定が重なったりすると、意図せず重複登録される場合があります。そのため、Contains()で確認してから追加する習慣を付けておくと安心です。

private void OnTriggerEnter(Collider other)
{
    if (!collectedItems.Contains(other.gameObject))
    {
        collectedItems.Add(other.gameObject);

        // 取得済みとして非表示
        other.gameObject.SetActive(false);

        Debug.Log("取得完了");
    }
}

SetActive(false)を使えば、「拾ったアイテムがその場に残り続ける」という違和感も防げます。あとで再出現させたい場合にも再利用しやすい方法です。

アイテム取得処理でよくある失敗

  • 同じアイテムが何度もListに追加される
  • ColliderやRigidbodyの設定不足でTriggerが発火しない
  • Listに追加しただけで取得演出が終わったと思ってしまう
  • Listから削除してもシーン上のオブジェクトが残る

アイテム取得の仕組みは、「取得判定」「Listへの記録」「見た目の更新」の3つに分けて考えると整理しやすくなります。

最初は少し遠回りに感じるかもしれませんが、この考え方が身につくと、インベントリやクエストアイテム管理など、より複雑なシステムにも応用しやすくなります。




Unityで配列を使ってオブジェクトを切り替える方法

武器、キャラクター、スキン、表示モデルのように「候補が最初から決まっているもの」を切り替えるなら、Listよりも配列が扱いやすいです。

たとえば、剣・弓・杖の3種類を切り替える場合、ゲーム中に候補が増減しないなら、配列に登録して番号で管理するだけで十分です。Listを使うこともできますが、増減しないものにListを使うと、かえって「いつ追加する?いつ削除する?」と考えることが増えてしまいます。

配列に切り替え対象を登録する

まずは、切り替えたいオブジェクトを配列に登録します。スクリプト側でGameObject[]を用意しておくと、UnityのInspectorから対象をドラッグ&ドロップできます。

using UnityEngine;

public class ObjectSwitcher : MonoBehaviour
{
    public GameObject[] objects;
    private int currentIndex = 0;

    void Start()
    {
        ShowOnlyCurrentObject();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            currentIndex++;
            ShowOnlyCurrentObject();
        }

        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            currentIndex--;
            ShowOnlyCurrentObject();
        }
    }

    void ShowOnlyCurrentObject()
    {
        for (int i = 0; i < objects.Length; i++)
        {
            objects[i].SetActive(i == currentIndex);
        }
    }
}

このままだと、右キーを押し続けたときに配列の範囲を超えてしまいます。配列は番号で管理するため、存在しない番号を指定するとエラーになります。

インデックスの範囲外エラーを防ぐ

配列でよくある失敗が、IndexOutOfRangeExceptionです。これは「存在しない番号の要素を見ようとした」ときに起きます。

対策として、Mathf.Clampを使って、番号が配列の範囲内に収まるようにします。

using UnityEngine;

public class ObjectSwitcher : MonoBehaviour
{
    public GameObject[] objects;
    private int currentIndex = 0;

    void Start()
    {
        ShowOnlyCurrentObject();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            currentIndex++;
            currentIndex = Mathf.Clamp(currentIndex, 0, objects.Length - 1);
            ShowOnlyCurrentObject();
        }

        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            currentIndex--;
            currentIndex = Mathf.Clamp(currentIndex, 0, objects.Length - 1);
            ShowOnlyCurrentObject();
        }
    }

    void ShowOnlyCurrentObject()
    {
        for (int i = 0; i < objects.Length; i++)
        {
            objects[i].SetActive(i == currentIndex);
        }
    }
}

これで、最初より左にも、最後より右にも進まなくなります。武器選択やキャラクター選択では、この形がかなり使いやすいです。

最後まで進んだら最初に戻す

左右キーでぐるぐる切り替えたい場合は、範囲内で止めるのではなく、最後まで進んだら最初に戻す処理にします。

if (Input.GetKeyDown(KeyCode.RightArrow))
{
    currentIndex++;

    if (currentIndex >= objects.Length)
    {
        currentIndex = 0;
    }

    ShowOnlyCurrentObject();
}

if (Input.GetKeyDown(KeyCode.LeftArrow))
{
    currentIndex--;

    if (currentIndex < 0)
    {
        currentIndex = objects.Length - 1;
    }

    ShowOnlyCurrentObject();
}

ショップの表示切り替えやキャラクター選択画面では、こちらのループ型のほうが自然に感じることも多いです。逆に、ステージ選択のように「これ以上進めない」と見せたい場合は、止める型のほうが合います。

配列管理が向いているケース

  • 登録するオブジェクト数が最初から決まっている
  • Inspectorで順番を指定したい
  • 現在選択中の1つだけを表示したい
  • 武器、キャラクター、スキンなどを順番に切り替えたい

配列は、Listのように途中で追加・削除する柔軟さはありません。その代わり、登録順がはっきりしていて、切り替え処理をシンプルに書けます。

「ゲーム中に集めるもの」はList、「最初から並べておくもの」は配列。こう分けておくと、オブジェクト管理のコードがかなり読みやすくなります。




UnityのTagを使ってオブジェクト管理を効率化する方法

シーン内のオブジェクトが増えてくると、「アイテムだけ反応させたい」「敵だけListに入れたい」のように、対象を種類ごとに分けたくなります。

そんなときに便利なのがTagです。Tagを使うと、GameObjectに「Item」「Enemy」「Target」のような目印を付けて、処理する相手を絞り込めます。

Tagで対象を絞り込む

たとえば、触れた相手がアイテムだった場合だけListに追加したいなら、CompareTag()を使います。

private void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Item"))
    {
        if (!collectedItems.Contains(other.gameObject))
        {
            collectedItems.Add(other.gameObject);
            other.gameObject.SetActive(false);

            Debug.Log("アイテム取得: " + other.gameObject.name);
        }
    }
}

このようにしておくと、壁や敵、床に触れてもアイテム取得処理は実行されません。余計なオブジェクトまでListに入ってしまう事故を防げます。

CompareTagを使う理由

Tag判定では、other.gameObject.tag == "Item"のような書き方もできます。ただ、UnityではCompareTag()を使う方法がよく使われます。

書き方特徴
CompareTag("Item")Tag判定用の分かりやすい書き方
gameObject.tag == "Item"文字列比較になり、書き間違いに気づきにくい

小さな違いに見えますが、プロジェクトが大きくなるほど「読みやすい判定」にしておく価値が出てきます。未来の自分にやさしいコードですね。

FindGameObjectsWithTagの注意点

シーン内にある特定Tagのオブジェクトをまとめて取得したい場合は、GameObject.FindGameObjectsWithTag()を使えます。

GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");

このコードでは、TagがEnemyのGameObjectを配列として取得できます。ステージ開始時に敵一覧を取得したい場合などに便利です。

ただし、毎フレーム実行するような使い方は避けたほうが無難です。対象を探す処理なので、必要なタイミングだけ実行するほうが管理しやすくなります。

TagとLayerの違い

Tagと似たものにLayerがあります。どちらもオブジェクトを分類する機能ですが、役割は少し違います。

Tagは「これはアイテム」「これは敵」のように種類を見分けるために使います。一方でLayerは、Raycastで当てる対象を絞ったり、カメラに映す対象を分けたりする場面でよく使います。

TagとLayerの違いを詳しく整理したい場合は、こちらも参考になります。

Listで管理する前にTagで対象を絞っておくと、意図しないオブジェクトが混ざりにくくなります。特にアイテム、敵、ターゲットのように種類が増えるゲームでは、早めに分類ルールを決めておくと後から楽になります。




Unityのオブジェクト管理で初心者が混同しやすいポイント

オブジェクト管理でつまずきやすい原因は、コードの書き方だけではありません。「List」「シーン上のGameObject」「表示状態」「削除処理」を同じものとして考えてしまうと、動きが分かりにくくなります。

ここでは、特に混同しやすいポイントを整理しておきます。ここが分かると、エラーが出たときも原因を切り分けやすくなります。

Listから削除してもオブジェクトは消えない

Listは、GameObjectへの参照を保存しているだけです。そのため、Remove()RemoveAt()でListから削除しても、シーン上のオブジェクト自体は残ります。

selectedObjects.Remove(clickedObject);

この処理は「メモ帳から名前を消す」ようなものです。実物のオブジェクトを消しているわけではありません。

画面上から消したい場合は、別途SetActive(false)Destroy()を使います。

SetActiveはDestroyではない

SetActive(false)は、GameObjectを一時的に無効化する処理です。非表示になり、Colliderやスクリプトも基本的に動かなくなりますが、オブジェクト自体は残っています。

clickedObject.SetActive(false);

一方で、Destroy()はGameObjectを破棄します。あとから同じ参照を使って再表示したい場合には向きません。

処理意味向いている用途
SetActive(false)一時的に無効化取得アイテムの非表示、再利用
Destroy()オブジェクトを破棄弾、爆発後の破片、不要な敵

インベントリのように「拾ったあと、あとで使う」可能性があるものは、まずSetActive(false)で考えると扱いやすいです。

TriggerとCollisionは別物

OnTriggerEnterOnCollisionEnterは、どちらも接触系の処理ですが、使う場面が違います。

Triggerは「重なったことを検知する」処理です。コイン取得やエリア判定のように、物理的にぶつかって止める必要がない場面に向いています。

Collisionは「物理的にぶつかったことを検知する」処理です。壁に当たる、敵にぶつかる、床に着地する、といった場面で使います。

アイテム取得なのにCollisionで作ろうとすると、物理挙動の影響で思ったより面倒になることがあります。触れたら取得するだけなら、Triggerのほうがシンプルです。

配列とListは完全な置き換えではない

配列でもListでも複数のGameObjectを扱えますが、向いている場面は違います。

固定された候補を順番に切り替えるなら配列、ゲーム中に追加・削除するならListです。どちらか一方だけ覚えるより、役割を分けて使えるようになるほうが実装は安定します。

  • 武器やキャラの切り替え:配列
  • 拾ったアイテムの記録:List
  • クリックしたターゲットの管理:List
  • 種類ごとの判定:Tag

迷ったときは、「これは最初から数が決まっている?それともゲーム中に増減する?」と自分に聞いてみてください。だいたいの方向性はそれだけで見えてきます。




まとめ

Unityでゲーム内オブジェクトを管理するときは、「何を記録したいのか」「あとでどう使いたいのか」を分けて考えると、かなり整理しやすくなります。

  • クリックしたオブジェクトを記録するならRaycastList
  • 触れたアイテムを取得するならTriggerList
  • 武器やキャラの切り替えなら配列
  • 対象を種類ごとに分けるならTag
  • 一時的に消すならSetActive(false)
  • 完全に不要ならDestroy()

特に大切なのは、Listは「シーン上のオブジェクトそのもの」ではなく、「あとで使うための参照」を管理しているという考え方です。ここが分かると、削除・非表示・再表示の処理で混乱しにくくなります。

私の感覚では、初心者のうちはListや配列の文法を丸暗記するより、「この処理は記録なのか、表示切り替えなのか、完全削除なのか」を先に考えるほうが伸びやすいです。オブジェクト管理は地味ですが、インベントリ、ターゲット選択、アイテム取得などに何度も出てくる大事な土台です。

基礎をまとめて学び直したい場合は、Unity全体の流れを体系的に確認できる本を手元に置いておくのも役立ちます。

Unityの教科書 Unity 6完全対応版
✅ Amazonでチェックする✅ 楽天でチェックする


よくある質問(FAQ)

Q
ListとDictionaryはどちらを使えばいいですか?
A

クリックしたオブジェクトや触れたアイテムを順番に記録するだけなら、まずはList<GameObject>で十分です。

Dictionaryは、「アイテムIDからすぐにデータを取り出したい」「敵のIDごとに状態を管理したい」のように、キーを使って検索したい場面で便利です。

最初からDictionaryを使おうとすると、キーの設計まで考える必要があります。まずはListで「追加・削除・切り替え」の流れを理解して、必要になったらDictionaryを検討すると進めやすいです。

Q
Listに保存したオブジェクトをセーブできますか?
A

Listに入っているGameObjectの参照そのものを、そのままセーブデータとして保存するのは基本的に向いていません。

セーブしたい場合は、オブジェクト名やアイテムID、取得済みフラグなど、復元に必要なデータを保存する形にします。

たとえば「Potionを3個持っている」「Key001を取得済み」のような情報を保存し、ロード時にそのデータをもとにインベントリやシーン状態を再現します。

本格的にセーブ処理まで作りたい場合は、保存用の仕組みを別で用意すると管理しやすくなります。

Easy Save
✅アセットストアでチェックする

Q
Input Systemでも同じように実装できますか?
A

Input Systemでも、クリックやタップを使ったオブジェクト取得は実装できます。

考え方は同じで、「入力を受け取る」「Raycastで対象を取得する」「Listに追加する」という流れになります。違うのは、クリック入力の受け取り方です。

この記事の例では理解しやすさを優先してInput.GetMouseButtonDownを使っています。まずは処理の流れをつかんでから、プロジェクトに合わせてInput System版へ置き換えると混乱しにくいです。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク