Unity公式チュートリアルSurvival Shooter日本語実践Chapter.7

7.Harming Enemies

今回は、エネミーを倒す処理:エネミー側のHPや死亡判定、アニメ、プレイヤーの射撃などを実装していく。動画の時間が長めなので必定、今回の記事も長くなりました。

元動画はコチラ。
https://unity3d.com/jp/learn/tutorials/projects/survival-shooter/harming-enemies?playlist=17144

EnemyHealthの実装

いつものようにEnemyHealthスクリプトをZonBunnyにアタッチしたら中身を確認していく。

変数

startingHealth:Enemyの初期HP
currentHealth:Enemyの現在Hp
sinkSpeed:Enemy死亡時、床に沈んでいくスピード
scoreValue:Enemyを倒したときに獲得できるスコア
deathClip:Enemy死亡時に再生されるSE

anim:アニメーターを格納
enemyAudio:deathClipを格納するためのオーディオリソース
hitParticle:Enemyに攻撃が当たった時に生成するパーティクル(=ヒットエフェクト)
capsuleCollider:死亡時にEnemyにアタッチしているColliderのTriggerをOnにするため、Colliderを格納する
isDead:Enemyの死亡判定に使う
isSinking:Enemyの沈んでる判定に使う

Awakeメソッド

もはやお約束。各変数にComponentを格納していく。新しく登場するGetComponentInChildren<>()は、子オブジェクトからComponentを探して、Inspector上で一番上にあるものを返す。と、言うことは子オブジェクトに同じComponentが複数アタッチされているときは要注意である。
あとは、currentHealthに初期HPの値をぶち込んでおく。

Updateメソッド

isSinkingがTrueであれば、Enemyオブジェクトを床下のほうへ移動させる(沈んでいるように見せる)。なお、もはや物理は関係ないのでFixedUpdateに書く必要はない。
なお、isSinkingメソッドは、後述のStartSinkingメソッドの中でTrueにされる。

TakeDamageメソッド

Enemyがダメージを受けたとき、に実行するメソッド。
ここで真似したいのは、ド頭でisDeadフラグをチェックし、すでにフラグがたっていればメソッドをそこで終えているところ。これによってif文の構造をシンプルにできているんやね、スマート。
さて、もしまだisDeadが立っていない=Enemyが生きているのであれば、やられSEを再生し、Healthを減らす。減らす量は実行元であるPlayerShootingクラスのShootメソッド(後述)からintの引数amountとして渡す。さらにヒットエフェクトのパーティクルを再生する。パーティクルを生成するPositionは、これも実行元からVector3の引数hitPointを渡してある。
そして最後に、Healthが0を割っていればDeathメソッドを実行する。

Deathメソッド

前述のTakeDamageメソッドから、ヘルスが0を割った時に実行するメソッド。
まずisDeadをTrueにする。
アタッチされているCapsuleColliderのTriggerをTrueにしているのは、死亡したEnemyには当たり判定を残さないようにするため。特にTriggerを利用するわけではない。
アニメーターのDeadパラメーターをオンにして、EnemyAudioを死亡SEに差し替えたらそれを再生。複数の音源を適宜代入することで、コンポーネントを一つだけで賄っている。ちなみにコンポーネントが複数になった場合は、配列で指定する方法がある。

https://increment-log.com/unity-sound-se-play/

StartSinkingメソッド

Enemy死亡アニメーション終了後に実行されるメソッド。
StartSinkingメソッドが実行されるタイミングは後述。
NavMeshをfalseにする。これは、~|~~
RigidbodyのisKinematicをTrueにする。isKinematicによってこのオブジェクトはほかの物理の干渉を受けることがなくなる。死亡したオブジェクトに計算のリソースを割く無駄を省くためだ。
isSinkingフラグも立てておき、二秒後にこのオブジェクトを破壊する=沈み始めてから約2秒後にこのオブジェクトは消滅する。

StartSinkingメソッドはどこから実行する?

いままで見てきたコードの中に、StartSinkingメソッドを実行する記述はなかった。ではどこから実行するのか。ここで新しい概念Animation Eventが登場する。
ざっくり言えば、「アニメーション中の特定のタイミングで、特定のメソッドを呼び出す仕組み」である(たぶん)。ここでは、死亡アニメーションの途中で、このStartSinkingメソッドを呼び出している。ZonBunnyモデルのAnimationの中にすでに設定されているので、ここでは確認だけ行う。


