feature image

2025年2月14日 | ブログ記事

2024年度冬ハッカソン23班「Mechanised Carrasius」

なにを作ったのか

冬ハッカソン23班です。宇宙でロボが対戦するゲーム「Mechanised Carrasius」を作りました。宇宙空間で銃を撃ちあって当たったら勝利という非常にシンプルなゲームです。

タイトル

メンバー

aruze_pino: 3Dグラフィック、エフェクト
kavos: プログラミング
Liscome: サウンド

制作風景

3Dモデル

プレイヤー

blenderにて制作しました。
メカの理想は大体虫に近しいものがあると思っています。歪に長い腕だったり、銃だったり、そういったアンバランスさこそがロボをロボ足らしめるんですね。人型ロボットを否定するつもりは全くありませんが、やはり異形のメカのロマンパワーははかり知れませんね。53万くらいあります。
デザインに関していうことはこれがすべてなんですが、何分突貫工事だったのでUV関係が終わっています…キャラクターモデリング等ならばきれいなトポロジーのノウハウはいくらでも転がってますが、人型から離れるとかなりトポロジーを意識するのは難しくなりますね…通常ならばリトポロジーをするのがセオリーです。みなさんはちゃんとやりましょう。

エフェクト

effekseerというツールを使って作成しました。

Effekseer


3Dゲームでのエフェクトは基本的に小さなパーティクルを何重にも同時に重ねて表現することでリッチな表現をします。
ノードでエフェクト制作が可能なので直感的にリッチなエフェクトを作ることができます。
初めての使用でもすぐに簡単にこのくらいのエフェクトは制作できます。↓

着弾エフェクト

サウンド

FedoraのAudio Productionグループに含まれていたソフトをいくつか適当に弄ったらできました。
ほぼ未経験だったのでとても苦労しました。

プログラミング

~2か月前~
私「最近DirectXとかやってみたいと思ってるんだよね」
「そうなんだ!じゃあゲームエンジン作ってよ!」
私「おもしろそう」
「じゃあそれで冬ハッカソン出ようよ!」
私(あと2か月で...??)

私「ゲームを起動したときに毎回表示される〇nityのロゴってうざくない?」
「わかる!わかる!」

このゲームは、UnityやUnreal Engineなどのゲームエンジンを使わず、DirectX12を使って自作したゲームエンジンを使用して開発しました。使った技術をいろいろ紹介します。

ゲームエンジン

2か月で作ったゲームエンジンです。AquaEngineといいます。

GitHub - kavos113/aqua-engine
Contribute to kavos113/aqua-engine development by creating an account on GitHub.

ゲームエンジンといっても、中身はDirectXの薄いラッパーライブラリみたいなものなので、そんなに大したものではありませんが、一応置いておきます。
あまり設計がよろしくないので、作り直したいですね。

ゲームエンジンを作るときに得られた知見は後々別の記事にしたいと思っています。

モデルの描画

3DモデルにはFBXファイルを使いました。プロプライエタリなファイル形式なのでデータのフォーマットが公開されておらず、FBX SDKという専用のライブラリを使う必要があります。つらいです

UI: Direct2D/DirectWrite

UIにはD3D11On12を利用してDirect2DとDirectWriteを使いました。
ImGuiなども考えましたが、せっかくDirectXからやるのでなるべくライブラリを使いたくないと思い、OS標準のDirect2Dを使うことにしました。割と柔軟に描画の設定ができるので良い感じです。

対戦: winsock2

このゲームの目玉でもある対戦機能ですが、1週間でサーバー・クライアント方式のものを作るのは無理があります。そこで...

通信対戦のようす

こうなりました。家に転がっていたスイッチングハブを介してLANケーブルで接続し、winsockを使ってUDP通信をすることで通信対戦を実現しました。なんか時代がいくらか巻き戻った感じです。ちなみに、有線で接続しているため遅延はほとんどないです。ワイヤレスにこだわらなければね、これでも十分なんです。ソースコードはここのファイルに全部書いてあります。
Network.cpp

サウンド: XAudio2

サウンドの再生にはXAudio2を使いました。X3DAudioが意外とうまく動いてくれました。XAudioも極めればもっといろいろ使えそうなので、勉強したいですね。最終日の3時間くらいで気合で書いたコードがこちらになります。雑な実装でしたが、サウンドを入れたことでゲームが華やかになりました。
AudioManager.cpp
ちなみに、BGM再生を別スレッドで行っているためメインのウィンドウを閉じてもBGM再生が止まらず、タスクマネージャーからキルしないといけないという残念なバグがあります。

DirectXを使ってつらかったところ

DirectXを使っていると、つらいところがたくさんありました。

the object is NULL

DirectXを使ったアプリケーションのソースコードは膨大になりますが、そのうち1カ所でも1が0に変わっただけで全体が動かなくなります。無限にデバッグです。

重い

低レイヤなAPIを直接使っているんだから軽いだろ~とか思っていましたが、普通に重いです。対戦ゲームなのにFPSが15くらいしか出ません。バッテリー駆動のノートPCだとFPS5です。オブジェクトもそんなに多いわけではないのに... Unityとかはちゃんと最適化しているんだなあと思いました。

