Making a node go in the direction of a swipe (Swift) - ios

I'm making a game in SpriteKit using Swift, and I want to be able to swipe on the screen and have a ball go in that direction. I already have the ball created and its just named "ball" as an SKSpriteNode. I already have it moving around the screen but I just need it to change directions towards swipes that take place. If I can't do this with swipes then I would consider taps.
Also, I have a border the size of the screen. Here is the code for that:
let worldBorder = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = worldBorder
self.physicsBody?.friction = 0
The border is already functioning as a border, but I need to keep it that way for when I start swiping.

Related

iOS 8 SpriteKit Display part of image on scene as it almost leaves scene?

I placed a circle image in the middle of the screen and had the image move to the left. But it eventually stops so half of it still shows on the screen. I don't want to remove the circle, just move it a little bit further to the left so less of the circle shows. I tried setting the moveTo value to negative but it had the same effect as the value being 0. Any ideas?
SKSpriteNode *circle = [self makeSprite:#"circle" x:.5 y:.5];
circle.position = CGPointMake(self.size.width*.5, self.size.height*.5);
[circle [SKAction moveToX:0.0 duration:3]];

Set permanent SKSpritenode image orientation

Hi I have a bunch of round SKSpriteNodes with a circle physical body. Now when these balls roll down a path I want some of these SKSpritenodes image to stay upright even when rolling. So think of an arrow pointing upwards. When the ball starts rolling the arrow spins in circles. But for some balls Id like the arrow to remain pointing up even when the ball rolls. Whats the best way of doing this?
Edit
So an answer was given but from testing it turns out it is not the correct one. Not allowing the ball to rotate affects the way it rolls down the path. So I guess what I want is rotation to be on but the image to always appear to the user like its not rotating. Thanks.
This looks like a job for SupermSKConstraint. Constraints are evaluated and applied after the physics simulation runs on each frame, so you can use them for tasks like making a node point a certain direction regardless of what physics does to it. For this, you'd want a zRotation constraint.
But there's a bit more to it than that. If you set a zero-rotation constraint on the ball:
// Swift
let constraint = SKConstraint.zRotation(SKRange(constantValue: 0))
ball.constraints = [constraint]
You'll find that SpriteKit resets the physics body's transform every frame due to the constraint, so it only sort-of behaves like it's rolling. Probably not what you want. (To get a better idea what's going on here, try adding a zero-rotation constraint to a rectangular physics body in a world without gravity, applying an angular impulse to it, and watching it try to spin in a view with showsPhysics turned on. You'll see the sprite and its physics body get out of sync and shake a bit -- probably due to accumulated rounding errors as the physics engine and the constraint engine fight it out.)
Instead, you can do a bit of what's in 0x141E's answer, but use constraints to make it less code (and run more efficiently):
Give the ball node a circular physics body. (And possibly no texture, if the only art you want for the ball is a non-rotating sprite.)
Add the arrow node as a child of the ball node. (It doesn't need its own physics body.)
Put a zero-rotation constraint on the arrow.
Wait, that doesn't work -- I told the arrow to not rotate, but it's still spinning?! Remember that child nodes are positioned (and rotated and scaled) relative to their parent node. So the arrow isn't spinning relative to the ball, but the ball is spinning. Don't worry, you can still solve this with a constraint:
Tell the constraint to operate relative to the node containing the ball (probably the scene).
Now the constraint will keep the arrow in place while allowing the ball to rotate however the physics simulation wants it to.
Here's some test code to illustrate:
// Step 1: A rectangular spinner so we can see the rotation
// more easily than with a ball
let spinner = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 300, height: 20))
spinner.position.x = scene.frame.midX
spinner.position.y = scene.frame.midY
spinner.physicsBody = SKPhysicsBody(rectangleOfSize: spinner.size)
scene.addChild(spinner)
spinner.physicsBody?.applyAngularImpulse(0.1) // wheeeeee
// Step 2: Make the arrow a child of the spinner
let arrow = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 20, height: 50))
spinner.addChild(arrow)
// Step 3: Constrain the arrow's rotation...
let constraint = SKConstraint.zRotation(SKRange(constantValue: 0))
arrow.constraints = [constraint]
// Step 4: ...relative to the scene, instead of to its parent
constraint.referenceNode = scene
Here are two methods to create a ball with a physics body and an arrow:
Add an arrow as a child of a ball
Add both the ball and the arrow directly to the scene
Here's what will happen when you add the above to the SpriteKit simulation:
The arrow will rotate when the ball rotates
Both the arrow and the ball will move/rotate independently
If you want the arrow to rotate with the ball, choose Option 1. If you want the arrow to remain fixed, choose Option 2. If you choose Option 2, you will need to adjust the rotation of the arrow to ensure that it points upward. Here's an example of how to do that.
-(void)didMoveToView:(SKView *)view {
self.scaleMode = SKSceneScaleModeResizeFill;
/* Create an edge around the scene */
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:view.frame];
// Show outline of all physics bodies
self.view.showsPhysics = YES;
CGFloat radius = 16;
SKNode *balls = [SKNode node];
balls.name = #"balls";
[self addChild:balls];
// Create 5 balls with stationary arrows
for (int i = 0;i<5;i++) {
// Create a shape node with a circular physics body. If you are targeting iOS 8,
// you have other options to create circular node. You can also create an SKSpriteNode
// with a texture
SKShapeNode *ball = [SKShapeNode node];
// Create a CGPath that is centered
ball.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-radius,-radius,radius*2,radius*2)].CGPath;
ball.fillColor = [SKColor whiteColor];
ball.position = CGPointMake(100, 100+i*radius*2);
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:radius];
[balls addChild:ball];
// Create an arrow node
CGSize size = CGSizeMake(2, radius*2);
SKSpriteNode *arrow = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:size];
arrow.name = #"arrow";
arrow.position = CGPointZero;
[ball addChild:arrow];
// Apply angular impulse to the ball so it spins when it hits the floor
[ball.physicsBody applyAngularImpulse:-1];
}
}
- (void) didSimulatePhysics
{
SKNode *balls = [self childNodeWithName:#"balls"];
for (SKNode *ball in balls.children) {
SKNode *arrow = [ball childNodeWithName:#"arrow"];
arrow.zRotation = -ball.zRotation;
}
}
sprite.physicsBody.allowsRotation = NO;
The allowRotation property should control exactly what you are asking.

Is there a way to make gravity come from a different part of the screen using spriteKit

Is there any way to change the default behavior of the gravity with the spritekit framework? Normally gravity pulls things towards the bottom of the screen. Is there a way to make it so that gravity could pull in a different direction?
The default value for gravity in SpriteKit is
self.physicsWorld.gravity = CGVectorMake(0.0, -9.8); //dx = 0, dy = -9.8
Which is what makes any object fall down towards the bottom of the screen.
Similarly, to make an object go in different directions, you can explicitly set in the initWithSize method
self.physicsWorld.gravity = CGVectorMake(-9.8, 0.0); //Towards left
self.physicsWorld.gravity = CGVectorMake(9.8, 0.0); //Towards right
self.physicsWorld.gravity = CGVectorMake(0.0, 9.8); //Upwards
self.physicsWorld.gravity = CGVectorMake(9.8, 9.8); //Towards top-right corner
I hope you get the point by now.
NOTE: The default value is -9.8 as the natural force of gravity we experience in the real world is 9.8 m/sec/sec. You can vary this value to change the intensity of the gravity experienced by the nodes in the scene.
You also need to understand more about CGVector and the gravity property of SKPhysicsWorld.

Setting the position of my ball

I'm learning how to use SpriteKit.
Question:
As practice, I'm trying to make a mock of pong. I want the ball's initial position to be in the center, and for the life of me, I cannot set its position to be in the center. It always ends up in the bottom left hand corner of the screen and I have no clue why. I've set the scene's scale mode equal to SKSceneScaleModeAspectFill, and I've tried each of the following lines of code in separate trials in order to get set its position to the center, but it has always remained in that bottom left hand corner.
//Attempt #1
self.ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)); //find the middle of each axis and put them together in one coordinate
//Attempt #2
self.ball.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); //find the width and height of the screen, divide each by 2 and assign them to an (x,y) coordinate together
//Attempt #3
self.ball.position = CGPointMake(160, 284) //Half the width and half the height
//Attempt #4
self.ball.position = CGPointMake(320, 568) //The width and the height (I'm desperately guessing at this point)
//Attempt #5
self.ball.position = CGPointMake(0,0) //I figured I'd give it a go
This ball is an SKSpriteNode by the way I didn't make a Ball subclass of SKSpriteNode or anything. The strange thing about this, is I've been able to bring up other sprites on the screen such as paddles and scores exactly where I want them. It's just this ball that isn't cooperating. What am I doing wrong? How can I prevent this issue in the future?
If you want to make ball's initial position to centre, then write below code:
[self.ball setPosition:CGPointMake(self.size.width/2, self.size.height/2)];
I'm using above code in my code and it is giving me perfect result.
Let me know it is working or not?
Happy Coding!

