読者です 読者をやめる 読者になる 読者になる

テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】戦車が撃ち合うゲーム「Tanks!」はどのように作られてるのか

ふと思いついて、Unityの「Tanks!」の中身を解析してみます。

ゲームの内容は、1対1で戦車が出て撃ち合い、先にHPを全損させた方が勝ち…といった感じです。

パンツぁーフォー。

f:id:tsubaki_t1:20160118002737g:plain

プロジェクトはAssetStoreに公開されているので、そこからダウンロード出来ます。
Complete/Scenes/CompleteMainScene.sceneに作業が完了したシーンがあります。今回は完成版から挙動を把握していくので、そちらを使用します。

f:id:tsubaki_t1:20160118001854j:plain

https://www.assetstore.unity3d.com/jp/#!/content/46209

uNetに対応したバージョンも公開されているので、ちょっと見てみるのも面白いかもしれません。こっちは4人対戦です。

tsubakit1.hateblo.jp

ステージの構造

この戦車ゲーはステージの自動生成ではなく、単体のステージを使いまわす感じで作られています。なので、シーン内にステージが最初からセットアップされています。

f:id:tsubaki_t1:20160118002416j:plain

上から視点でチョコチョ動くので小さいように感じますが、実はステージはかなり大きいです。そのためチュートリアルでもライトマップを速くベイクするために、Precomputed Realtime GIの解像度を下げるような指示があります。

【Unity】ライトマップのベイク時間を短時間で終わらせる - テラシュールブログ

f:id:tsubaki_t1:20160118003253j:plain

ステージに置いてあるオブジェクトは1つのモデルに結合されている訳ではなく、Fallout4のワークショップのようにオブジェクトが配置されています。

コライダーはMeshColliderは(遅いからと思いますが)使用しておらず、殆どメッシュの形に整えたSphere ColliderやBox Colliderで代用されています。

f:id:tsubaki_t1:20160118025821j:plain

このセット、ワークショップではプレハブ置いて終わり…って感じで完結してますが、結構簡単にステージを改造したり新しいステージを作れそうな感じがあります
地面を置いて、上にモデルを置きまくるだけ。とりあえずサボテンとか地形とか岩とか置いても様になります。やり方はこの辺りが参考になるかも。

Unityを使った、冬道や地下鉄ステージのメイキングムービー - テラシュールブログ

Unity初心者が知っておくと少しだけ幸せになれる、シーンにオブジェクトを配置する時に使える18のTips+3 - テラシュールブログ

f:id:tsubaki_t1:20160118004252j:plain

なおゲームは戦車を自走砲ぽい挙動でしか運用出来ませんが、一応砲台は回ります。砲台を回したいならば…自分ならTankShootingを改造するかな

f:id:tsubaki_t1:20160118025719j:plain

コンポーネントの役割

f:id:tsubaki_t1:20160118022737j:plain

Tanksは幾つかのコンポーネントで構成されています。これらのコンポーネントは、大雑把に「ゲームシステム側」と「戦車側」に分割出来ます。あとは「UI(uGUI)」でしょうか。

殆どゲームシステム側は各戦車に対して関連しておらず、各々が勝手に動いてる感じです。せいぜいTankManagerが一括管理するぐらいでしょうか。

ちなみに上の図は、矢印元が矢印先を参照している、点線の矢印はコールバック(OnColliderEnter等)やSendMessage、AnimationEventが送られてるって意味です。

このゲームに使われている各コンポーネントは大体こんな感じです。

  • GameManager(ゲーム全般管理)
  • TankManager(戦車の管理)
  • CameraControl(カメラの管理)
  • TankMovement(戦車の移動)
  • TankShooting戦車砲
  • TankHealth(戦車の体力)
  • ShellExplosion(砲弾)

ゲームシステム側の話

まずゲームシステム側の話ですが、殆どGameManagerが制御・管理しています。

 また、ゲームz実行時に色々と参照関連は整理しますが、殆ど独立して動作しています。流石に足りない物があるとエラーになりますが。

f:id:tsubaki_t1:20160118030812j:plain

GameManager

ゲームの進行管理はGameManagerがコルーチンで行ってたりします。コルーチンの設計自体は、結構面白い作りで作っています。

作りについては【Unity】ゲームの進行をコルーチンで制御する - テラシュールブログで紹介しているので、そちらを。つまり、ゲームの進行やルールを書き換えるならばココを書き換える感じになりそうです。
シーンの読み込みもGameManagerのお仕事です。

 CameraControl

CameraControlはCameraに対して管理・・・具体的にはカメラの位置調整を管理しています。
近づくとズームインして、離れるとズームアウトするのはCameraControlの効果です。敵が何体か居た場合でも、全てのキャラクターが視界内に収まるように調整してくれます。
ちなみにカメラはOrthographicで動作します。似たようなものを以前作りましたが、こっちの方がクォリティ高い…ううむ。

【Unity】距離に応じて2Dカメラを拡大・縮小する処理 - テラシュールブログ

追跡するべき戦車はGameManagerが教えてくれてくれます。

f:id:tsubaki_t1:20160118010648g:plain

TanksManager

TankManagerは、名前の通り戦車を作ったり管理したりします。
と言ってもやってる事と言えば「戦車の生成」と「戦車の位置のリセット」、戦車についている各コンポーネントのON/OFFくらいです。要するに戦車を一括管理する機能…といった感じです。

ちなみにTankManagerコンポーネントではなくGameManagerが持ってるクラスです。ここに3体目・4体目のSpawnPointを指定すると、出現する戦車を増やせたりします。操作系を何とかすれば3人・4人で戦争出来そうな気がします。

