I'm making a game with SpriteKit that involves a hero bouncing on a surface in the positive x and y direction. The hero has this size:
CGSize heroSize = CGSizeMake(hero.size.width-140, hero.size.height-35);
hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:heroSize];
hero.physicsBody.usesPreciseCollisionDetection = YES;
and uses applyImpulse to bounce in the positive x/y direction:
[self.physicsBody applyImpulse:CGVectorMake(xvelocity, yvelocity)];
SKAction *rotation = [SKAction rotateByAngle: -2.0/M_PI duration:.5];
[self runAction: rotation];
The ground has a friction level of 0.4 and restitution of .5. Because the hero rotates when bouncing, he will sometimes bounce backwards and have a negative X velocity. I was wondering if there is any way to prevent an SKSpriteNode from moving in the -X direction. Would a solution be to create a better size for the physics body of my SKSpriteNode? It seems like this could happen with any shape, but would be less likely with more circular objects. Any input is greatly appreciated.
Thanks
You can monitor your hero's velocity and limit negative x movement by using this:
if(hero.physicsBody.velocity.dx < 0) {
hero.physicsBody.velocity = CGVectorMake(0, hero.physicsBody.velocity.dy);
}
Related
I have an interesting problem. I create an SKSpriteNode with associated physics body.
SKTexture *shipTexture = [SKTexture textureWithImageNamed:#"Spaceship"];
self.heroSpriteNode = [HeroSpriteNode spriteNodeWithTexture:shipTexture size:CGSizeMake(40, 35.2)];
self.heroSpriteNode.physicsBody = [SKPhysicsBody bodyWithTexture:shipTexture size:CGSizeMake(40, 35.2)];
self.heroSpriteNode.physicsBody.dynamic = YES;
self.heroSpriteNode.physicsBody.mass = 1000.0;
self.heroSpriteNode.physicsBody.affectedByGravity = NO;
self.heroSpriteNode.physicsBody.allowsRotation = YES;
self.heroSpriteNode.physicsBody.angularDamping = 0.5;
self.heroSpriteNode.anchorPoint = CGPointMake(0.5,0.5);
self.heroSpriteNode.physicsBody.categoryBitMask = heroCategory;
self.heroSpriteNode.physicsBody.contactTestBitMask = groundCategory;
self.heroSpriteNode.physicsBody.collisionBitMask = groundCategory | edgeCategory;
The Scene itself has no gravity.
In the update routine I call applyTorque: to the physics body.
-(void) updateWithDeltaTime:(NSTimeInterval)seconds
{
CGFloat rotateTorque = self.rotateRate;
switch (self.rotateForceApplied)
{
case leftForceApplied:
break;
case rightForceApplied:
rotateTorque = -1.0 * rotateTorque;
break;
case zeroForceApplied: // separate from default in case behavior should change
rotateTorque = 0.0;
break;
default:
rotateTorque = 0.0;
break;
}
NSLog(#"before physics position: x %f, y %f", self.heroSpriteNode.position.x, self.heroSpriteNode.position.y);
[self.heroSpriteNode.physicsBody applyTorque:rotateTorque];
NSLog(#"after physics position: x %f, y %f", self.heroSpriteNode.position.x, self.heroSpriteNode.position.y);
}
The sprite rotates and appears to rotate in place. What it is actually doing is rotating around a center point (so no net lateral movement). This is seen by logging the sprite position before and after applying the torque. No other actions are being applied to the physics body. The movement in position is about 9 points in each direction at most.
Because the camera is pinned by constraints to the "hero" sprite, and the world moves with the camera (the centerOnNode: sample code), this causes the whole world to move in a circular pattern as the sprite spins. The world itself does not spin but moves at the same rate in a circular pattern with the spinning.
With the sprite anchorPoint being 0.5, 0.5 I would think it should rotate around a center point which should not change the position of the sprite.
What would I being doing wrong with this?
If it matters this is on iOS9, Xcode7, running on device not in the simulator. (The iOS9 SpriteKit documentation is publicly available on Apple's website, as is a public beta of iOS9 itself so this should not be breaking any NDA, and I don't think anything here is iOS9 specific anyway)
Sprite Kit is a physics engine that attempts to mimic characteristics of objects in the real world, so you should expect an object with a physics body in the simulation to behave as they would in nature. In this case, you are rotating a non-uniform physics body that may rotate non-uniformly and, possibly, move over time (unless the body is rotating about its center of mass). If you change the physics body to a circle, the sprite should rotate uniformly and should remain at a fixed location.
I want to create a metal ball on the screen, I had the material and run animation done. But When the ball was rolling that I hope the texture shouldn't roating. Because that made rolling ball not look like metal ball...
There is anyways or not? I could make SKSpriteNode don't rotate the ball.
SKSpriteNode *node = [self spriteNodeWithImageNamed:#"ball.png"];
node.name = #"ball";
node.size = CGSizeMake(sideSize, sideSize);
node.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius: sideSize/2];
node.physicsBody.restitution = 0.2;
node.physicsBody.friction = 0.01;
node.physicsBody.angularDamping = 0.5;
node.physicsBody.categoryBitMask = GMCategoryBall;
node.position = CGPointMake(wood.position.x,wood..position.y +wood..size.height);
node.physicsBody.contactTestBitMask =.....
node.physicsBody.collisionBitMask =.....
Here are some suggestions:
Add another SKSpriteNode without a physicsBody that is just there for looks. Have it always centered on your ball.
Add another SKSpriteNode as a sub-node of your ball, and set its rotation to the opposite of your ball's rotation.
Add another SKSpriteNode, set its physicsBody to a bit mask value that won't interact with anything else in the scene (0 is a good choice) and set a joint that keeps it locked to the ball. Turn off rotation for that Sprite.
I am having trouble getting collision detection to work with my two objects. Here is my current code:
_firstPosition = CGPointMake(self.frame.size.width * 0.817f, self.frame.size.height * .40f);
_squirrelSprite = [SKSpriteNode spriteNodeWithImageNamed:#"squirrel"];
_squirrelSprite.position = _firstPosition;
_atFirstPosition = YES;
[self addChild:_squirrelSprite];
SKAction *wait = [SKAction waitForDuration:3.0];
SKAction *createSpriteBlock = [SKAction runBlock:^{
SKSpriteNode *lightnut = [SKSpriteNode spriteNodeWithImageNamed:#"lightnut.png"];
BOOL heads = arc4random_uniform(100) < 50;
lightnut.position = (heads)? CGPointMake(257,600) : CGPointMake(50,600);
[self addChild: lightnut];
SKAction *moveNodeUp = [SKAction moveByX:0.0 y:-700.0 duration:1.3];
[lightnut runAction: moveNodeUp];
}];
SKAction *waitThenRunBlock = [SKAction sequence:#[wait,createSpriteBlock]];
[self runAction:[SKAction repeatActionForever:waitThenRunBlock]];
I was following this answer at first: Sprite Kit Collision Detection but when I set the physics body to my squirrel and nut they would just fall. Is there any way to not mess with the physics (I'm happy with how everything currently works in the app) and just make it so that when one object touches the other the game will end? Is there a way to just set a radius around a sprite? Thank you for any help or information that can be provided.
Physics bodies are required for collision detection. If you don't also want gravity, either set the physics world's gravity to zero or turn off the affectedByGravity property on each physics body.
You can use the Pythagorean theorem to determine the distance between two sprite nodes. Here's an example of how to do that:
CGFloat dx = sprite1.position.x - sprite2.position.x;
CGFloat dy = sprite1.position.y - sprite2.position.y;
CGFloat distance = sqrt(dx*dx+dy*dy);
// Check if the two nodes are close
if (distance <= kMaxDistance) {
// Do something
}
I'm trying to animate a helicopter-thing in my game using a virtual joystick. The below code works well if your flying it actively, but now I want to animate the helicopter to a hover rotating it to the negative angle and apply a negative/positive vector to it to make it rapidly stop and "hover." And possibly bounce back and forth until its hovering. Any suggestions?
//Just move the hell with no physics
//[heli setPosition:CGPointMake(heli.position.x+self.joystick.x*2, heli.position.y+self.joystick.y*2)];
//Apply physics to the heli
float multiplier = 2.5;
[heli.physicsBody applyForce:CGVectorMake(_joystick.x*multiplier, _joystick.y*multiplier)];
//joystick x position is -99 to 99
SKAction *rotation = [SKAction rotateToAngle:-1*(_joystick.x/2.0) duration:0];
[heli runAction: rotation];
//if i let go of the joystick it returns to zero - bounce to a hover
if (_joystick.x == 0) { //not working
//check the current velocity?
//[heli.physicsBody velocity];
[heli.physicsBody applyForce:CGVectorMake(-1*(_joystick.x*multiplier*2), -1*(_joystick.y*multiplier*2))];
}
I don't really know how to explain what i'm after, so I drew some (very) artistic diagrams to help convey the idea. I'll also try and explain it the best I can.
I'm essentially trying to 'shoot' bullets/lasers/whatever from a circle in the center of the screen, and for it to repeat this at a rather rapid rate. Here are two pictures which kind of show what i'm trying to achieve: (Don't have enough reputation to post them here.
(1) http://i.imgur.com/WpZlTQ7.png
This is kind of where I want the bullets to shoot from, and how many I'd like.
(2) http://i.imgur.com/psdIjZG.png
This is pretty much the end result, I'd like them to repeatedly fire and make the screen kind of look like this.
Can anyone refer me to what I should be looking at in order to achieve this?
When dealing with circles, it's usually easier to use polar coordinates. In this case, each direction can be represented with a magnitude and an angle, where the magnitude is the amount of the force/impulse to apply to the bullet and angle is the direction to shoot the bullet.
The basic steps are
Determine the number of directions
Determine the angle increment by dividing 2*PI (360 degrees) by the number of directions
Start at angle = 0
Shoot bullet in the direction specified by angle
Convert the angle and magnitude to cartesian coordinates to form a vector
Apply an impulse or a force to the bullet using the vector
Increment angle by angle increment
Here's an example of how to do that in Obj-C:
#implementation GameScene {
CGFloat angle;
SKTexture *texture;
CGFloat magnitude;
CGFloat angleIncr;
}
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
long numAngles = 15;
magnitude = 1;
angleIncr = 2 * M_PI / numAngles;
angle = 0;
texture = [SKTexture textureWithImageNamed:#"Spaceship"];
SKAction *shootBullet = [SKAction runBlock:^{
SKSpriteNode *bullet = [SKSpriteNode spriteNodeWithTexture:texture];
bullet.size = CGSizeMake(8, 8);
bullet.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:bullet.size.width/2];
bullet.physicsBody.affectedByGravity = NO;
bullet.position = self.view.center;
bullet.zRotation = angle-M_PI_2;
[self addChild:bullet];
CGFloat dx = magnitude * cos(angle);
CGFloat dy = magnitude * sin(angle);
CGVector vector = CGVectorMake(dx,dy);
[bullet.physicsBody applyImpulse:vector];
angle = fmod(angle+angleIncr,2*M_PI);
}];
SKAction *wait = [SKAction waitForDuration:0.25];
SKAction *shootBullets = [SKAction sequence:#[shootBullet, wait]];
[self runAction:[SKAction repeatActionForever:shootBullets]];
}
From what I understand, you want this sprite to shoot a bunch of projectiles every X seconds.
SKAction *ShootProjectiles = [SKAction runBlock:^{
//Create Projectile1
projectile1.physicsBody.applyImpulse(CGVectorMake(1, 0)); //Shoot directly right
//Create Projectile2
projectile2.physicsBody.applyImpulse(CGVectorMake(1, 1)); //Shoot diagnally Up and to the right
//Follow this pattern to create all projectiles desired to be shot in one burst
}];
SKAction *delayBetweenShots = [SKAction scaleBy:0 duration:5];
SKAction* ShootSequence= [SKAction repeatActionForever:[SKAction sequence:#[ShootProjectiles, delayBetweenShots]]];
[self runAction: ShootSequnce];
What this does is create as many projectiles as you desire and fire them in the direction of the vectors you define. It then waits 5 seconds (the scaleBy:0 action does nothing except delay) and then repeats over and over again until you remove the action.