【问题标题】:Sprite Kit Joints雪碧套件接头
【发布时间】:2014-01-14 21:17:01
【问题描述】:

我正在尝试制作一个动画角色,它可以在不移动躯干的情况下伸手去拿屏幕上的东西。

如果他不能够到,他的手应该朝这个方向移动最大量,然后被他的静态躯干的物理限制抵消。

所以在我的代码中,绿色矩形(hand)在我点击的地方移动,躯干随之移动。 我希望能够使红色矩形(body)静止,并使绿色矩形“点”在触摸点位置。

我尝试在场景和红体矩形之间应用固定关节,但这似乎不起作用。

- (void) createSceneContent
{
    SKSpriteNode *body = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(100, 100)];
    body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    [self addChild:body];

    body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:body.size];
    body.physicsBody.affectedByGravity = NO;
    body.physicsBody.dynamic = YES;

    self.hand = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(150, 20)];
    self.hand.position = CGPointMake(body.position.x + body.size.width / 2 + self.hand.size.width / 2, body.position.y);
    [self addChild:self.hand];
    self.hand.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.hand.size];
    self.hand.physicsBody.dynamic = NO;

    self.scene.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];

    [self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:body.physicsBody bodyB:self.hand.physicsBody anchor:CGPointMake(body.position.x + body.size.width / 2, body.position.y)]];

    [self.hand runAction:[SKAction moveByX:100 y:10 duration:0.1]];
}

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];

    CGPoint location = [touch locationInNode:self];
    [self.hand runAction:[SKAction moveTo:location duration:0.1]];
}

【问题讨论】:

    标签: ios iphone objective-c sprite-kit


    【解决方案1】:

    首先,如果您只希望手臂指向触摸的位置,您实际上并不需要在这里使用物理。
    只需将手臂节点的anchorPoint 更改为肩部(将销钉放在关节上的位置)并围绕该点旋转它(该点保存在辅助肩部节点中,以便稍后转换为它的坐标)。您可以使用atan2f 计算旋转角度。代码如下:

    - (void) createSceneContent
    {
        SKSpriteNode *body = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(100, 100)];
        body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
        [self addChild:body];
    
        self.hand = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(150, 20)];
        self.hand.position = CGPointMake(body.position.x + body.size.width*0.5, body.position.y);
        self.hand.anchorPoint = CGPointMake(0, 0.5);
        [self addChild:self.hand];
    
        SKNode *shoulderNode = [SKNode node];
        shoulderNode.position = self.hand.position;
        shoulderNode.name = @"shoulderNode";
        [self addChild:shoulderNode];
    
    }
    
    - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        UITouch *touch = [touches anyObject];
    
        CGPoint location = [touch locationInNode:self];
        CGPoint locationConv = [self convertPoint:location toNode:[self childNodeWithName:@"shoulderNode"]];
    
        self.hand.zRotation = (atan2f(locationConv.y, locationConv.x));
    }
    

    另一方面,如果您需要在这里使用物理实体,那么使用 SKActions 移动手臂可能不是一个好主意,您还可能需要设置 body.physicsBody.dynamic = NO 以使躯干静止。然后,确保正确添加销接头,并将其frictionTorque 属性设置为较高的值以减少悬空。使手点位于正确位置的方法之一是在更新方法中设置它的速度矢量 - 只需使用转换后的位置坐标(这里它们是相对于身体节点的中心)。完整示例代码:

    - (void) createSceneContent {
        self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
    
        body = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(100, 100)];
        body.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
        [self addChild:body];
    
        body.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:body.size];
        body.physicsBody.dynamic = NO;
        body.physicsBody.affectedByGravity = YES;
    
        self.hand = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(20, 150)];
        // experiment with the anchorPoint for different results
        self.hand.anchorPoint = CGPointMake(0.5, 0);
        self.hand.position = CGPointMake(body.position.x, body.position.y);
        [self addChild:self.hand];
    
        self.hand.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.hand.size];
        self.hand.physicsBody.dynamic = YES;
        self.hand.physicsBody.affectedByGravity = NO;
    
        SKPhysicsJointPin *pinHand = [SKPhysicsJointPin jointWithBodyA:body.physicsBody bodyB:self.hand.physicsBody anchor:CGPointMake(body.position.x, body.position.y-5)];
        [self.physicsWorld addJoint:pinHand];
        // experiment with the friction torque value to achieve desired results
        pinHand.frictionTorque = 1.0;
    }
    
    - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        UITouch *touch = [touches anyObject];
        location = [touch locationInNode:self];
    }
    
    -(void)update:(CFTimeInterval)currentTime {
        CGPoint locationConv = [self convertPoint:location toNode:body];
        // experiment with the multiplier (here: 10) for faster/slower movement
        self.hand.physicsBody.velocity = CGVectorMake(locationConv.x*10, locationConv.y*10);
    }
    

    希望有帮助!

    【讨论】:

    • 这绝对有效。最终我想用两个甚至更多部分的手臂构建一个更复杂的角色;所以协调所有的轮换会有点麻烦。我也想让这个角色自成一体,所以也许将手添加为身体的孩子?无论如何,我对如何轻松构建这样的可扩展角色感到有些困惑。为什么不将物理体与 SKActions 一起使用?
    • 如果您想将角色作为一个实体来控制,将手作为身体的孩子肯定会很有用。只要记住适当地重新调整位置和坐标之间的转换。但是,如果您想要实际复杂的关节,我建议您改用物理学(确保身体不是动态的,只有手臂,并确保它们不受重力影响)。在physicsBodies 上使用的SKAction 可能会导致行为不稳定和口吃,因为物理世界的规则可能与动作可能尝试做的事情相冲突。
    • 好的,我会尝试这样做。感谢您的意见。
    • 你将如何使用 atan2f 来计算 CGVector?我会在手的末端制作一个小的隐形 SpriteNode,我将与关节连接。然后我会在屏幕上获得触摸的位置,然后对这个不可见的精灵应用一个脉冲,它是一个 CGVector,带有点的 x 分量和带有乘数的点的 y 分量。这会不会也一样好用?
    • 如果你只是按原样将基于 CGVector 的脉冲应用到不可见的精灵上,你最终会让手臂旋转很多次。 :) 我刚刚编辑了我的原始帖子,向您展示了一个基于物理的手臂如何使用速度指向给定位置的简单示例,无需角度计算或辅助节点,您可以根据需要对其进行改进。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多