C#のようなマネージド言語でゲームを書くときの典型的な落とし穴は何ですか?[閉まっている]


66

C#のようなマネージ言語を使用してPC用のゲームを作成する際に、どのような落とし穴に遭遇し、どのように解決しましたか?


Stack Overflowでは、ゲーム固有の問題はほとんどないため、この質問の方が適切です。
クリスギャレット

31
@クリス:強く反対:質問は特にゲームについて言及しています!16msごとに更新をプッシュしなければならないときに発生する問題は、ほとんどのデスクトップアプリケーションで発生する問題とは大きく異なります。
アンドリューラッセル

問題は非常に不明確です。JavaとC#は、非常に一般的なアドバイスのみが両方に適用できるほど十分に異なります。これまでの答えはすべてC#でした。また、ターゲットプラットフォームについては言及していません-適切なアドバイスはデバイスによって異なります(たとえば、携帯電話、zune、xboxのプログラミング、pcのプログラミングとは異なります)。マネージド言語自体が「落とし穴」であると誰かが答えたのは、十分に広い質問でさえありました。
paulecoyote

@paulecoyote:C#についてのみ質問する質問に変更しました。また、言及された特定のプラットフォームがないので、それはPCについてです。
マイケルクレメント

プラットフォームを想定する@Michaelは、実装が大きく異なるため危険な前提であり、Windowsに具体的に言及し、「like」と「Java」を完全に削除するとよいでしょう。
paulecoyote

回答:


69

私はJavaについてあまり知らないので、これは.net開発者の観点からです。

一番大きいのはゴミです。Windowsの.NETガベージコレクターは素晴らしい仕事をしており、ほとんどの場合、赤ちゃんが座っていなくても逃げることができます。Xbox / Windows Phone 7では、これは別の問題です。数フレームごとにストールが発生する場合、ガベージコレクションが問題を引き起こしている可能性があります。現時点では、1MBの割り当てごとにトリガーされます。

ゴミを処理するためのヒントを次に示します。現実にはこれらのほとんどについて心配する必要はありませんが、いつか役に立つかもしれません。

  • の内容をGC.GetTotalMemory()画面に描画します。これにより、ゲームが使用する割り当て済みバイトの概算値が得られます。それがほとんど動かないなら、あなたは大丈夫です。急速に上昇する場合、問題があります。
  • すべてのヒープオブジェクトを前もって割り当てるようにしてください。ゲームを開始する前にすべてを割り当てない場合、割り当ての数に達するたびにストールします。割り当てもコレクションもありません。それと同じくらい簡単。
  • ロード後、を呼び出しますGC.Collect()。大規模な割り当ての大部分が途切れていることがわかっている場合は、システムに知らせるだけで十分です。
  • GC.Collect()すべてのフレームを呼び出さないでください。ガベージとそのすべてを維持するのは良い考えのように思えるかもしれませんが、ガベージコレクションよりも悪いのはガベージコレクションを超えていることだけを覚えておいてください。
  • ごみがどこから来ているのか探してください。文字列を連結する代わりに使用してのようないくつかの一般的な原因がありますStringBuilder(用心が、StringBuilder特効薬はなく、まだでき配分を引き起こす!。これは、文字列の末尾に番号を追加するような単純な操作は、ごみの驚くべき量を作成できることを意味します)、または使用してforeach使用してコレクションをループをIEnumerableもあなたは知らなくてもゴミを作成することができるインタフェースを(例えば、foreach (EffectPass pass in effect.CurrentTechnique.Passes)一般的なものです)
  • CLRメモリプロファイラなどのツールを使用して、メモリが割り当てられている場所を特定します。このツールの使用方法に関するチュートリアルはたくさんあります。
  • ゲームプレイ中に割り当てを行う場所がわかったら、その割り当て数を減らすためにオブジェクトをプールするなどのトリックを使用できるかどうかを確認します。
  • 他のすべてが失敗した場合は、コレクションをより速く実行してください!コンパクトフレームワークのGCは、コード内のすべての参照に従って、使用されなくなったオブジェクトを見つけます。より少ない参照を使用してコードをリファクタリングしてください!
  • IDisposableアンマネージリソースを含むクラスで使用することを忘れないでください。これらを使用して、GCがそれ自体を解放できないメモリをクリーンアップできます。

