U
タブ 01基礎11 レッスン — タップで開く
09 / 11 · 12 分
基礎

床の上でキャラクターを切り替える

ここまでのプロジェクト

Assets/

Scenes/

Arena.unity

FloorKnightMageArcherGameManager

Scripts/

GridSpawner.csSimpleMover.csCharacterSwitcher.csSwapCamera.cs

Prefabs/

P_Cube

すでにあるものこのレッスンで追加

ここが Tab 01 の節目です。平らな床、その上に立つ三人のキャラクター、そして 1 / 2 / 3 キーで操作対象を切り替えます。

アニメーション図

同時にアクティブなのは一人だけで、残りは床に立ったまま待機します。

ステップ 1 — 仮のキャラクターを三人

  1. 1

    GameObject▸3D Object▸Capsule を作り、Knight と名付けて Position を 0、1、0 にします。

  2. 2

    既定の Capsule は高さ 2 m でピボットが中心なので、Y = 1 にすれば足がちょうど床に着きます。

  3. 3

    二回複製して(Ctrl/Cmd + D)→ Mage を -3、1、0、Archer を 3、1、0 に置きます。

  4. 4

    それぞれに色付きの material を当てます:緑、紫、琥珀。これで一目で誰だか分かります。

  5. 5

    Characters という空の GameObject を作り、三人まとめてその中にドラッグします。

ステップ 2 — 全員共通の移動スクリプト

SimpleMover.cs — attach to all three characters
using UnityEngine;

public class SimpleMover : MonoBehaviour
{
    [SerializeField] private float speed = 6f;
    [SerializeField] private float turnSpeed = 12f;

    void Update()
    {
        // -1 .. 1 from A/D and W/S
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");

        Vector3 dir = new Vector3(h, 0f, v);
        if (dir.sqrMagnitude < 0.01f) return;      // no input, nothing to do

        dir.Normalize();                            // diagonal is not faster
        transform.position += dir * speed * Time.deltaTime;

        // face the direction of travel
        Quaternion target = Quaternion.LookRotation(dir);
        transform.rotation = Quaternion.Slerp(transform.rotation, target, turnSpeed * Time.deltaTime);
    }
}
  • GetAxisRaw は -1、0、1 を即座に返します。GetAxis は数フレームかけてならしますが、ここは raw の方が反応が鋭く感じます。

  • sqrMagnitude は平方根を取らない大きさです。計算が安く、ここでは閾値と比較するだけで済みます。

  • Slerp は毎フレームわずかな分だけ回すので、一瞬で向きを変えるのではなく滑らかな旋回に見えます。

ステップ 3 — 切り替え役

コツはシンプルです。リストを持って一つを有効にし、残りを無効にするだけ。オブジェクト全体ではなく SimpleMover を無効にすれば、キャラクターは全員床に見えるまま残ります。

CharacterSwitcher.cs — attach to an empty GameManager
using System.Collections.Generic;
using UnityEngine;

public class CharacterSwitcher : MonoBehaviour
{
    [SerializeField] private List<SimpleMover> characters = new List<SimpleMover>();
    [SerializeField] private Transform highlightRing;   // optional marker

    private int activeIndex = 0;

    void Start()
    {
        Select(0);
    }

    void Update()
    {
        // number keys 1..9
        for (int i = 0; i < characters.Count && i < 9; i++)
            if (Input.GetKeyDown(KeyCode.Alpha1 + i))
                Select(i);

        // Tab cycles to the next one
        if (Input.GetKeyDown(KeyCode.Tab))
            Select((activeIndex + 1) % characters.Count);
    }

    public void Select(int index)
    {
        if (index < 0 || index >= characters.Count) return;

        activeIndex = index;

        for (int i = 0; i < characters.Count; i++)
            characters[i].enabled = (i == index);      // only one may move

        if (highlightRing != null)
            highlightRing.SetParent(characters[index].transform, false);

        Debug.Log("Now controlling: " + characters[index].name);
    }

    public Transform ActiveCharacter => characters[activeIndex].transform;
}
  1. 1

    GameManager という空の GameObject を作って CharacterSwitcher をアタッチします。

  2. 2

    Inspector で Characters のサイズを 3 にし、Knight、Mage、Archer を各スロットへドラッグします。

  3. 3

    潰した cylinder(scale 1.2、0.02、1.2)を Highlight Ring に入れておくと、誰が選ばれているか一目で分かります。

  4. 4

    Play を押したら、WASD で移動、1 2 3 または Tab で切り替えてください。

なぜ GameObject ではなくスクリプトを無効にするのか?

✓ characters[i].enabled = false

Capsule は床に残ったまま、見えて、当たり判定もあります。ただ入力を読まなくなるだけです。

✖ SetActive(false)

キャラクターごとシーンから消えてしまいます。皆で床に立っていたいという意図には合いません。

ステップ 4 — アクティブなキャラクターをカメラに追従させる

SwapCamera.cs — attach to Main Camera
using UnityEngine;

public class SwapCamera : MonoBehaviour
{
    [SerializeField] private CharacterSwitcher switcher;
    [SerializeField] private Vector3 offset = new Vector3(0f, 12f, -14f);
    [SerializeField] private float smooth = 4f;

    void LateUpdate()                      // after everyone has moved
    {
        Transform target = switcher.ActiveCharacter;
        Vector3 wanted = target.position + offset;

        transform.position = Vector3.Lerp(transform.position, wanted, smooth * Time.deltaTime);
        transform.LookAt(target.position + Vector3.up);
    }
}

いまのリングにできること

  • 平らな床、material、カメラ、ライトを備えた 3D シーン。

  • 手でもループでも量産できるブロックの prefab。

  • 同じ床にいる複数のキャラクターと、その間を行き来する操作権。

  • 次のレッスンではこの上にメニューと音楽をのせますが、中身には触りません。

  • Tab 02 では Knight をその場で進化させます—— GameObject も名前も switcher のスロットもそのままで、モデル・アニメーション・スキル・artifact を備えた本物のキャラクターにします。Mage と Archer は capsule のまま残すので、違いがはっきり分かります。