要因1: インスタンシングをしていない

インスタンシングとは、同じオブジェクトを複数描画するときに、一回一回描画するのではなく、すでに描画したものをコピーして描画する手法のことです。今回はインスタンシングをやらなかった結果DrawIndexInstanced()が1フレーム当たり200回くらい呼ばれてしまっています。
また、同じオブジェクトなのに別のバッファとして利用しているため、同じデータが100個くらいあり、メモリを圧迫している可能性があります。

要因2: カリングをしていない

カリングにはいろいろな意味がありますが、ここでは「画面外のオブジェクトを描画しないようにする」処理のことです。これをやっていないために、常に世界全体を描画しており、重くなっている気がします。Mesh ShaderやWork Graphなどを使ってやってみたいです。

3次元回転がわからない

2次元では単純に何度回転するか、という情報だけでよいのですが、3次元空間では「どの軸を中心にどの方向に回転するか」という情報が必要になるため、回転がとても難しくなります。x, y, z方向にそれぞれ何度回転するかを指定しても、順番によって回転後の位置が変わってきます(行列積は非可換なので)。そのため、「今どの向きを向いているか」などを正確に把握する必要があり、結構大変でした。
ちょうど教養の線形代数の授業で学んだところが役に立ちました。ありがとう、線形代数学第二

ビュー行列を掛けても2次元座標系にならない

なぜ...?
相手のプレイヤーに的を表示するUIがあるのですが、そのためには相手のプレイヤーの3次元座標を2次元座標に変換する必要があります。このためにビュー行列を掛ければよさそうと思ったのですが、全然的外れでした。結局ごまかしながら調整しているため、完璧に相手を追跡できていません。

the object is NULL

ごめんなさい

テクスチャがおかしい

なんかおかしいんですよね。なんとかごまかしてはいますが、本来のモデルではこのような黒い部分は存在しないです。

シェーダーがわからない

シェーダーで法線情報を処理しようとしたら、いきなり全部の色が0になりました。具体的な値が見づらいのはつらいところです。

情報がない

DirectXを直で使っている人は少ないですし、使っている人もゲーム会社でゲームエンジンを作っている人とかなので、ネットの海に情報がなかなか流れてきません。GitHubの検索に大変お世話になりました。

Linker Error: このライブラリはMultiThreadedであり、MultiThreadedDLLとは異なります

統一してくれ~~
CMakeListsを書き換えて解決しました。

failed: find_package

vcpkg、難しい

DirectXを使ってよかったところ

DirectXはつらいだけじゃないですよ。

すべてのものに感動できる

DirectXで作るのは大変です。さらに、影やアニメーションなども自分で書かなければいけません。思い通りに動かないことがほとんどなので、それを難なく動かしている世間の3DCGに感動します。
特に、アニメでは顕著です。影が地面の起伏に合わせて変形していることに感動します。人間が階段を上るときに自然に足を動かせていることに感動します。すべてのものに感動できます。

全能感が得られる

DirectXでは全部自分でプログラミングしなければいけません。なので、プログラムが動いたときはもうどんなCGでも理解できるんじゃないかという気持ちになります。

すごいグラフィックができる(たぶん)

シェーダーを自分でプログラミングするので、作れるライティングの可能性は無限大です。きっと既存のゲームエンジンにもできないようなきれいなグラフィックを作ることもできるでしょう(たぶん)。私はそれ以前のテクスチャ描画でつまずいていましたが。

ひとこと

aruze_pino

全体の進捗管理とグラフィックを担当しました。終わると確信を持っていましたがkavosくんが頑張ってくれました。最終日に2時間仮眠を取っていたらカメラやエフェクトが実装されていたのは少しビビりました。彼らを奴隷のように酷使しつつ定期的に進捗を催促することによってブラックな労働環境を提供してしまったことは正直申し訳なく思っていなくもないです。ゲームエンジンを自作することの最大のメリットというのはやはりオリジナルのスプラッシュスクリーンを実装できるということでしょう。これがゲームエンジンを自作しようとした最大の動機にはなるかなぁと思っています。

Liscome

作曲のセンスを感じられなかったので機材のコレクターに戻ろうと思います。Audio-Technicaのモニターヘッドホンは定番ですがとても良いです。

kavos

すべてのプログラミングを担当しました。
正直終わるとは思っていなかったのですが(実際終わってはいないですが)、なんとか形あるものができてよかったです。DirectXからでもゲームが作れるということが分かったのはよい収穫になりました。
なかなかうまくモデルが描画できず、初日に完璧な3Dモデルを作ってくれたaruze君に申し訳ないですね。
もっとゲームエンジンの完成度を上げて、また自作でリベンジしたいです。

kavos icon
この記事を書いた人
kavos

24B CTFなどをやっています

aruze_pino icon
この記事を書いた人
aruze_pino

デザインに四苦八苦しながら3Dモデルを作っています。イメージの出力系に難あり。

Liscome icon
この記事を書いた人
Liscome

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2024年4月22日
CPCTF2024に参加しました
kavos icon kavos
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記