さけのさかなのブログ

同人ゲーム開発やってます。Unity使ったりする。

【Unity】Perspectiveカメラで2D画面の多重スクロール

 横スクロール2Dゲームのステージで、背景がスクロールしたときちょっとずつズレるみたいなのを実装する。

 素直にスクロール値を計算して毎フレーム位置を動かして……、とかやっても全く問題ないんだけど、まあ、とくに支障がないならカメラの機能だけでやってみようと。LateUpdateとか使って処理順意識するの嫌じゃん?

カメラ設定

 遠くのものがゆっくりと動く(ようにみえる)ために、Perspectiveカメラを使う。Orthographicカメラではこの現象は起こらない。

定数を決める

カメラ~基準オブジェクトの距離

 カメラがズレを起こさないメインとなるオブジェクト(基準オブジェクト)とカメラとの距離を決める。

 距離はカメラのニアクリップ、ファークリップ内に収めて(まあ普通おさまるけど)、あとはまあ、なんやら使いたい機能があったらそれに都合がいいようにする。スプライトだけの世界なら特になんでもいいはず。

で、コード

float 基準オブジェクトとカメラの距離;
float 背景オブジェクトとカメラの距離;
GameObject 背景オブジェクト;

背景オブジェクト.transform.localScale = Vector3.one * 背景オブジェクトとカメラの距離 / 基準オブジェクトとカメラの距離;

 という感じに、「遠くにあるものは小さく見える」を打ち消すように背景オブジェクトを拡大してやれば、いい感じに等倍に背景が描画されつつスクロールがズレてくれる。

 あとは背景の端が見えないように調整とかが要るんだけど、まあ、そこはオブジェクトの構造依存の話なので知らない。

使えないパターン

 横方向にはスクロールするけど縦方向はスクロールしない、とか、摂理に反することをしようとするとゴリゴリと毎フレーム位置を入れる処理が要る。しかたないね。

こっちも参考

gamesonytablet.blogspot.jp

【Unity】文字がふるえるエフェクト

 こんな感じ。
 一文字一文字をGameObjectにして座標をいじって……なんてやってられないので、いくつか問題があるもののBaseMeshEffectを継承して楽に作成する。

コード

gist.github.com

イケてない点

  • 他のMeshEffectと衝突する。
    • 何が起こるかというと、outlineとかをつけた時、アタッチ順によっては輪郭と文字がバラバラに動いたりする。
    • まあ、アタッチ順でイケてないことになるのはどのMeshEffectでも割とそうなので、致し方なしか。
  • 1文字6頂点決めうちの作りなのでUnityの変更に弱い。
    • ずっと前は1文字4頂点だったのが、あるとき今の6頂点に変更されたことがある。この値をとるAPIとかあればいいんだけど。
  • SetAllDirtyの使い方あってんの?
    • ModifyMeshを発火させる正式な手段ってあんのかな。

使う上で

  • NestedCanvasを使うこと

四倍剣^2パッチ1.02公開

 しました。  ここからダウンロードできます。

修正内容

  • ユニットウィンドウがクリックを阻害しないよう修正
    • ステータスウィンドウの向こうのにあるマスを選択できないやつの修正です
  • 詠唱メッセージの自動送り/手動送りを設定画面で切り替えられるよう修正

 という感じでプレイがちょい快適になるかもしれんやつです。

あと

 夏コミでスペースもらえてました。土曜日 西地区 "d" ブロック 51b。

紹介ページ兼オンラインマニュアル作成しました

幻想四倍剣^2 悔悟棒の謎 オンラインマニュアル

 というわけでこんな感じ。

 締め切り前の修羅場で取説つくるのはキツいナー、と毎回思ってたので、今回は細かい説明をオンラインマニュアルに放り投げて、入稿後に後付けで作れるようにしたのだった。

 意外と疲れた。

【Unity】 カスタムコルーチンでこのコールバックからの卒業

 Unity5.3からカスタムコルーチンを使えるぞ!これで何ができるの?いろんな条件で処理を止められるぞ
 ……という他に、コルーチンの戻り値を受け取るのにコールバックを使ってる部分をマシにできたりする。

 普通のコルーチンメソッドで書くとこんな感じなのを

    IEnumerator Routine(System.Action<int> callback)
    {
        var result = 0;
        for (int i = 0; i < 100; ++i)
        {
            yield return null;
            ++result;
        }

        callback(result);
    }

 こう書ける。

public class Keisan : CustomYieldInstruction
{
    public int Result { get; private set; }
    IEnumerator routine;

    public Keisan()
    {
        routine = Routine();
    }

    public override bool keepWaiting
    {
        get
        {
            return routine.MoveNext();
        }
    }

    IEnumerator Routine()
    {
        for(int i=0; i<100; ++i)
        {
            yield return null;
            ++Result;
        }
    }
}

 メソッドで書くほうが短いやんけ!

 まあ、コールバックとかツライときありますし。

 呼び方を比較するとこんな感じ。

IEnumerator Start()
{
    int kekka = 0;
    yield return Routine(result => kekka = result);
    Debug.Log(kekka);

    var keisan = new Keisan();
    yield return keisan;
    Debug.Log(keisan.Result);
}