OOPなしでゲームを作るには?[閉まっている]


10

現在、ゲーム開発の勉強とゲーム制作の練習をしています。

私はゲームで多くのOOPを使用しています。たとえば、発射される各ミサイルはMissileオブジェクトのインスタンスであり、オブジェクトのリストに追加されMissileます。ゲームの各戦車はTankオブジェクトです。等。

プログラム全体の設計はこれに基づいています。たとえば、Missileオブジェクトのあると、すべてのフレームでミサイルを移動したり、それらを描画したりできます。またTank、すべての戦車にオブジェクトのインスタンスがあると、何かと衝突したかどうかなど、各戦車をチェックできます。

ゲーム(パックマンよりも複雑)が非OO言語でプログラムされる方法を想像するのは難しいです。(もちろん、非OOプログラマを軽視しません)。所要時間だけでなく、ほとんどの場合、この方法でゲームを設計する方法についてもです。

オブジェクト指向プログラミングを使用せずにゲームを設計することは想像できません。ゲームプログラムの設計方法に関する私の完全な理解はOOPに基づいているためです。

質問したいのですが、今日、OOPを使用してプログラミングされていないゲームはありますか?開発プロセスの主要な要素としてOOPを使用しない「プロフェッショナル」ゲームはありますか?

もしそうなら、たとえば、OOPなしで、タンクとN個のミサイルの間の衝突検出をどのように実装できるかについて教えてください。


6
これは哲学的な質問ですか?戦車を「オブジェクト」と呼ばなくても、おそらく「エンティティ」、「アクター」、「エージェント」、「構造体」、または同じアイデアの別の名前が必要になります。タンクと呼ばれる、物を撃つことができるタレットを備えた回転する直方体を構成する属性と動作。プログラミング言語はこれと同じ考えを形式化するさまざまな方法を持っていますが、結局、それは戦車になるでしょう。
Anko

この回答で説明されているように、多くのゲームはコンポーネントベースのシステムを使用しています。gamedev.stackexchange.com
John McDonald 14

これは非常に広範であり(範囲を狭めることで修正できる可能性があります)、ゲーム開発に固有のものではありません(OOテクニックなしでソフトウェアを構築することは、ゲーム開発者が他のソフトウェア開発者よりも良い答えを与えるものではないためです)。ここでは話題から外れています。

StackOverflowに適している場合があります。または、ヘルプセンターをチェックして、この種の幅広いディスカッション指向のトピックを可能にするゲーム開発固有のサイト(GDNetなど)を選択して見つけることができます。幸運を!

回答:


16

オブジェクト指向プログラミングを使用せずにゲームを設計することは想像できません。ゲームプログラムの設計方法に関する私の完全な理解はOOPに基づいているためです。

次に、いくつかのプログラムをOO以外のスタイルで記述してみるとよいでしょう。これが実用的でないことを発見したとしても、おそらくあなたは将来に役立つであろう方法に沿って多くを学ぶでしょう。

OOスタイルは、ゲームはほとんど常にステートフルオブジェクトの操作に関するものであるため、ゲームに非常に適しています。レーザービームがロボットに当たると、ロボットのアイデンティティは同じままでロボットの状態が変化します。

ただし、機能的なスタイルでゲームをプログラムすることは可能です。機能的なスタイルでは、状態自体は変化しません。オブジェクトは不変です。オブジェクトを変更するのではなく、私がこれを変更した場合、宇宙はどのように異なるのでしょうか?次に、プロパティが変更されたまったく新しい宇宙を生成します。もちろん、以前から存在しているユニバースは不変であるため、多くを再利用できます。

関数型プログラミングでは、すべての関数は渡された情報のみから戻り値を計算する必要があります。「グローバルな状態」からの読み取りはありません。

これを行う場合、頭を乗り越えなければならない基本的な問題は、すべての更新が非破壊的であるということです。レーザーがロボットに当たっても、ロボットの状態は変化しません。最終的には、ロボットの状態が異なることを除いて、古い宇宙とまったく同じ完全に新しい宇宙を計算します。古い宇宙が必要な場合は、変更されていないままです。

この一連のブログ記事では、機能的なスタイルでゲームを書くことについてさらに考えています。

http://prog21.dadgum.com/23.html

この記事では、「シェルがタンクにぶつかった」という質問に具体的に対処します。

http://prog21.dadgum.com/189.html

実際、ブログ全体を読んでください。そこには良いものがあり、記事は短いです。


12

すべてのオブジェクト指向プログラムは、すべてのクラスを構造体で置き換え、すべてのメンバー関数をthis、引数となるオブジェクトを取るスタンドアロン関数に変換することにより、手続き型プログラムにリファクタリングできます。

そう

 missile.setVelocity(100);

なる

 setMissileVelocity(missile, 100);

またはその関数が取るに足らない場合は、

 missile.velocity = 100;

オブジェクト指向プログラミングと手続き型プログラミングの主な違いは、データの扱い方です。OOPでは、データはスマートです。自身を管理および操作します。しかし、手続き型プログラミングでは、データはばかげています。それ自体は何もせず、外部から操作する必要があります。

