Установите постоянную ориентацию изображения SKSpritenode

Привет, у меня есть куча круглых SKSpriteNodes с круглым физическим телом. Теперь, когда эти шары катятся по дорожке, я хочу, чтобы некоторые из этих изображений SKSpritenodes оставались в вертикальном положении, даже когда они катятся. Итак, подумайте о стрелке, указывающей вверх. Когда мяч начинает катиться, стрелка начинает вращаться по кругу. Но для некоторых мячей мне бы хотелось, чтобы стрелка оставалась направленной вверх, даже когда мяч катится. Как лучше всего это сделать?

Редактировать

Итак, ответ был дан, но тестирование показало, что это неправильный ответ. Не позволять мячу вращаться влияет на то, как он катится по траектории. Итак, я думаю, что я хочу, чтобы вращение было включено, но изображение всегда отображалось для пользователя, как будто оно не вращается. Спасибо.


person 4GetFullOf    schedule 07.11.2014    source источник
comment
Как может катиться мяч, если он не может вращаться?   -  person 0x141E    schedule 09.11.2014
comment
Я хочу, чтобы мяч вращался, но я хочу, чтобы изображение выглядело так, как будто оно не вращается для глаз пользователей @ 0x141E   -  person 4GetFullOf    schedule 09.11.2014


Ответы (3)


Похоже, это работа для SupermSKConstraint. Ограничения оцениваются и применяются после запуска физической симуляции для каждого кадра, поэтому их можно использовать для таких задач, как направление узла в определенном направлении независимо от того, что с ним делает физика. Для этого вам понадобится ограничение zRotation.

Но это еще не все. Если вы установите ограничение на нулевое вращение мяча:

// Swift
let constraint = SKConstraint.zRotation(SKRange(constantValue: 0))
ball.constraints = [constraint]

Вы обнаружите, что SpriteKit сбрасывает преобразование физического тела в каждом кадре из-за ограничения, так что он ведет себя только как будто катится. Вероятно, это не то, что вы хотите. (Чтобы лучше понять, что здесь происходит, попробуйте добавить ограничение нулевого поворота к прямоугольному физическому телу в мире без гравитации, применить к нему угловой импульс и посмотреть, как оно попытается вращаться в представлении с включенным showsPhysics. Вы увидите, как спрайт и его физическое тело рассинхронизируются и немного трясутся — вероятно, из-за накопленных ошибок округления, когда физический движок и движок ограничений борются друг с другом.)

Вместо этого вы можете сделать что-то из того, что указано в ответе 0x141E, но использовать ограничения, чтобы уменьшить количество кода (и работать более эффективно):

  1. Придайте шаровому узлу круглое физическое тело. (И, возможно, без текстуры, если единственное изображение, которое вам нужно для шара, — это невращающийся спрайт.)
  2. Добавьте узел стрелки в качестве дочернего элемента узла шара. (Ему не нужно собственное физическое тело.)
  3. Наложите на стрелку ограничение нулевого поворота.

Подождите, это не работает — я сказал стрелке не вращаться, но она все еще вращается?! Помните, что дочерние узлы позиционируются (а также поворачиваются и масштабируются) относительно своего родительского узла. Так что не стрелка крутится относительно мяча, а мяч крутится. Не волнуйтесь, вы все равно можете решить это с ограничением:

  1. Укажите ограничение, чтобы оно работало относительно узла, содержащего мяч (вероятно, сцены).

Теперь ограничение будет удерживать стрелку на месте, позволяя мячу вращаться так, как этого требует симуляция физики.

Вот некоторый тестовый код для иллюстрации:

// Step 1: A rectangular spinner so we can see the rotation 
//         more easily than with a ball
let spinner = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 300, height: 20))
spinner.position.x = scene.frame.midX
spinner.position.y = scene.frame.midY
spinner.physicsBody = SKPhysicsBody(rectangleOfSize: spinner.size)
scene.addChild(spinner)
spinner.physicsBody?.applyAngularImpulse(0.1) // wheeeeee

// Step 2: Make the arrow a child of the spinner
let arrow = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 20, height: 50))
spinner.addChild(arrow)

// Step 3: Constrain the arrow's rotation...
let constraint = SKConstraint.zRotation(SKRange(constantValue: 0))
arrow.constraints = [constraint]

