2025 年 5 月 25 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。

本日はセーブデータについてです。初心者の時にハマったところシリーズになります。

「Near The Sun」ではセーブデータをjson形式にして保存しています。
セーブ/ロード自体は簡単で、JsonUtility.ToJson()でセーブデータ化、JsonUtility.FromJson()でセーブデータ読み込み、JsonUtility.FromJsonOverwrite()でスクリプタブルオブジェクトへのセーブデータ読み込みをしているだけです。

じょーさんに暗号化のコードを書いてもらったので、セーブデータを見ただけでは改ざんできなくなっています。

暗号化!


さて、セーブデータでセーブしておくべき情報は以下のつです。
・現在攻略し終わったステージ
・現在持っているアイテムの種類と個数

このゲームではステージ内でのセーブができないのと、主人公の基礎能力が毎回リセットされるため、今どのステージにいて何のアイテムを持っているかだけでセーブデータが構成できます。

これ、ステージ内でセーブができるようにしたかったのですが、今の僕の技術だと難しかったです。通常メトロイドヴァニアではセーブはレストポイントでのみ行うことができるものが多いです。この時にセーブすべき要素は全て一緒にセーブしているのだろうなと思います。
このゲームでもチェックポイントに触れたらオートセーブ、のようにしてもよかったのですが、各ステージで保持しておくべき情報が全く異なる、仕様変更が大変になる、という予想がついたため、ステージの終わりでしかセーブができないようにしました。1ステージ30分ほどなので許してください……。

セーブすべき情報はテキストファイル/スクリプタブルオブジェクトなどにまとめて特定のフォルダに入れておいて、セーブ/ロード時はそのフォルダの中身を丸ごとセーブ、などにすればいいのでしょうか。アップデート時に開閉ドアをステージに増やしたり別オブジェクトに変えたりした場合にセーブデータの互換性を保つのが大変そうですね……。

ちなみに、JsonUtilityで「連想配列はjson化できない」という部分にハマって2年目まではきちんとしたセーブデータが作成されていませんでした。
「連想配列をメンバ変数に持つ自作クラス」はjson化できる上、その場でセーブ/ロードが可能なのでセーブできていると勘違いしていました……。作成されたjsonファイルをよく見ると{instanceID:387875}のようにinstanceIDのみが保存されていたんですね。シーンをロードしなおしてからセーブデータをロードするとインスタンスが見つからずエラーになります。

きちんと連想配列はバラしましょう

まあ連想配列をjson化する拡張もあるらしいので、そちらを使う手もあります。

総じて、そもそもセーブすべき内容を減らしたのがよく効いていると思います。
昔の自分、よくやった!

次回は僕がよく使っているドット絵作成ソフト、Asepriteについて話そうと思います。
ではこの辺で。

2025 年 5 月 18 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。

今回は「Near The Sun」の開発から一年、遂に新メンバーが参加!どうやって作業を分担すればいいのか、どのようにミーティングや情報共有を行っていけばいいのかについて話そうと思います。

2023年の8月、プログラマーのじょーさんが「Near The Sun」に参加してくれました!めでたい!
当時ノンリニア内の別プロジェクト(「Stealth」)が完成したタイミングで、ちょうど似た2Dプラットフォームがあって人手が足りないから興味ない?と誘ったところ、参加してくれました!
しかし、当時の僕は「いっしょにバリバリ作っていくぞ!」というよりは「緊張する、ヤバい、どうしよう!」と焦っていました。

もともと「Near The Sun」は二人で始めたプロジェクトでした。もう一人は音楽担当の方でしたが、1年間タスクを振らずにいたら音沙汰がなくなってしまいました。ミーティングや情報共有を怠っていたので当然ですね……。

そんなわけで、またいなくなられたらどうしよう、次こそは一緒に作品をつくっていきたい、逃がすものかと強く思っていました。しかし当時のプロジェクトはかなり中途半端、プログラミング初心者の僕が書いた基礎コードがなんとか動いているだけ……しかもどのようにタスクを分割すればいいのかもよくわからない……(じょーさんは僕よりも優秀なプログラマーです)。いっそのこと基礎の部分は一から書きなおしてもらったほうが早いのでは……。

