ヴァンサバ風ゲームの作り方#1|プロジェクトの準備とスライムちゃんを動かそう

スライムちゃんが8方向に歩き、向きに合わせて絵が変わる様子

移動するだけで武器が勝手に戦ってくれる「ヴァンパイアサバイバーズ」のようなゲーム。作ってみたいけど、何から手を付けたらいいか分からない・・・という人は多いと思います。実はこのジャンル、最初に作るのはプレイヤーの移動だけ。今回はヴァンサバ風サバイバーゲームのシリーズの1回目として、プロジェクトを作って、スライムちゃんを8方向に歩かせて、カメラが追いかけるところまで作ってみたいと思います!

目次

今回作るもの

  • Universal 2Dでプロジェクトを作り、フォルダとシーンを用意する
  • スライムちゃんの絵を取り込む(8方向×3コマ)
  • WASD・矢印キー・ゲームパッドのスティックで動かす
  • 進む向きに合わせて、絵が8方向に切り替わる
  • カメラがスライムちゃんを追いかける

作るスクリプトは2つです。

スクリプト役割付ける場所
PlayerMove入力を受け取って動かすPlayer
PlayerAnimator向きに合わせて絵を切り替えるPlayer

プロジェクトを作ろう

  • Unity Hubで新しいプロジェクトを作る
    • エディターバージョン:Unity 6.3 LTS(記事作成時点では6000.3.22f1で確認しています)
    • テンプレート:Universal 2D
    • プロジェクト名:SurvivorsLike(好きな名前でOK)

プロジェクトが開いたら、先にフォルダとシーンを整えておきます。

  • ProjectウインドのAssetsで右クリック>Create>Folderで「SurvivorsLike」を作る
  • その中に、Scripts・Sprites・Prefabs・Data・Animations・Audio・Scenes の7つのフォルダを作る
  • Assets>Scenes>SampleSceneをGameにリネームして、SurvivorsLike>Scenesに移動する
Assets>SurvivorsLikeの中にScripts・Sprites・Prefabs・Data・Animations・Audio・Scenesが並んでいる

最後に、Gameビューの画面サイズを決めます。このシリーズはPCで遊ぶ横画面のゲームとして作ります。四方から敵が来るジャンルなので、広く見える横画面のほうが遊びやすく、作っている最中も確認しやすいです(最終回ではWindowsのゲームとしてビルドします)。

  • Gameビューの左上の解像度のドロップダウンから16:9 Aspectを選ぶ
    • 実際の大きさで見たいときは、同じドロップダウンの+からFull HD(1920×1080)を足しておくと切り替えられます

スマホ向けの縦画面の作り方はペット育成ゲームのシリーズで紹介しています。このシリーズを作り終えてからスマホ対応をする場合も、画面の作り方はそちらが参考になります。

スライムちゃんの絵を取り込もう

シリーズで使う素材(スライムちゃん・敵・調理器具・床のタイル)は、下のリンクからまとめてダウンロードしてください。全11回ぶんが入っているので、最初の1回だけで大丈夫です。

取り込み方は2つあります。

  • かんたん:zipの中のSurvivorsLikeAssets.unitypackageをダブルクリック(またはAssets>Import Package>Custom Package…)
    • 取り込みの設定が入った状態で入るので、次の「取り込みの設定をしよう」は読むだけでOKです
  • 自分で入れる:zipの中のSurvivorsLikeフォルダを、UnityのAssetsにドラッグ&ドロップ
    • この場合は、次の「取り込みの設定をしよう」のとおりに自分で合わせてください

素材は自由に使ってOKです(クレジット不要。作ったゲームの公開・販売にも使えます)。素材そのものの再配布はご遠慮ください。

今回使うのはSurvivorsLike/Sprites/Slimeの中の27枚です。walk_11.pngからwalk_93.pngまで入っています。

ファイル名は「walk_(方向)(コマ番号)」です。方向はテンキーの並びと同じで、1が左下、2が下、9が右上になっています。

左まんなか右
上7 左上8 上9 右上
横4 左5 正面6 右
下1 左下2 下3 右下

向きは8方向です。まんなかの5は「どちらにも動いていないとき」で、中身は2(下)と同じ絵が入っています。テンキーの並びに合わせて番号を振っているので、5番も用意されている、という形ですね。