ZonBunnyモデルのAnimationタグ、Deathアニメをクリックしてみると……


0:33のあたりにEventが設定されているのを確認、このタイミングでStartSinkingメソッドが実行されているのだ。

EnemyAttackスクリプトの修正

EnemyAttackスクリプトで、コメント化されていた部分、これはEnemyHealthにまつわる部分だ。今回改めてここのコメント化を解除していき、中身を確認していく。

EnemyHealthクラスを取得、格納する

EnemyHealth enemyHealth;
enemyHealth = GetComponent();

Enemyのアタック条件に、「EnemyのHealthが0より大きいなら」を追加する

if(time >= timeBetweenAttacks && palyerInRange && enemyHealth.currentHealth > 0){
Attack();
}
currentHealthはここで呼び出されるため、Publicな変数になっていたことに注意。

PlayerAttackの実装

大まかに言って三つに分かれる
・射撃時のマズルフラッシュ(パーティクル)
・射撃時のサウンド
・射撃時の弾道表示

GunParticlesの実装

マズルフラッシュの実装。PrefabにあるGunParticlesから、ParticleSystemをCopyしてPlayer以下にあるGunBarrelEndオブジェクトにPasteする。PrefabをD&Dでアタッチしないこと。

LineRendererの実装

GunBarrelEndオブジェクトにLineRendererコンポーネントを追加。LineRendererコンポーネントは、語義の通り直線を描画するものであり、今回は弾道表示に使う。アタッチ直後はマゼンタ色の四角い箱が表示されている。

直線の色を変える

LineRendererで描画する直線の色を変更するために、Material以下のElement 0に、用意されているLineRenderMaterialを設定する。これでLineの色が黄色になる。

直線の形を変える

この箱を戦に変えるために、Parametersを調整する。StartWidth/EndWidthともに0.05に設定する。

Unity2018ではUIが変わっているので注意。

射撃時にスクリプトから適宜呼び出すため、LineRendererコンポーネント自体は非アクティブにしておき設定は終わり。

Lightの実装

マズルフラッシュが周囲を照らす表現の実装。同じくGunBarrelEndオブジェクトにLightコンポーネントを追加。

色を変える

Colorを黄色に設定。

こちらも射撃時にスクリプトから適宜呼び出すため、コンポーネント自体は非アクティブにして設定完了。

射撃時のサウンド実装

AudioSourceを追加し、PlayerGunShotを設定、PlayOnAwakeからチェックを外して設定完了。

PlayerShootingスクリプトの実装

GunBarrelEndにPlayerShootingスクリプトをアタッチ。中身を確認していく。

変数

public int damagePerShot:ショット一発のダメージ値
public float timeBetweenBullets:ショット後、次のショットを打てるまでの時間
public float range:ショットの届く範囲

float timer:各種同期のために時間を格納
Ray shootRay:ショットの当たり判定をとるためのRay
RaycastHit shootHit:上記Rayのぶつかった情報を格納
int shootableMask:ショットがぶつかるオブジェクトが存在するレイヤーを格納
ParticleSystem gunParticles:マズルフラッシュのパーティクルを格納
LineRenderer gunLine:弾道のLineRenderを格納
AudioSource gunAudio:銃声のAudioSourceを格納
Light gunLight:マズルフラッシュのlightを格納
float effectsDisplayTime:エフェクトの表示時間

Awakeメソッド

shootableMaskにShootableレイヤーをLayerMaskで取得。LayerMaskのおさらいをしておくと、

//layerMaskに存在するオブジェクトにだけ、Rayが衝突する
Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask);

つまりShootableレイヤーが設定されているオブジェクト(今回のプロジェクトの場合はZonBunnyとEnvironment)にだけrayが衝突するようにするための下準備である。
それ以外は各変数にコンポーネントを格納。

Updateメソッド

Fire1に設定されたボタンがおされている間(デフォルトでは左クリック)かつ、ショット後、次のショットが打てるようになるまでの時間が経過していれば、Shootメソッドを実行する。
さらに、ショット後、十分な時間が経過していれば、DisableEffectsメソッドを実行する。(timeBetweenBulletsにeffectDisplayTimeを乗算しているのは、射撃間隔とエフェクトとの整合性をとるためで、それ以上の意味はないっぽい)

