Боковая прокрутка SpriteKit не обновляет физику WorldWorld

Следуя приведенному здесь примеру (кроме Objective C) и стандартной документации Apple, я обнаружил, что physicsWorld не обновляет свои позиции, когда myWorld обновляет свою позицию. Я включил showsPhysics на моем skView, чтобы проверить это. Смотрите эти скриншоты.

Перед любым движением: экран 1После небольшого движения экран 2Становится немного дальше экран 3И как раз перед контактомэкран 4

Вот мой код для центрирования myWorld, Большая часть длины происходит из-за того, что я чрезвычайно многословен в отношении границ.

- (void)centerOnNode:(SKNode *)monkeyNode
{
    CGPoint monkeyPosition = monkeyNode.position;

    // Check if monkey died
    if (monkeyPosition.y < myWorld.frame.origin.y - sceneHeight/2) {
        [self monkeyDied];
    }

    // Check if monkey won
    if (monkeyPosition.x > skyFarRightSide.x) {
        [self monkeyWon:monkeyNode];
    }

    // Define limits
    CGFloat scrollTopLimit = skyFarTopSide.y - sceneHeight/2;
    CGFloat scrollBottomLimit = 0;
    CGFloat scrollLeftLimit = 0;
    CGFloat scrollRightLimit = skyFarRightSide.x - sceneWidth/2;

    // Normal (no limits hit) scrolling
    if (monkeyPosition.x > scrollLeftLimit && monkeyPosition.x < scrollRightLimit && monkeyPosition.y > scrollBottomLimit && monkeyPosition.y < scrollTopLimit) {
        [myWorld setPosition:CGPointMake(-monkeyPosition.x, -monkeyPosition.y)];
    }

    // At far left scrolling
    if (monkeyPosition.x < scrollLeftLimit) {
        // No y limits hit
        if (monkeyPosition.y > scrollBottomLimit && monkeyPosition.y < scrollTopLimit) {
            [myWorld setPosition:CGPointMake(0, -monkeyPosition.y)];
        }

        // Bottom limit hit
        if (monkeyPosition.y < scrollBottomLimit) {
            [myWorld setPosition:CGPointMake(0, 0)];
        }

        // Top limit hit
        if (monkeyPosition.y > scrollTopLimit) {
            [myWorld setPosition:CGPointMake(0, -scrollTopLimit)];
        }
    }

    // At far right scrolling
    if (monkeyPosition.x > scrollRightLimit) {
        // No y limits hit
        if (monkeyPosition.y > scrollBottomLimit && monkeyPosition.y < scrollTopLimit) {
            [myWorld setPosition:CGPointMake(-scrollRightLimit, -monkeyPosition.y)];
        }

        // Bottom limit hit
        if (monkeyPosition.y < scrollBottomLimit) {
            [myWorld setPosition:CGPointMake(-scrollRightLimit, 0)];
        }

        // Top limit hit
        if (monkeyPosition.y > scrollTopLimit) {
            [myWorld setPosition:CGPointMake(-scrollRightLimit, -scrollTopLimit)];
        }
    }

    // At far bottom scrolling
    if (monkeyPosition.y < scrollBottomLimit) {
        // No x limits hit
        if (monkeyPosition.x > scrollLeftLimit && monkeyPosition.x < scrollRightLimit) {
            [myWorld setPosition:CGPointMake(-monkeyPosition.x, 0)];
        }

        // Left limit hit
        if (monkeyPosition.x < scrollLeftLimit) {
            [myWorld setPosition:CGPointMake(0, 0)];
        }

        // Right limit hit
        if (monkeyPosition.x > scrollRightLimit) {
            [myWorld setPosition:CGPointMake(-scrollRightLimit, 0)];
        }
    }

    // At far top scrolling
    if (monkeyPosition.y > scrollTopLimit) {
        // No x limits hit
        if (monkeyPosition.x > scrollLeftLimit && monkeyPosition.x < scrollRightLimit) {
            [myWorld setPosition:CGPointMake(-monkeyPosition.x, -scrollTopLimit)];
        }

        // Left limit hit
        if (monkeyPosition.x < scrollLeftLimit) {
            [myWorld setPosition:CGPointMake(0, -scrollTopLimit)];
        }

        // Right limit hit
        if (monkeyPosition.x > scrollRightLimit) {
            [myWorld setPosition:CGPointMake(-scrollRightLimit, -scrollTopLimit)];
        }
    }
}

Есть ли элегантный способ исправить это? Пока что моя единственная идея - включить больше кода в centerOnNode который сбрасывает позиции каждого physicsBody в myWorld,

2 ответа

Решение

Я не знаю, что изменилось за последние 2 года, но другой ответ здесь больше не работал. Вместо этого теперь я комбинирую положение сегментов веревки с родительским (полная веревка). Так что я просто делаю

CGPoint convertedRopePosition = CGPointMake(ropePhysicsBody.node.parent.position.x + ropePhysicsBody.node.position.x, ropePhysicsBody.node.parent.position.y + ropePhysicsBody.node.position.y);
SKPhysicsJointPin *jointPin = [SKPhysicsJointPin jointWithBodyA:monkeyPhysicsBody bodyB:ropePhysicsBody anchor:convertedRopePosition];

Это необходимо, поскольку сегмент веревки расположен под полной длиной веревки, поэтому его положение относительно всей веревки, а не сцены.

Я заметил, что как только обезьяна вступает в контакт, все физические тела возвращаются на свои места. Тем не менее, суставы anchorPoint заканчивается в неправильном месте.

Я добавил следующий удобный метод в свой GameScene.m.

-(CGPoint)convertSceneToFrameCoordinates:(CGPoint)scenePoint
{
    CGFloat xDiff = myWorld.position.x - self.position.x;
    CGFloat yDiff = myWorld.position.y - self.position.y;
    return CGPointMake(scenePoint.x + self.frame.size.width/2 + xDiff, scenePoint.y + self.frame.size.height/2 + yDiff);
}

Я использую этот метод для добавления суставов. Он обрабатывает все преобразования системы координат, которые необходимо решить, что приводит к проблеме, поднятой в этом вопросе. Например, как я добавляю суставы

    CGPoint convertedRopePosition = [self convertSceneToFrameCoordinates:ropePhysicsBody.node.position];
    SKPhysicsJointPin *jointPin = [SKPhysicsJointPin jointWithBodyA:monkeyPhysicsBody bodyB:ropePhysicsBody anchor:convertedRopePosition];
    jointPin.upperAngleLimit = M_PI/4;
    jointPin.shouldEnableLimits = YES;
    [self.scene.physicsWorld addJoint:jointPin];
Другие вопросы по тегам