【问题标题】:How can I prevent the child of an SKSpriteNode from rotating with its parent?如何防止 SKSpriteNode 的子级与其父级一起旋转?
【发布时间】:2013-10-16 21:27:18
【问题描述】:

我正在使用 SpriteKit 编写一个涉及许多标记球的 iOS 游戏。我正在通过构建具有 2 个孩子的父 SKSpriteNode 来构建这些“滚动球”:

a) 一个 SKShapeNode(实际的圆形)

b) 和一个 SKLabelNode(标签)

球将在整个屏幕上移动,在二维中与彼此和其他对象交互,并且完全取决于预期的物理特性(想想台球)。但如果可能的话,我希望标签不随父级旋转,以便始终保持易于阅读。

最简单的方法是什么?

标签不应该是容器的子容器吗?有没有其他方法可以将它固定在 ballShape 上?或者我可以在标签上设置一些属性等?

这是我现在得到的:

double ballDiameter = 40;
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: 
                            CGRectMake(-ballDiameter / 2, -ballDiameter / 2, 
                                        ballDiameter, ballDiameter)];

SKSpriteNode *container = [[SKSpriteNode alloc]init];

container.name = @"rollingBall";

SKShapeNode *ballShape = [[SKShapeNode alloc] init];
ballShape.path = ovalPath.CGPath;

SKLabelNode *ballLabel = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
ballLabel.text = @"some random string";
ballLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
ballLabel.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;
ballLabel.position = CGPointMake(0,0);

[container addChild:ballShape];
[container addChild:ballLabel];

container.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ballDiameter / 2];
container.physicsBody.usesPreciseCollisionDetection = YES;

【问题讨论】:

  • 这很奇怪 - 我在刚启动的应用程序中做同样的事情。我只是想以某种方式添加一个销接头,所以标签被固定到父节点。
  • hmmm.. 这听起来比我下面的解决方案更有希望......但是如果标签固定到父级,它不会仍然旋转吗?
  • 它将是旋转的,但在某种程度上独立于父物理体,因此您可以调整定位等。我计划让我的看起来像摩天轮上的马车。大轮子转了转,但马车仍然悬在它下面。
  • 有趣...您有机会发布或分享一些代码吗?想看看你是怎么做的吗?
  • 我还没有尝试过,其他答案会让它暂时满意。

标签: ios rotation sprite-kit skphysicsbody


【解决方案1】:

将所有标签放在一个容器中,将标签添加到关联节点的用户数据中,然后更新标签位置。

// Add a container as a scene instance variable.
SKNode *labels;

- (void)addLabelContainer
{
    labels = [SKNode node];
    [self addChild:labels];
}

- (void)addLabelForNode:(SKNode*)node
{
    SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    node.userData = [NSMutableDictionary dictionaryWithObject:label forKey:@"label"];
    label.text = node.name;
    label.fontSize = 5;
    label.zPosition = node.zPosition + 1;
    [labels addChild:label];
}

- (void)removeLabelForNode:(SKNode*)node
{
    [[node.userData objectForKey:@"label"] removeFromParent];
    [node.userData removeObjectForKey:@"label"];
}

- (void)update:(NSTimeInterval)currentTime
{
    for (SKNode *node in self.children) {
        SKNode *label = (SKLabelNode*)[node.userData objectForKey:@"label"];
        if (label) {
            label.position = node.position;
        }
    }
}

https://github.com/pmark/MartianRover/blob/master/hiSpeed/hiSpeed/Scenes/LimboScene.m

【讨论】:

    【解决方案2】:

    这似乎有效

    -(void) didSimulatePhysics
    {
        [self enumerateChildNodesWithName:@"ball" usingBlock:^(SKNode *node, BOOL *stop) {
    
            for (SKNode *n in node.children) {
                n.zRotation = -node.zRotation;
            }
    
        }];
    }
    

    【讨论】:

    • 或者每次都设置 zRotation = 0。工作正常。这计算效率低吗?
    • 是的,它适用于我的目的,但我的直觉告诉我有更好的方法。对盲目地为所有孩子调整 zRotation 并不感到兴奋——我们将如何处理具有多个孩子的更复杂的 SKNode,其中一些我们可能仍想与容器一起旋转......?我喜欢使用 SKPhysicsJointPin 的想法,但不知道如何使它工作,因为引脚固定在场景的坐标系中。暂时将其标记为未答复,看看我们是否可以获得更多帮助。但是,是的,您的解决方案现在适用于我的钱包,非常感谢。
    • 您可以使用 node.UserData 来保存第二位信息,即允许旋转。然后,如果子节点允许旋转,它将旋转等。如果您需要帮助,可以更新答案。
    • 这行得通,但它只是在概念上闻起来不太对。变得越来越复杂并违反封装最佳实践,你不觉得吗?真的觉得我们应该能够参与实际的物理学。
    • 另外...通过设置扭矩和角度限制让标签旋转一点点会很棒...认为它看起来更逼真。再次感谢您的帮助。
    【解决方案3】:

    一个潜在的、超级简单的解决方案:

    container.physicsBody.allowsRotation = NO
    

    但这当然会阻止整个精灵旋转。

    【讨论】:

    • 是的,这违背了目的。
    【解决方案4】:

    虽然其他解决方案也可以,但我发现使用物理模拟移动它们时,两个节点之间的间隙很小。

    您可以使用 2 个物理实体并在它们之间添加一个销关节,这样它们将同时更新。我的 SKNode 子类的示例代码(注意:您需要将节点添加到场景/节点才能添加关节):

    SKSpriteNode *overlay = [SKSpriteNode spriteNodeWithImageNamed:@"overlay"];
    overlay.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10.0];
    overlay.allowsRotation = NO;
    [self addChild:overlay];
    
    self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:26.0];
    
    SKPhysicsJointPin *pinJoint = [SKPhysicsJointPin jointWithBodyA:overlay.physicsBody bodyB:self.physicsBody anchor:self.position];
    [self.scene.physicsWorld addJoint:pinJoint];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      相关资源
      最近更新 更多