DisableEffectsメソッド

弾道表示と、マズルフラッシュによる周囲を照らすLightをfalseにする。オブジェクトでなくコンポーネントなので、setActiveではなくenabledをfalseにすることに注意。

Shootメソッド

まずtimerをリセットする。これをしないと射撃間隔の条件付けが機能しないので要注意。
銃声を再生し、マズルフラッシュのライトをTrueに。
また、gunParticlesを止めているが、これは前のショットの名残が残っていたときにそれを強制的に消すためのもの。直後にgunParticlesを再生。
弾道表示をtrueにし、さらにLineの始点PositionをGunBarrelEndと同じ位置に代入。

//indexは、0なら始点、1なら二個目の点、2なら三個目の点の位置を、Vector3に設定する。
//つまりまっすぐな一本の線だけでなく、途中で折れる線も描けるということ
LineRenderer.SetPosition(int index, Vector3 position)

rayの始点をGunBarrelEndのPosition、方向をforwardに設定する。forwardってどっちやねん!と思うが、forwardとはオブジェクトのZ軸に対してPositiveな方向、を意味するもの、みたいだ。3Dのゲームを作るときは、Z軸のプラス方向が正面になるように作る。覚えておこう。

次にRayを、先ほど設定した場所・方向から、rangeの範囲まで飛ばし、shootableMaskのレイヤーのオブジェクトだけ衝突するように飛ばす。もしヒットしたら、EnemyHealthコンポーネントを衝突対象から取得。衝突対象がEnemyであれば(壁とか障害物じゃなければ)EnemyHealthコンポーネントが取得できているはずなので、TakeDamageメソッドを、damagePerShotとshootHit.pointを渡して実行。最後に弾道を表示する直線の二個目の点(今回の場合は終点)を衝突地点に設定する。
もしRayが何にも衝突しなければ、弾道のLineの終点はRayのrange終点と等しくなる。

PlayerをPrefabにApplyしておく

ここまでいろいろ実装してきたPlayerの変更をPrefabに反映させるためApplyする

実装確認

無事に動くは動くが、Enemy死亡時にFatalErrorが発生。これは、Enemyに設定してあるNavMeshAgentが消えることで、SetDestinationメソッドが実行できなくなっているために起きているエラー。エネミー死亡時に、同時にNavMeshをFalseにしてやることで発生しなくなる。

長かったーー!!終わり!

第8回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.8

第6回はコチラ

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.6

恋は雨上がりのように 感想

映画版を見てよかったので感想をまとめておく。原作も、連載当初から追って途中間は空いたが最後まで読んだ。ネタバレあり。

最初、「年の差恋愛どうする?!」みたいな漫画だと思ってた。途中まででいったん読むのをやめてしまったのも、そこに興味を持てなくなったからだった。でも劇場公開されて評判を見るとどうも違うらしい。そこで改めて最後まで読んでみるとこれは、夢に向けてくすぶるおじさんの再生の物語だった。女子高生あきらの青春を描く物語であり、中年店長が青春を取り戻す物語であった。

おそらくこの作品のターゲットは、店長に感情移入するような人間たちだ。かつて夢を抱き、もがき、やがて大人という立場がそれを許さなくなり、諦めたツラをして日々を送っている、そういう「われわれ」。

そこに登場する「橘あきら」という女子高生。彼女の存在は、「われわれ」にとって非常にもどかしく、「なぜ?」と問いかけずにいられない。「なぜ、足のケガで陸上をすべて諦めてしまったのか」。

「若さ」には力強いエネルギーが宿る。「やりたいからやるんだ」「とにかくこれだけをやり続けるんだ」。しかし時にこのエネルギーは盲信を招く。「これしかないんだ」「少しでも失敗したらもう意味がないんだ」。
「われわれ」の目には、あきらが陸上を諦めたのはこの極端な「イチかゼロか」のように映る。リハビリして、少しずつ慣らしていけばいいじゃないか。まだ若いんだから。そう思う。
でも彼女たちは「3年間」という単位で生きている。常に自分の能力が右肩上がりでなければならないと感じている。今までがそうだったように。一度でも下降に転じてしまったら、「もうやり直しても仕方ない」「本当はかくあるべきだった自分にはたどり着けない」。そう断じてしまう。それが「若さ」の罪である。

