ビデオゲームで弾丸はどのように機能しますか?


64

C#でビデオゲームを設計しているときに、この質問に出会いました。

BattlefieldCall of Dutyなどのゲームを考慮すると、数百または数千の弾丸が同時に飛んでいます。イベントは絶えずトリガーされますが、私が知っている限りでは、これは処理能力を大量に消費します。さまざまなゲーム開発者が(2Dおよび3D)箇条書きをどのように管理し、それぞれにとって最も効率的な方法は何かを知りたいです。

私は質問読ん弾丸はビデオゲームでシミュレートされているどのように?ただし、プログラムの設計の観点からは、箇条書きがどのように機能するかについては触れません。

いくつかのアイデアがありましたが、それぞれに欠点があります。


私が考えることができる最も効率的な方法(2Dゲームの場合):

Bulletと呼ばれるクラスを作成し、ユーザーがボタンを長押ししても、0.01秒ごとにBulletオブジェクトが作成されるとします。この箇条書きの内容:

  • 1速度

  • 2ショットの開始位置

  • 3スプライトテクスチャ

  • 4ヒットエフェクト

箇条書きは独自のクラスになるため、描画、移動、およびアクションリスナー自体を管理できます。

インスタンス化されたこれらのオブジェクトの数千個を処理してから破棄するのは、プロセッサ上で難しいのではないでしょうか?RAMスペース?


3Dゲームの効率的な方法-私が考えていたもう1つの考えは:

武器クラスを作成するとしましょう。この武器にはさまざまな機能があり、そのうちのいくつかは次のとおりです。

  • 1武器の照準を検出し、ターゲットを見ているかどうかを判断します

  • 2銃撃のアニメーションをトリガーする

  • 3 doDamage()メソッドがあります。これは、銃が向けられているものからヘルスを差し引くものを示します

  • 4ボタンが押されたときに弾丸アニメーションクラスに通知する

次に、BulletAnimationなどの静的クラスを作成して、それがトリガーされた銃の場所、その銃が向けられている場所(弾丸の宛先)、および弾丸に使用する適切なスプライトと速度に関する情報を取得できます。次に、このクラスは、位置と目的のスプライトの両方に基づいてスプライトを描画し(おそらく新しいスレッドにidk)、銃から発射される弾丸をシミュレートします。


後者はコーディングがはるかに難しいようで、一度に何千もの弾丸に対してこれを行うために静的関数を絶えず呼び出すには、多くの処理能力が必要ではないでしょうか?開始位置と終了位置の両方で絶えず更新を取得することも困難です。

私の質問は、ゲームクリエーターが最も効率的に行う方法は何ですか?この方法は2Dゲームから3Dゲームに変わりますか?


16
今日でも、ほとんどのゲームは弾丸の飛行をシミュレートしないことに注意してください。「十分に高速」と見なされるものについては、代わりに単純なヒットスキャンが実行されます。基本的に、トリガーを押すと同時に衝撃が発生すると想定されています。いずれにせよ、「数百または数千の弾丸」はそれほど大きなものではありません。これは、ゲームが非常に初期のコンソール(さまざまな弾丸ゲーム)以来のものであり、今日のマシンの数千倍も強力ではありません。弾丸ごとにできる限り少ない作業のみを行うように注意する必要があります:)
Luaan

42
箇条書きは通常、pew-pew-pewテクノロジーを介して機能します:)
MonkeyZeus

5
数百または数千の弾丸が同時に飛び回ることはありません。そんなに速くそれらを発射する銃はありません。強力なファランクスでさえ毎秒75発です。ウィキペディアにリストされている「有効射程」に基づいて、弾丸は最大で約3秒間飛ぶので、ファランクスは一度に225個の弾丸を空中に置くことができます。M16は約12ラウンド/秒で突破し、その速度を維持できません(持続射撃の最大値は0.25ラウンド/秒です)。一度に発砲する銃はそれほど多くありません!
コートアンモン