f:id:tsubaki_t1:20160118013231j:plain

f:id:tsubaki_t1:20160118013237j:plain

戦車とか砲弾側の話

次はプレイヤー側です。要するに戦車の動作関連がこちらに当たります。

なおゲームマネージャー側に対して参照が無いので、戦車単体でも動かせたりします。もし戦車ゲーを作りたいなら、とりあえずコレを突っ込むのもアリかもしれません。

f:id:tsubaki_t1:20160118014134g:plain

戦車のプレハブはAssets/Complete/Prefabs/CompleteTankにあります。

f:id:tsubaki_t1:20160118020802j:plain

さて、各コンポーネントの関連についてです。

ピンク色がオリジナルなクラス、肌色がUnity標準のクラスです。なお本当はAudioSourceとかAudioClipが色々な処から参照されてたりしますが、分かりにくくなるので消してあります。

f:id:tsubaki_t1:20160118015641j:plain

Tankと名前が付いている機能が幾つかありますが、お互いに全く参照しておらず独立して動いてるのが中々に面白い所です。

お互いに参照していないので、TankMovementTankShootingTankHealthどれか欠けても動作します。いっそのこと3人で操作すれば良いんじゃないかな。

f:id:tsubaki_t1:20160118020738j:plain

TanksMovement

TankMovementは戦車の移動を制御するコンポーネントです。
このコンポーネントRigidbodyVelocityに対して直で値を操作して戦車を移動させます(ので、初期状態は坂道が登れないです。戦車の癖に!)

Player Numberを指定する事で、起動時に操作する人が切り替わります。1だとWASD、2だとカーソルで動きます。
あとは速度やら、戦車のエンジン音のピンチやら、そういったパラメータです。

f:id:tsubaki_t1:20160118015952j:plain

履帯が作る移動時の煙は、TankMovementではなく「移動したら煙を出す」パーティクルを設定しているだけです。戦車プレハブの持ってる「***DustTrail」とか、そんな感じ。

f:id:tsubaki_t1:20160118020342j:plain

 TankShooting

戦車砲を発射するのはTankShootingのお仕事です。
Shellに登録したプレハブにRigidbody的に力を与えて発射します。

また、PlayerNumberがまたあります。1だとSpaceキー、2だとEnterで発射になります。

f:id:tsubaki_t1:20160118022136j:plain

ちなみに、発射の力はAddForceではなくVelocity直弄りです。そんなに物理演算が嫌いか…!(GJと言っておこう)発射時は色々と発射音が付いて来たりします。

f:id:tsubaki_t1:20160118022513j:plain

面白いのが、発射時の力を表現する矢印バーで、これはuGUIのスライダーで作られています。Aim Sliderがソレにあたります。
SliderのValueを変更すると伸びるようになっているので、これをWorldSpaceで配置し管理しているみたいです。
Canvasは1戦車につき1つ、これが正しいのか微妙なのかは…中々に難しい所。

f:id:tsubaki_t1:20160118022603j:plain

f:id:tsubaki_t1:20160118023101g:plain

TankHealth

TankHealthは戦車のライフと、ライフを表現するUIを管理します。つまり戦車の足元にある円です。

これもSliderで作られてます。Slider大人気…!

f:id:tsubaki_t1:20160118023547g:plain

TankHealth自体は殆ど何も機能を持っておらず、ShellExplosionからTankDamage(int amount)経由でダメージを受ける、「ダメージを受けたらHPバーを減らしたり色を変えたり」して、HPが無くなったら「自身のGameObjectのActiveをFalseに」設定し、「爆発パーティクルを表示」といった機能を持ちます。

特に「死んだ」をGameManagerへ通知するのではなく、GameObjectを非アクティブにして、GameManagerからポーリングでチェックしてもらうのは若干如何なものかと思わなくもないです。

なお、装甲は上下左右全部同じです。ダメージ判定はShellExplosionの爆発からしか来ないので。やるならShellExplosionに直撃ボーナス付けるか、TankHealth側でも直撃判定するか、どちらかかな。

ShellExplosion

ShellExplosionは、砲弾についてるコンポーネントで、砲弾と一緒に飛んでいきます。

f:id:tsubaki_t1:20160118024129j:plain

役割は非常に単純で、

  • 弾(物理演算で動作)と一緒に飛んでいく
  • 地形または敵と当たったら爆発する(音とパーティクルを出す)
  • 周辺のRigidbodyを収集して、距離に応じてダメージをTankHealthに与える

といった感じです。

3番目は正確には、飛行中にコライダーからOnTriggerEnterコールバックを受け取ったら、Physics.OverlapSphereで周辺のコライダーを全部収集して、Physics.AddExplosionForceで周辺の戦車を吹っ飛ばし、ついでにTankHealthがあればダメージを飛ばします。

もっと範囲の広い攻撃や地雷、あとレインボー砲みたいなレーザー作りたい場合は、こいつを色々と改造すると良い気がします。
ミサイル?バランス崩壊は確定的に明らか。

感想

さすがワークショップ用だけあってかなりシンプルです。

この手の奴は次はVR Sampleを解析したい処です。
自宅のPCでOculus Configuration Utilityがマトモに動けば。

どうでも良いけど、コンバットチョロQ復活しないかな…

関連

本件のリパブリック(ステルスアクション)版です。ステルス部分はオミットされてるので、単純な絵作りとアニメーション制御についてです。

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

ワークショップの風景です。自動文字起こしなので、英語をそのまま聞いた方が速いかもしれません。

www.youtube.com

ネットワーク対応版のTanksをプレイする方法です。ネットワークサービスが入ってくるので少しややこしい所があります。

tsubakit1.hateblo.jp