ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

【Unity】「ProBuilder Basic」を使ったシンプルなステージ作成

time 2016/06/21

というわけで、今回はステージ作成についてのお話です。
アセット「ProBuilder Basic」を使ってみました!

https://www.assetstore.unity3d.com/jp/#!/content/11919

旧名では「Prototype」と呼ばれていたそうです。
所謂エディタ拡張系のものですが、非常によくできていて使いやすかったです。

ProBuilderに手を出した経緯

今までステージ作成は Terrain と Blender を組み合わせて行っていました。
・・・が、

・Unity と Blender を交互に操作する必要がある
・Blender 側を変えると Unity 側でリインポートするため、微調整だけでも時間が掛かる
・たまに Blender 側の変更が Unity 側に反映されない
・Blender はZ軸が上だけど、Unity はY軸が上で(ry
・Terrain で作った地形の微調整が難しい

などの点でやっていられなくなったので、グーグル先生に相談。
ぐぐると、テラシュールブログさんで「ProBuilder Basic」というアセットが紹介されていました。

機能はいろいろありそうですが、Unity 上でモデルをいじれるのが非常によろしいです。
複雑なモデルを作るのは厳しそうですが、シンプルなオブジェクトを作るのであれば十分。
配置後でも変更できるので、「この面だけちょっと上に・・・」といった場合でも問題ありません。
面だけでなく、辺や頂点を移動させることもできます。

現状ではゲームとして成立していないのが何よりも致命的な点です。
いくらシステムやキャラクターを作ってもテストプレイできないので、有用かどうかの妥当性を図ることができません。
「カンガルー作る前にゲーム出来るようにしろ」という知人のお言葉は正論だと思います。

そんなわけで、ビジュアル面をいじりたい気持ちを抑えつつ、ProBuilder を使ってシンプルなステージを作っていきます!
使い方はテラシュールブログさんで紹介されているので、この記事では割愛します。

ステージの作成

とりあえず適当に配置してステージっぽくしていきます。
大抵はキューブ型で十分ですが、時々階段や円状のオブジェクトも混ぜていきます。
どうせならチュートリアル的な面も兼ねていきたいので、二段ジャンプや壁ジャンプなどが必要となるよう構成してみます。
あとはセンスとイマジネーションで気合で作ります。

shot2ss20160619222553038

Vキーを押しながら左ドラッグするとピッタリくっ付けやすいです。
今までは視点変更をしながら頑張って配置していましたが、これを使うとラクラクです。
というかもっと早く知っておくべきでしたorz

配置後に特定の面を伸ばしたり縮めたりもできます。
その場合は Ctrl を押しながらドラッグすると、マス目の分だけ伸縮されるのでやりやすいです。
逆にオブジェクト生成後に Scale を変えてしまうとマス目の大きさが変わってしまうので注意します。

shot2ss20160621212214983

前に作っていた「ステージ上に配置するオブジェクト」も入れてみます。
「壊せる箱」とか「ダメージを受けるトゲ」とかですね。

shot2ss20160619222659087

壁ジャンプは専用の壁に密着している時にジャンプボタンで行えます。
詳しい実装は以下の記事をご参照下さい。

https://gomafrontier.com/unity/349

カメラワークの調整

3Dゲーム且つカメラワークはオートなものを目指しています。
ということは、ステージの構成や場面に応じてカメラを移動・回転させる必要がありますね。
このあたりの実装は以前やっていますが、ちょっと古いので再度載せておきます!

shot2ss20160619222834238

mainCamera の Transform を直接あれこれすると、「プレイヤーを中心にカメラを回す」という処理が困難です。
なので、カメラを空オブジェクトの子に設定し、その空オブジェクトにスクリプトを付けます。
また、空オブジェクトは常にプレイヤーの位置を参照・移動するようにします。

using UnityEngine;
using System.Collections;

public class CameraController : MonoBehaviour {

    private GameObject mainCamera;
    private GameObject player;

    private Vector3 defaultAngle;
    private Vector3 defaultPosition;

    public float default_angle_y;

    void Start() {
        // パラメータに値を設定
        player = GameObject.FindGameObjectWithTag("Player");
        mainCamera = GameObject.FindGameObjectWithTag("MainCamera");

        defaultPosition = new Vector3(0, 25f, -70f);
        defaultAngle = new Vector3(20f, default_angle_y, 0f);

        initAngle(default_angle_y, defaultPosition, defaultAngle);
    }

    void Update() {
        // キャラクターを見失った場合再取得
        if (player == null) {
            player = GameObject.FindGameObjectWithTag("Player");
        }

        transform.position = player.transform.position;
    }

    /// <summary>
    /// カメラアングルの初期化を行う
    /// </summary>
    /// <param name="angle">カメラのY軸初期角度</param>
    /// <param name="position">カメラの位置</param>
    /// <param name="rotation">カメラの角度</param>
    private void initAngle(float angle_y, Vector3 position, Vector3 rotation) {
        mainCamera.transform.position = transform.position;
        mainCamera.transform.localPosition = position;
        mainCamera.transform.eulerAngles = rotation;

        transform.eulerAngles = new Vector3(0f, angle_y, 0f);
        transform.position = player.transform.position;
    }

    /// <summary>
    /// カメラアングルを切り替える
    /// </summary>
    public void changeAngle(Vector3 position, Vector3 angle) {
        // カメラ位置
        mainCamera.transform.position = transform.position;
        mainCamera.transform.localPosition = position;

        // カメラ本体角度
        iTween.RotateAdd(mainCamera, iTween.Hash(
            "rotation", angle,
            "time", 1f
        ));
    }

    /// <summary>
    /// プレイヤーを中心にカメラ位置を回転させる
    /// </summary>
    public void rotateCameraPosition(Vector3 camera_rotate_angle) {
        // カメラ回転
        iTween.RotateTo(gameObject, iTween.Hash(
            "rotation", camera_rotate_angle,
            "time", 1f,
            "onupdate", "rotateCameraAngle"
        ));
    }

    public void rotateCameraAngle() {
        mainCamera.transform.LookAt(gameObject.transform.position);
    }
}

ステージ中のカメラアングル切り替え用として、専用のスクリプトを作成します。
BoxCollider などで Trigger を持たせたオブジェクトに付与して使います。

using UnityEngine;
using System.Collections;

public class AngleChange : MonoBehaviour {

    [SerializeField]
    private Vector3 position;

    [SerializeField]
    private Vector3 angle;

    [SerializeField]
    private Vector3 camera_rotate_angle;

    private CameraController cameraController;

    void Start () {
        cameraController = GameObject.FindGameObjectWithTag("PlayerManager").GetComponent<CameraController>();
    }

    void OnTriggerEnter(Collider c){
        if (c.gameObject.tag == "Player") {
            cameraController.changeAngle(position, angle);
            cameraController.rotateCameraPosition(camera_rotate_angle);
        }
    }
}

スクリプト的にはどんな角度にも回転できますが、基本は以下の3つで行こうと思います!

・サイドビュー
横から見た視点です。
あまり奥行のない2D気味なエリアはこれでいきます。

shot2ss20160619223131086

shot2ss20160619223150495

・クォータービュー
斜め上から見下ろしたような視点です。
奥行のある3Dマップならこの視点が一番でしょうか。

shot2ss20160619223029231

shot2ss20160619223059855

・トップビュー
ほぼ真上から見たような視点です。
上2つと比べて使いどころは少なそうですが、狭い空間や迷路状ではこの視点が良いかも。

shot2ss20160619223437887

shot2ss20160619223546927

細かい部分の修正

その他ステージを作っていく上で、細かい点を修正していきます。

階段の上り下り

階段を作ったわけですが・・・。

20160621_01

あうっ(´Д⊂

ということで、CharacterController のパラメータをちょっといじります。
「Step Offset」の値を適度に上げ、階段程度の段差なら上れるようにします。

20160621_02

うーん・・・どうも減衰して上手く登れません。
一応「Slope Limit」を上げると登れるのですが、傾斜もぐんぐん登れてしまうためそれはそれで問題です。
「そもそも階段要るか?」という話ではありますが・・・。
現状でもジャンプ連打で登れるので、また暇なときに調査してみます。

水と滝

「Frineds of Ocean」というタイトル的に水は外すことができない要素です。
Unity5 から無料版でもリアルな水面のアセットが使えるようになったので、これを使ってそれっぽくしました。

shot2ss20160621211941143

また、段差があるので滝みたいのも欲しいですね。
これまた前に作ったのを配置してみました。
不自然ですが、これ以上となると流体シミュレーションとかしないときつい気もするので、まあ妥協できるレベルかなーと思います。

まとめ

今回作った部分までで、上から見るとこんな感じになりました!

shot2ss20160621212057963

今後はこのステージを作り込みつつ、いろいろと要素を盛り込めていければと思います!
とりあえずゲームとしての体裁を作ってしまいます!

down

コメントする