Oliver Wang

インディーゲーム開発者

どうも、Oliverです!

Godot、Unity、Unreal Engineを使って、一人でインディーゲームを作っています。ゲームプレイの仕組みを考えたり、表現を試したり、パフォーマンスを詰めたりするのが好きです。hi、bonjour、こんにちは、你好、どれでも気軽に声をかけてください。フランス語、日本語、中国語も、ある程度なら話せます!

ゲーム業界での年数
5+
ゲーム開発の年数
3+
未完のヒット作
12+
GodotUnityUnreal EngineC#C++PythonGDScript🇨🇦
ベビーカーに座る幼い娘におどけた表情を見せるOliver。娘の顔は画面の外。黒いシャツを着て室内に座り、横を見ているOliver。
オレンジ色の爆発と緑のパーティクルの下で、ゾンビの大群が画面を埋め尽くしている。

デイ・オブ・パーガトリー

生存者は一人、ゾンビは多すぎるほど。大群、とんでもない量のエフェクト、豊富なバリエーションとカスタマイズを詰め込んだサバイバー系ゲームです。GPUが途中で音を上げないようにするのも大事なテーマ。

GodotC#Python独自ECSGPUインスタンシング高度なシェーダー地形ストリーミング
生存者が開けた場所に立ち、その周囲を大量のゾンビと明るいパーティクルが取り囲んでいる。

大群、どんと来い

独自のECS風シミュレーション、バッチ描画、軽量な衝突判定、プールしたGPUエフェクトで、この混沌をさばいています。

緑と黄色のエフェクトに包まれたゾンビの群れに、赤と白のダメージ数値が重なって表示されている。

一枚のクアッドで、五桁

ダメージ数値をインスタンス化したクアッドに集約。MSDFグリフとGPU上のアニメーションで、一桁ごとのメッシュを不要にしました。

苔の生えた地面が、砂地へとなだらかに混ざり合っている。

どこまでも続く地形

ベイクしたプロシージャルテクスチャ、確率的タイリング、高さベースのバイオームブレンドを使った地形チャンクのストリーミング。

もっと詳しく

大規模な敵シミュレーション

キャッシュ効率を意識したデータ構造、軽量な物理・衝突判定、MultiMeshによる描画を、独自のECS風アーキテクチャでまとめています。ゾンビ一体ごとに重いノードの集合を作らずに、大群を扱うための仕組みです。エフェクトの多くはプールしたGPUパーティクルで処理するので、爆発や血しぶき、ソウル回収の演出が重なっても、オブジェクトの生成と破棄を繰り返さずに済みます。

GPU描画と最適化

エフェクト作りでは、見栄えと同じくらい「処理を減らすこと」も意識しています。ジオメトリのバッチ化、オーバードローの削減、不透明・透明マテリアルの使い分けに加え、余白の多いテクスチャで無駄なピクセルを描かないよう、頂点を調整することも。選択的なグロー、軽量な疑似シャドウ、いろいろなシェーダーの工夫で、パフォーマンスを犠牲にせず画面をにぎやかにしています。

独自のMSDFダメージ表示

ダメージ数値にまで、専用レンダラーを作りました。数字一桁ごとにジオメトリを用意する代わりに、一つのダメージ表示を一枚のインスタンス化したクアッドに詰め込んでいます。文字ID、色、方向、タイミング、スケール、エフェクトのパラメーターを、四つのfloatに格納。シェーダーがそれを展開してMSDFグリフを参照し、クアッドの形を調整しながら、ポップ、揺れ、浮遊、点滅まで処理します。すべてGPU上で。

プロシージャル地形のベイク

地面をきれいに見せたかっただけなのに、気づけば地形のプロシージャルベイクシステムになっていました。確率的タイリングでテクスチャの繰り返しを目立たなくし、高さベースのブレンドで複数のバイオーム素材を自然につないでいます。ただ、テクスチャのサンプリングやブレンドを重ねると処理は重くなります。そこで毎フレーム計算する代わりに、チャンクのテクスチャへベイク。複雑な処理はチャンク生成時に済ませ、その後は軽い結果を使えるようにしています。

フレーム予算に合わせた地形ストリーミング