とりあえずタイトル画面の実装からやってもらいました。敵の実装やプレイヤ―関連は既存の読むべきコード量が多く、一番最初には下手なコードをたくさん読んでもらうよりは、形になる部分を担当してもらって、「作品に関わっている感」を感じてもらいたかったからです。
その後、ギミックの作成、ステージのレベルデザイン、特殊な敵の作成……というようにタスクを振っていきました。でも今思うとたくさん既存のコードを読んでくれたんだろうな……と思います。感謝。

ちなみに定期ミーティングは行っていません。毎週話すことが生まれるわけでもなく、定期開催でだんだんとダレていくよりは必要な時に対面で集まったほうがいいですからね。
ただ、対面は2か月に1度くらい会いたいですね……。飯会を立てるか……。

その後もシナリオに関係する演出は僕が担当、アクションに関する部分はじょーさんが担当で2年間回しています。じょーさんがいなければギミックや敵の類は半分以下になり、演出は文字だけのものが増え、開発期間はもう1年延びていたでしょう。一人きちんと作品に取り組んでくれる人がいてくれるのはめちゃくちゃありがたいです……。

あと、プログラミングはできるようになっておいてよかったと思います。「どの情報を伝えれば実装ができるか」の判断がつきます。本当は音楽もできるようになった方がいいんだろうな……。文字数が多くなっても仕様はきちんと伝えることを気を付けています。

下の方に画像がありますが、画像はログに残っていませんでした

そんなわけで、新メンバー登場の話でした。
こんなゲーム制作初心者のプロジェクトに入ろうと思ってくださって、ほんとうにありがたいです。完成したときに「このプロジェクトに入ってよかった」と思ってほしいですね。

次回はセーブデータ周りについて詰まったこと/考えたことを書こうと思います。世の中のメトロイドヴァニアってセーブデータの構造どうなっているんだろう……。
ではこの辺で。

2025 年 5 月 11 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。

今回は簡単そうに見えて奥が深い、壁ジャンプについて話していこうと思います。
思っていたよりパラメータが多くて実装にかなり苦労しました……。

壁キックと聞いて、あなたはどの作品の壁キックを思い出すでしょうか。
「マリオ」シリーズ、Celeste、SANABI、ScourgeBringer、Dead Cells……2Dプラットフォーマーでは実装されていない作品の方が少ないのではないでしょうか。

壁ジャンプについて、実装に悩んだ点は3つあります。

1.壁ジャンプによって壁を上ることができるか?
マリオUやCelesteでは、片面の壁だけでは壁キックをしても登ることはできない(はず)です。壁キックをしていても、だんだんと高度が下がっていきます。それに対しSANABIやScourgeBringer、Dead Cellsでは壁キックにより壁を上ることができます。
これらの作品を大まかに見ると、特殊な地形そのものがパズルになっている作品が前者で、ハイスピード・地形を縦横無尽に駆ける作品が後者になっているようですね。
「Near The Sun」は特殊な地形を持つ上にハイスピードに地形を駆け回る作品なのですが、爽快感を失わせたくなかったこと、また、壁に張り付いている間にどちらにせよエネルギーが回復されて上昇できることから、壁を上ることができるようにしました。

2.壁ジャンプの軌道は?
壁ジャンプの軌道、おそらく最初に考えるのは下のような軌道でしょう。

何も入力しなければ赤色の多重線、右や左に入力をいれると左右に力が入り右側の青色の軌道や左側の青色の軌道に近づく感じですね。
これを単純な関数で実装する方法、どうすればいいんでしょうか。
…………いやほんとに、どうすればいいんでしょう。
だんだんと掛ける力を大きくすればいいのか、それなら途中で一度左右入力を外した場合はどうなるのか、そもそも壁に近づく向き/遠ざかる向きで力の大きさを変えるべきか……考えることは多く、また調整もしやすくないといけません。
そして、軌道を考える上ではy軸方向の移動、つまり落下が2次曲線的に動くことも考慮に入れないといけません。ジャンプの入力時間で最大到達点もジャンプ時間変わりますし。

