X、Y 位置の配列を格納するモデル オブジェクトがあります。位置は格子状に配置されます。このモデルには、画面上にスポーンするタイルの位置を設定するために使用する givePositionForBlock メソッドもあります。
配列からランダムに位置を取得し、ユーザーが制御する特定の他のタイルから十分に離れているかどうかを確認します。十分に離れていない場合は、その位置を配列に戻し、別の位置を試します。フリーズを引き起こすのはこの方法です。エラーログなどはありません。emptyBlocks 配列がほぼ空になると、常に同時に発生します (約 3 回に 1 回発生します)。
これは、グリッドがいっぱいになると、ユーザーが制御するタイルから十分に離れたタイルを見つけるのが難しくなるためです。
グリッドがいっぱいになるとspawnOffsetを減らし、特定の時点で単にspawnOffsetルールを無視することで、これを解決しようとしました。しかし、常にうまくいくとは限りません。while ループを削除すると、正常に動作します。しかし、そうしないと、プレイ中にオブジェクトがユーザーの目の前に出現する可能性があるかどうかを確認する必要があります。
- (CGPoint) givePositionForBlock {
CGPoint position = [[self givePosition] CGPointValue];
BOOL generatedPositionOk = NO;
float spawnOffset = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 256: 128;
GameScene *scene = [GameScene sharedGameScene];
SnakePiece *snakeHead = [scene.tileArray objectAtIndex:0];
int tries = 0;
int maxtries = 50;
// decrease the minimum required distance as the grid gets filled
if ([emptyBlocks count] < 70 && [emptyBlocks count] > 35 ) {
spawnOffset = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 128: 64;
} else if ([emptyBlocks count] < 35 && [emptyBlocks count] > 20){
spawnOffset = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 64: 32;
} else if ([emptyBlocks count] < 20){
generatedPositionOk = YES;
}
// check if the position is far enough away.
while (generatedPositionOk == NO) {
if ((position.x > snakeHead.position.x+spawnOffset || position.x < snakeHead.position.x-spawnOffset) ||
(position.y > snakeHead.position.y+spawnOffset || position.y < snakeHead.position.y-spawnOffset )) {
generatedPositionOk = YES;
break;
} else {
//if not then put the position back in the array and take a new one.
//repeat until suitable position is found.
[self insertPositionInEmptyBlocksArray:position];
position = [[self givePosition] CGPointValue];
generatedPositionOk = NO;
tries++;
//maximum amount of times it can try to find a suitable position.
//if the max is exceeded use the position anyway
if (tries > maxtries) {
generatedPositionOk = YES;
break;
}
}
}
return position;
}
上記で使用した givePosition メソッドを次に示します。
- (NSValue *) givePosition {
int x;
CGPoint randomPointGl;
if ([emptyBlocks count] > 0) {
x = arc4random() % [emptyBlocks count];
randomPointGl = [[emptyBlocks objectAtIndex:x]CGPointValue];
[filledBlocks addObject:[NSValue valueWithCGPoint:randomPointGl]];
[emptyBlocks removeObjectAtIndex:x];
}
return [NSValue valueWithCGPoint:randomPointGl];
}