コマ番号は1〜3の3枚です。

取り込みの設定をしよう

27枚まとめて設定します。

  • ProjectウインドでSlimeフォルダを開き、walk_11をクリック → 一番下のwalk_93をShift+クリック(27枚すべて選択)
  • Inspectorで次のように設定して、Apply
項目値
Texture TypeSprite (2D and UI)
Sprite ModeSingle
Pixels Per Unit200
PivotCustom(X:0.5、Y:0.2)
27枚を選んだ状態のInspector。Sprite ModeがSingle、Pixels Per Unitが200、PivotがCustomの0.5/0.2
  • Pixels Per Unit:200
    • 「何ピクセルを1マス(1ユニット)とするか」の設定。絵が200×200ピクセルなので、200にするとスライムちゃんがちょうど1マスの大きさになる
    • このシリーズでは、敵も床のタイルも200ピクセルでそろえてあります
  • Pivot:Custom(0.5, 0.2)
    • 絵の中の「ここが位置の基準」という点。真ん中(0.5, 0.5)のままだと、体の中心が基準になってしまう
    • 高さの2割ぐらいの位置にすると、足元が基準になります。後から敵や影を足すときに、立っている場所がそろって見えます

スライムちゃんを置こう

  • Projectウインドからwalk_21.png(正面の1コマ目)を、Hierarchyにドラッグ&ドロップ
  • 名前を「Player」にリネーム
  • Transformの Position を (0, 0, 0) にする

ドラッグしただけで、Sprite Rendererが付いたゲームオブジェクトが出来ます。

次に、動かすための部品を足します。

  • Playerを選んで、Add Component>Rigidbody2D
    • Gravity Scale:0(見下ろし型なので落ちてほしくない)
    • Constraints>Freeze Rotation:Z にチェック(敵にぶつかってもクルクル回らないように)
    • Collision Detection:Continuous(速く動いても壁をすり抜けないように)
  • Add Component>Circle Collider 2D
    • Offset Y:-0.25、Radius:0.2(足元に小さく置く)
PlayerのInspector。Sprite Renderer、Rigidbody 2D(Gravity Scale 0、Collision Detection Continuous)、Circle Collider 2D

当たり判定は、絵の全体ではなく足元に小さく置くのが見下ろし型の定番です。絵をまるごと囲んでしまうと、頭の上をかすめただけで「当たった」ことになってしまいます。

ColliderとRigidbodyについては3-4 ColliderとRigidbodyで紹介しています。

入力で動かそう(PlayerMove)

入力にはInput Systemを使います。6-7 Input Systemの記事のとおり、先に準備をしておきましょう。

  • ProjectウインドでAssets>Settings>InputSystem_Actionsを1回クリック
    • Universal 2Dのテンプレートでは、Assetsの直下ではなくSettingsフォルダの中に入っています
  • InspectorのGenerate C# Classにチェックを入れて、Apply

これで、最初から入っているMoveアクション(WASD・矢印キー・スティック)をスクリプトから使えます。

  • SurvivorsLike>Scriptsで右クリック>Create>MonoBehaviour Script で「PlayerMove」を作り、中身を次のように書き換える
using UnityEngine;

// スライムちゃんを、入力の方向に動かす
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerMove : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 5f; // 1秒に進むマス数

    private InputSystem_Actions inputActions;
    private Rigidbody2D body;
    private Vector2 moveInput;

    // ほかのスクリプトから「今どっちに動いているか」を読めるようにしておく(下のPlayerAnimatorで使います)
    public Vector2 MoveInput => moveInput;

    private void Awake()
    {
        inputActions = new InputSystem_Actions();
        body = GetComponent<Rigidbody2D>();
    }

    private void OnEnable()
    {
        inputActions.Enable();
    }

    private void OnDisable()
    {
        inputActions.Disable();
    }

    private void Update()
    {
        moveInput = inputActions.Player.Move.ReadValue<Vector2>();

        // 斜めが速くならないように、長さを1までに抑える
        if (moveInput.sqrMagnitude > 1f)
        {
            moveInput = moveInput.normalized;
        }
    }

    private void FixedUpdate()
    {
        body.linearVelocity = moveInput * moveSpeed;
    }
}
PlayerMoveのポイント
  • [RequireComponent(typeof(Rigidbody2D))]
    • このスクリプトを付けると、Rigidbody2Dが無ければ自動で付く。付け忘れの事故を防げます
  • Awake / OnEnable / OnDisable
    • Input Systemのお決まりの形。Enable()を忘れると入力が一切来ません
  • 斜めの速さ
    • キーボードで右と上を同時に押すと、入力は(1, 1)になります。そのまま使うと斜めだけ約1.4倍速くなってしまう
    • normalizedで長さを1にそろえると、どの向きでも同じ速さになります
  • body.linearVelocity
    • Rigidbody2Dの速度。「1秒にどれだけ進むか」を直接指定しています
  • Update と FixedUpdate
    • 入力を読むのはUpdate(毎フレーム)、物理で動かすのはFixedUpdate(一定間隔)。これが2Dアクションの定番の分け方です

