ぬるーむ

Unity初心者が誰もが知っているゲームの模倣をしています。個人的な備忘録ですが、入門書を読み終えたばかりの初心者の方は「こんなへなちょこでもいいのか!」「俺の方がうまく作れる」と作成意欲がわいたりするかもしれません。

Unityでぷよぷよを作ってみた 2


スポンサードリンク

ぷよの自由落下

毎フレーム、状態がFreeFallのとき以下の処理を行う。

  1. 落下可能なぷよを取得し、落下可能リストに追加する。
  2. 落下可能リストにあるぷよを下にあるものから順番に自由落下させる。
  3. ぷよが落下できなくなったら、そのぷよの落下可能フラグを消す。
  4. 落下可能リストから落下可能フラグの無いものを全て消す。
  5. 落下可能リストにぷよが残っていたら2へ戻り、空だったら状態をVanishに遷移させる。
落下可能ぷよの取得
private static readonly int width = 6;
private static readonly int height = 14;
private static readonly Puyo[,] field = new Puyo[width, height];

//空白の上にあるすべてをぷよを取得
public List<Puyo> GetDroppablePuyoes()
{
    var list = new List<Puyo>();

    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            if (field[x, y] == null)
            {
                PickDroppablePuyoes(x, y, list);
                break;
            }
        }
    }

    return list;
}

//空白の上にあるぷよを一列取得し、ぷよのあった部分を空白にする
private void PickDroppablePuyoes(int x, int y, List<Puyo> list)
{
    for (int i = y + 1; i < height; i++)
    {
        var p = field[x, i];

        if (p != null)
        {
            p.Droppable = true;
            list.Add(p);
            field[x, i] = null;
        }
    }
}
private static List<Puyo> droppablePuyoes = new List<Puyo>();
private enum State { Normal, FreeFall, Vanish, Wait }

private void Update()
{
    switch (state)
    {
        case State.Normal:
            CheckInput();
            mover.Fall(speed);

            if (!mover.CanMove())
            {
                isDelaying = true;
                delayCount--;

                //上へずらす
                mover.AdjustToAbove();

                if (delayCount < 0)
                {
                    //ぷよの固定
                    field.Fix();

                    //落下可能なぷよを取得
                    droppablePuyoes = field.GetDroppablePuyoes();
                    
                    //FreeFallへ遷移
                    state = State.FreeFall;
                }
            }
            else
            {
                isDelaying = false;
            }

            break;

        case State.FreeFall:
            //自由落下処理
            break;

        case State.Vanish:
            //ぷよ消去処理
            break;

        case State.Wait:
            //待機中
            break;
    }
}
自由落下

BaseMoverを継承したSingleMoverでぷよを自由落下させる。

public class SingleMover : BaseMover
{
    public override bool CanMove()
    {
        var x = Mathf.RoundToInt(transform.position.x);
        var cy = Round4thDecimalPlace(transform.position.y);
        var y = Mathf.FloorToInt(cy);

        if (!field.IsInside(x, y)) return false;

        if (field[x, y] != null) return false;

        return true;
    }

    //小数第4位で四捨五入
    private float Round4thDecimalPlace(float n)
    {
        return (float)(Math.Round(n * 1000, MidpointRounding.AwayFromZero)) / 1000;
    }
}
public class Puyo : MonoBehaviour
{
    private readonly static float acceleration = 0.25f;
    private static Field field;
    private SingleMover mover;
    private float speed;

    public PuyoColor Color { get; private set; }
    public float X { get => transform.position.x; }
    public float Y { get => transform.position.y; }
    public int IntX { get => Mathf.RoundToInt(transform.position.x); }
    public int IntY { get => Mathf.RoundToInt(transform.position.y); }
    public bool Droppable { get; set; }
    public bool Checked { get; set; }

    public void Setup(Field field)
    {
        Puyo.field = field;
        mover.Setup(field);

        speed = acceleration;
    }

    //自由落下
    public void FreeFall()
    {
        //フレーム毎に速度を上げる。最大1まで。
        speed = Math.Min(speed += acceleration, 1f);
        mover.Fall(speed);

        if (!mover.CanMove())
        {
            mover.AdjustToAbove();
            Fix();
            //落下できなくなったら、フラグを消す
            Droppable = false;
        }
    }

    public bool CanMove()
    {
        return mover.CanMove();
    }

    public void Fix()
    {
        if (field[IntX, IntY] != null)
        {
            Debug.Log(X + ", " + Y);
            throw new Exception("block overlap");
        }

        field[IntX, IntY] = this;
    }

    private void Awake()
    {
        mover = GetComponent<SingleMover>();
        Color = puyoColor;
    }
}
private enum State { Normal, FreeFall, Vanish, Wait }

private void Update()
{
    switch (state)
    {
        case State.Normal:
            //落下、移動、回転、固定などの処理
            break;

        case State.FreeFall:
            //落下可能なぷよを下にあるものから順に落下させる
            droppablePuyoes.OrderBy(p => p.IntY).ToList<Puyo>()
                .ForEach(p => p.FreeFall());

            //落下できなくなったぷよは全てリストから消す
            droppablePuyoes.RemoveAll(p => !p.Droppable);

            if (droppablePuyoes.Count == 0)
            {
                //Vanishへ遷移
                state = State.Vanish;
            }

            break;

        case State.Vanish:
            //ぷよ消去処理
            break;

        case State.Wait:
            //待機中
            break;
    }
}