もちろん、地形のベイク自体にも処理時間はかかります。カメラの表示範囲に合わせてプールからチャンクを取得し、新しいベイク処理は設定可能なキューで複数フレームに分散。カメラがワールドを移動しても、地形生成が一度に全部の仕事を抱え込まないようにしています。

キャラクターの着せ替えと強化

キャラクターは、差し替え可能な装備スプライト、色、アニメーションデータを組み合わせて構成しています。頭、服、武器、アクセサリーを自由に組み替えても、服装の組み合わせごとに別のアニメーション一式を用意する必要はありません。ダメージ、移動速度、弾数、攻撃挙動などを変える、ステータスベースの強化システムもあります。着せ替えUIはまだ形になっていませんが、土台のシステムはできています。

2.5D描画と深度ソート

見た目は2Dですが、裏側は実は3Dです。ゾンビ、プレイヤー、死体を深度で並べつつ、独自の座標調整やシェーダーの工夫で、重なり方を整えています。ゾンビは倒れると死体を残しますが、これも独自の深度制御を加えたMultiMeshで描画。何十万体分が積み重なっても、シーンツリーが埋まらないようにしています。異なるレイヤーの間でライティングをそろえるには少し追加の計算が必要でしたが、そのおかげで銃口の光などがシーン全体を自然に照らせます。

青とオレンジの星雲が広がる星空に、光る惑星が浮かんでいる。

タイプ・ディフェンダー

文字たちが攻めてくるなら、タイピングで撃退! Godotで制作しているタイピング・ローグライクです。統一感のあるきれいな画面、派手なエフェクト、とんでもない数の敵、そしてそれを滑らかに動かすことに力を入れています。

GodotC#GDScriptPythonArch ECSMSDFインスタンシング
無数の星を背景に、青と青緑の星雲が広がっている。

宇宙をいい感じに

高度なシェーダー、ボリューメトリックな星雲、ポストプロセスのライティング。全部がなじむまで、とにかく調整しました。

光る緑の惑星の周りを、何百ものオレンジ色の文字が渦を巻くように取り囲んでいる。

文字、文字、文字!

独自のMSDF、MultiMesh、ECSによるグリフ描画パイプラインで、何千もの文字を効率よく描画します。

オレンジと青の星雲を背景に、明るく光る白い惑星と、その周囲の小さな色とりどりの惑星が見える。

その裏側の仕組み

独自の軌道運動の物理挙動を持つECSベースの敵と、試行錯誤やパフォーマンスを重視したデータ指向のシステム。

もっと詳しく

独自のグリフ描画

敵は一文字ずつのグリフでできていて、それぞれが移動と描画のデータを持っています。土台はArch ECS。独自のMSDF描画とGodotのMultiMeshを組み合わせ、何千もの文字を、何千もの個別ノードを作らずに動かしています。

モジュール式の敵アーキテクチャ

敵は、ただプレイヤーに向かってくるスプライトではありません。軌道上を回るパーツ、弾かれる挙動の物理処理、親子間の座標変換などの仕組みが裏で動いています。モジュール式の構成にすることで、新しい敵や挙動を試すたびに、一から書き直さずに済むようにしました。

プロシージャルな宇宙とシェーダー

宇宙の表現には、独自シェーダー、プロシージャルな背景、星雲、ポストプロセスを使っています。全部が同じ世界の一部に見えるように、かなり調整を重ねました。画面が光る文字で埋まり始めると、なおさらです。

高速なシミュレーション

やりたいことは単純です。敵をもっと、文字をもっと、混沌ももっと。実装は、そう単純ではありません。独自のシミュレーションシステム、バッチ描画、変換データの丁寧な管理で、敵が増えても滑らかに動くようにしています。

青いグリッドの上に草地の浮島が並び、黄色い選択枠と建築ツールバーが表示されている。

キュービルダーズ

Unityで作った、カラフルな小さなレベル制作サンドボックス。ブロックを置き、島を形作り、自分だけの世界を組み立てます。直感的な操作とすっきりしたUIで、気軽にレベルを作れることを目指しました。

UnityC#エディターツールUI/UXデータ駆動アセット
もっと詳しく

迷わず、どんどん組み立てる

カラフルな3Dワールドを、ブロック一個ずつ組み立てるグリッド式の建築システムです。シンプルな配置操作と画面上のガイドで、エディターの使い方に悩むより、作ることに集中できるようにしています。