3
これを指摘するために、オブジェクトが非常に単純な場合、オブジェクトを個別のクラスにすることは決して良くありません。弾丸のタイプごとに1つのbulletFieldインスタンスを用意することをお勧めします。コードの長さやその他のわずかなオーバーヘッドにより、弾丸ごとに余分な4バイトワードが節約されます(タイプが整数の場合)。さらに、1つのオブジェクトでリストを簡単にスキャンできます。
グレートダック

4
@Cort-ゲーム空間に銃器が1つしかない場合、それは本当です。OPはBattlefieldやCoDのようなゲームについて言及しました。そこでは何十人ものプレイヤーが自動銃を同時に発射できました。各ラウンドが実際に宇宙で物理的に説明されている場合、ばかげた数があるのは不合理ではありません。
ジェシーウィリアムズ

回答:


78

なぜそれらをシミュレートするのが難しいと思うのかは確かにわかりますが、弾丸(実際にはすべての発射物)にはそれらを簡単にするのに十分な制約があります。

  1. それらは通常、ボリュームのあるものとしてではなく、単一のポイントとしてシミュレートされます。これにより、円に対する線など、非常に単純なサーフェスに対してのみ衝突を行う必要があるため、衝突検出が大幅に容易になります。

  2. それらがどのように移動するかはわかっているので、保存または計算する必要のある情報はあまりありません。リストはかなり正確でした。通常、弾丸を撃ったのは誰か、そのタイプは何かなど、それに関連するものがいくつかあります。

  3. すべての発射物は非常に似ているので、それらを事前に割り当てて、動的に作成するオーバーヘッドをすべて回避できます。1000個の発射物の配列を割り当てることができますが、今ではインデックスだけでそれらにアクセスでき、それらはすべてメモリ内でシーケンシャルであるため、それらの処理は迅速になります。

  4. ライフタイム/範囲は固定されているため、古い箇条書きを期限切れにして、メモリを新しい箇条書きに非常にすばやくリサイクルできます。

  5. 彼らが何かにぶつかったら、期限切れにすることもできます。

  6. それらがいつ作成されたかを知っているので、新しいものが必要で、事前に割り当てられたリストに空きがない場合、最も古いものを取得してリサイクルすることができます。弾丸が少し早く期限切れになると、人々は気付かないでしょう。

  7. それらはスプライト(通常)または低ポリゴンモデルとしてレンダリングされ、画面上のスペースをほとんど占有しないため、レンダリングが高速です。

これらすべてを考慮すると、弾丸は比較的安価になる傾向があります。私たちの予算が弾丸で消費されてレンダリングされた場合、通常は一度に発射できるショットの数を制限するように再設計します(これは多くの古いアーケードゲームで見られます)、すぐに移動するビーム武器を使用します、発射速度を遅くして予算内に収まるようにします。


12
私は5)に反対しなければなりません。これは実際、現代のゲームでは全体を複雑にしているだけです。初期の射手ではこれは許容範囲でしたが、最近ではCODでさえプレイヤーが木製の壁を通して射撃することができます。6)競合システムでは受け入れられませんが、まれな問題になります。
SBoss

17
@SBossは、言い換えると、「侵入できないものにぶつかったら、期限切れにすることもできるので、寿命が限られています。」そして、6の場合、キャラクターごとの最大発砲率に上限を設定し、長さの配列を保持することで最悪のケースを得ることができますnum_characters * max_bullets_per_character
ラチェットフリーク

14
@SBossたとえば#6はもっといいと思います。トップダウンの宇宙ゲーム。動きの遅い弾丸が、何かにぶつかったり消えたりする前に、画面から遠く離れて移動する場合があります。明らかに、弾丸が速く動き、世界の境界に素早く到達するCoDタイプのゲームでは問題ではありません。
BlueRaja-ダニーPflughoeft

