• ゲーム製作日記その2

    2018-08-12 01:19
    ■8/11

    ・SEの音量調整画面
    ・ステージ開始時点の所持武器・弾数情報の保存→リトライ時にロールバック
    ・武器選択ボタン押下時に、所持中武器一覧を出す
    ・出口へのナビゲーションマーカー

     画面外や背面にあるときの処理がやたら面倒だった・・・ Camera の WorldToViewportPoint だけではうまく行かないし、「背面を見回して探す際には、プレイヤーは左右旋回を優先的に行なう」ということを考慮して置かなければいけない(多分、宇宙空間だのドッグファイト中だのだったら、そうとは限らなくなる)。

    ・ステルス兵のシェーダー

     いい感じ! このままガンとしてステルス、でもいいけど、計算変えれば何でもできる。
      ・目だけ光らせる
      ・ダメージを受けたとき、通常兵同様に点滅させる
      ・HPが一定値を切ったらバチバチ言わす
     0~1で lerp 使って諸々の適用率を変えてるんだけど、1を超えた値を入れると、何でか知らんが、Bloom エフェクトと作用して激しく光ったりする。ステルスが解けるときの演出としていいかも知れない。

    どうしたどうした

    ■8/12

    ・グレネードランチャーの当たり判定(自傷ダメージは低めに見積もったほうがいい?)

    ・被ダメージ表現のプロトタイプ


     プレイヤーキャラクターはロボットなので、血で表現するというわけにも行かず、さりとてガラスが割れるなどの表現だと画面が見にくくてしゃあないだろうから、血っぽくてかつロボットっぽいものを作ってみた。ダメージを受けた敵弾とのコライダーの接触方向(≒敵方向)を元に、対応する六角形を光らせる。
     もちろん一枚一枚ポリゴンを置いているわけではない。オーバレイしている Canvas に 1枚の RawImage を貼り付け、シェーダプログラムで表現している。


     まずは上図のようなハニカム画像を作っておく。各六角形の内部はグラデーションせずに同一色で塗ってあり、各チャンネルには、
      R:ベクトルX
      G:ベクトルY
      B:画面中央からの距離
     が入っている。
     アンチエイリアスなどでにじんでしまうと手筈どおりに行かないので、Mipmap の生成を抑制するなどしている。

     最後に受けた銃弾のベクトルとその経過時間をシェーダに渡す。

     R,Gからなるベクトルが近い(内積が1に近い)ほど、そして経過時間が短いほど、そして画面中央からの距離が遠いほど強く光る・・・というような実装。

     六角形を小さくしたら、なんだか安っぽさが極まってしまったので、あえて逆にでかくしてみている。湾曲させて、トンボの目っぽい表現にするのが目標。そのあたり、テクスチャを生成する際に済ませておいて、シェーダ側では計算しなくていいのがミソ。ただし計算方法が良く分かんなくて頭痛い。シェーダのほうが楽くさい。

    ■8/13

    ・雑コラみたいだった操作説明画像をキレイなオリジナル画像にしてみた


     これより先にもっとやることあんだけど、たまにはこんなのも。でも本当にさ、この中で
    「しゃがむ」だけはまだできないからね。はよせい。

    ■8/14

    ・しゃがみ追加。ダッシュ後は急減速せず、スライディング風になるように調整

    ■8/15

    ・BGMを付与

    ■8/16

    ・アイテムドロップ機構のプロトタイプ
    ・グレネードランチャーの弾道予測線
    ・グレネードが着地後転がっていきすぎるので、衝突時にスピードを殺す調整
    ・グレネード爆発前のチカチカを追加
    ・AI の経路目的地の算出を修正
    ・武器切り替え時の一覧がボタン離したら一瞬で消えちゃうのを修正
    ・アサルトライフル、SMG等の集弾率調整
    ・レティクルとの連動

     レティクル専用シェーダを作ったけど、ばかばかしいのか効率いいのか良く分からん。
     テクスチャから取る演算×線一本分×4枚の方がずっと多そうだけどどうかしら。

    ■8/17

    ・Windows標準ジョイスティック対応

    ■8/18

    ・敵モブのジャンプモーションの追加(以前は単なるスライド移動だった)
    ・スタンショットガンのプロトタイプ



     踏むとしびれるやーつ。ディスオナとかホライズンのパクリのやーつ。
     ごく小さい効果範囲のスタンマインをばら撒くことを考えてたので「ショットガン」にしたんだけど、一定範囲の奴を1発ずつコントロールして配置したほうがいいのかしらん、と決めあぐねてる。
     上図のは後者のつもりで作ったけど、サイズ的に中途半端やなぁ。1発ずつなら半径1mくらいでいいんじゃないか?

    ■8/19

     ・ミサイルランチャーを実装。

     命中精度がいまいちなので、弾数多めでいいかな。

     ・SF風ステージのテスト
     ・ショットガン用のレティクルを追加
     ・ボタンアイコンなどで中途半端に利用してたアセットを削除、代わりに自作

    ■8/20


     ・ミサイルロックオンマーカーをちょっとマシに

     今のところ、発射すると未ロックアイコンになっちゃう。命中するまではロック中にするかそれとも別のアイコンにするか。

     「命中率が低い&弾数多い」だとグレランと差別化できないと思い、命中率を高めようとして追尾力をあげた。そしたら、目標の周囲をくるくる回ってしまう。爆発範囲内に入った瞬間炸裂させる、とでもでしたらいいだろうか。

     ・音量、コントローラ選択、軸反転設定の保存(いまさら)

    ■8/21


    ・工兵の追加



     ひとまず回復能力を授けてみた。

    ■8/22


    ・アサルト兵を想定したAIの調整

     後ろに向かって撃つとか振り返り時に硬直するとかおかしなところが多かったので修正。いまのところ遮蔽物も無く単純な構造のマップだが、不自然な動きが大分無くなった。Sprint, Run, Walk の切り替えが急激過ぎるので、もっとゆっくり遷移するよう調整したい。

    ・スタンマインの効果範囲変更、5発水平発射に変更、発動機構
    ・スタン中のモーション(アサルト兵のみ)・エフェクト

     Stan じゃなかった Stun だったー。やられたー。
  • 広告
  • Unity (特にuGUI) とマルチコントローラ対応

    2018-08-09 05:49
    ※徹夜明けで書いてるので間違ってたらごめんね! コードも半端なんで、ヒント程度に読んでね!

     Unity のゲームプログラムで、何らかのキャラクターの移動をキーボードで行なう場合、

     float dx = Input.GetAxis("Horizontal");
     float dy = Input.GetAxis("Vertical");

    とでもしておけば、プレイヤーがキャラクターを上下どちらに動かしたかったのかが分かる。
     この際、どのキーが対応しているかは、Edit→ProjectSetting→Input での設定や、インストールしたプレイヤーの個別設定によって決まる。だがプログラマ・プレイヤー双方が何も気にしなくても、初期設定で WASD とカーソルキーが割り当たっている。

     uGUI においても、ナビゲーション機能(通常の Windowsアプリケーションでの Tabキーの役割)によって、プレイヤーの操作が反映できる。ただし、前もってどれかひとつのボタンを Select メソッドで選択状態にしなければならない。
     縦に並んだボタン群の3つ目のボタンを押す際には、プレイヤーは S, S, Enter と入力すればよい。もちろん↓,↓,Returnでもいい。
     これは、EventSystemオブジェクトのStandaloneInputModuleコンポーネントの設定による。対応キーを直接指定するのではなく、Axis名と Button名を指定しておき、どのキーがそれらに対応するかは上述と同じく Input 設定で決まる。
     これも、プログラマは何も考えなくていい。初期設定でこうなっている。
     
    これね

     さて、Windows環境においてのコントローラでのプレイを想定する場合、親切に考えるのなら、
     ・Windows 標準のジョイスティック
     ・XBOX360コントローラ(箱コン)
     ・PS4コントローラ
     の3通りに対応しなければならない。つーか俺自身どれも使うことがあるので、全部対応したい。(ちなみに Windows標準~は、PS1コントローラをUSBアダプタで変換し、XBOXコントローラは PS3 コントローラをソフトウェアで変換している。どんだけ PS好きやねん)

     左スティックの入力は、ハードウェア→Unity間では第1軸(X Axis)、第2軸(Y Axis) の入力として受け取っており、これは Input設定では "Horizontal", "Vertical" に割り当たっている。これまたプログラマは気にしなくてもいい。
     キャラクタの移動も、uGUIのナビゲーションも、WASD・カーソルキー・左スティックに同時に対応している。

     問題は D-Pad(十字ボタン)である。基本的に、まったく対応していない。でも、uGUIの選択項目を D-Pad で移動したい事だってあるじゃないか。
     だが、これは実際、非常に面倒。
     まず、uGUI で使うことを考慮し、Input設定で D-Pad の入力を "Horizontal", "Vertical" に割り当てたとする。しかし、そうなると、左スティックと D-Pad 双方でキャラクタの移動を制御することになり、所持アイテム選択などの操作に D-Pad を使えなくなる。
     また、コントローラによって D-Pad の入力軸が違う。XBOX360コントローラだと 6軸、7軸になるらしいが、PS4コントローラだと 7軸、8軸である。あらまあ。
     おまけに Mac だと軸じゃなくてボタンになるそうですよ。いやですわねぇ。

    ■俺的解決法

     とにもかくにも、Unity の Input設定だけでは、どうしようもない。なんらかのスクリプトを書く必要がある。
     本当は今のバージョンの Unityだったらこんなの必要ないのかもしれないし、解決してくれる便利なアセットがあるのかもしれないが、30秒検索しても見つからなかったので、現在開発中のゲーム用に、独自の解決法を考えてみた。

     まず、EventSystemオブジェクトに、以下のコンポーネントを追加する。
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;

    public class InputOverrideModule : MonoBehaviour {
    void Start() {
    GetComponent<StandaloneInputModule>().inputOverride =
    gameObject.AddComponent<MyInput>();
    }
    }

    public class MyInput : BaseInput {
    public override float GetAxisRaw(string axisName) {
    ControlSetting setting = (略);

    if (!(setting is KBMSetting)) {
    int bs = setting.getNavigateButtons();
    if (axisName.Equals("Horizontal")) {
    if ((bs & ControlSetting.LEFT) != 0) {
    return -1;
    } else if ((bs & ControlSetting.RIGHT) != 0) {
    return 1;
    } else {
    return 0;
    }
    } else if (axisName.Equals("Vertical")) {
    if ((bs & ControlSetting.DOWN) != 0) {
    return -1;
    } else if ((bs & ControlSetting.UP) != 0) {
    return 1;
    } else {
    return 0;
    }
    }
    }
    return base.GetAxisRaw(axisName);
    }

    }

     StandaloneInputModule の inputOverride 変数に、BaseInput を継承した独自コンポーネントを指定することで、uGUI におけるナビゲーション機能に対して、キーボード、マウス、コントローラ左スティック以外の入力を割り込ませることができる。
     例えば GetAxisRaw メソッドがコールされた場合、"Horizontal" が指定されていたならば、D-Pad の入力を返してやればよい。

     D-Padの入力状態の評価は、抽象クラス ControlSetting を継承したサブクラスで行なう。
    public abstract class ControlSetting : MonoBehaviour {
    public static int UP = 1;
    public static int DOWN = 2;
    public static int LEFT = 4;
    public static int RIGHT = 8;
    (略)
    public abstract int getNavigateButtons();
    }

    public class KBMSetting : ControlSetting {
    (略)
    }

    public class PS4Setting : ControlSetting {
    (略)
    public override int getNavigateButtons() {
    int bs = 0;
    bs |= (Input.GetAxis("PS4DPadDownUp") > 0 ? UP : 0);
    bs |= (Input.GetAxis("PS4DPadDownUp") < 0 ? DOWN : 0);
    bs |= (Input.GetAxis("PS4DPadLeftRight") > 0 ? RIGHT : 0);
    bs |= (Input.GetAxis("PS4DPadLeftRight") < 0 ? LEFT : 0);
    return bs;
    }
    }
     あとは Input 設定に、"PS4DPadDownUp", "PS4DPadLeftRight" を 7軸, 8軸から取るようにしてやればいい。

     左スティックと D-Pad を同時に対応したい場合は、getNavigateButtons() メソッド内に判定処理を追加すればいい。
     もしくは、MyInput クラスの GetAxisRaw メソッド内で return 0; となっているところを取りやめて、return base.GetAxisRaw(axisName); に処理が渡るようにし、親クラスの実装に任せてやってもいいだろう。(その場合は、WASD・カーソルキー・左スティック・PS4 D-Pad の同時対応になる)

     あとはゲームオプションにおけるユーザの選択によって、ControlSetting のどの継承クラスを使うかを選択してもらえばいい。

     というような感じで、上記では完全に略したけど、○選択×キャンセルの設定も行なった。それをスワップ可能なようなクラス設計・オプション画面設計をするつもりでいる。

     そのほか、ControlSetting では以下のようなメソッドを用意してあり、ゲーム中に参照している。抜粋。
      public abstract bool isWeaponSelectPressed(int num);  //D-Padとか
    public abstract bool isJumpPressed(); //×とか
    public abstract bool isDashPressed(); //L3とか
    public abstract bool isPrecisionPressing(); //L2とか
    public abstract bool isShootPressing(); //R2とか
    public abstract bool isShootReleased(); //同上
    public abstract bool isReloadPressed(); //□とか
    public abstract bool isInteractPressed(); //△とか
    public abstract bool isInteractReleased(); //同上

     ゲームエンジンだけじゃ対応しきれなくて、世界中のプログラマがこんなことやってんだろうなぁ、きっと。
     それとも Unity以外だともっとマシだったりするのかしら。

  • ついに「ゲーム」を作り始めた

    2018-07-26 19:21

     自分向けのゲーム(解く俺自身が最適な解き方を分かっているので呼称は「ゲーム未満」)を作ろうと思い立って1年ちょっと。
     しかし結局、ある特定の方向けの「ゲーム」を作り始めた。
     面白いものではないかもしれないけど、できる限り、お腹一杯なネタになるものを目指して、いろいろ構想を練ること数ヶ月。
     ついに「これだ!」という方向性がしっかり見え、プログラミングを開始した。

     組み始めてまだ数時間だけど、
      ・FPS視点、射撃、精密射撃、ダッシュ
      ・弾丸のオート連射
      ・NavMesh の動的生成
      ・敵の定期的スポーンとプレイヤーへの接近
      ・敵の近接攻撃
      ・当たり判定とパーティクルエフェクト
      ・ステージ内の敵モブ数チェックと追加スポーン管理
     までできた。

    いまんとこ、狭すぎて超クソゲー
    リロードモーションとかめんどくさいんでビームライフル
    (その代わりオーバーヒート要素をつける予定)

     もちょっとかければ
      ・敵HPの減少、撃破ステージクリア判定
      ・攻撃を受けたときの自己HP管理、ゲームオーバー判定
     くらいまではできるか。
     その次の段階で弾数管理、ドロップアイテム、ステージのランダム自動生成あたりかな。そこまで作れば、おおむね骨組みはできるぞ。

     武器や敵モブはタイプの違うものでも追加しやすいよう、前もって想定して組んでいる。安めのアセットをいくつか見つけたので、それさえ拾ってくればバリエーションは増える。

     ただし、射撃を行なう敵モブも考えないとつまらないね。
     一定程度離れたところで、かつ、こちらのカバーリング可能範囲の死角に移動するようにしなければならない。

     他にゲームとして面白くするには、あとは最低でも
      ・キャラクターの機動力と行動選択性(ジャンプとよじのぼり、しゃがみ、近接攻撃)
      ・破壊可能な障害物(爆発や倒壊で敵を巻き込める)
      ・隠密要素
      ・弱点や部位破壊要素
     あたりが必要か。
     また、シェーダーを組むことで、以下のようにゲーム性やユーザビリティを上げる。
      ・弾丸命中時や炎上中などの敵の点滅表示
      ・光学迷彩もちの敵
      ・マーキングして輪郭透視

     概ねそのあたりの、ごく一般的で常識的なレベルのものを盛り込んで行き、面白いゲームを作る努力はそこで一旦終わる。実はそのあと、別の方面に作りこむのが、本作の肝。そしてそれは本作最大の秘密。

     いつか完成・納品して、明かせるときが来たらそのときに。

    <進捗追記 7/29>
    ・レーザービームのオーバーヒート機構
    ・レーザー音の実装、地形命中時の弾痕エフェクト
    ・敵命中時の点滅エフェクト、敵HPの減少
    ・撃破した敵の倒れるモーション(仮)、撃破数によるステージクリア判定
    ・敵スポーン時のエフェクト
    ・敵の近接攻撃のサウンドエフェクト、ヒットによるプレイヤーHP減少
    ・グレネードランチャーの実装(ただしグラフィックのみ。爆発時の範囲ダメージはまだ)
    ・武器の切り替え
    ・各種弾数管理とUI表示、HP表示、撃破数表示

    密着するとスケルトンの攻撃がからぶったり、まだまだよ

    ステージは仮組みの固定のみ

     次あたりやるべきはステージだな。でないと、射撃を行なう敵のAI構築が進まない。

    <進捗追記 7/30>
    ・スタート時のロビールームの仮組み
    ・攻略ステージ部屋サイズの決定、壁ユニット等に用いるモジュールの選出
    ・エレベータ実装のプロトタイプ(ダーク無印DLCのみたいな)
    ・プレイヤーのジャンプ
    ・レーザービジュアルなどの向上
    ・アセットの購入、歩兵B・重装兵・弓兵を作成(矢のリリースは未実装)
    ・Animator と Root Motion, NavMeshAgent, CharacterControler の協調処理

     重装兵も、上位のやつにはドラウグルのシャウトみたいな遠隔攻撃持たせた方がいいかしらん。

    <進捗追記 7/31>

    ・SF系のアサルト兵、重装兵、近接兵、工兵のアセットをセットアップ
    ・AIルーチンと Animator の設計見直し
    ・モブの射撃システムの設計(アサルト兵、弓兵のみ)
    ・PS4パッドへの対応(マウス+キーボードだけだとデバッグしにくくてしょうがない)


    とりあえず弓兵とアサルト兵はできた

     いまのところ水平位置にしか撃てない。弾丸の向きをプレイヤーの居る方向に向かせるのは簡単だけど、モデルの砲口の向きと合わないので、Override レイヤー使って Spine を曲げてやらないとね。

    <進捗追記8/1>

    ・敵の射撃手段を水平方向以外にも対応させる(グラフィック上の砲口も含む)
     アセットが Humanoid だったので、IKの処理だけで簡単にできた。ありがたや!


     ちょっと上を向きすぎてるけど、まあいいさ。
     命中しないことが明白な場合には、後退したり河岸を変えたりしつつ、さらに最適なシュートレンジも考える・・・というAIにしたいところ。

     次はまた近接持ちに焦点がうつる。いまのところ、プレイヤーが別階層に行ってしまうと、足許に固まってぶんぶんふってるだけになる。さりとてやることもない。
     
     ・指定2点間の空中移動能力を追加



    <進捗追記8/2>

    ・キーボード/コントローラセッティングを整理(XBOXコントローラ対応の準備)
    ・スタート画面からゲーム画面や設定画面までのフロー整理(途中)
    ・武器切り替えを瞬時にできないように変更
    ・プレイヤーキャラの頭部の影を出すように修正
    ・敵テンプレートとスポーンシステムの見直し。いろんなタイプの敵を簡単に作れるような下準備。


     グレネードを3発連続でバースト射撃する重装兵を作ったりして。しかも消費スタミナ設定が小さいため、連続11発まで撃てる。死ぬわ。
     だがグレネードの当たり判定はまだ作っていない。残念だったな!

     近接兵に複数のモーションを与え(と言ってもアセットについてきた2種類だけだけど)、ランダムで選択させるようにした。同様に、射撃手も2種類以上の対応が可能にしてある。

     さて、次は武器をいろいろ作ってみるか。

    <進捗追記8/3>

    ・マップの自動生成の準備。いまだ固定マップではあるが、マップチップだけを与えて、
     それを規定どおりに複製して生成する手順を踏む。


     敵キャラクターは NavMeshAgent に任せずルートモーションで移動させている(参考にさせていただいたサイト)。
     だけどアセット付属のルートモーションでは直進しかできないため、急速な方向転換ができない。キャラクターが NavMeshAgent の要求についていけず、位置の乖離が生まれてしまう。結果、空中を歩いたりする。
     キャラクタ位置に NavMeshAgent を強制してもいいのかもしれないが、その場合ぽろっと落ちてしまって、それはそれでよくない。かわいいけど。
     これをそろそろ解決しなければいけない。急速旋回を許すか、左右方向のルートモーションを付与するか。

    <進捗追記8/3>

    ・上記の問題、その場でのゆっくりの旋回を行なうように変更できた。まだ完全ではないが、大幅に解消された。
    ・火炎放射器の作成


     Unityのアセットをほとんどそのまま使用。秒間75ヶのパーティクルが、1つ当たるたびに1のダメージ。それだけでもうすでに、ちょうどいい感じだぞ。
     残量も、フレームごとに -= 75 * Time.deltaTime にすればいい。あとは敵HPとの相互調整次第。
     HORIZON の炎上ゲージみたいな要素も入れようかな・・・面倒かな。

    <進捗追記8/4>
    ・サブマシンガン、アサルトライフル、スナイパーライフルの追加
     (でもリロード操作の表現がまだ雑、弾丸威力の減衰もまだ)
    ・「溜め武器」の実装。命中時の効果やエフェクトなどは未定

    これらの武器はドロップでも手に入り、所持中の武器と換装する

    <進捗追記8/5>
     ・マップチップに階段を追加。
     ・溜め武器「ソニックバズーカ」の実装続き。



     命中判定を中心に空間がゆがむ・・・というのをフレームバッファを使ってやってみたんだけど、いまいち派手さが無い。一考の余地あり。
     ? つーか良く考えたら圧縮武器なんだから空気の密度が変わってレンズ効果が出る、が正解だわな。

    <進捗追記8/6>



    ・アイテムテンプレートの作成。もうちょっとかっこよくしたいよね。
     回復アイテムは触ればいいだけ。完成。
    ・武器チェンジの文字列はビルボードで常にこっちを向くよ。
     △ボタン長押しで選択中武器と取り替える実装を追加。

    <進捗追記8/7>



    ・ロビールームほぼ完成
    ・アイテムやインタラクトポイントの仕様を整理
    ・各種文字列に TextMeshPro を活用していたが、
     使い方がまずいらしくプチフリするので TextMesh に変更
    ・演出に使うシェーダの開発

     ここと戦闘ステージを行き来するシステムが、今のところあんまりピンときていない。ステージ遷移の演出のことも考えるべき、それが仮にフェードアウト/インだけだとしても。
     でもこうやって作ってしまえば試行錯誤しやすいし、もろもろ課題も見えてくるのではないかな。

     ゲーム中断してこの部屋に戻ってくるために、ポーズの機構も作らなければならない。BGM等の必要なものを除いて、MonoBehavior を一時 !enbled にすればいいらしいんだけど。そんなうまくいくかなぁ。

    <進捗追記8/8>

    ・スタートメニューから戦闘開始、クリア、次ステージの生成などの一連の流れ(途中)

     ゲームオーバーとステージリトライの処理がまだ。
     あとはドロップアイテムさえ設定すれば、ひととおりゲームの流れにはなる。

    <進捗追記8/9>

    ・前回の続きで、以下の要素が概ねできた
     スタート画面/ポーズ画面/ステージ開始のインタラクト/ゲームオーバー/
     ステージリトライ/ステージ中断してロビーに戻る/ステージクリア時の出口出現/
     次ステージの自動生成

     ポーズしてアニメーションも何もかも全部止めることができたけど、まだアヤシイ。
     ポーズが有効になったのと同じフレームでプレイヤーのHPがゼロになることが、今のところありえる。その場合ポーズ明けでちゃんと死んでくれるだろうか? まあ多分それは大丈夫だと思うんだけど、じゃあまあ死んでくれたとして、そしたらちゃんとゲームオーバー画面に遷移できるだろうか? ポーズ明けの遷移とかぶっておかしくなるのでは? というわけで調べて直す。
     あとステージクリア時に、敵は消えるけど敵の弾だけはまだ生きてる。これは間違いなくまずい。

    <進捗追記8/10>

    ・ショットガンの実装

     フレームスロワと同様、パーティクルでの実装にした。仕様を勘違いしていて、何粒当たろうが1粒あたった分の計算ダメージしか出てなかった。
     ともに修正したが、そのわりにはフレームスロワのダメージが出ない。近接タイプの敵は突っ込んでくるせいかよく当たり、射撃兵は密接しても大して当たらない。むー。