僕自身も、大学受験の時に似たようなことがあった。さあ受験の天王山と煽り立てられ臨んだ高3の夏休み、始めのうちは根詰めてガリガリ勉強していたものの、1日のサボりが3日になり、3日が7日になり、結局ほぼ丸々勉強せずに過ごした。
その時頭の中を堂々めぐっていたのは「いまさら勉強したって意味がない」「周りは俺がサボっている間にも進んでしまったのだから、今から追いつけるわけがない」、というまさに極端な「イチかゼロか」思考だった。

あきらにとって、ひいては「若さ」にとって、一度の挫折はそれほど大きなものだ。でも「われわれ」から見るとそれが非常にもったいない。「3年間」のその先もあるとわかっているから、諦めるなと口を出したくなる。口を出していると思う。「はて、自分は人のことを言えるほどご立派だろうか」。

「もう若くないから」「仕事があるから」「家族があるから」。そういう理由でごまかしていた何かが、鎌首をもたげてくる。やりきって諦めたならいいだろう。でも自分はそうじゃなかった。やりきってみる前に、何かのせいにして見ないフリをしていた、努力したって才能がない、無駄だとわかったようなツラこいてたクセに、本当はまだ、恋をしている。僕だって「イチかゼロか」に囚われていたじゃないか。

あきらの恋愛をエンジンとした彼女の青春の再生、「あまやどり」のお話でありながら、それをリードするのは店長自身の鬱屈である。店長自身もあきらとのかかわりを通じて自らと向き合い、長い「あまやどり」を終え再び歩き出していく。僕も長いこと片思いをしていたけれど、最近自分でゲームを作り始めてようやく「あまやどり」が終わったような気がしている。恋は、雨上がりのように。

第10回Unity1Weekへ参加した話

完成したゲームはこちら~
https://unityroom.com/games/10yensoccer

初日月曜日

朝起きてお題「10」を見る。
10年、10人、10世代、これは俺屍やロマサガ、ヴィーナス&ブレイブスのような壮大な大河RPGも作れるな……と思ったので、10円サッカーにすることにした。この企画で一番大切なのは自分の能力を適正に判断して作れるものを作りきることだと前回学んだのだ。
会社へ向かうチャリンコを漕ぎながら、10円サッカーの企画をモリモリにしていく。10円サッカーなのに500円玉とか使えたらチートっぽくて、クラスの成金ぽくていいよなぁと思ったのでそういう内容にする。

が、今日はジムの日なのだ。おうちに帰ってPCに向かったらもう12時だった。今日と明日とで、10円玉をはじいて、間を通していくプロトタイプを作り終えたい。

2日目火曜日

月曜のうちに仕様が決まってとても気分が良い。コインをクリックしたらチャージして飛ばす処理は、前に作ったゲームをほぼ流用して実装できた。過去の自分が助けに来てくれる激アツ展開である。ちゃんと一枚だけ選んで飛ばすようにできたところで気づけばもう2時。明日もあるので寝ることにした。

3日目水曜日

飲みの誘いがあったので帰ったのは11時。正直割と寝たかったとはいえUnityを立ち上げて少し触ればだんだんやる気が出てくるもので。10円サッカーの肝である「ほかの二枚の間を通さなければならない」を実装したかったが、やり方が皆目見当つかなかったので作業が停滞。これはまずいと、いったん切り上げてゴールキーパーの仮画像を作ることにした。小学生の時に絵画教室に通っていたので絵心はばっちりだ。

……。

こいつをゴール付近において、右に左にうようよさせる。あとゴールのところを通過したらGoalの文字が出てくるようにした。今日は終わり

4日目木曜日

昨日できなかった「ほかの二枚の間を通す」実装に取り組む。2枚の間にColliderをつけたObjectを置いて、適宜大きさ、方向、位置を調整する方針。方向と位置はうまくいったものの大きさのところで躓く。二点間のベクトルの長さ1と、オブジェクトのScale1とが一致しないのだ。大体ベクトル1に対してScale6くらい。2時間くらいうなって解決策が思いつかなかったので、ベクトルの長さを6倍する荒業で今回はしのぐことにした。

5日目金曜日