考えるべきもう1つのことは、浮動小数点のパフォーマンスです。.NET JITerはかなりの量のプロセッサ固有の最適化を行いますが、SSEまたはその他のSIMD命令セットを使用して浮動小数点演算を高速化することはできません。これにより、ゲームのC ++とC#の速度が大きく異なる可能性があります。モノを使用している場合は、利用できる特別なSIMD数学ライブラリがあります。


完全に同意します。「より小さい」プラットフォームでのガベージコレクタの実装は完全なガベージのようです。
クリス

ただし、「ヒープオブジェクトを前もって割り当てる」ことに関する声明に関しては、良い投稿です。値型についての真実
ジャスティン

コードを最適化するとき、最適化しようとしているプラ​​ットフォームを理解することは本当に価値があります。それは実際には値型/参照型についてのコメントではなく、長生きするオブジェクトはスタック上にある可能性は低いです。ロード時に可能な限り多くの割り当てが行われるようにすることは、ゲームプレイ中にその魔法の1mbバリアに到達しないようにすることです。xnaがターゲットとするすべての.net実装にはきちんとした保証があり、時間内に近くに割り当てられたオブジェクトはスペースが近くなり、perfに適しています。
Cubed2D

また、xboxの現在のコンパクトフレームワークはメソッド呼び出しのインライン化にアレルギーがあることを言及するのを忘れていたようです。ただし、最悪の場合のパフォーマンスシナリオの場合は、これを保持します。refsバージョンのmathsメソッドを使用すると、そのままではいように見えます。
Cubed2D

10

典型的なパフォーマンスの落とし穴は、ゲームの設計/開発におけるガベージコレクターを考慮していません。ガベージの生成が多すぎると、ゲームで「しゃっくり」が発生する可能性があります。これは、GCが長時間実行されると発生します。

C#の場合、値オブジェクトと「using」ステートメントを使用すると、GCからの圧力を軽減できます。


3
さらに、割り当て/フリーのヘビーループを終了した場合、または予備のサイクルがある場合は、ガベージコレクターに明示的に実行するように指示できます。
バレットJ

16
このusing文はガベージコレクションとは関係ありません!IDisposableオブジェクト用です-アンマネージリソース(つまり、ガベージコレクターによって処理されないリソース)を解放するためのものです。
アンドリューラッセル

9

C#でゲームを書く際に遭遇した最大の問題は、まともなライブラリがなかったことです。私が見つけたもののほとんどは、直接ポートですが、不完全であるか、マーシャリングのパフォーマンスが大幅に低下するC ++ライブラリのラッパーです。(OGREライブラリの場合はMOgreとAxiom、Bullet物理ライブラリの場合はBulletSharpについて具体的に説明しています)

