絶対に完成させるゲーム制作#3|壁を置いて、歩くすがたを付けよう

生け垣で区切られた夜の芝生を、スライムちゃんが上・右・下・右・上と向きを変えながら歩く。壁にぶつかるたびに、ぽよんとつぶれて戻り、最後は扉に入ってエンディングへ

前回は、タイトルとエンディングの間にステージをはさんで、扉に入ったらクリアできるようにしました。でも、まっすぐ扉に向かえば終わってしまうし、スライムちゃんはずっと正面を向いたまま・・・。今回は、生け垣の壁で迷路を作り、歩く向きに合わせてスライムちゃんの絵を切り替えます。さらに、壁にぶつかったら「ぽよん」とつぶれる演出も付けますよ!

目次

今回作るもの

今回のゲームの流れ。「タイトル」から「はじめる」で「ステージ」へ、「扉に入る」で「エンディング」へ、「タイトルへ」でタイトルに戻る。流れは前回と同じで、「ステージ」の中に壁の迷路・歩く向き・ぽよんを足す

ゲームの流れは前回と同じです。今回は、ステージの中身だけを足していきます。

  • 生け垣の壁をプレハブにして、迷路を作る
  • 歩く向き(上下左右)に合わせて、スライムちゃんの絵を切り替える
  • 壁にぶつかると、ぽよんとつぶれてから元に戻る

作るスクリプトは2つ、前回までのスクリプトに1つメソッドを足します。