無理ですよ、ほんとに……。
ちなみにコードはこうなってます。

だいぶ昔に書いたコードなのでかなり忘れている

まず、1行目のxmoveamountが「何も入力がないときに描く軌道」ですね。
何も入力がないと9・10行目に飛びます。
9・10行目で主人公を動かしています。
何も入力がない場合
1フレームの経過時間×(前フレームの速度+壁から離れる方向×力の大きさ×1フレームの経過時間)だけ動かしています。
また、ジャンプから一定時間経過後、入力があった場合に(
壁から離れる方向×力の大きさ×1フレームの経過時間 )に値を乗算しています。
外側には2.5倍、内側には2倍を掛けています。
正直、これでなんでうまく動いているのかあまりよくわかっていません。自分で書いたコードなのに……。いろいろ試してうまく動いたのでこれを使っています。

3.壁ジャンプの発動条件は?
そんなの、壁でジャンプキーを押したら発動でしょ?と思われるかもしれませんが、いくつか他の条件があります。
まずは、左右の入力方向・左右の向きです。壁の方を向いているときにジャンプキーで発動、壁の方へ入力を入れているときにジャンプキーで発動、壁の近くにいれば入力関係なく発動の3パターンが考えられます。
一見「壁の近くにいれば入力関係なく発動」が一番発動しやすそうに見えます。実際、Celesteでは壁を向いているか、左右に入力されているかは関係なく壁キックを行うことができます。
しかし本作では空中にいる場合、壁ジャンプとダッシュのボタンが共通なので、ボタンの入力だけではプレイヤーがダッシュを発動したいのか壁ジャンプを発動したいのかが曖昧です。
そこで、本作では上下方向・壁から遠ざかる方向に入力が入っていればダッシュ、壁方向・方向入力なしの場合は壁ジャンプが発動・また、壁スライド中は入力方向関係なくダッシュが発動という仕様にしました。
これにより、プレイヤーは思い通りにダッシュ・壁ジャンプを発動することができます。

というわけで、壁ジャンプについて話してきました。実装は簡単そうに見えますが、実は奥の深い動きです。
本作でも壁の反対方向に入力を入れ続けたとき、途中からグンと押されるような動きになっていて爽快感を損なっています。この点は改善する余地がありますね。
実は壁ジャンプの前にジャンプ自体語ることが多いのですが……。
かの有名な「桜井正博のゲーム作るには」のリンクを貼っておくのでぜひ見てください。

https://www.youtube.com/watch?v=zxOBCjqP8-Y

次回は「2022年8月、『Near The Sun』に新メンバー登場!」について話そうと思います。
それではこの辺で。

2025 年 5 月 4 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。

制作記第6回、今回は「Near The Sun」の体力ゲージについて話します。

「Near The Sun」は2Dステルスアクションです。
敵の視界に入るとステルスモードに入り、敵から姿が見えなくなります。
しかし、ステルスモードはエネルギーを消費します。
エネルギーが全てなくなってしまうとステルスモードが維持できなくなり、敵に見つかってしまいます。

つまり、「残りエネルギー」はHPです。
また、エネルギーを消費して回避兼攻撃のダッシュを行うため、エネルギー残量の管理はとても重要です。

さて、この重要なエネルギー残量、どのようなUIで表現するかとても迷いました。工夫したことをいくつかあげます。

1.主人公に重ねて表示されるUI
アクションゲームを遊んでいて、「キャラを動かすのに必死で、左上の体力ゲージを確認できない!」となったことはありませんか?
このゲームでは主人公があちこちに飛び回ります。左上のHPゲージを確認している暇などありません。
そこで、エネルギーゲージは主人公に重ねて表示することにしました。
また、エネルギーの残量割合は満タンの時に確認する必要はありません。そのため、エネルギーが満タンの時はUIを表示しないようにしました。UIが表示されていると、せっかくの主人公のアニメーションも見えなくなってしまいますしね。

