1

私はiOS用のCocos2Dを使用していますが、おそらくCocos2Dに精通している必要はなく、私の質問に答えるにはObj-Cだけです。

長い間使ってきたこのゲームの開発中に敵のクラスがありましたが、今では複雑になり、より整理されて読みやすくするために何かをする必要があります。

現在の動作は次のとおりです。特定の回数割り当てて可変配列に挿入する敵クラスがあります。その後、いつでもその可変配列をめくることができます。敵のクラスが割り当てられると、敵の名前の文字列を初期化して渡すように指示されます。initには、敵の名前をチェックして適切な値を設定する一連のif /ifelseステートメントがあります。これは問題なく機能しましたが、デザイン的には、敵を追加するときにこれらすべての名前を調べるのが非常に混乱しました。

私が今やりたいのは、すべての異なる敵の敵クラスからサブクラスを作成することです。そのクラスの他の種類の敵と同じように、敵のプロパティにアクセスする必要があります。

現在、敵のクラスの初期化では、次のようなものがあります。

-(id) initWithEnemy:(NSString *)kind {

    if([kind isEqualToString:@"enemyName"]){

    //set values

    }
    else if([kind isEqualToString:@"anotherEnemyName"]){

    //set values

    }

    //etc, etc..

}

今、私はこの設定値を他のファイルで発生させたいと思っています。1つ、または各敵のヘッダー/メインファイルのセット。そのため、initWithEnemy内では、渡された「kind」文字列から敵の名前クラスを割り当てることができるのではないかと考えていました。NSClassFromStringを使用できるかどうかわかりません。少し実験しましたが、以前のようにクラスのプロパティにアクセスする方法がよくわかりません。以前と同じ方法でプロパティにアクセスしたとしても、それはすべての敵の名前クラスがすべて同じ量のプロパティを持っている必要があることを意味しますか?

4

2 に答える 2

2

敵を具体的なサブクラスを持つ抽象的な基本クラスに分割することができます。これは良いアプローチです。ただし、継承よりもコンポジションを使用する方がよい場合が多いことに注意してください。これは、オブジェクトをホルダークラスに挿入して、何かをモデル化する場所です。そうしないと、「モンスター」と「ウィザード」の両方である敵がいて、単一の継承チェーンではそれが許可されないという問題が発生する可能性があります。

ここで適切と思われる2つのデザインパターンがあります。どちらも、複雑なインスタンス化ルールをクラス自体から切り離すことに焦点を当てています。1つはファクトリパターンで、もう1つはビルダーパターンです。クラス階層に分割する場合は前者が適切であり、そうでない場合は後者が適切です。

申し訳ありませんが、これ以上の例を提供することはできません-これをiPadで作成し、ドアを出る途中です。

于 2013-01-31T23:06:43.670 に答える
2
  1. 文字列の代わりに、enum

    typedef enum {
        kEnemyInvalid = 0,
        kEnemyName1,
        kEnemyName2,
        [...]
    } EnemyType;
    
  2. Enemyすべての敵タイプのグローバルプロパティを使用してクラスを作成します。

  3. タイプごとに必要な敵のサブクラスを作成します。クラスが複数の敵タイプをカバーする可能性があります。
  4. 関数(おそらくクラスメソッド)を作成します

    Class EnemyClassFromEnemyType(EnemyType type) {
        switch (type) {
            case kEnemyName1:
               return [EnemyName1 class];
            case kEnemyName2:
               return [EnemyName2 class];
            default:
               return Nil;
        }
    }
    

    この関数は、敵のタイプとそれを実装するクラスを接続します。それをより美しくする方法はいくつかありますが、私の好みの方法はX-Macrosを使用することです。

  5. それでは、敵を作成するためのファクトリメソッドを作成しましょう

    + (Enemy*)createEnemyWithType:(EnemyType*)enemyType {
        Class enemyClass = EnemyClassFromEnemyType(enemyType);
        return [[enemyClass alloc] initWithType:enemyType];
    }
    

X-マクロを使用して同じ

ヘッダーファイル

#define ENEMY_DEFINITIONS \
  ENEMY_DEFINITION(kEnemyInvalid, = 0, Nil) \
  ENEMY_DEFINITION(kEnemyName1,, [EnemyName1 class]) \
  ENEMY_DEFINITION(kEnemyName2,, [EnemyName2 class])

#define ENEMY_DEFINITION(name, intValue, enemyClass) name intValue, 

/**
 * Your enum declaration.
 */
typedef enum {
    ENEMY_DEFINITIONS
} EnemyType;

#undef ENEMY_DEFINITION

Class EnemyClassFromEnemyType(EnemyType type);
NSString* NSStringFromEnemyType(EnemyType type);

実装ファイル

#define ENEMY_DEFINITION(name, intValue, enemyClass) [name] = @#name,

NSString* EnemyTypeStringTable[] = {
    ENEMY_DEFINITIONS
}

#undef ENEMY_DEFINITION

NSString* NSStringFromEnemyType(EnemyType type) {
    return EnemyTypeStringTable[type]
}

#define ENEMY_DEFINITION(name, intValue, enemyClass) classTable[name] = enemyClass;

Class EnemyClassFromEnemyType(EnemyType type) {
    static Class* classTable = nil;

    if (classTable == nil) {
        classTable = malloc(sizeof(Class) * sizeof(EnemyTypeStringTable) / sizeof(NSString*));

        ENEMY_DEFINITIONS
    }

    return classTable[type];
}

#undef ENEMY_DEFINITION

X-Macrosテクニックを使用する利点は、すべてを1か所にまとめることができ、他に何も変更せずにタイプを簡単に追加できることです。列挙型はプロパティを持つことができるため、Java列挙型のようなものが得られます。

于 2013-01-31T23:18:42.923 に答える