はじめに
1か月ほどで某配管工のような3Dアクションゲームを作りました。
以下のサイトにて遊べます。
SpaceJumpGame | unityroom
今後のゲーム制作にも役立ちそうな知見をまとめました。
(参考にならない)コードはGitHubにあげてます
https://github.com/Papyrustaro/Unity3DActionGame
バージョン
Unity2019.4.0f1
Cinemachineを使ったカメラの追従
プレイヤーが常に画面の中心になるようにカメラを移動すると、どの方向にプレイヤーが進んでいるのかわかりにくい。
ワンテンポ遅れて追従するようなカメラをCinemachineを利用することで簡単に実装できる。
CinemachineVirtualCameraのFollowにプレイヤーの(中心の)Transformを代入する。
あとはBodyとAimのタイプと、各種パラメータを設定するだけでそれっぽくなる。
今回はBodyをFraming Transposer、AimをDo nothingと置き、カメラの回転は別途スクリプトで書いた。
特に操作したパラメータは、画面のどこに対象物が映るようにするのか(Screen X/Y)、対象物とカメラの距離(Camera Distance)
Cinemachineを使った特定経路のカメラの移動
今回メニュー画面で、カメラがステージの周りを回り続けるようにしている。
これもCinemachineを利用して簡単に実装している。
CinemachineSmoothPathでカメラの通過点を設定。
スクリプトからCinemachineTrackedDollyのm_PathPositionの値を変えることで通路上のどこにいるのかを変えている。
エディタ上から特定の処理を呼ぶ
今回はNaughtyAttributesというエディタ拡張を利用した。
https://github.com/dbrizov/NaughtyAttributes
これによって手作業でやっていたInspectorの操作などを大幅に削減できる。
以下はシーンに存在するスイッチと、スイッチで切り替わるステージを代入するスクリプトとInspector上の見え方。
[SerializeField, ReadOnly] private List<SwitchOnOffStageInHitHead> switches;
[SerializeField, ReadOnly] private List<SwitchOnOffStage> switchStages;
/*~~~~~~~~~~*/
/// <summary>
/// シーンに存在するswitch、onOffStageを代入・初期化。Inspector上から
/// </summary>
[Button(enabledMode: EButtonEnableMode.Editor)]
private void SetAllSwitchesAndOnOffStages()
{
this.switches = new List<SwitchOnOffStageInHitHead>();
foreach(GameObject obj in GameObject.FindGameObjectsWithTag("SwitchOnOff"))
{
this.switches.Add(obj.GetComponent<SwitchOnOffStageInHitHead>());
}
this.switchStages = new List<SwitchOnOffStage>();
foreach(GameObject obj in GameObject.FindGameObjectsWithTag("SwitchOnOffStage"))
{
this.switchStages.Add(obj.GetComponent<SwitchOnOffStage>());
}
}
自前で用意したい場合はこちらの記事などを参考にしてみては。
https://kan-kikuchi.hatenablog.com/entry/CustomEditor_Button
DoTweenはいいぞ(いいぞ)
今回初めてDoTweenを利用してみましたが、とにかく便利。
Unity全利用者使ってみるべき。
入門ブログを以前書きましたが、簡単なUIの処理にも重宝した。
これからもかなりお世話になりそう。
https://qiita.com/papyrustaro/items/2435369d13373417e1fd
WebGLでのJoy-Con操作
Unity上とWebGLビルド上ではどうもJoy-Conの入力が違うらしい。
アナログスティックは検知できない、という記事も見かけたが、全入力検知できた。
正直全く詳しくないので、環境次第では上手くいかないかもしれない。
以下のサイトにて、unityroomでのパッド入力の確認ができるようにしています。
https://unityroom.com/games/inputchecker
衝突したColliderの法線ベクトルが知りたい
まず、調べた限りTrigger(OnTrigger...)ではできない。
OnCollision...の中で、collision.contacts[0].normalでできる(1つでいいなら)
https://docs.unity3d.com/ja/current/ScriptReference/Collision-contacts.html
https://docs.unity3d.com/ja/current/ScriptReference/Collision.html
スクリプトからEventTriggerを設定する
ButtonなどのGUIでは、選択されたときやカーソルが上に乗ったときに特定の処理をさせたいことが頻繁に起こる。
そんなときにEventTriggerを利用しているのだが、Inspector上で毎回処理を代入するのが非常に面倒。
スクリプトでawakeなどで代入するのが楽。
https://light11.hatenadiary.com/entry/2018/01/31/234716
しかし、この場合だと処理を登録してもInspector上から見えないのが欠点。
見えないが登録はされている。
このせいで、予めスクリプトによる代入ができないのが悩みどころ。
床の移動にあわせてプレイヤーも移動させる
Rigidbodyによる摩擦計算を利用すれば、乗っている床が移動してもプレイヤーは乗ったままだが、
CharacterControllerを利用してプレイヤーを動かしていた場合、そうはいかない。
何もしないと、プレイヤーの座標はそのままで床だけ移動してしまう(しまいには落ちる)
一番手っ取り早い方法はプレイヤーgameObjectを移動床の子オブジェクトにすることだが、できることが制限されるので今回は別の方法を検討。
今回は移動する可能性のある床に接地したら、床のTransformを記憶し、前フレームからの移動分プレイヤーも移動させることで、移動リフトの上に乗ることを実装した。
移動リフトはいろんなゲームで登場するのでもっと賢い実装がありそうだ...
その他
壁キック実装
ブログを別で書きました。
https://papyrustaro.hatenablog.jp/entry/2020/06/17/121100
アニメーションによって、gameObjectが移動しないようにする
(怒涛のURL貼り付け)
http://tsubakit1.hateblo.jp/entry/2017/11/03/235913
http://aluminum-pepe.hatenablog.com/entry/2019/01/07/064816
https://gametukurikata.com/program/scriptisgrounded
アニメーションを瞬時に変える
has exit time をfalseに
transration duration を0に
時にはanimationclip自体の編集も
CharacterControllerを使用したときにキャラが地面から浮く
SkinWidthが原因。リファレンスではradisの10%。
ライティング
これ以上わかりやすい資料があるでしょうか、というほどわかりやすい資料
https://learning.unity3d.jp/2224/
線を描く
LineRendererを使う。
Inspector上からメソッドを呼ぶことで、特定のVector配列で線を引くことも可能
移動リフトの線を引く例
/// <summary>
/// Inspectorからリフトの軌道上の線を作成
/// </summary>
[ContextMenu("GenerateLineOfOrbit")]
public void GenericLineOfOrbit()
{
List<Vector3> paths = new List<Vector3>();
paths.Add(this.transform.position);
for(int i = 0; i < this.path.Length; i++)
{
paths.Add(this.path[i] + paths[i]);
}
LineRenderer lineRenderer = this.gameObject.AddComponent<LineRenderer>();
lineRenderer.positionCount = paths.Count;
lineRenderer.SetPositions(paths.ToArray());
lineRenderer.startWidth = 0.1f;
lineRenderer.endWidth = 0.1f;
}
プロパティをinspector上から変更する
自動でいい感じのColliderを作成する
SDユニティちゃんにライトが当たらない
shaderのせいみたいだが、変えると見栄えが...おとなしく初期設定に戻した。
Particleが場所や観る角度によって見え方が変わる
影がついているのが原因
ShaderをParticles/Standard Surfaceなどから、Particles/Standard Unlitなどに変えることで解決(壁張り付き時の煙)