LR

開発日誌

―リトル・リコレクターのメンバーが、それぞれの目線で開発の様子をお届けします―

ストライプ

こんにちは。デザイナーの清水です。

今回は漫画の話です。ウェブ連載している4コマ漫画ではなく、ゲーム中で見ることができる漫画の方についてお話しします。

リトル・リコレクターでは、ゲームを進めていると要所要所で漫画を読むことができ、ムービーの代わりにストーリーを語ってくれます。
これらの漫画は、あらすじを決める → ネームを描く → 線画 → 着彩という流れで制作していて、その中でも特別頭を使う工程の一つがネームなので、今回はネームの話をしようと思います。

ネームの要素を分解する

ネームを作るにあたって必要な要素は、話の内容いくつのコマに分割するかコマをどうレイアウトするか、の3つが主要なものかなと思います。
本作で読める漫画にはセリフがありませんが、セリフがある場合はどのコマのどの位置にセリフを書くかというのもここに含まれそうです。

そしてこれらの要素を同時に考えるのは結構難しいです。私は難しい作業はいくつかの要素に分解して、それぞれをプロセス的に分けて作業するようにしており、これも例外ではありません。
ネームの要素の中で一番思考を停滞させるのがレイアウトの部分です。こっちは話の内容を決めてしまいたいのに、コマをどこにどういうサイズで配置するのかというところで悩みます。なのでここを分離します。

レイアウト以外の部分だけを決めたものがこちらです。

ネームの前段階

記憶を頼りに描いたので製作中に描いたものそのものではないですが、こんなイメージです。


こういう感じでネームの前駆体みたいなものを作っておいて、それを見ながらコマ割りをしていきます。
レイアウト中に「ここはもうちょっと細かくコマを割らないと話が飛ぶな」とか「ここは冗長だな」とか、そういうことに気づいたりするので、適宜足したり削ったりしつつ組んでいきます。

そうして最終的に、

1ページ目
2ページ目
3ページ目

こういう感じの漫画になります。左から読むことに注意。ゲーム中ではコマが順番に表示されるので迷うことはないと思います。

週間連載のようにスピード感が求められる場合にはこの二度手間感が気になるかもしれませんが、そうでない場合は、ネームを2段階に分けてみると結構スラスラ作れるかもしれません。おすすめです。

ということで、漫画のネームの話でした。それではまた次の記事でお会いしましょう。

こんにちは!デザイナーの森です。
さて今回は、『リトルリコレクター』のUIアニメーションについての取り組みを紹介しようと思います。

リトルリコレクターで使用したアニメーションツールは、Unityのアセットストアで販売されている「Feel」アセットです。1つのコンポーネントだけで以下のような動きを一括で制御できる便利ツールです。スクリプトを一切使用せず複雑な動きを実現出来るので、2Dデザイナーにとってありがたいツールです。

  • カメラ・UIの揺れ
  • 音・エフェクトの発生
  • 時間制御
  • ポストエフェクトの操作
  • オブジェクトのスケール・回転・色変更

公式Webサイトはこちら


完成したUIアニメーション

遺跡で集めた素材を売却、交換したり、拠点を強化する役割の画面になります。アイコン的でなく物質的なモチーフが多いため、動きについても少しリアル感を持たせたものをイメージしました。

※映像は開発中のため変更の可能性があります。


初稿のUIアニメーション

動きをイメージしながらデザインを作成したため、アニメーション自体で悩むことはありませんでした。
ただ、完成と比較するとかなりもっさりしているのがわかると思います。ディレクターの笹口さんと清水さんに「ボタンを押してすぐ反応するほうが手触りがいい」と全体的に早めるフィードバックをいただき、1.2倍ほど早くする修正を行いました。