スクリプト役割付ける場所
PlayerFacing動いている向きで、歩くコマを切り替えるスライムちゃん
SquashOnBump壁にぶつかったら、ぽよんとつぶれるスライムちゃん
FrameAnimation(#1で作ったもの)コマを入れかえるメソッドを足す-

生け垣の壁を作ろう

芝生の上に生け垣を3つ並べた比べ。上はそのままの1×1。真ん中はScaleのXを4にしたもので、生け垣の絵が横に引き伸ばされている。下はDraw ModeをTiledにしてSizeを4×1にしたもので、生け垣が4つきれいに並んでいる

迷路の壁には、Sprites/Itemsのhedge(生け垣)を使います。1マス(100×100ピクセル)の絵なので、そのままだと小さな四角が1つだけです。

長い壁にしたいとき、Scaleで伸ばすと、上の図の真ん中のように絵まで引き伸ばされてしまいます。そこで、Sprite RendererのDraw ModeをTiledにします。Tiledにすると、Sizeを大きくしたぶんだけ、同じ絵がタイルのように並びます。

生け垣の絵を、並べられるようにしよう

hedgeを選んだInspector(Import Settings)。Mesh TypeがFull Rectになっていて、右下にApplyのボタン

Tiledで並べる絵は、取り込みの設定を1つ変えておきます。

  • ProjectウインドでSprites/Itemsのhedgeを選ぶ
  • InspectorのMesh TypeをFull Rectにして、Apply

Mesh TypeがTightのままだと、Tiledにしたときに絵の並び方がくずれます(Inspectorに注意のメッセージも出ます)。Tightは、絵の透明なところを切り落として形を作る設定なので、四角いタイルとして並べられないためです。

壁の形を作ろう

WallのInspector。Sprite RendererのSpriteがhedge、Draw ModeがTiled、SizeのWidthとHeightが1、Order in Layerが-1

Stage1シーンを開いて、壁を1つ作ります。

  • hedgeをHierarchyにドラッグ&ドロップして、名前をWallにする
  • Sprite Renderer
    • Draw Mode:Tiled
    • Size:(1, 1)のまま
    • Order in Layer:-1
  • Add ComponentでBox Collider 2Dを付けて、Auto Tilingにチェック

Auto Tilingにチェックを入れると、当たり判定の大きさがSprite RendererのSizeに合わせて、自動で変わります。壁を長くするたびに、当たり判定を直さなくてよくなります。

Order in Layerを-1にしておくと、スライムちゃん(3)より後ろに描かれます。上から見たゲームでは、スライムちゃんの髪が少し壁に重なることがありますが、そのときもスライムちゃんが手前に見えます。

プレハブにしよう

ProjectウインドのAssets/CompleteGame/Prefabsフォルダに、青い箱のアイコンのWallが出来ている

この壁を、何個でも置けるようにプレハブにします。

  • CompleteGameフォルダの中にPrefabsフォルダを作る
  • HierarchyのWallを、Prefabsフォルダにドラッグ&ドロップ
  • Hierarchyに残ったWallは、消しておく(次の節で、プレハブから置き直します)

プレハブは、ゲームオブジェクトの「型」です。型を1つ作っておけば、同じ壁をいくつでも置けます。あとで生け垣の色を変えたくなっても、プレハブを直せば、置いた壁が全部まとめて変わります。くわしくは7-1 プレハブの基本概念と作成方法で紹介しています。

迷路を作ろう

Stage1シーンを開いたエディタ。HierarchyのWallsの下に、WallTop・WallBottom・WallLeft・WallRight・Wall1・Wall2・Wall3。Gameビューに、生け垣で囲まれた芝生と、中に縦の壁2本と横の壁1本。左下にスライムちゃん、右上に扉

プレハブを並べて、迷路にします。

  • Hierarchyで右クリック>Create Emptyで、空のゲームオブジェクトを作り、名前をWallsにする(Positionは0, 0, 0)
  • PrefabsフォルダのWallを、Wallsの上にドラッグ&ドロップして、子にする
  • 下の表のとおりに、名前・Position・Sprite RendererのSizeを変える
  • 7つ置き終わるまで、くり返す
名前PositionSize
WallTop(0, 5)(20, 1)
WallBottom(0, -5)(20, 1)
WallLeft(-9.5, 0)(2, 9)
WallRight(9.5, 0)(2, 9)
Wall1(-4, -1.5)(1, 6)
Wall2(2, 1.5)(1, 6)
Wall3(4, 0)(3, 1)

上の4つが画面のまわりを囲む壁、Wall1〜3が迷路の中の壁です。WallLeftとWallRightは、画面の端にすき間が出来ないように、半分ほど画面の外にはみ出させています。

Wall1のInspector。上にPrefabのWall。TransformのPositionが-4, -1.5, 0、Sprite RendererのDraw ModeがTiledでSizeが1, 6、Order in Layerが-1。Box Collider 2DのAuto Tilingにチェック

再生すると、スライムちゃんが壁で止まるようになります。前回は画面の外まで歩いていけましたが、もう迷子にはなりません。

スライム

壁があるだけで、急に「ステージ」っぽくなりましたね!

壁にぶつかって止まるのは、スライムちゃんのRigidbody 2DとCircle Collider 2D、壁のBox Collider 2Dのおかげです。壁にはRigidbody 2Dを付けていないので、押しても動かない「動かない壁」になります。ColliderとRigidbodyの関係は、3-4 当たり判定とPhysics:ColliderとRigidbodyで紹介しています。

向きで絵を替えよう

スライムちゃんの歩くコマを4段に並べた図。下はslime_walk_21・22・23・22、左は41・42・43・42、右は61・62・63・62、上は81・82・83・82。上の段は後ろ姿

今のスライムちゃんは、どっちに歩いても正面を向いたままです。素材には、上下左右の4つの向きの歩くコマが入っているので、動いている向きに合わせて、使うコマを切り替えます。

番号の十の位が向き(2が下、4が左、6が右、8が上)、一の位がコマです。どの向きも、#1のタイトルと同じく1 → 2 → 3 → 2の順に並べます。

FrameAnimationにコマの入れかえを足そう

#1で作ったFrameAnimationは、決めたコマを順番に出すだけでした。ここに、コマを入れかえるメソッドを足します。一番下のSetFramesが、今回足すところです。

using UnityEngine;

// 絵(コマ)を順番に切り替えて、パラパラまんがのように動かす
public class FrameAnimation : MonoBehaviour
{
    [SerializeField] private Sprite[] frames;               // 出す順番に並べたコマ
    [SerializeField] private float secondsPerFrame = 0.15f; // 1コマを出す時間

    private SpriteRenderer spriteRenderer;
    private int frameIndex;
    private float timer;

    private void Start()
    {
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    private void Update()
    {
        timer += Time.deltaTime;
        if (timer < secondsPerFrame)
        {
            return;
        }
        timer -= secondsPerFrame;
        frameIndex = (frameIndex + 1) % frames.Length;
        spriteRenderer.sprite = frames[frameIndex];
    }

    // コマを入れかえる(今と同じコマなら何もしない)
    public void SetFrames(Sprite[] newFrames)
    {
        if (frames == newFrames)
        {
            return;
        }
        frames = newFrames;
        frameIndex = 0;
        timer = 0f;
        spriteRenderer.sprite = frames[frameIndex];
    }
}
  • frames == newFrames
    • 今使っているコマと同じなら、何もしない。同じ向きに歩いている間は毎フレーム呼ばれるので、ここで止めないと、ずっと1コマ目に戻されて動かなくなる
  • frameIndex = 0とtimer = 0f
    • 向きが変わったら、新しい向きの1コマ目から出し直す

PlayerFacingを作ろう

ScriptsフォルダにPlayerFacingを作ります。

using UnityEngine;

// 動いている向きに合わせて、歩くコマ(上下左右の4つ)を切り替える
public class PlayerFacing : MonoBehaviour
{
    [SerializeField] private Sprite[] downFrames;  // 下に歩くコマ
    [SerializeField] private Sprite[] leftFrames;  // 左に歩くコマ
    [SerializeField] private Sprite[] rightFrames; // 右に歩くコマ
    [SerializeField] private Sprite[] upFrames;    // 上に歩くコマ

    private Rigidbody2D rb;
    private FrameAnimation frameAnimation;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        frameAnimation = GetComponent<FrameAnimation>();
    }

    private void Update()
    {
        Vector2 velocity = rb.linearVelocity;
        // 止まっているときは、最後に向いていた向きのまま
        if (velocity.magnitude < 0.1f)
        {
            return;
        }
        // 左右と上下で、大きく動いている方の向きにする
        if (Mathf.Abs(velocity.x) > Mathf.Abs(velocity.y))
        {
            if (velocity.x > 0f)
            {
                frameAnimation.SetFrames(rightFrames);
            }
            else
            {
                frameAnimation.SetFrames(leftFrames);
            }
        }
        else
        {
            if (velocity.y > 0f)
            {
                frameAnimation.SetFrames(upFrames);
            }
            else
            {
                frameAnimation.SetFrames(downFrames);
            }
        }
    }
}
  • rb.linearVelocity
    • 今の速さと向き。入力ではなく「実際に動いている向き」を見るので、PlayerMoveは1行も変えずにすむ
  • velocity.magnitude < 0.1f
    • ほとんど止まっているときは、向きを変えない。手を離したときに、最後の向きのまま止まる
  • Mathf.Abs(velocity.x) > Mathf.Abs(velocity.y)
    • 斜めに歩いているときは、左右と上下の大きい方の向きにする。Mathf.Absは、マイナスを取った大きさ
PlayerのInspectorで、Player Facingを開いたところ。Down Framesにslime_walk_21・22・23・22、Left Framesに41・42・43・42、Right Framesに61・62・63・62、Up Framesに81・82・83・82

PlayerにPlayerFacingを付けて、4つの配列にコマを入れます。

  • Down Frames:slime_walk_21、22、23、22
  • Left Frames:slime_walk_41、42、43、42
  • Right Frames:slime_walk_61、62、63、62
  • Up Frames:slime_walk_81、82、83、82

Projectウインドでコマを3枚選んで、配列の名前(Down Framesなど)の上にドラッグ&ドロップすると、3つまとめて入ります(入った順番が1 → 2 → 3になっているか、確かめてください)。そのあと+で4つ目を足して、2コマ目をもう1回入れると早いです。

再生して矢印キーで歩くと、歩く向きにスライムちゃんが向きを変えます。上に歩くと、ちゃんと後ろ姿になりますよ。

Unityには、Animator(アニメーションの状態をつなぐ仕組み)もありますが、このシリーズでは使いません。向きが4つだけなら、コマを入れかえるスクリプトの方が、何が起きているかを追いやすいからです。Animatorは12-2 アニメーションを付けよう:AnimationとAnimatorで紹介しています。

ぶつかったらぽよん

下の壁にぶつかる瞬間を3コマ並べたもの。スライムちゃんが下の生け垣に向かって歩く → 横に広がってぺちゃんとつぶれる → 元の形に戻る

壁で止まるようにはなりましたが、ぶつかったときに何も起きないと、ちょっとさみしいですよね。そこで、壁にぶつかった瞬間に、スライムちゃんをぽよんとつぶして、元に戻します。

  • 上下の壁にぶつかったら、横に広がって、縦につぶれる
  • 左右の壁にぶつかったら、縦に伸びて、横につぶれる

ぶつかった向きでつぶれ方を変えると、「ぶつかった!」という手応えがはっきり出ます。

SquashOnBumpを作ろう

ScriptsフォルダにSquashOnBumpを作ります。

using System.Collections;
using UnityEngine;

// 壁にぶつかったら、ぽよんとつぶれてから元の形に戻る
public class SquashOnBump : MonoBehaviour
{
    [SerializeField] private float minBumpSpeed = 2f;     // これより遅くぶつかったときは、つぶれない
    [SerializeField] private float squashSeconds = 0.08f; // つぶれるまでの時間
    [SerializeField] private float returnSeconds = 0.2f;  // 元の形に戻るまでの時間

    private Vector3 baseScale;

    private void Start()
    {
        baseScale = transform.localScale;
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.relativeVelocity.magnitude < minBumpSpeed)
        {
            return;
        }
        // 横の壁なら横に、上下の壁なら縦につぶれる
        Vector2 normal = collision.GetContact(0).normal;
        Vector3 squashScale;
        if (Mathf.Abs(normal.x) > Mathf.Abs(normal.y))
        {
            squashScale = Vector3.Scale(baseScale, new Vector3(0.7f, 1.25f, 1f));
        }
        else
        {
            squashScale = Vector3.Scale(baseScale, new Vector3(1.25f, 0.7f, 1f));
        }
        StopAllCoroutines();
        StartCoroutine(Squash(squashScale));
    }

    private IEnumerator Squash(Vector3 squashScale)
    {
        yield return ChangeScale(transform.localScale, squashScale, squashSeconds);
        yield return ChangeScale(squashScale, baseScale, returnSeconds);
    }

    // from の大きさから to の大きさへ、seconds 秒かけて変える
    private IEnumerator ChangeScale(Vector3 from, Vector3 to, float seconds)
    {
        float time = 0f;
        while (time < seconds)
        {
            time += Time.deltaTime;
            transform.localScale = Vector3.Lerp(from, to, time / seconds);
            yield return null;
        }
        transform.localScale = to;
    }
}
  • OnCollisionEnter2D
  • collision.relativeVelocity
    • ぶつかったときの速さ。壁ぞいにそっと触れただけでつぶれないように、minBumpSpeedより遅いときは何もしない
  • collision.GetContact(0).normal
    • ぶつかった面の向き。横を向いていれば左右の壁、縦を向いていれば上下の壁
  • Vector3.Scale
    • x・y・zをそれぞれかけ算する。元の大きさ(0.8)に対して、横1.25倍・縦0.7倍のようにつぶす
  • ChangeScale
    • 前回のScreenFlashのChangeColorと同じ形。色の代わりに大きさを、Lerpで少しずつ変える。一度覚えた形は、いろいろな演出に使い回せます
