I am new to xcode's sprite kit and I'm an trying to apply an impulse to a SKSpriteNode's physics body.
Here is how I create the scene:
self.backgroundColor = [SKColor colorWithRed:0 green:0 blue:0 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.friction = 0.0f;
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
ballCategory = 1;
wallCategory = 2;
self.physicsBody.categoryBitMask = wallCategory;
Here is how I create the player AND give it its impulse:
player = [SKSpriteNode spriteNodeWithImageNamed:filePath];
player.size = CGSizeMake(100, 100);
player.position = CGPointMake(150, 250);
player.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:player.frame];
player.physicsBody.categoryBitMask = ballCategory;
player.physicsBody.collisionBitMask = wallCategory;
player.physicsBody.friction = 0.0f;
player.physicsBody.restitution = 1.0f;
player.physicsBody.linearDamping = 0.0f;
player.physicsBody.allowsRotation = NO;
[self addChild:player];
CGVector impulse = CGVectorMake(100,100);
[player.physicsBody applyImpulse:impulse];
Is there anything obvious that I am missing because I've been following the iOS Developer Library Sprite Kit Programming Guide perfectly? Thanks in advance for the help!
You are creating the player's physicsBody as an edge body - these are always static (immovable by forces/impulses). You should change that line to:
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size];
This example makes it a dynamic volume based on a rectangle which will be affected by physics forces. You can read up on the types of physics bodies here.
Related
I've noticed something very odd with my subclassed SKSpriteNode with physicsBody attached and responding to impulses.
It has a SKPhysicsBody attached, but when applying impulses to the sprite it vibrates during movement. It's highly annoying and looks awful.
What could be causing this?
Here's the setup code:
self.texture = [[SKTextureAtlas atlasNamed:#"karl"]textureNamed:#"karlidle-1"];
self.size = CGSizeMake(69.0, 93.0);
self.userInteractionEnabled = NO;
self.name = #"karl";
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(69.0, 93.0)];
self.physicsBody.dynamic = YES;
self.physicsBody.allowsRotation = NO;
self.physicsBody.affectedByGravity = YES;
self.physicsBody.usesPreciseCollisionDetection = YES;
self.physicsBody.mass = 1.0;
self.physicsBody.linearDamping = 0.0;
self.physicsBody.angularDamping = 0.0;
self.physicsBody.restitution = 0.3;
self.physicsBody.categoryBitMask = karlCategory;
self.physicsBody.collisionBitMask = obstaclesCategory|floorCategory|wallCategory;
self.physicsBody.contactTestBitMask = obstaclesCategory|floorCategory|wallCategory;
and applying the impulse:
if (self.physicsBody.velocity.dy >= kKarlMaxVelocity) {
self.physicsBody.velocity = CGVectorMake(0, kKarlMaxVelocity);
}
else if (self.physicsBody.velocity.dy <= kKarlLowVelocityBoostThreshold){
self.physicsBody.velocity = CGVectorMake(0, kKarlVelocityImpulseIncrement*kKarlVelocityBoost);
}
else{
[self.physicsBody applyImpulse:CGVectorMake(0, kKarlVelocityImpulseIncrement)];
//[self.physicsBody applyForce:CGVectorMake(0, 3000) atPoint:self.frame.origin];
//self.physicsBody.velocity = CGVectorMake([self returnNormalisedXVelocity], self.physicsBody.velocity.dy);
}
One thing to note is I clamp the velocity so it doesn't go nuts, but turning this off doesn't seem to fix the issue.
I have created a hero node and enemy node, when they collide,game over.But I have problem with precise collision. Sometimes there is overlap.Sometimes collision happens when one node doesn't reach the other's frame. can anybody give me some advise? appreciate your help~
my hero is affected by gravity, when tap, it will change the direction of gravity.
following is some of my code:
-(void)addRectHero {
rectHero = [SKSpriteNode spriteNodeWithImageNamed:#“hero.png”];
rectHero.scale = 0.2;
rectHero.position = CGPointMake(self.size.width/2, self.size.height*0.3);
rectHero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rectHero.size];
rectHero.physicsBody.restitution = 0.0;
rectHero.physicsBody.allowsRotation = NO;
rectHero.physicsBody.dynamic = YES;
rectHero.physicsBody.affectedByGravity=NO;
rectHero.physicsBody.categoryBitMask = heroCategory;
rectHero.physicsBody.contactTestBitMask = enemyCategory;
rectHero.zPosition = 100;
rectHero.physicsBody.collisionBitMask = enemyCategory;
rectHero.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild:rectHero];
}
-(void)createEnemy{
randomStartPoint =(float)((random()%(int)(self.size.height/3))+self.size.height/3);
startPoint = CGPointMake(self.size.width + 50, randomStartPoint);
enemyNode = [SKSpriteNode spriteNodeWithImageNamed:#"enemy_4.png"];
enemyNode.scale =0.5;
enemyNode.position = startPoint;
enemyNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemyNode.size];
enemyNode.physicsBody.dynamic = NO;
enemyNode.physicsBody.categoryBitMask = enemyCategory;
enemyNode.physicsBody.contactTestBitMask = heroCategory;
enemyNode.physicsBody.collisionBitMask = heroCategory;
enemyNode.physicsBody.usesPreciseCollisionDetection = YES;
enemyNode.physicsBody.allowsRotation = NO;
enemyNode.physicsBody.restitution = 0.0;
enemyNode.name = #"enemy";
[self addChild:enemyNode];
}
-(void)didBeginContact:(SKPhysicsContact *)contact{
if (!_gameIsOn) {
return;
}
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask<contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody=contact.bodyB;
secondBody=contact.bodyA;
}
if (firstBody.categoryBitMask == heroCategory && secondBody.categoryBitMask == enemyCategory) {
[self runAction:sound_play completion:^{
[self gameOver];
}];
[self stopTimer];
}
}
I create a lot of enemies in update method: (I also tried self repeatActionForever method to create enemy but the problem still exists)
-(void)update:(CFTimeInterval)currentTime {
if (_lastTime)
{
_dt = currentTime - _lastTime;
}
else
{
_dt = 0;
}
_lastTime = currentTime;
if( currentTime - _lastEnemyAdded > 1 && _gameIsOn)
{
_lastEnemyAdded = currentTime + 1;
[self createEnemy];
}
}
In your ViewController make sure you have skView.showsPhysics = YES; Run your game again and look if your physics bodies are what you expect them to be. It sounds like you are creating a larger physics body than what you want.
If the issue ends up being a larger than desired physics body, try creating a physics body like this:
// to create a circular physics body
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10 center:CGPointMake(0, 0)];
// to create a rect physics body
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(20, 20) center:CGPointMake(0, 0)];
Use the center coordinates to properly center the body.
To create a physics body made up of more than one shape, you can do something like this:
SKPhysicsBody *firstBody = [SKPhysicsBody bodyWithCircleOfRadius:20 center:CGPointMake(0, 0)];
SKPhysicsBody *secondBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(20, 20) center:CGPointMake(0, 20)];
self.physicsBody = [SKPhysicsBody bodyWithBodies:#[firstBody, secondBody]];
I've set the physics body for both the background and the other sprite node, yet the node can still leave the the border. It doesn't fall through the bottom, it can leave on the sides though.
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:#"bg"];
bg.position = CGPointMake(self.scene.size.width/2, self.scene.size.height/2);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
[self addChild:bg];
SKSpriteNode *player = [SKSpriteNode spriteNodeWithImageNamed:#"ball"];
player.position = CGPointMake(self.frame.size.width*.5, 200);
player.name = #"player";
player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:30];
player.physicsBody.categoryBitMask = playerCategory;
player.physicsBody.contactTestBitMask = barCategory;
[self addChild:player];
What i think is happening is the body of the the background node is wider than what the view is showing. How can i make it so that the body dimension is what ever the view is.
Change the initialisation line of GameScene in GameViewController to
GameScene *scene = [[GameScene alloc]
initWithSize:CGSizeMake(self.view.frame.size.width,
self.view.frame.size.height)];
I have a SKSpriteNode that collides and bounces off another SKSpriteNode. What I want is to be able to detect the collision, but not have it bounce off. I want it to bounce off other nodes, but not this one. Is that possible?
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.zone = [SKSpriteNode spriteNodeWithImageNamed:#"Oval.png"];
self.zone.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame)); self.zone.xScale = 0.3;
self.zone.yScale = 0.3;
self.zone.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.zone.frame.size.width/2];
self.zone.physicsBody.restitution = 0.0f;
self.zone.physicsBody.density = 0;
self.zone.physicsBody.friction = 0.4f;
self.zone.physicsBody.categoryBitMask = zoneCategory;
self.zone.physicsBody.dynamic = NO;
self.ball = [SKSpriteNode spriteNodeWithImageNamed:#"Ball.png"];
self.ball.position = CGPointMake(80,0);
self.ball.name = #"BallNode";//how the node is identified later
self.ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.ball.frame.size.width/2];
self.ball.physicsBody.restitution = 0.1f;
self.ball.physicsBody.friction = 0.4f;
self.ball.physicsBody.categoryBitMask = ballCategory;
self.ball.physicsBody.dynamic = NO;
I don't want ball and zone to bounce. Any ideas?
set collisionBitMask and contactTestBitMask of those two bodies
like:
self.zone.collisionBitMask = 0xFFFFFFFF & (~ballCategory);
self.ball.collisionBitMask = 0xFFFFFFFF & (~zoneCategory);
self.zone.contactTestBitMask = ballCategory;
then when contact occurs expect call of didBeginContact: in your SKPhysicsContactDelegate.
There will be no collsion.
I'm attempting to apply an impulse to a sprite node in SK every time I touch, but nothing is happening. The touch is registering, but there is no impulse.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *torso = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(40, 60)];
torso.position = CGPointMake (250,250);
torso.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(40, 60)];
torso.physicsBody.dynamic = YES;
[self addChild: torso];
SKSpriteNode *arm = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(15, 50)];
arm.position = CGPointMake (235,235);
arm.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(40, 60)];
arm.physicsBody.dynamic = YES;
[self addChild: arm];
SKPhysicsJointPin *leftArm = [SKPhysicsJointPin jointWithBodyA:torso.physicsBody bodyB:arm.physicsBody anchor:torso.position];
[self.physicsWorld addJoint:leftArm];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[_torso.physicsBody applyImpulse:CGVectorMake(12, 10)];
NSLog(#"touch");
}
My sprite node does have another node linked to it, but I tried the impulse on it without the additional node and it still did not work.
For some reason, in order to move my sprite node I had to create it like this
_torso = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(40, 60)];
rather than
SKSpriteNode *torso = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(40, 60)];
Once I set a breakpoint and saw that _torso was nil, I referred to some previous work and saw my mistake.