1
ゲームの大部分は、弾丸(外部弾道学)をまったくモデル化していません。ほとんどのゲームは、「ヒットスキャン」と呼ばれる手法を採用しています。
アロン

45

おそらく、弾丸を実装する最も効率的な方法の1つは、hitscanとして知られるものを使用することです。その実装はかなり単純です-発砲するときに、銃が何を目指しているかを確認し(おそらく光線を使用して最も近いエンティティ/オブジェクト/メッシュを見つけます)、それを「ヒット」し、ダメージを与えます。実際に高速で目に見えない弾丸が発射されたように見せたい場合は、ダメージを与える前に距離に応じてわずかな遅延を追加して偽装することができます。

このアプローチは、発射された発射体の速度が無限であることを基本的に想定しており、通常、レーザーやパーティクルビーム/キャノンなどの武器タイプと、おそらく何らかの形の狙撃ライフルに使用されます。

次のアプローチは、発射された弾丸を発射体としてモデル化することです。発射体は、衝突や、場合によっては重力や空気抵抗によって方向と速度が変化するエンティティー/オブジェクトとしてモデル化されます。追加の物理方程式により、ヒットスキャンアプローチよりも複雑であり、実際の弾丸オブジェクトがあるためにリソースを集中的に使用しますが、より現実的な弾丸を提供できます。

発射物ベースの弾丸とゲーム内の他のオブジェクトとの衝突を管理する場合、オブジェクトをクワッドまたはオクトツリーに分類することで衝突検出を大幅に簡素化できます。オクトリーは主に3Dゲームで使用されますが、クアッドツリーは2Dまたは3Dゲームで使用できます。これらのツリーのいずれかを使用する利点は、衝突チェックの回数を大幅に削減できることです。たとえば、これらのツリーのいずれかを使用せずに、レベルでアクティブなオブジェクトが20個ある場合、弾丸との衝突について20個すべてをチェックする必要があります。20のオブジェクトをツリーの葉(エンドノード)に分割すると、チェックの数を、弾丸と同じ葉に多くのエンティティが存在するまで減らすことができます。

これらのアプローチ(ヒットスキャンと発射物)については、どちらも2Dまたは3Dゲームで自由に使用できます。それは、武器が何であるか、そして作成者が武器が機能することをどのように決定したかにさらに依存します。


設計パターン、Hitscan、およびクワッド/オクツリーに関する情報は非常に役立ちます。また、情報をありがとう!
エリック

8
ヒットスキャンをせずに発射体をシミュレートすると、薄いオブジェクトは非常に高速で移動するため、細いオブジェクトを反ってしまう可能性があります。その場合、ゲームのすべてが偽物であることを忘れないでください。弾丸の長さはわずか数センチですが、弾丸の長さが1メートルであるかのように衝突検出を行うことができます。このようにすると、弾丸がオブジェクトを打つことなくオブジェクト内をゆがむことをあまり心配することなく、優れた弾丸ドロップと飛行時間シミュレーションを実行できます。
ロイT.

2
弾丸の物理学(たとえば、砲弾とは対照的に)が重力(弾丸の落下)や空気抵抗などを尊重するゲームはありますか?(つまり、焦点が精密なターゲット射撃またはそのようなものに焦点を当てている特殊なゲーム以外のゲーム:FPSなど)私はゲーマーではありませんが、そのレベルの忠実度が(ときどき)必要であることに驚いています。
-davidbak

3
@davidbak:典型的なゲーム内の出会いとゲームのジャンルから期待されるリアリズムに強く依存します。あなたが大部分(のみ?)近接戦闘で戦っている場合、実際、そのレベルの忠実度は必要ありません。しかし、長距離戦闘のオプションが存在する場合(例えば、狙撃兵、またはよりRPGに近い設定の射手)、ミサイルに影響を与える重力は、今日のようなものです。ロケットランチャーを上に向けると、ロケットがどこかに着陸して爆発することを期待できますか?それでも、軌道は常に実際の物理学から計算されるわけではなく、単なる近似(パフォーマンス上の理由から)
hoffmale