2.円形のゲージ
HPゲージは直線系のUIが多い印象があります。しかし今回は主人公に重ねて表現するため、直線のUIだと左右に大きくはみ出してしまう可能性がありました。
そのため、円形のUIを採用しました。
円形のUIのデメリットは、エネルギー最大値の上昇を表現しにくいことです。
UIを重ねて2周分表示させるとか、横に並べるなどをしなければ最大値の増加が表現できませんが、直感性が失われます。
今回は主人公のレベルアップが段階的であって線形でないこと、最大値の細かい上昇を表現する価値が薄いため、デメリットがそこまで致命的でないことから円形のゲージを採用しました。

3.非線形なゲージの減少
実は残りエネルギーが30%になっても円形ゲージの表示は残り30%のようには表示されません。残り100%→90%の時の方が10%→0%よりも減るゲージの面積が大きいです。
これにより、ゲージの表示がギリギリになりやすくなり、プレイヤーに緊張感、敵に見つかった時の失敗感、ギリギリ視界から抜けることができた時の安心感を強く与えることができます。
本当に細かい数値が大きな意味を持つカードゲームなどではこの表現は許されないと思いますが、このゲームのUIは大雑把な円形UIで瞬間的にゲージが減少するため、最適な表現となっています。

また、残りダッシュ可能回数を右側に分離したことも工夫した点です。これによりある程度自由なUIデザインをすることが可能になりました。

ちなみに、形はシェーダーグラフで作成、imageではなくspriteでUIのレイヤーに表示しています。そのため、imageのfillAmountは使っていません。
offsetをアニメーションさせてタイトルの背景にも使っています。

polar coordinateを利用している
タイトルの背景に使用

さて、ここまでUIについて話してきました。
プレイヤーに重ねる円形UI、たまたま本作ではハマりましたが、かなりデメリットが大きいため、改めて考えると他の作品であまり使われてない理由がよくわかりますね。

次回は簡単そうに見えて奥が深い、壁ジャンプの実装について話そうと思います。
ではこの辺で。

2025 年 4 月 27 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。


制作記第5回、今回はシェーダーグラフの勉強について、初期にやったことをまとめます。
僕自身、完全にシェーダーグラフを理解しているわけではないのですが……これからシェーダーグラフについて勉強を始めたいと思っている人には役立つのではないでしょうか。

まず、シェーダーグラフとはUnityの機能の一つで、シェーダーをノードで作成することができます。

ノードベース!

シェーダーはゲームの物体がどのように描画されるかを決める計算方式です。
例えば、あるテクスチャの不透明度をn倍して描画する!みたいな感じですね。

通常、シェーダーを書くにはhlslなどの言語を学ぶ必要があります。
しかし、シェーダーグラフを使えばコードが書けなくてもシェーダーを作ることができます!
僕はプログラマーなので、コードが書けないわけではないのです。しかし、シェーダーのコードは書くための「約束事」が多いので、たまにしかシェーダーを書かない僕は毎回書き方を一から調べることになります。その手間を短縮してくれるシェーダーグラフは本当にありがたいです。

シェーダーを作ることができると、いろいろなエフェクトや光に対するシーンの構成が簡単にできるようになります!

さて、前置きが長くなりました。シェーダーグラフを学ぶためにやったこと、まず最初は「発光するオブジェクト」の作り方を調べたことでした。
これは調べればいくらでも記事が出てきます。
シェーダーグラフは「技術を向上させる」、というよりは「何ができて、何ができないかを知る」というタイプの勉強です。高速化とかを考え始めるとまた変わってくるのでしょうが……。
なのでおすすめなのは、とりあえず使えそうなシェーダーを5個ほど作ってみることです。
おすすめは
・ディゾルブ UIや消滅表現に汎用的に使えて、ノードの構成が簡単
・アウトライン UVの概念を学ぶのに適している
・汎用シェーダー エミッションマップ、加算、乗算、透明度について自由に値を設定できるシェーダーです。めちゃくちゃ便利。
・炎 外部に露出させる設定項目の割り切り方が学べます。
・ぼかし シェーダーグラフが苦手な「隣り合ったピクセルの値の取得」ができるようになります。