Rigidbody2Dの速度の名前が変わっています

Unity 6からvelocityがlinearVelocityになりました。古い記事のコードをそのまま貼ると赤くなるので、velocityと書いてあったら読み替えてください。

速さの決め方

moveSpeedの5は「1秒に5マス進む」という意味です。画面には横に約18マスぶんが映るので、画面の端から端まで3.5秒ぐらい。

  • 速すぎると敵から簡単に逃げ切れてしまい、緊張感がなくなる
  • 遅すぎると囲まれたときに何も出来ない

このジャンルは「ギリギリで逃げ回る」のが気持ちいいので、後で敵の速さ(#3で1.5)と比べながら調整します。

付けて動かしてみよう

  • Playerを選んで、Add Component>PlayerMove
  • 再生(▶)して、WASDや矢印キーを押す

スライムちゃんが上下左右に動けばOKです!ただ、今はどっちに歩いても正面の絵のまま。次でここを直します。

8方向の絵を切り替えよう(PlayerAnimator)

進む向きから「テンキーのどの数字か」を求めて、その方向の3枚をパラパラ切り替えます。

  • SurvivorsLike>Scriptsに「PlayerAnimator」を作る
using UnityEngine;

// 進む向きから8方向の絵を選んで、パラパラ動かす
public class PlayerAnimator : MonoBehaviour
{
    [SerializeField] private PlayerMove playerMove;
    [SerializeField] private SpriteRenderer spriteRenderer;
    [SerializeField] private Sprite[] walkSprites;          // walk_11〜walk_93 の27枚
    [SerializeField] private float secondsPerFrame = 0.15f; // 1コマを何秒見せるか

    // 1コマ目→2コマ目→3コマ目→2コマ目 の順に見せると、足の運びが自然につながる
    private static readonly int[] FrameOrder = { 0, 1, 2, 1 };

    private int direction = 2; // 最後に向いていた方向(テンキーの並び。2は正面)
    private int orderIndex;
    private float timer;

    private void Update()
    {
        Vector2 input = playerMove.MoveInput;

        if (input == Vector2.zero)
        {
            // 止まっているときは1コマ目で立ち止まる
            orderIndex = 0;
            timer = 0f;
        }
        else
        {
            direction = DirectionFrom(input);

            timer += Time.deltaTime;
            if (timer >= secondsPerFrame)
            {
                timer -= secondsPerFrame;
                orderIndex = (orderIndex + 1) % FrameOrder.Length;
            }
        }

        spriteRenderer.sprite = walkSprites[(direction - 1) * 3 + FrameOrder[orderIndex]];
    }

    // 入力の向きを、テンキーの並びの数字(1〜9)にする
    private static int DirectionFrom(Vector2 input)
    {
        return 5 + Axis(input.x) + Axis(input.y) * 3;
    }

    // -1(左・下)/0(まんなか)/1(右・上)のどれかにする
    private static int Axis(float value)
    {
        if (value > 0.4f)
        {
            return 1;
        }
        if (value < -0.4f)
        {
            return -1;
        }
        return 0;
    }
}
PlayerAnimatorのポイント
  • テンキーの並びを数字の計算にする
    • まんなかが5。右に1つで+1、上に1つで+3
    • 右上なら 5+1+3=9、左下なら 5−1−3=1。画像のファイル名とそのまま一致します
  • Axisの0.4
    • スティックを少しだけ倒したときに、向きがガタガタ切り替わらないようにするための境目
    • どちらにもあまり倒れていないときは5(正面)になります。5の絵は2(下)と同じ絵なので、これで自然に見えます
  • FrameOrder = { 0, 1, 2, 1 }
    • 1→2→3→2の順。3コマしか無くても、行って戻ることで4コマぶんの動きになります
    • 1→2→3→1→2→3 だと、3から1に戻るときにカクッとします
  • (direction - 1) * 3 + FrameOrder[orderIndex]
    • 27枚を「方向ごとに3枚ずつ」並べた一覧から、何枚目かを計算しています
    • 方向2の1コマ目なら (2−1)×3+0 = 4枚目(0から数えて3番)、つまりwalk_21
  • 止まったときは向きを変えない
    • 入力が無いときはdirectionを書き換えないので、最後に歩いていた向きのまま1コマ目で立ち止まります
  • Animatorを使わないのはなぜ?
    • 8方向ぶんのアニメーションクリップを作ると、それだけで8個。さらに止まっているときの絵も足すと管理が大変になります
    • 今回のように「絵を差し替えるだけ」なら、スクリプトのほうがずっと短く済みます。Animatorを使ったやり方は12-2 アニメーションで紹介しています

付けて、27枚を渡そう

  • Playerを選んで、Add Component>PlayerAnimator
  • Player Move:Player(自分自身)をドラッグ
  • Sprite Renderer:Player(自分自身)をドラッグ
  • Walk Sprites:ProjectウインドでSlimeフォルダの27枚をすべて選択して、InspectorのWalk Spritesの文字の上にドラッグ&ドロップ
    • 27個の枠が一気に埋まります。walk_11から順番に並んでいるかを確認してください(順番がずれると、向きと絵が合わなくなります)
PlayerのPlayer Animator。Player MoveとSprite RendererにPlayerが入り、Walk Spritesが27枚

再生して歩き回ると、向きに合わせて絵が切り替わります!

カメラがついてくるようにしよう

このままだと、スライムちゃんが画面の外に出て行ってしまいます。Cinemachineでカメラに追いかけてもらいましょう。

  • Window>Package Managerを開く
  • 左上の+>Install package by name… に com.unity.cinemachine と入力してInstall
    • Unity Registryから「Cinemachine」を探してInstallでもOKです

入ったら、カメラを置きます。

  • メニューのGameObject>Cinemachine>Targeted Cameras>2D Camera
  • 出来たCinemachineCameraを選んで、Inspectorで設定
    • Tracking Target:Playerをドラッグ
    • Lens>Orthographic Size:5(縦に10マスぶんが映る)
CinemachineCameraのInspector。Tracking TargetにPlayer、LensのOrthographic Sizeが5
スライム

昔の記事だと「Follow」って書いてあるんですが・・・

フェアリー

Cinemachine 3から名前が変わってTracking Targetになったんだ。2系の記事を見ながらだと迷うから気をつけてね

Main CameraにはCinemachineBrainが自動で付きます。これが「Cinemachineのカメラの言うとおりにMain Cameraを動かす」係です。

ぴったり付いてこない場合は、CinemachineCameraに付いているPosition ComposerのDampingを小さくすると、ぴたっと追いかけます。少し遅れて付いてくるほうが動きが柔らかく見えるので、好みで調整してください。

動かして確認!

再生して、次の4つを確認しましょう。

#1の動作確認

  • WASD・矢印キー・ゲームパッドのスティックで動く
  • 斜めに歩いても、まっすぐ歩くときと速さが変わらない
  • 8方向で絵が変わり、止まると最後に向いていた方向のまま立ち止まる
  • カメラがスライムちゃんを追いかける
スライム

まだ何も無い真っ青な場所を歩いているだけですけど・・・

フェアリー

動かせるようになったのが一番大きい一歩だよ!次はここをお菓子工房にしようね

あとがき

今回はプロジェクトを作って、スライムちゃんを8方向に動かして、カメラが追いかけるところまで作りました。背景は真っ青なままですが、操作出来るものが画面にいるというのは、ゲーム作りの中でいちばん嬉しい瞬間かもしれません。次回はTilemapでお菓子工房の床を作って、外に出られないように囲みたいと思います!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (1件)

コメントする

目次