Scale CCSprite from bottom right hand corner

So here's the gist of what I'm trying to do here.
I have an array of foreground sprites that I scroll forever as the player moves along. What I would like to do, is when the player starts passing a certain point on the Y axis, scale down those foreground sprites while still moving them.
I'd like to be able to scale the sprites from their bottom left hand corners when the player is going up, and I've got this working without any problems.
The real problem is that I'd also like to scale the sprites from their bottom right hand corners when the player is coming down. Now I thought that I could do this by setting each sprite's anchor point to 1,0 before scaling it, but that doesn't seem to work. The sprites still scale from their bottom left hand corners.
What am I missing here?
// do logic to identify the scale factor we want
for (CCSprite *sprite in foreground_sprites)
{
CGPoint old_anchor = sprite.anchorPoint;
[sprite setAnchorPoint:ccp(1,0)];
[sprite setScale:scale_factor];
[sprite setAnchorPoint:old_anchor];
}
Have you tried messing with this property?
ignoreAnchorPointForPosition(false);
I'm using cocos2d-x, there should be something similar to that
If I understand correctly, you want to scale from the bottom left while the player's Y position increases but scale using the bottom right while they are descending?
Well you can't just change the anchor point alone. The anchor point and position go hand in hand to position the sprite on the screen. So if you positioned the sprite on to the screen using an anchor point of (0,0) then if you want to switch it's anchor point to (1,0) while keeping it in the same location on the screen, you'll need to update the position.
CCSprite* sprite = ...;
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointZero;
...
sprite.anchorPoint = CGPointMake(1.0f, 0.0f);
sprite.position = CGPointMake(sprite.position.x + (sprite.contentSize.width * sprite.scaleX * sprite.anchorPoint.x),
sprite.position.y + (sprite.contentSize.height * sprite.scaleY * sprite.anchorPoint.y));
Hopefully I understood your problem correctly and was able to help.

Resources