今日はお休みなのでいろいろと気が楽である。昨晩は解決策が思いつかなかったが、Lerpを使って二点間の座標を連続的に取得しつつ、そこに辺1の正方形をずーっと並べていく、というのが手かもしれない。でも今回はめんどくさいのでやらない。
あと、起動直後にクラッシュするため遊べてなかったFallout76が発売1週間でセールされ、特に補填もなく頭に来た。二度とベゼスダのゲームは定価で買わないと誓った。グラボの相性が悪いのか?GTX1060を買いに行かなければならない。

そしてこの日、開発が行われることはなかった……

※ちなみにこの件は、Spriteが16○16である一方でPixelPerUnitが100だったために発生した現象であった。アドバイスくださった@naichilabさん、@divideby_zeroさんありがとうございます。

6日目土曜日

胸いっぱいの自己嫌悪とともに昼前に起床。のろのろちびりちびりとゲームしたりしながらだらだら開発していたが、深夜0時を回ったあたりでようやくエンジンがかかり始め結局朝の7時まで作業続行。おかげでネックになっていたお手付き処理が片付いた。

7日目日曜日

最終日。前日のブーストにもかかわらず9時には起床。朝食をとってそのまま速やかに開発へ取り掛かる。
プレッシャーもあってか、遅れに遅れたタスクをどんどん挽回できた。そのままリミットの夜8時まで開発をぶっ通し、最後SEの実装がちょっと間に合わなかったが、当初にマストでやりたいと思っていたことはほぼできた。悔いの残る状態でアップした前回に比べると充実感で満ちている。

某所に残した振り返りも合わせてコチラに残しておく。

★振り返り
Unity1weekテーマ:10円サッカー
https://unityroom.com/games/10yensoccer

#月
プロトタイプ制作(✔3個の円をドラッグしてはじく)
#火
プロトタイプ制作(✔どの円をはじくか決められる、 ~ほかの2つの間を通さなければならない~ )
#水
~プロトタイプ制作( ほかの2つの間を通さなければならない )~
~ゴール時の処理 (スコアとしての所持金、リザルト画面)~
✔一定軌道で行ったり来たりするゴールキーパーくんの設置
#木
✔プロトタイプ制作( 残った二枚のコインの間に、Colliderをつけたオブジェクトを設置する)
~制限時間~
~ゲームオーバー処理(場外、キーパーに止められた、所持金ゼロになった)~
~ゴール時の処理 (スコアとしての所持金、リザルト画面)~

#金
~残った二枚の間を通らなかった時のお手付き処理~
~制限時間~
~ゲームオーバー処理(場外、キーパーに止められた、所持金ゼロになった)~
~ゴール時の処理 (スコアとしての所持金、リザルト画面)~
~ステージに障害物設置~
~イラストを差し替え~
#土
✔残った二枚の間を通らなかった時のお手付き処理
✔ゴール時の処理 (スコアとしての所持金、リザルト画面)
✔タイトル画面

#日
予備日
✔制限時間
~ゲームオーバー処理(場外、キーパーに止められた、所持金ゼロになった)~
✔ステージに障害物設置
✔イラストを差し替え
✔サウンド実装
✔ビルド提出

#追加で可能であれば
3枚のコインの編成:10円玉以外でも遊べる。そのコインでゴールをとればスコアに影響する。
✔ゴールした場所によって獲得スコアに倍率
オンラインランキング

#無念なバグ
たまに、左クリックを離してもコインが飛んでいかない。かなり気持ち悪い
SEの実装が一部間に合わなかった。

#割とイケてると思うもの
制限時間の表示を、背景の色が変わっていくことで表現した。UX的にもイケてると思う。

#実装項目単位で見ると、最低限やりたかったことは割と帳尻があっている。
#追加でやりたかったこともちょびっと拾えてる
#前回と比べたらサイクルも回るところまで作れたしけっこうな満足感
#コインの種類を増やすのはけっこうやってみたかったし、実装もそれを見据えて配慮してあるので、SurvivalShooterに戻る前にSEつけるついでにやってしまおうと思う。
#そろそろ、「趣味でゲーム作ってますわ~」って人に言えるようになりつつある。6月に勉強を再始動してから半年か~~~。

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.6

6.Player Health

