【Unity】第7回 unity1week「当てる」参加作品「SATELLITE ONE」の開発
お疲れ様です。ぐーるです。
体調最悪のコンディションでしたが、なんとか提出することが出来ました。
公開されたので再掲。ワンショットシューティング、「SATELLITE ONE」よろしくお願いします! #unity1week https://t.co/tmStl0FFAC
— ぐーるさん (@uuha_goul) 2018年2月25日
思い出と実装をメモっておきたいと思います。
お題について
「当てる」かー、今回は神題だなと。
前提を考えなければアイデアはいくらでも出せそうだ、と。
デザインをほとんど必要とせずサクッと出来る、シンプルなものがいいなぁとか漠然と考えていて
降ってきたアイデアがSATELLITE ONEです。
内部設計について
いつもそうだけど物理的なunity.sceneは一つだけ。
内部的な画面は
- OpeningScene
- GameScene
- ResultScene
の3つ。
各画面間の切り替えはシンプルなステートマシンで管理。
public interface IState{ void OnStateEnter(); void OnStateExit(); } public class StateMachine : MonoBehaviour { public List<IState> states = new List<IState>(); private IState prevState; private IState currState; public void AddState(IState state) { foreach (var st in states) { if (st == state) { return; } } states.Add(state); } public void RemoveState(IState state) { states.Remove(state); } public void ChangeState<T>() where T : IState { if (currState is T) { return; } if (currState != null) { prevState = currState; prevState.OnStateExit(); // 抜ける前にOnStateExit()を呼ぶ } foreach (var st in states) { if (st is T) { currState = st; currState.OnStateEnter(); // 切り替わると同時にOnStateEnter()を呼ぶ } } } }
/** * // Zenjectで紐付け * [Inject] * private MainScene _mainScene; * [Inject] * private StateMachine _stateMachine; * // ~~ * _stateMachine.AddScene(_mainScene); // 起動時にStateMachineに登録しておく * // ~~ * _stateMachine.ChangeScene<MainScene>(); // _mainScene画面へ切り替え */ public class MainScene : MonoBehavior , IState{ //~~~~~ }
こんな感じでZenjectと組み合わせ。
楽か?って言われるとこの規模だとそこまででも無いけど
Zenject化するのが癖になってしまった。
ターゲットサイトについて
これは円形のプレーンな板をBlenderで用意しておいて、
その上で円を描くShaderを動かしています。
Shader "Custom/Ring" { Properties{ _TargetX("Target X", float) = 0 _TargetY("Target Y", float) = 0 _TargetZ("Target Z", float) = 0 _Alpha("Alpha" , float) = 0 _Color("Color" , Color) = (0,0,0,0) _BG("BG" , Color) = (0,0,0,0) } SubShader{ Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" } // alphaに対応するのに必要 Blend SrcAlpha OneMinusSrcAlpha // alphaに対応するために必要 LOD 200 CGPROGRAM #pragma surface surf Standard alpha:fade #pragma target 3.0 float _TargetX; float _TargetY; float _TargetZ; float _Alpha; float4 _Color; float4 _BG; struct Input { float3 worldPos; }; void surf(Input IN, inout SurfaceOutputStandard o) { float dist = distance(fixed3(_TargetX, _TargetY, _TargetZ), IN.worldPos); float val = abs(sin(dist*3.0 - _Time * 100)); float alpha = _Alpha; if (val > 0.98 && alpha > 0){ o.Albedo = _Color; o.Alpha = alpha; } else { // ↓何でも良い //discard; o.Alpha = 0; //o.Albedo = _BG; //o.Alpha = _BG.a; } } ENDCG } FallBack "Diffuse" }
[SerializeField] private Material _ringMat; // Update is called once per frame void Update () { // 適当なinputのラッパーだと思って下さい。なんでもいいです。 if(_inputManager.isTouchDownOnly(0)){ RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(_inputManager.GetTouchDownPosition(0)); if (Physics.Raycast(ray, out hit)){ var p = hit.point; p.y += 0.1f; this.transform.position = p; // タッチしたポイントをShaderに渡して中心点を移動した位置にする _ringMat.SetFloat(Shader.PropertyToID("_TargetX") , p.x); _ringMat.SetFloat(Shader.PropertyToID("_TargetY"), p.y); _ringMat.SetFloat(Shader.PropertyToID("_TargetZ"), p.z); } } }
ステージ制作について
SATELLITE ONEのステージは以下の2つの要素から成る。
- フロア
- 敵
そして敵は以下の要素を持っている
- 移動ルートポイント
- ルートポイントごとの移動速度
- 移動イージング
回転とかは賑やかしなので割愛。
ステージ作りがとにかく面倒だなと。
フロアはしょうがないとして、敵の移動ルートを量産出来れば、
ステージがどんどん作れそうだなと考えた。
ステージ制作画面
別でステージ製作専用のエディタを用意した。
- 敵を選択して選択状態に
- 動かしたい所をクリック
- AddPointボタンを押下でルートポイントを追加
という流れでどんどんルートポイントを置いていくことが出来る。
Playで動きの確認、そしてSaveでcsv出力している。
loadももちろん完備。
ここまで必要なのか?と思ったが
結局ゲーム側でも必要な機能がほとんどだったのでついでで。
csvのロードについて
ステージを追加量産するために
Application.dataPathを利用してパスでファイルを読むようにしてたら
当たり前だけどWebGLに出力したら動かない。
(開発中は紐付けなくてもcsvファイルを新規追加読み込み可能なので便利だった)
FileInfo fi = new FileInfo(Application.dataPath + "/Resources/stage/data/" + stageId + ".csv"); var result = new List<string>(); StreamReader reader = new StreamReader(fi.OpenRead()); while (reader.Peek() > -1) { string line = reader.ReadLine(); result.Add(line); } return result;
Editor上だけ使って実ゲームではTextAsset化して泥臭く紐付けて使うことに…。
とほほ。
[SerializeField]
private TextAsset[] _stageDatas;
おまけ
人工衛星なんですが、これはUnity標準のプリミティブオブジェクトの組み合わせで作ってます。
最初は無かったんですが、余りに味気なさすぎたので急遽追加しました。
適当に置いているだけなのですが、ちょっとゲームらしくなってくれたかなと。
感想
後はBGMのON/OFF付けたり、Post Processing Stack付けて微妙な色合いを出したり。頭痛と闘いながら調整。
今回もどうにか参加できました。
何故インフルエンザなんてかかるのか!?
ちゃんと予防接種受けてるのに。
前回は可愛い感じだったので、今回は硬めに。
みなさんお疲れ様でしたー!
次は可愛めで行きたい!