// Step 4: ...relative to the scene, instead of to its parent
constraint.referenceNode = scene
person rickster    schedule 09.11.2014

Вот два метода создания шара с физическим телом и стрелой:

  1. Добавьте стрелку в качестве дочернего элемента шара
  2. Добавьте и мяч, и стрелку прямо на сцену.

Вот что произойдет, если вы добавите вышеуказанное в симуляцию SpriteKit:

  1. Стрелка будет вращаться, когда вращается мяч
  2. И стрелка, и шарик будут двигаться/вращаться независимо друг от друга.

Если вы хотите, чтобы стрелка вращалась вместе с мячом, выберите вариант 1. Если вы хотите, чтобы стрелка оставалась неподвижной, выберите вариант 2. Если вы выберете вариант 2, вам нужно будет отрегулировать вращение стрелки, чтобы убедиться, что она указывает вверх . Вот пример того, как это сделать.

-(void)didMoveToView:(SKView *)view {
    self.scaleMode = SKSceneScaleModeResizeFill;

    /* Create an edge around the scene */
    self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:view.frame];

    // Show outline of all physics bodies
    self.view.showsPhysics = YES;

    CGFloat radius = 16;

    SKNode *balls = [SKNode node];
    balls.name = @"balls";
    [self addChild:balls];

    // Create 5 balls with stationary arrows
    for (int i = 0;i<5;i++) {
        // Create a shape node with a circular physics body. If you are targeting iOS 8,
        // you have other options to create circular node. You can also create an SKSpriteNode
        // with a texture
        SKShapeNode *ball = [SKShapeNode node];
        // Create a CGPath that is centered
        ball.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-radius,-radius,radius*2,radius*2)].CGPath;
        ball.fillColor = [SKColor whiteColor];
        ball.position = CGPointMake(100, 100+i*radius*2);
        ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:radius];

        [balls addChild:ball];

        // Create an arrow node
        CGSize size = CGSizeMake(2, radius*2);
        SKSpriteNode *arrow = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:size];
        arrow.name = @"arrow";
        arrow.position = CGPointZero;

        [ball addChild:arrow];
        // Apply angular impulse to the ball so it spins when it hits the floor
        [ball.physicsBody applyAngularImpulse:-1];
    }
}

- (void) didSimulatePhysics
{
    SKNode *balls = [self childNodeWithName:@"balls"];
    for (SKNode *ball in balls.children) {
        SKNode *arrow = [ball childNodeWithName:@"arrow"];
        arrow.zRotation = -ball.zRotation;
    }
}
person 0x141E    schedule 09.11.2014
comment
SKConstraint при правильном использовании является более простым и эффективным решением (согласно мому ответу). Но оно доступно только в iOS 8 / OS X 10.10 — если вам нужно что-то, что работает в iOS 7 / OS X 10.9, вам понадобится что-то похожее на это решение. - person rickster; 10.11.2014
comment
Хотя вы могли бы немного упростить это: оставьте стрелки как дочерние узлы шаров (чтобы их положение автоматически совпадало с шарами), а в didSimulatePhysics просто установите zRotation стрелки на отрицательное значение zRotation ее родителя. - person rickster; 10.11.2014
comment
спасибо, это похоже на ответ рикстера, но он ответил первым, поэтому я дал ему правильный ответ! Однако, спасибо - person 4GetFullOf; 12.11.2014

sprite.physicsBody.allowsRotation = NO;

Свойство allowRotation должно контролировать именно то, что вы просите.

person meisenman    schedule 07.11.2014
comment
спасибо! я только что видел это в справочнике по классам... на самом деле это свойство physicsBody, хотя должно быть mySprite.physicsBody.allowsRotation = NO; - person 4GetFullOf; 08.11.2014
comment
Спасибо. Вы на 100% правы, что я пропустил это. Просто отредактировано, чтобы отразить правильный ответ. - person meisenman; 08.11.2014
comment
Как только вы задаете вопрос и получаете ответ, вы обычно задаете новый вопрос, если ваш вопрос полностью меняется. Вы бы не отменили выбор ответа и не изменили бы свой вопрос. - person meisenman; 10.11.2014
comment
Я бы сказал, что он разъяснил свой вопрос, но не изменил его полностью. Если вы отключите allowsRotation, мяч не будет катиться из-за физики — даже предварительное редактирование вопроса выглядит так, как будто он просит катиться. - person rickster; 10.11.2014