How to make a node to rotate around a point outside of the node in a spritekit game project - ios

I came across this answer, but the answer is not clear to me. Can someone provide some sample code?
Create an SKNode and set its position to the center of rotation. Add the node that should rotate around that center as child to the center node. Set the child node's position to the desired offset (ie radius, say x + 100). Change the rotation property of the center node to make the child node(s) rotate around the center point.
Specifically, "Change the rotation property of the center node" to what?
var centerNode: SKSpriteNode = SKSpriteNode(imageNamed: "image1")
centerNode.position = CGPointMake(self.frame.width/2, self.frame.height/2)
self.addChild(centerNode)
var nodeRotateMe: SKSpriteNode = SKSpriteNode(imageNamged: "image2")
nodeRotateMe.position = CGPointMake(self.frame.width/2 + 100, self.frame.height/2 + 100)
centerNode.addChild(nodeRotateMe)
// Change the rotation property of the center node to what??
centerNode.zRotation = ?

You have a couple of options:
1) You could rotate the centerNode over time in your SKScene's update: method by changing its zRotation property manually. You'll have to change the value slowly, at every call to update: to achieve a gradual rotation.
Note that the zRotation property is in radians, with means a 180 degree rotation would be equal to pi (M_PI). SKScene strives to update: at 60 FPS, which means to rotate 360 degrees over 5 seconds, you'd need to increment by 1/300th of a degree every call to update, which would be 1/150th of pi every update.
centerNode.zRotation = centerNode.zRotation + CGFloat(1.0/150.0 * M_PI)
Of course, there is no guarantee that your scene will be able to update at 60 FPS, so you may have to monitor the currentTime variable in update: and adjust accordingly.
2) Probably better, you could use an SKAction to rotate the centerNode for you.
let rotateAction = SKAction.rotateByAngle(CGFloat(2 * M_PI), duration: 5.0)
centerNode.runAction(rotateAction)
Note that the rotation angle is in radians, not degrees. Also note that the centerNode need not be a Sprite Node if you don't want to display an image there; it could be a regular SKNode.

Related

Rotate Sprite on touch swift 3 IOS