構造もオブジェクト指向であると考える場合、構造の1つの配列を複数の配列に置き換えることができます。1つはミサイルの変数になるすべてのものです。そう

struct Missile {
     int x;
     int y;
     int velocity;
}

Missile missiles[256];

なる

int missileX[256];
int missileY[256];
int missileVelocities[256];

この設計では、同じミサイルの複数の属性を含む操作を実行する関数は、構造体への参照ではなく配列インデックスを取得するようになりました。その実装は次のようになります。

function updateMissilePosition(int index) {
     missileX[index] += missileVelocity[index];
}

1
しかしmissile、オブジェクトのインスタンスです。非OOPでは、インスタンスはありませんが、正しいですか?もしそうなら、どのようにしてsetMissileVelocity(missile、100)を実行できますか?
user3150201 2014

1
@ user3150201あなたは完全に正しいわけではありません。ほとんどの非OOP言語(そして私は真面目なゲーム開発に適したものについてはほとんど議論します)は構造をサポートしています。構造は一種のクラスに似ていますが、パブリック変数以外は何も含まれていません。それはあなたがタイプを作成できるようになるので、Missile構造がいくつかのフィールド、などである、xyangleとしますvelocity
フィリップ

@ user3150201回答を更新して、構造なしでそれを行う方法に関するセクションを追加しました。
フィリップ

フィリップ、いい答えですが、なぜオブジェクト指向をプログラムしたくないのかわかりません。OOP以外の言語を読むのは本当に難しく、わずらわしいかもしれません。コードはすぐに混乱する可能性があります。
Zhafur、2014

2
@Zhafurあなたはあなたの声明が大規模なフレームベイトであることを知っていますね?
フィリップ

6

私はそれを次のように行います:

  • すべてのOOPクラス/メソッドはにアクセスできますthisthis非OOアプローチで利用するにはthis、最初のパラメーターとして、どちらのインスタンス(次のポイントを参照)にするかを渡すだけです。
  • さて、インスタンスについては、structsをとして関数に渡すことができますがthis、エンティティやパーティクルなどの多作のオブジェクトに対して良好なキャッシュパフォーマンスを達成する最良の方法は、単一のインデックスをプリミティブの複数の配列に単に渡すことです。または小さいstructs。したがって、このインデックスは、元のクラスの個々のデータメンバーごとに使用されます。たとえば、

...

class Entity //let's say you had 100 instances of this
{
   int a;
   char b;
   function foo() 
   {
      .../*can access 'this' herein*/
   }
}

あなたはそれを

int a[100];
char b[100];
function foo(int index);

これで、通常は何になるかを取得するために、関数にインデックスを渡していますthis

良好なキャッシュの局所性(参照の局所性)のためにデータをインターリーブする最善の方法に応じて、上記のプリミティブの配列またはの配列のいずれかを使用する場合があることを覚えておいてくださいstruct。もちろん、まともなキャッシュパフォーマンスはこれ以外にも、特にコードを記述している言語/プラットフォームに大きく依存しますが、JavaのようなVMベースの動的に割り当てられた言語でも、プリミティブの大きな線形配列はオブジェクトインスタンスよりも優れたパフォーマンス特性を表示します。これの主な理由は、オブジェクトが参照によってアクセスされることです。これは、メモリ全体をジャンプしてデータにアクセスすることを意味します。大規模な配列からプリミティブに連続してアクセスするのに比べて非効率的です。

構造体やプリミティブの配列としてエンティティなどを構築する方法の詳細については、Mick WestのEvolve your Hierarchyを参照してください。


0

既存の回答に加えて、手続き型言語でポリモーフィズムを実行する方法を知りたい場合があります。

2つの方法があります。

タイプの保存

この場合、構造体にはタイプ識別子のフィールド(おそらく列挙switch型)があり、タイプ固有のアクションを実行する必要があるときにステートメントを使用してチェックされます。

もう1つの方法は次のとおりです。

保存関数ポインタ

経験のあるプログラミング言語については触れていませんが、さまざまな言語で、コールバック、デリゲート、イベント、高次関数、または単に関数オブジェクトと呼ばれることもあります。

この場合、型は保存しませんが、特定のアクションを実行する関数へのポインター/参照を保存します。タイプ固有のアクションを実行する必要がある場合は、この関数を呼び出すだけです。これは通常の仮想メソッドによく似ています。

各機能を個別に設定できるようにすることで、戦略パターンを解放できます。


衝突検出に関する最後の段落について。あなたはおそらく複数の種類の戦車と複数の種類のミサイルを持っていると思います、そしてそれらが衝突するとき、各組み合わせは潜在的に異なる結果をもたらす可能性があります。これがあなたが探しているものである場合、OOP言語でさえまだ解決されていない問題があります:this異なるタイプの複数のパラメータを持つことができる複数のディスパッチとマルチメソッド。この問題には、2つの選択肢があります。

  • タンクとミサイルの各組み合わせ用のネストされたスイッチ。
  • タンクとミサイルの各組み合わせの関数へのポインターを含む2次元のディスパッチ配列。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.