PlayerのInspector。Player Move・Player Facingの下にSquash On Bump。Min Bump Speedが2、Squash Secondsが0.08、Return Secondsが0.2

PlayerにSquashOnBumpを付けたら、再生して壁にぶつかってみましょう。

右に歩いてきたスライムちゃんが縦の生け垣にぶつかり、横がきゅっと細くなって縦に伸びてから、元の形に戻る
フェアリー

つぶれるのは0.08秒で一瞬、戻るのは0.2秒でゆっくり。前回のキラッと同じで、速さに差を付けるのがコツね!

完成チェック

タイトルでEnterを押すとステージへ。生け垣の迷路を、向きを変えながら上・右・下・右・上と歩き、壁にぶつかるたびにぽよんとつぶれる。扉に入ると白く光って暗くなり、エンディングへ。Enterで「タイトルへ」を押すとタイトルに戻る。右下に押したキーが出る

Titleシーンを開いて再生し、最初から最後まで通して遊びます。

  • 「はじめる」を押すと、生け垣の迷路のステージに切りかわる
  • スライムちゃんが壁を通りぬけず、画面の外にも出ない
  • 上下左右に歩くと、その向きの絵に切りかわる(上は後ろ姿)
  • 壁にぶつかると、ぽよんとつぶれて元に戻る
  • 扉に入ると、白く光ってからエンディングへ。「タイトルへ」でタイトルに戻る