前回作ったHPバーをもとに、実際にHPの値を設定して、敵に当たったら減っていくようにするぞ。いよいよゲームらしくなってくるで~。

Unity公式ページ

“Unity公式チュートリアルSurvival Shooter日本語実践Chapter.6” の続きを読む

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.4

4.Creating Enemy #1

4章のエネミー作成、やっていきます。今回は初めて見るNavMeshという機能が登場します。敵を任意の目的地に向かって歩かせることのできるドチャクソ便利機能のようなので、しっかりマスターしたいね。

“Unity公式チュートリアルSurvival Shooter日本語実践Chapter.4” の続きを読む

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.3

3.Camera Setup

第3章では、カメラがPlayerの動きを追いかける機能の実装を行います。動画の時間も短いし、サクッとやっていくでー。

“Unity公式チュートリアルSurvival Shooter日本語実践Chapter.3” の続きを読む

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.2

2.Player Character

第二章のプレイヤーキャラクター周りを実装、解説していきます。第一章に比べて今回の動画は35分!心が折れそうだ……

“Unity公式チュートリアルSurvival Shooter日本語実践Chapter.2” の続きを読む

Unity公式チュートリアルSurvival Shooter日本語実践Chapter.1

前回のモチベ対策記事で書いた通り、Unity公式チュートリアルをなぞる形で、3Dゲームのおさらいと、クオリティが担保されたゲームを作ることによるモチベ回復を狙っていきます。このチュートリアルは英語のものしか用意されていないため、ついでに日本語解説もわかる限りつけていきます。

作るもの

https://unity3d.com/jp/learn/tutorials/s/survival-shooter-tutorial

筆者の開発環境

Windows10
Unity2018.2.1f1
Unity歴5か月くらい

“Unity公式チュートリアルSurvival Shooter日本語実践Chapter.1” の続きを読む

個人開発のモチベーション低下対策を考えてみる

前回の「ゲームプロデューサーになろう」の開発中期から、明らかに開発のモチベが落ちてます。
このままではよくないので、モチベ低下の原因を探り、次のタイトルの開発ではその対策を講じていきます。

#モチベが下がっている理由
割と明白です。一つは、やりたいことに対して、アート、実装のクオリティが追い付かず結果、「こんなもんがやりたかったんだっけ」という満足しない着地点に終わっているせいです。
「ゲームプロデューサーになろう」も「フットバ出前」もどちらもそんな感じで、当初やりたかった実装からはだいぶ妥協した結果、遊び心地も微妙な感じになってます。
始めのころは、ほんとに自分で書いたコードが動くだけでもうれしいものでしたが、もうその時期は過ぎ去ってしまったみたいです。
次のステップとして自分の中で「人が触ってみて、ほんのひとかけらでもいいので面白いと思ってもらう」というハードルを設けていたのですが、このハードルは予想以上に高いことが分かったのでいったんこの旗は降ろすこととします。
また、明確な目標、マイルストーンが引かれていないのも問題です。期日を決めるとか、誰か具体的な友人知人に見てもらうとか、まだ気の早い話ですがなにかの展示会を目指すとか。そういう意味ではUnity1weekは期日も決まってるし遊んでもらいやすいし、ぴったりでした。

#上記への対策
Unityの公式チュートリアルをやってみます。アセットはクオリティのあるものが用意されていますし、コード自体もきちんとした書き方をおさらいできるでしょう。企画やアートのことを考えなくてよいので、すこしプログラミングの頻度が下がっていた分リハビリに丁度良いだろうと思います。たしか来週?からUnity1weekがあるので、0ベースで作るのはそこで再開、ということにします。
また、並行してドット絵の練習も進めます。テキストは購入しているので、こちらもそれに沿って進めるだけ。頭を使わなくていいので簡単ですね。

継続に当たってはマンネリが難関として立ちはだかります。チュートリアルをなぞるのは一見すると後退するように感じますが、変化をつけて刺激を与えるという意味でもこの対策をうってみます。

#愚痴
と同時に、自分にゲーム作りの適性があったならこんなことしなくてもすいすい進むんだろうな、もっと若いころから始めていれば……というのはいつも心に引っかかってます。
手を進めている自分の方が100億倍理想に近づけているので、やり続けるしかないのですが、30手前にするともっと時間のあったころのことばかり恨めしく思い返されるのもまた事実。まあしゃーない。