I am trying to replicate the flappy bird game as a practise.
When playing flappy bird when you touched the screen the bird tilted upwards slightly (and went up) then when you released he would kind of rotate downwards and drop.
I have all the physics set up I just need to know how to rotate the bird up (whilst keeping the flappy wing animation) and then rotate him to face down again when you let go.
Easy I'm sure?...
In update frames method put
-Swift 3-
let value = Bird.physicsBody!.velocity.dy * ( Bird.physicsBody!.velocity.dy < 0 ? 0.005 : 0.001 )
Bird.zRotation = min( max(-0.5 //determines how much rotation when falling down, value), 1 //determines how much when jumping up )
bird will rotate whenever impulse is applied
Without knowing SpriteKit I would consider rotating your coordinate system as in the second answer to this question. #ToddFincannon proposes to save the graphics state, translate/rotate your coordinate system (most probably to the center of your sprite), draw and restore. Roughly copying his answer that will translate into
let c = UIGraphicsGetCurrentContext()!
c.saveGState()
c.translateBy(x: sprite.midX, y: midY)
c.rotate(by: angle * .pi / 180)
// Draw your sprite at 0, 0 (it is already translated)
c.restoreGState()
In order to be rotated upwards you will likely need a negative angle.

Keeping Direction of a Vector Constant while Rotating Sprite

I'm trying to make a game where the sprite will always move to the right when hit by an object. However since the Sprite rotates constantly and the zero radians rotates with the Sprite causes my calculated magnitude to go the opposite direction if the sprite is facing left and hits the object. Is there a way to keep the direction of the magnitude always pointing to the right even if the zero is facing left?
// referencePoint = upper right corner of the frame
let rightTriangleFinalPoint:CGPoint = CGPoint(x: referencePoint.x, y: theSprite.position.y)
let theSpriteToReferenceDistance = distanceBetweenCGPoints(theSprite.position, b: referencePoint)
let theSpriteToFinalPointDistance = distanceBetweenCGPoints(theSprite.position, b: rightTriangleFinalPoint)
let arcCosineValue = theSpriteToFinalPointDistance / theSpriteToReferenceDistance
let angle = Double(acos(arcCosineValue))
let xMagnitude = magnitude * cos(angle)
let yMagnitude = (magnitude * sin(angle)) / 1.5
Not sure if this works for you:
I would use an orientation constraint to rotate the sprite. The movement can be done independent from the orientation in that case.
I made an tutorial some time ago: http://stefansdevplayground.blogspot.de/2014/09/howto-implement-targeting-or-follow.html
So I figured out what was going on.
It seems like the angle doesn't rotate with the Sprite like I originally thought and the vector that I am making is working with the code above. THE problem that I had was that I also set the collision bit for the objects which is wrong. If I only set the contact bit for the objects against the sprite the my desired outcome comes true.

Firing a "shot" in SpriteKit

I need to fire a "shot" from a static SKSpriteNode towards another dynamic node. I've created a shot as a sprite node as the shot and moved it to by SKAction to the main sprite node, like so:
let node = info["node"] as SKSpriteNode // The static node
let shot = SKSpriteNode(color: UIColor.blueColor(), size: CGSize(width:node.frame.width / 3, height: node.frame.height / 1.2))
shot.physicsBody = SKPhysicsBody(edgeLoopFromRect: shot.frame)
shot.position = node.position
shot.physicsBody?.categoryBitMask = shotMask
shot.physicsBody?.contactTestBitMask = spriteMask
shot.physicsBody?.collisionBitMask = 0
shot.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(shot)
shot.runAction(SKAction.moveTo(sprite.position, duration: 1.0))
My problem is that the shot stops after it reaches the point. Is there a way to make the shot continue moving in it's direction, or is there another way of doing what I need? Thanks!
Don't use a SKAction to move the shot. Instead change the shot's position by directly modifying it's position.
shot.position = CGPointMake(shot.position.x+1, shot.position.y);
Run the above in your update method. To speed up the shot, change the +1 to whatever value you need. Obviously you will need to remove the shot node from parent once it leaves the screen, hits the target, etc...
You'll need to calculate the vector from the shot's origin to it's destination. Then extend the vector until the shot will be off screen, possibly by finding the unit vector (a vector of length 1) and multiplying it by 3000 or so. As you have a definite endpoint now, you could still use an SKAction.

Swift Spritekit dissipating Gravity field

I have a game in swift using spritekit. If you tap the screen it will create a radial gravity field and pull all the other objects in. I create the gravity field like so
var fieldNode = SKFieldNode.radialGravityField();
fieldNode.falloff = 0.5;
fieldNode.strength = 1;
fieldNode.animationSpeed = 0.5;
It works but my problem is that I only want a sprite to be affected only when it is when it within a certain distance to the centre of the radial gravity, and i will have more than 1 sprite. The way I see it is that there are 2 ways to do it, 1. When a sprite is too far turn off the radial gravity for that sprite or 2. Make the radial gravity dissipate after a certain radius. There is also an overall gravity for the scene.
So the main question is:
How can I either turn off 1 gravity for a sprite OR make a radial gravity dissipate ?
A field node's region property determines its area of effect. The associated SKRegion object lets you define a circular region by its radius.
You can also use the fieldBitMask on a physics body and the categoryBitMask on a field to selectively control which fields affect which bodies.
Try using:
let radius: CGFloat = 1000.0
gravityField.strength = Float(pow(radius, 2)) * pow(10, -3)

Rotating a Cocos2d sprite to match a joystick

I'm using a SneakyJoystick in Cocos2d, and I'm trying to get a sprite to rotate to face the same direction as the joystick is pointed (this is top down).
I can get it to rotate to face it, but it snaps into position as the rotation is updated every frame or so.
How can I make the sprite rotate smoothly towards the target angle, without jumping to it? I wasn't able to figure out how to do this with a CCRotateTo because the angle to rotate towards could change at any time.
I ended up fixing this simply by using a rotation method that I made, which rotates the node/sprite in the correct direction at the correct amount each update.
- (void)rotateNode:(CCNode*)aNode degrees:(float)targetRotation withSpeed:(float)rotationSpeed withTimeDelta:(ccTime)dt
{
rotationSpeed = rotationSpeed * dt;
// Convert the difference between the two angles to radians
float diff = (targetRotation - aNode.rotation) * (M_PI / 180);
// Find the rotation of the vector created by the sin and cos of the difference
float rotationDifference = atan2f(sinf(diff),cosf(diff));
// Rotate the clip accordingly
aNode.rotation += MAX(
MIN(
(180/M_PI) * rotationDifference,rotationSpeed), -rotationSpeed
);
}
Have you tried:
[CCRotateBy actionWithDuration:0.5f angle:CC_DEGREES_TO_RADIANS(90.0f)];
Obtain the Angle between the last Update the current Update, also if you wanted it so the character had a set time to turn around, you can scale your duration by the amount of the angle.

Resources