シェーダーグラフを学ぶと思った通りのエフェクトが出せるようになるのが一番大きいです。シェーダーグラフについて、いつくかシェーダーを作成した後次の本でエフェクトとシェーダーについて学びました。

Unity ゲームエフェクトマスターガイド

少し前のバージョンでの解説ですが、問題なく学習することができます。
また、次のサイトも参考になります。

https://zenn.dev/r_ngtm/books/shadergraph-cookbook

ありがたいですね。
あとは、UnityJapan公式が出している次の動画がとてもわかりやすいです。

https://www.youtube.com/watch?v=3TXHMS8xFJ0

このあたりを一通り終わらせたらシェーダーグラフ中級者なんじゃないでしょうか。売られているシェーダーの本を見て、「この本に載ってるエフェクト、全部作れるな……」とほくそ笑むことができるようになります。

ぜひシェーダーグラフを勉強してエフェクトもりもりなゲームを作りましょう!

エフェクトもりもり

次回は残り体力ゲージについて話そうと思います。
ではこの辺で。

2025 年 4 月 20 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。

制作記第4回、今回は視界の実装方法についてです。

「Near The Sun」は2Dステルスアクションです。
ロボットの視界に入ると、主人公はステルスモードに入ります。
ステルスモードに入っている間は敵に見つからないのですが、ステルスモードの間はエネルギーを継続的に消費します。
エネルギーが0になるとステルスモードが切れてしまい、敵に見つかってしまいます。
敵に見つかるとチェックポイントから再スタートになります。

敵の視界が通常のアクションでいう「敵の攻撃」に当たるため、敵の視界はゲーム内で明示する必要があります。

さて、ここで「視界が地形に遮られるにはどうしたらよいか?」という課題がでてきます。

「敵の視界が地形に遮られる形」を明示する必要がなければ、扇形の画像を張り付けて動かすだけで済みます。
プレイヤーが敵から見えているかどうかは、敵の目の位置からプレイヤーへRay(当たり判定を判別するレーザーのようなもの)を飛ばして、地形に遮られているかを判断すればよいです。
この処理の場合、ざっくりと敵の視界の範囲に当たり判定をつけておいて、プレイヤーが当たり判定の中にいるときにRayを飛ばせばいいので、計算負荷は大したことがありません。


しかし、今回は視界の範囲を表示する必要があります。
視界の範囲を表示するためには、地形と視点の位置を把握し、扇形の形状を毎フレーム計算する必要があります。
また、プレイヤーが敵の視界の中にいない時も計算をする必要があるため、なるべく計算負荷を抑える必要があります。

まず、最初に言っておきます。この問題の綺麗な解法を思いつくことはできませんでした。
思いついたのは3つ。一つは、地形を完全にグリッド状に配置することで、Rayなどを使用せずに、視点と地形から扇形の形を計算する方法。もう一つは、視点にLight2Dを置いて、地形にShadowCasterを配置し、光の強さを透明度に変換する方法。最後に、視点から扇状にRayを複数飛ばし、Rayがヒットした場所を繋いで扇形を作る方法。

光の強さを透明度に変換
Rayをたくさん飛ばす


結論から言うと、3つ目のRayを飛ばしまくる方法を採用しました。
一つ目の案では、地形を作る方法に制限を持たせることになります。細くて降りることができる足場などに対応ができなくなります。二つ目の案では、単純に当時その技術がなく、また、地形にShadowCasterを配置するのが手間です。

そのため、計算負荷を許容して3つ目のRayを飛ばす方法を採用しました。
こちらの動画を参考に実装をしました。

https://www.youtube.com/watch?v=73Dc5JTCmKI


プレイヤーが近くにいないときは視界の計算をしない、地形と干渉しない視界は扇形の画像にする、近くに複数の遮られる視界を複数置かないなどの対策で計算処理の頻度そのものを減らしています。

もっと軽い処理で実現できる方法はないものか……。
もしご存じでしたら教えて欲しいです。