マネージ言語(Interpretedとは異なり-JavaもC#も実際に解釈されなくなりました)は、実際に言語を遅くするもの(マーシャリング、ガベージコレクション)を十分に理解している場合、ネイティブ言語と同じくらい速くなります。本当の問題は、ライブラリ開発者がまだ気付いていないことだと思います。


これは、解釈される代わりにC#とJavaが管理されることの良い点です...私の質問をより正確にするために編集しました:)
マイケルクレメント

2
一般にマーシャリングはパフォーマンスのボトルネックですが、ブリット可能なタイプ(パフォーマンスに大きな影響を与えずにアンマネージメモリに直接マップできるタイプ)を認識することも役立ちます。msdn.microsoft.com/en-us/library/75dwhxf7.aspx
ショーンエドワーズ


4

C#とJavaは解釈されません。これらは中間バイトコードにコンパイルされ、JITの後、ネイティブコードと同じくらい高速になります(または、取るに足らないほど十分に近くなります)。

私が見つけた最大の落とし穴は、ユーザーエクスペリエンスに直接影響するリソースを解放することです。これらの言語は、C ++のように決定論的なファイナライズを自動的にサポートしません。C++のように、予期しない場合は、メッシュが破壊されたと思った後にシーンの周りに浮かぶ可能性があります。(C#はIDisposableを介して決定論的なファイナライズを達成しますが、Javaが何をするのかわかりません。)

それ以外に、マネージド言語は、ゲームが必要とする種類のパフォーマンスを、クレジットを獲得するよりもはるかに多く処理することができます。適切に記述されたマネージコードは、不十分に記述されたネイティブコードよりもはるかに高速です。


うん、メモのおかげで、すでに解釈/管理されたものを修正しました;)また、シーンの周りに浮かぶメッシュの良い点。GCの問題を考えるとき、そのことを考えなかった…
マイケルクレメント

1
IDisposableタイムクリティカルで管理されていないリソースの確定的なクリーンアップを許可しますが、ファイナライズまたはガベージコレクターに直接影響しません。
サムハーウェル

4

JavaもC#も解釈されません。両方ともネイティブマシンコードにコンパイルされます。

それらとゲームの両方の最大の問題は、ゲームプレイ中にガベージコレクトしないようにコーディングする必要があることです。それを達成するためにジャンプしなければならないフープの数は、そもそもそれらを使用する利点をほとんど上回っています。これらの言語をアプリケーションやサーバーのプログラミングに使用するのを楽しくする機能のほとんどは、ゲームプログラミングでは使用しないでください。


ガベージコレクションは、少なくともC#では、かなり適切に処理できるため、これが取引を壊すとは言いません。適切なスレッド化とプログラム状態の認識により、パフォーマンスの問題を回避できます。それはまだあなたが考えなければならない別のことであり、それはマネージド言語を少し管理しにくくします。
カランツァ

4
.NET 4では、ガベージコレクターが3世代すべてのオブジェクトのバックグラウンドコレクションをサポートしていることに注意してください。これにより、ゲームのガベージコレクションのパフォーマンスへの影響を効果的に最小限に抑えることができます。関連リンク:geekswithblogs.net/sdorman/archive/2008/11/07/...
マイク・ストローベル

ガベージコレクターは進化しており、Mike Strobelが指摘しているように、この落とし穴をほぼなくすものが既に生産されています。
サムハーウェル

2
C#もJavaもネイティブマシンコードにコンパイルされません。C#はMSILにコンパイルされ、Javaはバイトコードにコンパイルされます。ガベージコレクションは「長い」一時停止を与えませんが、「しゃっくり」を与える可能性があります。
Cloudanger

2

これらのような言語(またはXNA、TorqueXエンジンなどのツールを使用)でゲームを作成するときに見られる大きな落とし穴の1つは、同等のゲームを作成するために必要な専門知識を持つ優秀な人々のチームを見つけるのに苦労することですC ++やOpenGL / DirectXで簡単に人を見つけることができます。

ゲーム開発業界は、C ++にまだ非常に重くのしかかっています。大きなゲームや洗練された小さなゲームをプッシュするために使用されるツールとパイプラインのほとんどはC ++で書かれており、私が知る限り、 XBox、PS3、およびWii用のgetは、C ++との互換性がある場合にのみリリースされます(最近では、XBoxツールセットがより管理されている可能性があります。

今すぐコンソール用のゲームを開発したい場合、XBoxでXNAとC#を取得し、XBox Live Indie Gamesと呼ばれるゲームライブラリのサイド部分でのみ取得します。コンテストなどで勝った人の中には、ゲームを実際のXBox Live Arcadeに移植するために選ばれる人もいます。それ以外は、PC用のゲームを作成する計画です。

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