今回も、タイトルからエンディングまで、ちゃんと遊べる形のままです。ステージが迷路になったぶん、扉にたどり着いたときのうれしさも増えました。

ビルドして遊ぼう

Build ProfilesでWindowsがActive。Scene ListにTitle・Stage1・Endingの3つが入っていて、右下にBuildのボタン

前回と同じように、ビルドして.exeで遊びます。

  • File>Build Profilesを開いて、Buildを押す
  • 前回と同じBuild/StarGardenのフォルダを選ぶ(上書きしてOK)
  • 出来たStarGarden.exeを起動して、迷路を抜けて扉までたどり着けるか遊んでみる

今回はシーンを増やしていないので、Scene Listはそのままで大丈夫です。

Stage1シーンを保存(Ctrl+S)してからビルドしましょう。保存していない変更は、ビルドしたゲームに入りません。壁を置いたのに.exeでは壁が無い、というときは、まず保存を確かめてください。

あとがき

今回は、生け垣の壁をプレハブにして迷路を作り、スライムちゃんが歩く向きに合わせて絵を替えて、壁にぶつかったら「ぽよん」とつぶれるようにしました。新しく作ったスクリプトは2つだけですが、動かしたときの気持ちよさは、前回とはずいぶん違うと思います。

次回は、いよいよ星を置きます。星を全部集めないと、扉が開かないようにして、取ったときにはキラキラと「+1」が出る演出も付けますよ!

スライム

迷路の中を歩くの、ちょっとクセになってきました・・・。ぶつかるのも、わざとやりたくなりますね!

フェアリー

ぽよんが楽しくなったら、手応えの演出は成功ね!次は星を集めて、扉を開けにいこう!

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

コメント

コメント一覧 (1件)

コメントする

目次