リザルトの結果表示といった見せ場の場合は緊張のニュアンスで溜めが必要ですが、遷移アニメーションは何度も行き来することになるためストレスを感じない長さが理想です。画面遷移時のアニメーションが0.8秒以内、戻るアニメーションはより早く0.5秒以内に収めるとストレスは少ないように思います。
再生順序についても、画面遷移時のアニメーションが2~3ステップ、戻るアニメーションが1ステップで完結するものが良いです。段階が分かれすぎているとバラバラでまとまりがないイメージになってしまいがちなので、ヘッダー・フッター・選択ボタンなどグルーピングするとバラバラ感が少なくなります。

絵を描くことにも言えることですが、今回の私のように一人で作っていると、客観的視点を見失いがちです。そういったときは遠くから薄目で見てみたり、録画してSNSの自分のトークに貼ってみたり、休憩を挟むとおかしな点に気づきやすくなります。


データ作りにおける注意点

始まり・選択中・終わりと個々にアニメーションを作って実装してみると、いろいろ不具合が出てきてしまいました。その1つが『相対座標で動かしたことによる不具合』です。

「現在地点→縦横〇px移動」という風に組んでいたため、別のアニメーションで現在地点が変わると目的地まで変わってしまいます。結果、どこか想定外の位置へピューンと飛んでいってしまうわけです。
なので、「画面上の縦横〇px地点→縦横〇px地点に移動」というように、絶対座標で動かすことにしました。
これで、変化に耐えられるつくりになりました。

アニメーションインスペクター 工房遷移後アニメーションの設定項目

このように便利なアセットですが、『できることが多い=設定項目が多い』ということなので、理解するのに大変苦労しました。これからも手触りが良くなるように鋭意制作中です!
製品版が出た際にはぜひプレイしてみてください。

それではまたお会いしましょう!

こんにちは。プログラマの寺沼です。

今回は、セーブデータのお話です。

皆さんは、Steamでゲームをする際、PCのどこにセーブデータが保存されるか知っていますか? 私は、あまり気にしていません。 これでは、PCが壊れた時や、新しいPCに移行する際に、セーブデータの復旧が困難だと思われるかもしれませんが、Steamには「Steamクラウド」という機能があります。

これは、Steamのサーバーでユーザーのセーブデータを保存しておき、いつでも復旧できる機能です。 これで、PCに万が一の事があっても安心、ということですね。

なお、対応していないゲームもあるので、あらかじめ対応しているかどうかを確認しておくとよいでしょう。 『リトル・リコレクター』では、体験版はSteamクラウドに対応していませんが、製品版では対応予定です!

ちなみに、Nintendo Switchでも、Nintendo Switch Onlineに加入することで、似たような機能を使うことができます。

それでは、また次回。

こんにちは。デザイナーの清水です。

今回は、アイテムの色によってレア度を表現するとき、どの色がどの色よりレアに見えるんだろう? という話をしようと思います。

ゲームをやっていると、レア度という概念はよく出てきますよね。

石ころとダイアのイラスト

レア度を表現するためには色々方法があります。
たとえば、大きさ。

大きさの違う王冠

ほかには色とか……

金銀銅の王冠

エフェクトなど。

キラキラが増していく王冠

場面場面によって適した表現方法は変わります。
今回考えたいのは、アイテムのレア度についてです。


リトル・リコレクターのアイテムには4つのレア度があります。
アイテムなので、アイコンの大きさは美観的に統一したいところです。エフェクトの豪華さ、みたいなものもぱっと見で比較しにくいので、正確なレア度の高低を表現するのには不向きです。

そこで色分けによってレア度を表現したいわけですが、3つまでなら金・銀・銅でよさそうですが、4つ以上になると難しくなります。
4つめを虹色にしてしまうなどもありますが、ソシャゲみたいになってゲームの世界観を邪魔しそうです。

なので、今回はシンプルな色味でレア度を分けることにしました。
最初に考えた色分けがこちら。

グレー、青、黄色、赤にカラーリングされたアイテム

一番レア度の低いものは色彩がなく、そこから三原色を振ってみたものですが……

グレーが銀、黄色が金に見えてしまい、レア度の順序がわからなくなるという声がメンバーから上がりました。
たしかにそうも見えます。たまたま素材を連想させる組み合わせになってしまって、わかりにくくなってしまいました。

