【ステージメモ】ステージギミックの作成

というわけで、本日はステージ上のギミックに関するお話です!
ステージの地形や敵配置も重要ですが、ステージギミックを合わせてこそアクションゲームというものです。

あまりにも鬱陶しいギミックを仕掛けても面倒な上、そのような代物を作る知識もありません。
ということで、オーソドックスなものから実装してみました!

ダメージトラップ

触れるとダメージを受けるものです。
オーソドックスなトゲや、高温地帯のマグマなど、いろいろ考えられそうです。

中でも代表的なのは「うに」です!

shot2ss20151202223931357

何故「うに」かと言えば、海が(一応)テーマのゲームだからです。
それ以上でも、それ以下でもありません。
純粋に痛そうでもあり、球状なので全方位をカバーできます。

ちなみにモデルはBlenderのDuplication機能を使って作成しました。
球状のオブジェクトの頂点にコーン状のオブジェクトを複製しています。

処理的には接触時にPlayerクラスのDamage()を呼び出すだけです。
が、谷底など落ちたら復帰できない場所に配置してあるものは、接触したら手前に戻すようにしたいですね。
なので、空の子オブジェクトとして「returnPoint」を設定し、接触時にプレイヤーの位置をそこに戻すようにします。

using UnityEngine;
using System.Collections;

public class Trap : MonoBehaviour {

    public float damage;

    private Transform returnPoint;

    void Start () {
        returnPoint = transform.FindChild("returnPoint");
    }

    private void OnTriggerEnter(Collider c) {
        if (c.gameObject.tag == "Player") {
            c.GetComponent<Player>().damage(damage);
            if (returnPoint) {
                StartCoroutine("playerReturn", c.gameObject);
            }
        }
    }

    private IEnumerator playerReturn(GameObject player) {
        yield return new WaitForSeconds(1f);
        player.transform.position = returnPoint.position;
    }
}

いちいちGetComponent()しているのが微妙なところです。
SendMessage()でも良いのですが、後々引数が増えそうなので直接呼んでいます。

returnPoint がないトラップはワープを行わないようにします。
if文で適当に制御してあげれば良いと思われます。

ジャンプエリア

該当の判定内に入っている状態でジャンプすると、大ジャンプが行えるものです。
ステージに高低差を付けたり、純粋なアクション操作を要求するギミックとして使います。

shot2ss20151202224351021

分かりやすいようにエフェクトを付けてみました。
Effekseerの描画方法をリングにし、頂点数を4にすることで正方形が作れます。
その正方形に合うようにBoxColliderを調整します。

using UnityEngine;
using System.Collections;

public class JumpArea : MonoBehaviour {

    public float height;
    private Player player;
    
    protected void OnTriggerEnter(Collider c){
        if(c.gameObject.tag == "Player"){
            player = c.GetComponent<Player>();
            player.getCharacterMotor().jumping.baseHeight = height;
        }
    }
    
    protected void OnTriggerExit(Collider c){
        if(c.gameObject.tag == "Player"){
            player.getCharacterMotor().jumping.baseHeight = 5f;
        }
    }
}

やっていることはすごく単純で、Enter時にCharacterMotorのジャンプ関係の値を上げるだけ。
Exitした時にデフォルト値に戻さないとずっと維持されてしまうので気を付けます。

Effekseerの良い点として、Unity側での拡大・縮小に合わせてエフェクトが拡縮するところが挙げられます。
様々な大きさのジャンプエリアを作る場合でも対応できます。

リフト

一定間隔で上下左右に動くリフトです。
リフトをコントロールするためのクラスを作成し、リフト用オブジェクトに付けます。

using UnityEngine;
using System.Collections;

public class Lift : MonoBehaviour {
    
    public float speed, repeat_dist, delay;
    public int moveDirection;

    private float radian;
    private Vector3 defaultPosition;
    private bool isMoveing;
    
    void Start () {
        defaultPosition = transform.position;
        radian = 0;

        if (delay > 0) {
            StartCoroutine("startDelay", delay);
        } else {
            isMoveing = true;
        }
    }
    
    void Update () {
        if(isMoveing){
            switch (moveDirection) {
                case 0:
                    transform.position = defaultPosition + new Vector3(Mathf.Sin(radian) * repeat_dist, 0, 0);
                    break;
                case 1:
                    transform.position = defaultPosition + new Vector3(0, Mathf.Sin(radian) * repeat_dist, 0);
                    break;
                case 2:
                    transform.position = defaultPosition + new Vector3(0, 0, Mathf.Sin(radian) * repeat_dist);
                    break;
            }
            radian += speed * Time.deltaTime;
        }
    }
    
    IEnumerator startDelay(float time){
        yield return new WaitForSeconds(time);
        isMoveing = true;
    }
}

配置位置からの反復距離をrepeat_distとして設定します。
また、XYZのどの軸に対して移動するかを選択できるようにします。
直打ちするのもアレなので、インスペクターからプルダウンで選択できるよう、エディタ拡張用のクラスを作成します。

 
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(Lift))]
public class LiftEditor : Editor {

    private static readonly string[] Directions = {"X", "Y", "Z"};

    public override void OnInspectorGUI(){
        var lift = target as Lift;

        lift.speed = EditorGUILayout.FloatField
                ("Speed", lift.speed);
        lift.repeat_dist = EditorGUILayout.FloatField
                ("repeat_dist", lift.repeat_dist);
        lift.delay = EditorGUILayout.FloatField
                ("delay", lift.delay);
        lift.moveDirection = EditorGUILayout.Popup
                ("MoveDirection", lift.moveDirection, Directions);
    }
}

LifeEditorクラスのファイルはAssets/Editorの下に配置します。
これでLiftのmoveDirectionを設定する際、プルダウンでXYZを選択できるようになります。
他の変数も設定しておかないと、インスペクターに表示されなくなるので注意します。

20151202

動かすだけなら簡単ですが、3Dアクションでよくある「なめらかな動き」にするには工夫が必要らしいです。
位置を移動させる際にMathf.Sin()を使い、ラジアンを取って計算したりするそうですが・・・。
ここは知人に教えてもらって実装した部分なので、自分でもよく分かっていませんorz

また、CharacterMotorを使用している場合、MoveingPlatformの設定値が非常に重要です。
パラメータに関しては以下にまとめてあります。

【再編集】Unity開発メモまとめ「CharacterMotor」

まとめ

ということで、ちょっとしたステージギミックを作成してみました!
ただステージを進んで敵を倒すだけではつまらないので、適度に配置していきたいところです。

今日のイラスト

マリンパ、シルリスに続いてモグフィーです。
前から「暗い配色」と言われていましたが、描いてみると改めて実感します。
マフラーとか靴くらいは明るめの色にしてあげてもいいかもしれません。

mogffy11

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*