1
Bad Company 2が弾丸を落として以来、@ davidbak Battlefield。ライフル、ピストル、戦車の砲弾、ロケット、その他すべてに。バトルフィールド3はOriginで無料で、確認できます(IIRC)。もちろん、Battlefield 4にもこの「機能」があります。これを見ることができる他のゲームは「Sniper Elite」です。2または3は新しいタイトルです。そのゲームでは物理学が重要な役割を果たします。
Apache

7

私は決して専門家ではありませんが、あなたの質問に答えるには、はい、あなたはあなたが言及するものの多くを必要とするでしょう。

2Dの例では、弾丸の位置と速度を設定できます。(弾丸の実装方法に応じて、ライフタイムまたは最大距離も必要になる場合があります。)通常、2(x、y)の値が含まれます。浮動小数点数の場合、それは16バイトです。弾丸が100個ある場合、それはわずか1600バイトまたは約1.5kです。それは今日のマシンでは何もありません。

次に、スプ​​ライトについて言及します。各弾丸を表すために必要なスプライトは1つだけです。そのサイズは、描画するビット深度と、画面に表示される大きさによって異なります。たとえば、チャネルごとにフルフロート32ビットで256x256で圧縮されていない場合でも、スプライトの場合は1MBです。(そして、それは非常に大きくなります!)各弾丸の位置に同じスプライトを描画しますが、スプライトのコピーごとに追加のメモリを必要としません。ヒットエフェクトの場合も同様です。

0.01秒ごとに発火することに言及しています。それはあなたの武器から毎秒100弾です。未来的な武器であっても、それは非常にたくさんあります!このウィキペディアの記事によると:

トリガーがプルされると、ラウンドが発生するレートが周期レートになります。通常の周期的な発射速度は、アサルトライフルの場合600〜900 RPM、場合によっては1,000〜1,100 RPM、サブマシンガンとマシンピストルの場合は900〜1,200 RPM、マシンガンの場合は600〜1,200 RPMです。攻撃ヘリコプターや他の戦闘車両に搭載されたM134ミニガンは、毎秒100ラウンド(6,000 RPM)を超える発射速度を達成できます。

それで、攻撃ヘリコプターの速度になります!

バトルフィールド/コールオブデューティなどで言及しているような大規模な世界では、それらはすべての弾丸の位置を計算できますが、アクションが遠く離れている場合はすべてを描画しません。または、あなたが近づくまでそれらをシミュレートしないかもしれません。(これほど大きなものには取り組んでいないので、この部分について少し推測していることを認めなければなりません。)


6

インスタンス化されたこれらのオブジェクトの数千個を処理してから破棄するのは、プロセッサ上で難しいのではないでしょうか?RAMスペース?

コンピューターがどれだけ速いかを過小評価していると思います。これ、80年代および90年代のシステムで問題になることありました。元のスペースインベーダーが、現在の弾丸がヒットするまで別の弾丸を発射できない理由の1つです。画面にスプライトが多すぎると、一部のゲームで「スローダウン」が発生しました。

でも最近は?テクスチャリングとライティングを行うために必要なピクセルあたり数千の操作に十分な処理能力があります。何千もの移動オブジェクトには問題はありません。これにより、すべてのフラグメントが他のフラグメントと衝突処理を行い、弾道曲線をたどる破壊可能な地形(Red Factionなど)を行うことができます。

アルゴリズム的に少し注意する必要があります-何千ものオブジェクトがある場合、他のすべてのオブジェクトに対してすべてのオブジェクトをチェックする素朴なアプローチを行うことはできません。通常、弾丸は他の弾丸との衝突をチェックしません。