動的なアセットブラウザーとUI

配置できるブロックのライブラリを、スクロール可能な選択メニューにそのまま反映。アセットを探したり切り替えたりしやすくしています。アニメーション付きのパネル、状況に応じた操作、すっきりしたUIで、作業の流れを邪魔しない使い心地を目指しました。

UnrealのBlueprintグラフで、複数のノイズ処理ノードが接続され、出力につながっている。

リフト

C++とUnreal Engineで作った、プロシージャルノイズ生成の実験場です。独自のノイズアルゴリズム、SIMDによる高速化、固定小数点演算、それにいろいろなビット演算の工夫で、生成処理のパフォーマンスをできる限り引き出しています。

Unreal EngineC++開発ツールSIMDプロシージャル生成固定小数点演算
もっと詳しく

SIMDでノイズを高速化

プロシージャルノイズには、同じような計算の繰り返しがつきものです。大量に生成すると、なおさら。Riftでは独自のノイズアルゴリズムにGoogle HighwayによるSIMD高速化を組み合わせ、サンプルを一つずつではなく、複数まとめて計算しています。柔軟性を保ちつつ、CPUの力をできる限り引き出すのが目標です。

固定小数点演算

浮動小数点演算は、ハードウェアによって結果がわずかに変わることがあり、再現性が必要なプロシージャル生成には都合がよくありません。Riftでは固定小数点演算を使い、同じ入力から同じノイズが得られるようにしています。生成済みデータをすべて保存せず、シードからワールドを再構築したいときなどに役立ちます。

ビット演算とメモリの最適化

裏側では、低レベルな最適化もいろいろやっています。ビット操作、コンパクトなデータ表現、演算の選び方を工夫して、大量のノイズデータを処理するときの無駄を減らしています。かなり細かい工夫もありますが、同じ計算を何百万回と繰り返す場面では、その積み重ねが効いてきます。

ノードで組み立てるノイズ

ノイズは、いろいろな関数を組み合わせると、ぐっと面白くなります。Riftには、ノイズの処理をつなぎ、パラメーターを調整し、複雑なパターンを試せるビジュアルなノード式ワークフローがあります。調整のたびにC++を書き直さなくても、低レベルな計算の仕組みを扱いやすくするためのものです。

ゲーム作りの合間は?

  • 三人称視点のキャラクターが、茅葺き屋根の家や畑、村人たちを見渡している。

    Bellwright

    自分だけの、のどかな村

  • 一人称視点で、掘り進めた長い岩のトンネルを見ている。手前には武器が見える。

    7 Days to Die

    資源を求めて、ひたすら穴掘り

  • 木造の家が並ぶ石畳の村の通り。手前の火鉢で火が燃えている。

    スカイリム

    MOD導入10時間、プレイ1時間

  • 木造の建物のそばで、味方の後ろにいるプレイヤーがシールドを回復している。

    エーペックスレジェンズ

    全滅する、その直前

  • 紫色に照らされたリズムゲームの空間に、ブロックとセイバーの軌跡が広がり、コンボ数と倍率が表示されている。

    Beat Saber

    いい汗かいてます

  • ネオンが光る自動販売機のそばに男性が立ち、画面下には会話の字幕が表示されている。

    サイバーパンク2077

    こちらこそ、はじめまして

  • 敵の集団と戦うキャラクターの上に、「Paragon Level 466」の表示が出ている。

    ディアブロ III

    終わらないトレハン

  • 大きな斧を持った鎧姿のキャラクターが、木の足場と燃えるたいまつのそばに立っている。

    ダークソウル Ⅲ

    百回目の死に挑む

  • 円形の石床の上で、キャラクターが木人に魔法を使っている。戦闘ログとホットバーも表示されている。

    ファイナルファンタジーXIV

    学者で火力の限界に挑戦

  • 草地の丘に、たいまつで照らされた石造りの神殿が立ち、幅の広い階段が入り口へ続いている。

    マインクラフト

    神殿完成!(7DTDでも使用)

  • ヒーロー選択画面でTracerが選ばれ、両チームの対戦ランクのエンブレムが表示されている。

    オーバーウォッチ

    これは手ごわそう

気軽に話しましょう。

プロジェクトの相談、お仕事のお話、ちょっとした雑談も歓迎です。

hello@wangoliver.com