そこで、黄色を緑に変えて、素材を連想させない純粋な色と分かるようにしました。

グレー、青、緑、赤にカラーリングされたアイテム

このようにした結果、ただの色ということが分かるようになり、レア度の順番に関する先入観が発生しないようになりました。

まだ、色を見ただけではどの順番でレア度が上がるのか分からないという問題はありますが、基本的にレア度の低いものから順にゲームに登場するので、プレイしている中で「このゲームではこういう順番なんだな」と理解してもらうことができます。

レア度を色で表現する場合は、別な色分けルールと混同されそうな色を避けることに注意が必要ですね。


ということで今回は「アイテムのレア度と色の話」についてでした。
また次の記事でお会いしましょう。

皆さんお久しぶりです。プログラマーの堀内です。
中編からだいぶ間が空いてしまいました。

さて、今回ですが前回の中編に続き『リトルリコレクター』の軽量化(最適化)についての続きになります。
前回の記事をご覧になっていない方は前編中編を読んだ上で、ご覧になっていただくとわかりやすくなっております。

背景の軽量化

エフェクト

まず、前回の記事で取り上げたエフェクトの軽量化です。
エフェクトの軽量化として比較的簡単に行える対応は、「描画されるエフェクトの数を減らす」「エフェクトに使用しているテクスチャの解像度を落とす」というものです。
しかし、それを行えば見栄えが大きく劣化してしまうという問題があります。このゲームの最大の売りの一つは絵なので、なるべく見栄えの劣化を伴わない対応を模索していました。

気にならない範囲でテクスチャの解像度を落としてはみたものの、画面の大半を霧が覆っており、それだけでは対処しきれない負荷がかかっていました。
十分な速度を出すためには、見た目を犠牲にしてでもテクスチャ解像度を更に下げるか、霧の密度が落ちるのを覚悟でエフェクトの数を減らすか、という局面に陥っていました。

今の仕組みを維持している限り、これ以上の最適化は難しいと判断し、霧の表現の実現方法を全く別のものに差し替えることで、見た目の劣化を抑えながら負荷の軽減が実現できる仕組みを作ることにしました。
具体的には、これまでパーティクルを使用して実現していたものを、軽量なシェーダーに置き換えるというものです。

パーティクルからシェーダーへ

パーティクルはオブジェクトを放出することでエフェクトを表現する仕組みのため、霧の密度を上げようとするとそれだけオブジェクトの数が増えることになります。
中編でお話した「半透明描画の重なり」の問題がここで直撃してきます。霧を濃くしようとすればするほど、半透明オブジェクトが積み重なり、描画コストが跳ね上がっていました。

一方シェーダーであれば、一つのオブジェクトに対して自由な密度の霧を描画することができます。
オブジェクトの数が劇的に少なくなった結果(近・中・遠景で3つまで抑えられました)、前回記事で問題にしていた「半透明描画の重なり」を大幅に抑えることができ、処理の重さの最大の原因を取り除くことができました。

具体的なオブジェクト数の変化のイメージとしては、以下のようなものです。

方式 霧オブジェクト数(目安) 半透明の重なり
パーティクル 数十〜数百個 非常に多い
シェーダー 3個(近・中・遠景) ほぼなし

この変更だけで、描画負荷が大きく改善されました。

見た目はどうなったか

霧最適化前

最適化前(パーティクル)

霧最適化後

最適化後(シェーダー)

そして気になる見た目の劣化度合いについてですが、嬉しいことに、パーティクルを使用していたときよりも自然な霧表現にすることができ、結果的に一挙両得の結果となりました。
パーティクルを使用していたときは霧というよりも湯気に近い印象だったのですが、シェーダーにする過程で表現を調整した結果、霧の動きや形状をより自然なものにすることができたためです。

パーティクルはあくまで「点の集まり」で霧を表現するため、どうしても粒感が出てしまいます。
シェーダーではピクセル単位で霧の濃度や動きを計算できるため、より滑らかで自然な見た目を実現しやすいという利点もありました。
負荷を下げようとした結果、見た目まで良くなるというのは開発していて素直に嬉しい瞬間でした。