ちょっとした逸話:ネットワーク化されたDoomの最初のバージョン(90年代のオリジナル)は、発射された弾丸ごとに1パケットをネットワーク経由で送信しました。1人以上のプレイヤーがマシンガンを手に入れたとき、これは簡単にネットワークを圧倒する可能性があります。90年代には、ネットワークが使用できなくなったときに、大学や職場のネットワークでDoomを違法にプレイして、ネットワーク管理者とトラブ​​ルを起こす人が多くいました。


この文脈でチェーンソーがどのように機能したのか疑問に思う
16

1
IIRC、最初のネットワーク運命の本当の問題は、代わりにブロードキャストパケットを使用することで、各パケットをすべての対向するプレーヤーに個別に送信する必要がないことです。これにより、送信されるパケットの数は減りましたが、残念ながら、ゲームをプレイしていないものも含めて、ネットワーク上のすべてのマシンにかなりのCPU負荷がかかりました。
-supercat

1

私は専門家とはほど遠いですが、暇なときにマルチプレイヤー2Dシューティングゲームに取り組んでいます。

私の方法

クライアントとサーバーの間にはさまざまな箇条書きのクラスがあります(オフラインでプレイする場合でも、サーバーインスタンスは別のプロセスで開始され、「メイン」ゲームによって接続されます)。

ティック(毎秒60)ごとに、クライアントはプレーヤーのマウスポインターと画面の中心(キャラクターのいる場所)の間の方位を計算し、サーバーに送信される情報の一部になります。プレイヤーもその瞬間に発砲している場合(武器がロードされ準備が整っていると仮定)、サーバー側の弾丸インスタンスが作成されます。それ)。次に、弾丸インスタンスは、いくつかの数学関数を使用して、クライアントから収集したベアリングからXおよびY速度を算出します。

それ以降のティックごとに、弾丸はそれらの座標だけ移動し、事前定義された量だけ基本ダメージを減らします。この値が1未満になった場合、または世界の固体オブジェクトにヒットした場合、弾丸インスタンスは削除され、テストポイントの衝突は2Dで非常に安価であるため、急速に発砲する武器でさえパフォーマンスにほとんど影響しません。

クライアントについては、弾丸情報は実際にはネットワーク経由で受信されません(テストでは無駄であることが判明しました)。代わりに、ティックごとの更新の一部として、各キャラクターは 'fired'ブール値を持ちます。サーバーオブジェクトとほとんど同じように機能する弾丸オブジェクト。唯一の違いはスプライトを持っていることです。

つまり、表示される箇条書きはサーバー上での完全な正確な表現ではありませんが、プレーヤーにとっては違いはほとんど目立たず、ネットワークの利点は矛盾を上回ります。

さまざまな方法に関する注意

私のゲームを含む一部のゲームは、弾丸を物理オブジェクトであるかのように各ティックを移動しますが、他のゲームでは、発射方向にベクトルを作成するか、作成されたティックで弾丸の全パスを計算します。たとえば、ストライクゲーム。弾丸の発射のアニメーションなど、いくつかの小さなクライアント側のトリックがありますが、すべての意図と目的のために、各弾丸は単なるレーザーです。

複雑なヒットボックスを持つ可能性のある3Dモデルでは、最初に単純なバウンディングボックスとの衝突をテストし、それが成功した場合は、より詳細な衝突検出に進みます。


0

衝突検出と呼ばれます。8ビットコンピューターは、ハードウェアのプレーヤーミサイルグラフィックスを使用してこれを行いました。現代のゲームエンジンは、物理エンジンと線形代数を使用します。武器の現在の方向は3Dベクトルとして表されます。それは、火の方向に無限の線を提供します。動いているすべてのオブジェクトは、線との衝突を検出する最も単純なオブジェクトであるため、1つ以上の境界球を持っています。2つが交差する場合、それはヒットです。そうでない場合、ヒットはありません。しかし、シーナリーが邪魔になる可能性があるため、同様に確認する必要があります(階層境界ボリュームを使用)。交差点を持つ最も近いオブジェクトは、ヒットしたオブジェクトです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.