今回の実装は2023年2月ごろに行いました。

扇形の視界の表示方法についてもちょっと工夫していることがあるので、いつか記事にしたいですね。

次回はシェーダーの学び始め方(初期にやったこと)をまとめようかと思います。

2025 年 4 月 13 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。

制作記第3回、今回はgitでやらかした話とエディタ拡張についてです。

gitというプロジェクトの管理方式をご存じでしょうか。
ファイルそのものだけでなく、その差分履歴を保存する管理方式です。
サーバーにプロジェクトデータをあげてgitで管理することで、複数人での作業を簡単に行うことができます。
このgitという方式、僕はゲームを作り始めるまで知りませんでした。

「Near The Sun」ではgitでunityのプロジェクトを管理しています。
unityのプロジェクトフォルダには最上階層に「Assets」「Library」「Logs」「obj」「Packages」「ProjectSettings」「Temp」「UserSettings」という8つのフォルダが存在します。
この中で共有するべきフォルダは「Assets」「ProjectSettings」「Packages」の3つで、それ以外のフォルダは個々人のPCで内容が変わるため、共有すべきではありません。

が、ゲームを作り始めた当時そんなことは全く知りませんでした。
単なるクラウドと同じに思っていたため、プロジェクト内のすべてのファイルをサーバーにアップロードしていました。
その結果、毎度毎度Libraryフォルダ内のファイルが大量にアップロードされることに……。

これが間違いと気づいたのが2022年の12月。
やっと指定したフォルダをgit管理しない「.gitignore」ファイルの存在を知り、プロジェクトに追加。しかしうまくgit管理を外せず、以下のサイトを参考にキャッシュを消すことで、どうにか希望のフォルダのみをgit管理できました。
https://qiita.com/kohei_wd/items/f1d224c9257d1e242b58

ゲーム開発の落とし穴をすべて踏み抜いていますね。
2023年の8月にプログラマが一人プロジェクトに参加してくれることになるのですが、それより前に気づいて本当に良かった……。(実は今もUserSettingsのフォルダは管理対象から外れていません。どうにかしないといけないんだけどね……)

次はエディタ拡張について。
超基本システムの実装が終わった12月、「ステップアップUnity」という本を読んでエディタ拡張に興味を持ちます。

「ステップアップUnity」

学んだことはとりあえず実践で生かす方針なので、ストーリー管理用のウインドウを作成することにしました。

完成形

「Near The Sun」のストーリー部分の管理方式は以下のようにになっています。
1.テキスト本体、話者、画像、背景のトランジションなどはcsvファイルで管理
2.何行目で音を鳴らすか、話者以外の画像を出すか、暗転させるかはスクリプタブルオブジェクトで管理
3.csvファイルとスクリプタブルオブジェクトからダイアログ管理用のオブジェクトに情報を流し込む
4. ダイアログ管理用のオブジェクトが文字を一文字ずつ出して入力待ち、話者画像の入れ替え

このウインドウでは2と3の部分を担当しています。なんと、csvファイルのパスを入れ、何行目にどんなアクションを起こすかを設定して「GenerateStoryManager」ボタンを押せば、スクリプタブルオブジェクトに情報が保存され、ダイアログ管理用のオブジェクトに情報を流し込むスクリプトが生成されます!
ゲームを作り始めて1年未満でこの仕組みを作ったのはえらい!

……はい、今はもうあまり使ってないです。
この方式で一部のストーリーができてしまっているため、形式的に使ってはいます。しかし、何行目に何を起こすかはインスペクター上でのコールバックチェーンにより実現してます。だってその方が楽だから。
それに、スクリプトの自動生成は間違っていた時に直すのが面倒くさすぎて……。もっと単純なレベルでの自動生成をすべきでしたね。めちゃくちゃなコードが1000行以上続いているのでもう見たくもないし、新しい機能を追加したくもありません。
まあ、コールバックチェーンもあまり複雑なことをするのは向いてなさそうですが……みなさんこの辺りどうやってるんですか!!!???

力技

