Wednesday, 27 August 2014

How to create a "cross" (or "plus") shape spinning object with Sprite Kit Physics?

Was following the example in this Free PoBo site, but want to create a "cross" (or "plus") shape instead of just a seesaw.

Uploaded a small test project here, basically it creates a scene as shown below, some seesaws with one of them replaced by the cross thing I tried to put it.

When you tapped on anywhere on the screen, you will either create a small ball or square box which will drop down from where you tapped. When the object hits the seesaw it spins as expected.

Problem is, the cross object doesn't always spin as expected - only when the object hits the middle green circle of the cross shape object, then it will start spinning. Otherwise the object just drop through the blue area as if it doesn't exist. Wonder what have I done wrong??!!

This is how the cross been added in the code:


        float wWidth = 100.0f;
        float wHeight = 10.0f;
        
        
        [self addCross:CGPointMake(self.frame.size.width*0.75f, self.frame.size.height*0.60f)
                  game:self
             whipWidth:wWidth*0.5f

            whipHeight:wHeight];


-(CGMutablePathRef)getCGMutablePathRef:(float)ww thickness:(float)tt {
    
    CGMutablePathRef boundingPath = CGPathCreateMutable();
    float halfTT = tt*0.5;
    
    CGPathMoveToPoint(boundingPath, NULL, halfTT, halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, halfTT+ww, halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, halfTT+ww, -halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, halfTT, -halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, halfTT, -halfTT-ww);
    CGPathAddLineToPoint(boundingPath, NULL, -halfTT, -halfTT-ww);
    CGPathAddLineToPoint(boundingPath, NULL, -halfTT, -halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, -halfTT-ww, -halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, -halfTT-ww, halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, -halfTT, halfTT);
    CGPathAddLineToPoint(boundingPath, NULL, -halfTT, halfTT+ww);
    CGPathAddLineToPoint(boundingPath, NULL, halfTT, halfTT+ww);
    CGPathAddLineToPoint(boundingPath, NULL, halfTT, halfTT);
    
    return boundingPath;
    
}

-(void)addCross:(CGPoint)pos game:(SKScene*)game  whipWidth:(float)whipWidth whipHeight:(float)whipHeight {
    
    idNumber++;
    
    SKSpriteNode * anchor = [SKSpriteNode spriteNodeWithColor:[UIColor clearColor] size:CGSizeMake(1, 1)];
    anchor.position = pos;
    anchor.name = [NSString stringWithFormat:@"whip_anchor-%d",idNumber];
    anchor.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1];
    anchor.physicsBody.affectedByGravity = false;
    anchor.physicsBody.dynamic = false;
    [game addChild:anchor];
    
    CGMutablePathRef boundingPath = [self getCGMutablePathRef:whipWidth thickness:whipHeight];
    
    CGMutablePathRef boundingPath2 = [self getCGMutablePathRef:whipWidth thickness:whipHeight];
    
    SKShapeNode* polygon = [[SKShapeNode alloc]init];
    
    polygon.path = CGPathCreateMutableCopy(boundingPath2);
    
    polygon.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:boundingPath];
    CGPathRelease(boundingPath);
    CGPathRelease(boundingPath2);
    
    polygon.name = @"polygon";
    
    polygon.lineWidth = 0.01;
    polygon.fillColor = [SKColor blueColor];
    polygon.lineWidth = 0;

    polygon.physicsBody.affectedByGravity = NO;
    [anchor addChild:polygon];
    
    SKSpriteNode * gear = [SKSpriteNode spriteNodeWithImageNamed:@"ball"];
    gear.size = CGSizeMake(whipHeight+5, whipHeight+5);
    gear.name = [NSString stringWithFormat:@"gear-%d",idNumber];
    [anchor addChild:gear];
    
    SKPhysicsJointPin* jointPin = [SKPhysicsJointPin jointWithBodyA:anchor.physicsBody
                                                              bodyB:polygon.physicsBody
                                                             anchor:anchor.position];
    [game.physicsWorld addJoint:jointPin];
    
    
    idNumber++;

}

[2014-08-29 Update]
Posted the question on stackoverflow.com

[2014-09-03 Update]
Was trying different ways of creating the polygon - clock-wise, anti-clock-wise, …etc. Sometimes only the left hand side of the cross works and sometimes the right hand side, sometimes keep getting this "Assertion failed: (area > 1.19209290e-7F), function ComputeCentroid, file /SourceCache/PhysicsKit/PhysicsKit-6.5.4/PhysicsKit/Box2D/Collision/Shapes/b2PolygonShape.cpp, line 122." error similar to this link due to polygon not convex,  quite frustrating.

Finally got it working today by joining the second rectangle to the first one using fixed joint. The code as below:

-(void)addCross2:(CGPoint)pos game:(SKScene*)game whipWidth:(float)whipWidth whipHeight:(float)whipHeight {
    
    idNumber++;
    
    SKSpriteNode * anchor = [SKSpriteNode spriteNodeWithColor:[UIColor clearColor] size:CGSizeMake(1, 1)];
    anchor.position = pos;
    anchor.name = [NSString stringWithFormat:@"whip_anchor-%d",idNumber];
    anchor.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1];
    anchor.physicsBody.affectedByGravity = false;
    anchor.physicsBody.dynamic = false;
    [game addChild:anchor];
    
    SKSpriteNode * whip = [SKSpriteNode spriteNodeWithImageNamed:@"box"];
    whip.name = [NSString stringWithFormat:@"whip-%d",idNumber];
    whip.size = CGSizeMake(whipWidth, whipHeight);
    whip.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(whipWidth, whipHeight)];
    whip.physicsBody.mass = objMass*0.5f;
    whip.physicsBody.friction = 0;
    whip.physicsBody.linearDamping = 0;
    [anchor addChild:whip];
    
    SKSpriteNode * gear = [SKSpriteNode spriteNodeWithImageNamed:@"ball"];
    gear.size = CGSizeMake(whipHeight+5, whipHeight+5);
    gear.name = [NSString stringWithFormat:@"gear-%d",idNumber];
    [anchor addChild:gear];
    
    
    ///////////////
    // extra whip
    SKSpriteNode * whip2 = [SKSpriteNode spriteNodeWithImageNamed:@"box"];
    whip2.name = [NSString stringWithFormat:@"whip-%d-2",idNumber];
    whip2.size = CGSizeMake(whipHeight, whipWidth);
    whip2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(whipHeight, whipWidth)];
    whip2.physicsBody.mass = objMass*0.5f;
    whip2.physicsBody.friction = 0;
    whip2.physicsBody.linearDamping = 0;
    [whip addChild:whip2];
    
    ////////////
    // join with whip 1 using fixed joint
    SKPhysicsJointFixed* jointPin2 = [SKPhysicsJointFixed  jointWithBodyA:whip.physicsBody
                                                                    bodyB:whip2.physicsBody
                                                                   anchor:whip.position];
    
    [game.physicsWorld addJoint:jointPin2];
    
    //////////////
    
    
    SKPhysicsJointPin* jointPin = [SKPhysicsJointPin jointWithBodyA:anchor.physicsBody
                                                              bodyB:whip.physicsBody
                                                             anchor:anchor.position];
    
    [game.physicsWorld addJoint:jointPin];


   
    idNumber++;

}


[Update 25/Apr/2015]
The guys at free-pobo.com/waveworks.de are really nice and they provided a new working sample using rotating mills as I request, see further info here. Even have a YouTube video for it!

Really appreciated!


No comments:

Post a Comment