0

最近、Cocos2d を学ぶために、objective-c を独学しています。

古典的な落下宝石テトリスのようなゲームで基本を独学する新しいプロジェクトを開始しました。最初に行った手順は、[編集] > [リファクタリング] を使用してプロジェクトを ARC 用に有効にし、テンプレートの最後の 4 つのファイルを選択することでした。

これまでのところ、CCSprite をサブクラス化することで、動的に色付けされたスプライトを持つ 1 つの gem を追加し、XCoordinates に沿って移動しながら上から下に移動させることができました。gem には、後でマッチング メソッドを実装できるように、gemPos の位置 (たとえば 5,3) が与えられます。

プロジェクトをしばらくテストした後、いくつかのブロックが重なり合うと、EXC_BAD_ACCESS 警告が表示されます。ARC が有効になっている場合、なぜこれが起こるのか混乱しています。

私の不器用なコードは次のとおりです(.hファイルを省略しています):

デフォルトの helloworld レイヤー:

-(id) init
    {

        if( (self=[super init]) ) {

            oldGems = [[NSMutableArray alloc]init];

            [self setIsTouchEnabled:YES];

            [self newGem];

            [self scheduleUpdate];

        }
        return self;
    }

    - (void)registerWithTouchDispatcher
    {
        [[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
    }

    - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
    {
        CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
        oldPos = touchLocation;
        return TRUE;
    }

    - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
    {
        CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
        [self updateXCoord:(CGPoint)touchLocation];
    }

    - (void)updateXCoord:(CGPoint)touchLocation
    {


        CGPoint distance = ccpSub(touchLocation, oldPos);
        float xDistance = distance.x;

        if (abs(xDistance) >= 36) {
            if (touchLocation.x > oldPos.x) {
                [_thisGem setPosition:ccp([_thisGem position].x + 36, [_thisGem position].y)];
                [_thisGem setGemPos:ccp([_thisGem gemPos].x+1,[_thisGem gemPos].y)];
                NSLog(@"The gem position is %@", NSStringFromCGPoint([_thisGem gemPos]));
                oldPos = touchLocation;
            } else {
                [_thisGem setPosition:ccp([_thisGem position].x - 36, [_thisGem position].y)];
                [_thisGem setGemPos:ccp([_thisGem gemPos].x-1,[_thisGem gemPos].y)];
                NSLog(@"The gem position is %@", NSStringFromCGPoint([_thisGem gemPos]));
                oldPos = touchLocation;
            }
        }


    }

    - (void)newGem
    {
        if (_thisGem) {
            PCGem *oldGem = _thisGem;
            NSLog(@"Old gem position at %@", NSStringFromCGPoint([oldGem gemPos]));
            [oldGems addObject:oldGem];
        }

        _thisGem = [[PCGem alloc] initWithGemColor];
        [_thisGem setPosition:ccp(160, 450)];
        [self addChild:_thisGem];
        [_thisGem setGemPos:ccp(4,10)];

        NSLog(@"Gem added with %@ color", [_thisGem gemColorName]);
    }

    - (void)update:(ccTime)dt
    {

        if ([_thisGem gemPos].y > 0)  {

            [self spaceBelowOccupied];

            [_thisGem setPosition:ccp([_thisGem position].x, [_thisGem position].y-1)];
            [_thisGem setGemPos:ccp([_thisGem gemPos].x, floor([_thisGem position].y / 36))];

        } else {
            [self newGem];
        }
    }

    - (void)spaceBelowOccupied
    {    
            for (PCGem *occupiedTile in oldGems) {
                if (CGRectIntersectsRect(occupiedTile.boundingBox, _thisGem.boundingBox)) {
                    NSLog(@"Collision detected!");
                    [self newGem];
                }
            }
    }

そして私の不器用な PCGem クラス:

    - (id)initWithGemColor
    {
        if ((self = [super initWithFile:@"gemGS.png"])) {


            NSArray *gemColorList = [NSArray arrayWithObjects:(NSString *)@"blue", (NSString *)@"red", (NSString *)@"green", nil];

            NSInteger randColor = arc4random_uniform(3);

            switch (randColor) {
                case 0:
                {
                    [self setGemColorName:[gemColorList objectAtIndex:0]];

                    ccColor3B gemColorRGB = {0,0,255};
                    [self setColor:gemColorRGB];
                    break;
                }
                case 1:
                {
                    [self setGemColorName:[gemColorList objectAtIndex:1]];

                    ccColor3B gemColorRGB = {255,0,0};
                    [self setColor:gemColorRGB];            
                    break;
                }
                case 2:
                {
                    [self setGemColorName:[gemColorList objectAtIndex:2]];

                    ccColor3B gemColorRGB = {0,255,0};
                    [self setColor:gemColorRGB];
                    break;
                }
            }

        }

        return self;

    }

これは、私が答えを見つけることができないように見える別の質問に私を導きます. ARC 対応の Cocos2d プロジェクトの例では、ノードの便利なメソッドが使用されているのを見てきました。もちろん、これは alloc]init]autorelease] です。しかし、ARC で Autorelease を使用することはできず、クラッシュの原因になると思いましたか? これはどのように作動しますか?

私の悩みに対するアイデアはありますか?説明をいただければ幸いです:)

乾杯、

エイドリアン

4

1 に答える 1

0

列挙中に配列を編集したことが原因である可能性があると思います。更新関数では、spaceBelowOccupied を呼び出します。

- (void)spaceBelowOccupied
{    
        for (PCGem *occupiedTile in oldGems) {
            if (CGRectIntersectsRect(occupiedTile.boundingBox, _thisGem.boundingBox)) {
                NSLog(@"Collision detected!");
                [self newGem];
            }
        }
}

次に、 for ループ内で newGem が呼び出され、このループが成功した場合:

if (_thisGem) {
        PCGem *oldGem = _thisGem;
        NSLog(@"Old gem position at %@", NSStringFromCGPoint([oldGem gemPos]));
        [oldGems addObject:oldGem];
    }

次に、オブジェクトを列挙しながら配列にオブジェクトを追加しています。したがって、spaceBelowOccupied をこれに変更して、動作するかどうかを確認します。

 - (void)spaceBelowOccupied
{    
        for (PCGem *occupiedTile in [oldGems copy]) {
            if (CGRectIntersectsRect(occupiedTile.boundingBox, _thisGem.boundingBox)) {
                NSLog(@"Collision detected!");
                [self newGem];
            }
        }
}

そうすれば、oldGems のコピーを作成して列挙し、それが完了すると自動解放されます。

于 2013-06-02T04:11:01.293 に答える