まあ、そもそもどんなイベントを実装するかわからない状態でイベントの管理プログラムなんて組めるわけないので、割とよくやったんじゃないでしょうか。
手順が面倒くさいだけで、少なくともどんなイベントでも対応可能なシステムではありますし。

最近はずんずんイベントを作っているので、だんだんとイベントシーンを作るペースが上がってきました。エディタ拡張は楽しいので、次回作はさらに最適化されたシステムを作りたいですね。できればあと一生使える財産になるものを……。

ではまた。次は

2025 年 4 月 8 日 | カテゴリー: ニュース

今年も新歓の季節がやってきました!

4/8(火) 20時~ 第1回新歓説明会

@オンライン(Zoom)

オンラインでサークルの話を聞けます。カメラもマイクも必要ないので、気軽に参加してください!

4/12(土) 20時~ 第2回新歓説明会

@オンライン(Zoom)

1回目と同様に、サークルについて説明します。

4/18頃(日程調整中) ゲーム制作体験会

@場所調整中

ゲーム制作の体験活動ができます。初心者でも楽しんで取り組めます!

4/25(金) 19時~  新入生プロジェクト発足、ミーティング

@場所調整中

入部手続きの後、新入生のみなさんで新しくゲーム開発プロジェクトを結成します。

今後も随時、新歓情報を掲載予定です!
活動や入部、その他について質問があれば
新歓用メールアドレス:nonlinearshinkan2025@gmail.comまでどうぞ!

2025 年 4 月 6 日 | カテゴリー: Near The Sun, 製作について

15期のドッグウッドと申します。
今回は基本システム実装の話です。

基本システム実装は、ゲーム製作、特に初心者にとって最も難しい段階だと思います。
自分ができることも、これからできるようになることも曖昧なまま、それでも拡張性の高いコードを書かないといけないのですから……。
下手なコードを書けば将来どうしようもなくなる、スパゲッティコードになるぞと脅されますが、それでも作り始めなければモノは完成しません。

主人公の動作制御については割とまともなものが書けた……気がします。開発から2年半経ちましたが、一応まだ動いているので。
ステートの遷移と実際の移動を別ファイルに分ける、や主人公の動作をステートとアクションに分けて考える……などの設計はうまくいったのですが、今でも正解がわかりません。誰か答えを教えてほしい。

うまくいかなかったこととしては、主人公を1フレームごとに定数値で動かしていたとか、RigidbodyのAddForceでキャラを移動させていて動作が安定しないとか……初心者あるあるのミスはほとんど踏み抜いた気がします。
UIをステージ作成機能で組んでしまったせいで、解像度の変更に対応できなくなるという問題もありましたね。

当時のステージの様子

そんなこんなで試行錯誤を繰り返しながらも、2022年12月には、主人公の挙動、敵からのダメージ処理、会話システム、アイテムによるレベルアップなどが形になってきました。

そして、2022年の大晦日。除夜の鐘を聞きながらバックログと格闘していると、ふと気づきました。
制作開始からすでに4か月が経過しているのに、ストーリーはほぼ未着手。考えているのはトゥルーエンドの結末だけ。
敵の動きもほとんど実装できていない。グラフィックは仮素材のまま、音は一切入っていない……。



あれ、これっていつ完成するんだろう……。

2025 年 4 月 5 日 | カテゴリー: 中の人の戯言

ノンリニア16期のu.s.です。

ここには、私がUnity/C#のシェーダーを扱っている中で起きた問題と、それに対する自分なりの解決策を、備忘録としてまとめておきます。

状況1
「シェーダーのプロパティを Material.SetInteger や Material.SetFloat から変更したけど、変更が見た目に反映されてない!」

もしかしてそのプロパティ、Toggleとして扱ってる?

Toggleの場合、大抵プリプロセッサを用いた描画の条件分岐を行う。
例えば、”_AlphaSquare” というToggleプロパティを定義した場合、ToggleがONのときに “_ALPHASQUARE_ON” というキーワードが定義される:

Properties {
	[Toggle] _AlphaSquare ("Alpha Square", Float) = 0
}

として

