Reputation: 761
I'm a long time web developer but this is the first time I have made a game or worked with Objective C. I really (really!) like working with Objective C so far and have gotten quite far on my game. Thanks in advance for your help!
I'm trying to make 3 spike balls that are SKSpriteNodes rotate in a circle around my hero ship (see image) after the hero gets a pickup. All looks and animates great until I add physics bodies to the balls, which are required so they can collide with monsters. I want the hero ship to be unaffected by the attached physics bodies so that the hero movement can remain smooth and constant – I'm moving the hero with:
[self.heroShip.physicsBody applyForce:CGVectorMake(moveByX, moveByY)];.
Here it is without the physics bodies. I'm attaching 3 children nodes to an anchor node, attaching the anchor node to the hero ship, and then rotating the anchor. The following animation looks exactly like I want it to.
SKSpriteNode * spikeballAnchor = [[SKSpriteNode alloc] init];
SKSpriteNode * spikeball1 = [SKSpriteNode spriteNodeWithImageNamed:@"spikeball"];
spikeball1.name = HERO_SPIKEBALL;
spikeball1.position = CGPointMake(100, 0);
[spikeballAnchor addChild:spikeball1];
SKSpriteNode * spikeball2 = [SKSpriteNode spriteNodeWithImageNamed:@"spikeball"];
spikeball2.name = HERO_SPIKEBALL;
spikeball2.position = CGPointMake(-50, 86);
[spikeballAnchor addChild:spikeball2];
SKSpriteNode * spikeball3 = [SKSpriteNode spriteNodeWithImageNamed:@"spikeball"];
spikeball3.name = HERO_SPIKEBALL;
spikeball3.position = CGPointMake(-50, -86);
[spikeballAnchor addChild:spikeball3];
[spikeballAnchor runAction:[SKAction repeatActionForever:[SKAction rotateByAngle:(M_PI_2 * 2) duration:1]]];
[self.heroShip addChild:spikeballAnchor];
But the spike balls need to collide with enemy monsters! When I add the following physics body to a spike ball it quickly flies out of orbit.
SKSpriteNode * spikeball1 = [SKSpriteNode spriteNodeWithImageNamed:@"spikeball"];
spikeball1.name = HERO_SPIKEBALL;
spikeball1.position = CGPointMake(100, 0);
spikeball1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spikeball1.size];
spikeball1.physicsBody.categoryBitMask = spikeballCategory;
spikeball1.physicsBody.contactTestBitMask = monsterCategory;
spikeball1.physicsBody.collisionBitMask = defaultCategory;
[spikeballAnchor addChild:spikeball1];
Ok. So I have tried just about everything I can think of and have scoured the web for a solution. Giving examples of everything I have tried would take a lot of space so I'll summarize.
I have tried making the anchor a physics body, pinning the spike balls to the anchor, and pinning the anchor to the hero. No luck.
I have tried creating a SKPhysicsJointLimit, SKPhysicsJointPin, and a SKPhysicsJointFixed between the anchor and the balls. In all the these rigs the physics of the spike balls throw the ship off. I have tried setting the mass of the anchor and the balls to zero. Strangely, even with no mass, they still seem to affect the ship's movement. Additionally I have tried setting friction, linearDamping, and angularDamping of the physics bodies to zero.
Also the joints only seem to work when I add the child nodes before setting the physics bodies.
The following is the closest/best result I have gotten (one spike ball in example) but I am unable to make the rotation of the balls not affect the ship! When I run this the ball does not rotate consistently (the ship's movement speeds up and slows down the rotation around the joint) and the movement of the ball throws the ship's movement off, creating an undesirable pendulum effect on the ship. This needs to work with 2 and 1 ball as they get destroyed.
SKSpriteNode * spikeballAnchor = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(10, 10)];
[self.heroShip addChild:spikeballAnchor];
spikeballAnchor.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spikeballAnchor.size];
spikeballAnchor.physicsBody.pinned = true;
spikeballAnchor.name = HERO_SPIKEBALL;
SKSpriteNode * spikeball1 = [SKSpriteNode spriteNodeWithImageNamed:@"spikeball"];
spikeball1.name = HERO_SPIKEBALL;
spikeball1.position = CGPointMake(100, 0);
[spikeballAnchor addChild:spikeball1];
spikeball1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spikeball1.size];
spikeball1.physicsBody.categoryBitMask = spikeballCategory;
spikeball1.physicsBody.contactTestBitMask = monsterCategory;
spikeball1.physicsBody.collisionBitMask = defaultCategory;
[spikeballAnchor runAction:[SKAction repeatActionForever:[SKAction rotateByAngle:(M_PI_2 * 2) duration:1]]];
SKPhysicsJointFixed * joint = [SKPhysicsJointFixed jointWithBodyA:spikeballAnchor.physicsBody bodyB:spikeball1.physicsBody anchor:spikeballAnchor.position];
[self.physicsWorld addJoint:joint];
I have considered trying to move the anchor and its children independently of the ship but I'm worried they will get out of sync and it will add a little more management to remove them when the hero dies if the anchor is not a child of the hero. But that's not a deal breaker if I can keep their position's perfectly in sync.
Sorry for being so verbose. Any help is most appreciated!
// Collision Bits
static const int defaultCategory = 0;
static const int projectileCategory = 1;
static const int spikeballCategory = 2;
static const int monsterCategory = 3;
static const int heroCategory = 4;
static const int pickupCategory = 5;
static const int boundariesCategory = 50;
Upvotes: 2
Views: 738
Reputation: 3196
Not an answer to a question so a bit offtopic, but I see another problem in your code: your categories are intersecting, because they are used as bitmasks. I mean, your monsterCategory
includes spikeballCategory
and projectileCategory
, because in binary 3 = 1 | 2
.
monsterCategory 3 0b00000011
projectileCategory 1 0b00000001
spikeballCategory 2 0b00000010
So you might notice your spikeballs can act like monsters and vice versa, and projectiles can act like monsters and vice versa.
Upvotes: 0