スクリプトの最適化

原因が一箇所に絞れないケース

次にスクリプト周りの最適化の話です。
スクリプト周りでは計測をした際に、一概にここの処理が原因で負荷がかかっているという箇所が、実はあまり見つかりませんでした。

エフェクトのように「これが重い」とはっきり特定できるケースと違い、スクリプトの負荷は細かい処理が積み重なって全体的に重くなっているケースが多いです。
こういった場合は、一つひとつの処理を見直して少しずつ削っていくアプローチが有効です。

そこでいわゆる重たい計算や不要な処理などを、必要なとき以外は実行しないようにすることで全体的な負荷を削って行きました。

具体的に見直した処理

具体的には以下のような処理を対象にしました。

  • 数値計算(除算や平方根、三角関数など)
  • 物理演算
  • GC(ガベージコレクション)
  • UI

数値計算
除算は乗算に比べてコストが高いため、頻繁に呼ばれる箇所では逆数を使った乗算に置き換えました。
また距離の比較をする際に Vector3.Distance(内部で平方根を計算)を使っていた箇所を、sqrMagnitude(二乗距離)での比較に変更しました。
平方根の計算はコストが高いため、大小比較だけが目的であれば二乗のまま比較するほうが効率的です。

// 変更前
if (Vector3.Distance(a, b) < threshold) { ... }

// 変更後
if ((a - b).sqrMagnitude < threshold * threshold) { ... }

物理演算
画面外や非アクティブなオブジェクトに対して物理演算が走り続けていた箇所を見直し、不要なタイミングでは演算が走らないようにしました。
Unityの物理演算はオブジェクトが静止していても一定のコストがかかるため、使わないときは Rigidbody.Sleep() を呼ぶか、コンポーネント自体を無効化するのが有効です。

GC(ガベージコレクション)
毎フレームの処理の中でメモリの確保(new)が走っていた箇所を見直しました。
GCはメモリの解放タイミングが予測しにくく、処理が一瞬止まるスパイクの原因になります。
対策としては、オブジェクトを使い回す「オブジェクトプール」パターンを採用したり、ループ内での不要な配列生成を避けるようにしました。
また、最初にまとめてメモリを確保しておくことで、プレイ中のGC発生を抑えることができました。

UI
UnityのUIはCanvasが更新されるたびに再計算が走る仕組みになっています。
静的なUI(変化しない背景や枠など)と動的なUI(HPバーやスコアなど)が同じCanvasに混在していると、動的な部分が更新されるたびに静的な部分まで再計算されてしまいます。
これを別々のCanvasに分けることで、不要な再計算を防ぎました。

積み重ねの大切さ

これらの変更は一つひとつは小さなものですが、毎フレーム呼ばれる処理であれば積み重なって大きな差になります。
1フレームあたり16ms(60FPS)という限られた時間の中では、0.1msの節約でも積み重なれば体感できる差になります。

スクリプト周りでは、細かな処理の積み重ねで負荷が高まっていき原因が突き止めづらくなっていくので、スクリプトを書く際は、なるべく負荷のかからない方法を取るのがとても大切でした。


さいごに

まだまだ最適化の取り組みとしてはあるのですが、実際に効果が一番現れたものを今回は紹介させていただきました。

今回の最適化を通じて改めて感じたのは、「問題の本質を見極めてから手を動かす」ことの重要さです。
エフェクトの件では、削るのではなく「仕組みごと変える」という発想の転換が突破口になりました。
スクリプトの件では、目立たない小さな改善の積み重ねが全体の底上げにつながりました。

最適化に正解はなく、ゲームの内容や環境によって有効な手段は変わってきます。
ただ「計測して、特定して、改善する」というサイクルを丁寧に回すことが、どんな場合でも基本になると思っています。

前編・中編・後編と長くなりましたが、最後までお読みいただきありがとうございました。

 <  1 2 3 13  > 

page top