#pragma shader_feature _ALPHASQUARE_ON

fixed4 frag(v2f IN) : SV_Target
{
	fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color;

	#ifdef _ALPHASQUARE_ON
	c.rgb *= (c.a * c.a);
	#else
	c.rgb *= c.a;
	#endif
	
	return c;
}

という感じで書くと、シェーダーのインスペクターにおける “Alpha Square” という名のToggleのON/OFFに応じて処理を分岐させることができる。

ところで、このプリプロセッサによる分岐は、動的ではなく静的なものである。

#ifdef … #else … #endif による分岐を仕組むと、コンパイル時に各分岐に対応するシェーダーが作成され、キーワードの有無に応じて分岐がなされるようになる。

つまり、キーワードによる分岐のパターン数だけシェーダーを出力し、ランタイムではそれらをキーワードの定義状況によって切り替える、というのを行っているっぽい。

インスペクターにおけるToggleのON/OFFは、キーワードの有効/無効が伴うみたいだが、Material.SetXxxx からToggleプロパティの値そのものを変更しても、ランタイムにおける対応するキーワードの有無には関わらない。

この場合に、ToggleのON/OFF切り替えと同じ効果をスクリプトから得たい場合は、Material.EnableKeyword / Material.DisableKeyword を用いて直接キーワードをいじることになる。

さっきの例だとこんな感じ。

[SerializeField]
private Renderer _renderer;

public void AlphaSquare(bool b)
{
    if (b)
    {
        _renderer.material.EnableKeyword("_ALPHASQUARE_ON");
    }
    else
    {
        _renderer.material.DisableKeyword("_ALPHASQUARE_ON");
    }
}

これだと何をしてるのかよく分からない!という場合は、そもそもプリプロセッサを使わずに動的なif文でシェーダーを記述すれば、従来の Material.SetXxxx を用いた描画処理の分岐もできそう。 (動的な分岐はパフォーマンスの観点から避けるべきと聞くが…実際どうなのでしょう?)

参考文献:
@up-hash. “「Shaderでif文を使ったら遅い」は正しくない🧐”. 2023-12-20.
https://qiita.com/up-hash/items/e932ccae110d687e225f

状況2
「エディターでは問題なく動いてたのに、ビルドしたら、シェーダーの効果がなくなってしまった!」

Unityでは、使われていない(と思われる)シェーダーはビルドから省かれるようになっているらしい。

このため、そのタイプのマテリアルを少なくとも一つ、アセットに用意して、 Unity にそのシェーダーバリアントを使う事を明示する必要があります。そのマテリアルは シーンで使われていなくてはなりません 。もしくは、 ランタイム時にリソースを読み込んで おくという方法もあります。そうしないと Unity からは、まだ使っていないように見えるため、ビルドから除外されてしまいます。

Unity Technologies. ” マテリアルパラメーターへのスクリプトを使ったアクセスと変更 – Unity マニュアル “. 2024-02-10. https://docs.unity3d.com/ja/2018.4/Manual/MaterialsAccessingViaScript.html

そのシェーダーをアタッチしたマテリアルがシーン上に1つでも存在すれば、それをビルドでも使うということを明示したことになるので、問題なく動作する。

しかし、例えばシーンロード後にInstantiateするプレハブのマテリアルに使っているものなど、最初からシーン上に存在しないようなシェーダーは、ビルド時に「使わない」と判断されてしまうらしい…

これを防ぐために、次のようなことを考えた。

私が使っている UnityEditor のバージョン 2022.3.23f1 には、Project Settings > Graphics に “Always Included Shaders” という項目がある。

早い話が、ビルド時に省略されたくないシェーダーをここにセットすれば、それらを全てビルド時に必ず含めてくれるようになる。

他にも対処法はあるかもしれないが、おそらくこれが一番手っ取り早くて分かりやすい方法なんじゃないかな?と思う。

ということで、もしビルド時のシェーダーの挙動がおかしいぞ?となった場合は、それがビルドから除外される対象になってないか確認し、上記の設定などを介して、除外を免れられるようにしてあげると解決するかも。