0

私は、ランダムなスクリプト化されたエンカウンターを備えたコア グラフィックスを使用して、より単純なゲームを構築してきました。

-(void)spawnStuff{
CGPoint position;
CGPoint position1;

int chance = random()%10;
switch (chance) {
    case 0:
            [self spawnWall];
        Position.y = 580;
        Position.x = 160;
        wall.center = Position;

        [self spawnWall];
        Position1.y = 480;
        Position1.x = 80;
        wall.center = Position1;

}
-(void)spawnWall{
UIImage* myImage = [UIImage imageNamed:@"Wall.png"];
Wall = [[Sprite alloc] initWithImage:myImage];

CGRect rect = CGRectMake(0, 0, 90, 50);
more initilization stuff }

そして、このコード行を 20 ~ 30 異なるこれらの壁の位置で繰り返す可能性があり、10 の異なるシナリオのみで、クラスのコードの約 3 分の 1 であり、少し冗長になり始めています。巨大なメソッドはちょっと怖いです。これはこれにアプローチする正しい方法ですか?

4

1 に答える 1

0

この種のことを頻繁に行う場合は、可能なアクションの配列を保持し、必要に応じてランダムに選択することをお勧めします。次のようなものは、その方法を示しているはずです。

配列を自由に追加/削除できることに注意してください。これにより、使用可能なブロックが変更されます...これは、下部に、ブロックをランダムに選択して100回実行することを示しています。

コード内の適切な場所からブロックを追加/削除して、ローカルに保つことができます。これで少なくとも始められるはずです...

// If we want to perform some action randomly, then we build an array
// of possibly actions (blocks), and then randomly pick one and execute it.
// Figure out what type of block you want...

typedef void(^ActionBlock)(void);
NSMutableArray *possibleActions = [NSMutableArray array];
[possibleActions addObject:^{
    NSLog(@"Doing Action Foo");
}];
[possibleActions addObject:^{
    NSLog(@"Doing Action Bar");
}];
[possibleActions addObject:^{
    NSLog(@"Doing Action Baz");
}];
[possibleActions addObject:^{
    NSLog(@"Doing Action FooBar");
}];
[possibleActions addObject:^{
    NSLog(@"Doing Action Blarg");
}];
[possibleActions addObject:^{
    NSLog(@"Doing Action Zip");
}];

// Now, when I want to pick an action to perform...
for (int i = 0; i < 100; ++i) {
    ActionBlock block = [possibleActions objectAtIndex:arc4random_uniform(possibleActions.count)];
    block();
}

編集

typedef void(^ActionBlock)(void);

typedef であり、特定の種類のブロックの型を定義します。確かに、関数とブロックの構文は少し読みにくいです。たぶん、私は一歩後退する必要があります。私はそれがあなたを怒らせないことを願っています. に似ています

typedef int IntType;
typedef void const * OpaqueType;

少し読みやすいです。1 つ目は整数型の IntType 型を定義し、2 つ目は "const-void へのポインタ" 型の OpaqueType 型を定義します。その後、次のような変数を宣言できます...

IntType someInteger;
OpaqueType someOpaqueValue;

さて、基本的な C では、関数ポインターを宣言することもできます。いくつかの関数があるとしましょう...

int functionOne(int arg1, double arg2) {
    // do whatever...
}
int functionTwo(int arg1, double arg2) {
    // do whatever...
}

その関数を簡単に呼び出すことができます...

int result = functionOne(42, 3.14159);

関数を指す変数を作成して、他の関数と同じように呼び出すこともできます。

int(*function)(int,double) = functionOne;
int result = function(42, 3.14159); // Calls functionOne
function = functionTwo;
result = function(42, 3.14159); // calls functionTwo

ただし、その構文は入力するのが少し面倒です。したがって、特に関数とブロックについては、typedef を作成します。関数の typedef を作成するには、関数ポインター変数を作成するのと同じですが、変数名の代わりに型を配置するだけです。そう...

typedef int(*MyFunction)(int, double);

int を返す関数へのポインターを表す型を宣言し、int と double の 2 つのパラメーターを取ります。

現在、ブロックの構文は、^ を * と交換することを除いて、関数ポインターの場合と同じです。で、アウトタイプ…

typedef void(^ActionBlock)(void);

ActionBlock は、void を返し、パラメーターを取らないブロックを表す型であることを意味します。

したがって、ActionBlock 型の変数を宣言し、それらを void リターンを持ち、引数を持たないブロックに割り当てることができます。例では、これはまさに私がしたことです。

コードでは、このようなブロックの束を作成することに注意してください...

[possibleActions addObject:^{
    NSLog(@"Doing Action Foo");
}];

コンパイラを使用すると、コードが実際に言うように、明らかなものを省略することができます... 引数を取らず、戻り値の型が void のブロックを作成し、それをコレクションに追加します。

これを複数回行い、関数を呼び出す準備ができたら、コレクションを反復処理します。ただし、コンパイラは関数/ブロックを呼び出す方法を知りたがっており、コレクションから取得するのは . そのため、取得したオブジェクトを型にキャストして、それが void を返し、引数を取らないブロックであることをコンパイラに伝える必要があります。

これを行うと、関数/ブロックを呼び出すことができます。それでは、最後の部分をもう一度見てみましょう (いくつかのコメント付き)。少しコンパクトではありません。

for (int i = 0; i < 100; ++i) {
    // We have a bunch of blocks stored in the array.
    // We want to pick one at random, so we will get a random number
    // between [0, size of our array).
    uint32_t index = arc4random_uniform(possibleActions.count);

    // Now, we have a random index into our array.  Get the object in that position.
    id randomObject = [possibleActions objectAtIndex:index];

    // We have an opaque id type, but we know it's a block.  Cast it to a block type.
    ActionBlock block = randomObject;

    // Now, we have our block, in a type that the compiler will let us invoke.
    // Call it like any other function.
    block();
}

編集

よし、どうぞ。iVar、NSTimer *_timer を作成します。didLoad でスケジュールし、didUnload と dealloc で無効化します。

- (void)dealloc {
    [_timer invalidate];
}

typedef void(^ActionBlock)(void);

- (void)callRandomFunction:(NSTimer*)timer {
    // Our userInfo is actually our array of blocks
    NSArray *actions = timer.userInfo;
    ActionBlock block = [actions objectAtIndex:arc4random_uniform(actions.count)];
    block();
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableArray *possibleActions = [NSMutableArray array];

    // Create the list of possible functions that can be called...

    // Now setup a timer that performs callRandomFunction: every second
    // Pass the array of blocks as the userInfo of the timer.
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(callRandomFunction:) userInfo:possibleActions repeats:YES];

    // Whatever else you need in here...
}

- (void)viewDidUnload
{
    [_timer invalidate];

    // Any other unload stuff...

    [super viewDidUnload];
}
于 2012-07-29T22:08:45.163 に答える