[Unity] ブロック崩しをあのアプリ風にする #8 ブロックを動かす

前回までで必要なものはある程度揃ったので、適当にブロックを並べるだけでそれなりに遊べると思います。
しかし目的はアプリ風として完結させる事なのでまだ最低限の基盤ができただけにすぎません。ステージセレクトや本家のようにブロックが下がってくる機能などまだまだやることは多いです。

今回はブロックの移動とゲームオーバー判定を作ります。

ブロックを移動させる



1ターン終わるごとにブロックが少し下がってきて下までついたらゲームオーバーです。
長らく放置してきたけどこのシリーズの#2の下の方でブロックを自動生成させるという項目を書きました。それを拡張させていこうと思います。

ヒエラルキーのBlockBornBlockManagerにリネームします。

Block同士の間隔

前回は適当に並べたのでちゃんと計算したいと思います。
今フィールドのサイズは横9、縦16、ブロックが0.8*0.8なので縦には最大20個でぴったり入るけど、横は11個と余りが0.25出ます。(むしろ縦は中途半端でもいい)
この余り0.25を壁とブロックの隙間12箇所に当てようとすると1箇所あたり0.02083...と割り切れません。

なので壁とブロックの間のみ0.125の間隔をあける方向でいきたいと思います。


並べる時はブロックのXを-4.1+0.125と書いてenterを押すと位置を計算してくれるのでcommand + Dで複製、そこから0.8ずつ足していくと楽だと思います。
計算しといてなんですが、見た目で気にならないならそれでも問題ないです

ステージ作成

とりあえず適当にステージを作ってそれらのブロックをWave1という空のオブジェクトに入れてプレハブ化しておきます。この時Wave1のポジションは全て0にしてから追加します。

こんな感じに並べてみました。

BlockManagerスクリプト

Waveの生成と移動の処理です


using System.Collections.Generic;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class BlockManager : MonoBehaviour {

    public GameObject[] waves;
    private GameObject wave;

// ゲームオーバーになるz座標
    private float gameOverLine;

// 危険ラインのz座標
    private float dengerLine;

// ゲームオーバーテキスト
    public Text gameOverText;

// 危険ゾーンテキスト
    public Text dengerText;  

    void Start () {
        BlockSet(0);
        GameObject obj = GameObject.Find ("Bwall");
        gameOverLine = obj.transform.position.z + 
            obj.transform.lossyScale.z/2 + 0.4f;
        dengerLine = gameOverLine + 0.8f;
    }
//〜中略〜

    IEnumerator Move(Vector3 pos){
        while(wave.transform.position.z >= pos.z){
            wave.transform.position -= new Vector3 (0, 0, 0.1f);
            yield return null;
        }
        wave.transform.position = pos;
        CrossOverJodg ();
    }

// 線を超えているか判定
    void CrossOverJodg(){
        bool isDenger = false;
//waveの子要素ブロックを一つずつ取り出す
        foreach (Transform child in wave.transform) {
//gameOverLineより下なら
            if (child.position.z <= gameOverLine) {
                dengerText.enabled = false;
                gameOverText.enabled = true;
                break;
            }
//dengerLineより下なら
            else if (child.position.z <= dengerLine) {
                isDenger = true;
            }
            dengerText.enabled = isDenger;
        }
    }
}


インスペクターからWavesにWave1を登録しておきます。


Start

StartではWaveを作成するメソッドであるBlockSetを呼び出しています。BlockSetは引数に指定された番号のWaveを作成するので、いくつも登録して置いてその都度切り替えます。

MoveBlock

やっていることはボールの集合コルーチンの時と変わりません。 StartCoroutine("Move",pos)の第2引数に移動先座標を持たせて、Moveコルーチンではフレームごとに0.1ずつ下がります。

BallManagerから呼び出せるように修正

BallManagerに追記します。

//〜中略〜
    BlockManager blockManager;

void Start() {
    blockManager = GameObject.Find("BlockManager").GetComponent();
    isShooting = false;
    BallBorn ();
}
//〜中略〜

public void BottomTouch(GameObject ball){
    ball.GetComponent().velocity = Vector3.zero;
    if (returnBall == 0) {
        ballBornPoint.position = ball.transform.position;
    } 
    else {
        StartCoroutine ("setPos",ball);
    }
    returnBall += 1;
    if (returnBall == maxBall) {
        isShooting = false;
        blockManager.MoveBlock ();
    }
}
//〜中略〜

BlockManagerのBlockManagerコンポーネントを取得しておいてボールが全て戻ってきたタイミングでMoveBlockを呼び出してます。


全てのボールが戻ってきた時点でちゃんとブロックが下がってきてます。
それはいいんだけど新たな問題が出てきました。3回目の発射で上に向かって進んでいると思ったらいつの間にか元に戻ってます。

時をすっ飛ばされている

これはすり抜け現象が原因だと思います。

本当は手前のブロックで当たり判定をしないといけないところが、フレームの更新タイミングで1つ上のブロックの位置まで移動してしまうのでそこでも判定が行われて、あらぬ方向に反射してしまいます。もっとひどいとブロックや壁を平気で超えていきます。

すり抜け対策

色々と方法はありますが、今回はFixedUpdateの回数を増やします。

Edit > Project Settings > TimeからFixed Timestepを小さくします。

今ボールのスピードを12に設定してます。何回か試したところ0.05くらいでとりあえず目立つ不自然な動作は改善できたと思います。


しかし完全に対応できるわけではないし、処理が重くなります。この辺は落とし所を探っていく事になりそうです。
ゲームオーバーは次回にします

コメント