Rotating a Cocos2d sprite to match a joystick - ios

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.

Related

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.

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

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.

Spritekit physics and camera smoothing

I've been struggling with this problem for a while, which appears to be buried deep inside the spritekit physics engine.
My first question would be: Does Spritekit process its physics updates in a different thread than the main thread?
I have a "world" node in the scene which I move around to simulate a "camera" view. As such, I can center the "camera" on my player character node. Since the player jumps up and down a lot, I want to smooth the camera. Without camera smoothing, there's no problems. But when I add camera smoothing, as such: (this code is called from didFinishUpdate)
CGPoint ptPosition = self.position;
float fSmoothY = m_fLastCameraY + (ptPosition.y - m_fLastCameraY) * 0.1;
CGPoint pointCamera = [self.scene convertPoint:CGPointMake(ptPosition.x, fSmoothY) fromNode:self.parent];
[gameScene centerOnPoint:pointCamera];
m_fLastCameraY = fSmoothY;
If I call the above code from didSimulatePhysics, it does the exact same thing. It stutters whenever it falls down (due to the Y camera smoothing).
When plotting it out, you can see that the player Y (the red line) is stuttering over the course of the frames.
How can I fix this, or work around it if it can't be truly "fixed"?
I suggest you apply an infinite impulse response (IIR) filter to smooth the camera. You can do that by...
First, declare the instance variables
CGFloat alpha;
CGFloat fSmoothY;
and then Initialize alpha and fSmoothY
// alpha should be in [0, 1], where a larger value = less smoothing
alpha = 0.5;
fSmoothY = ptPosition.y;
Lastly, apply the filter with
fSmoothY = fSmoothY * (1-alpha) + ptPosition.y * alpha;

Cocos2D Gravity?

I am really looking to try to have gravity in my game. I know everyone says use Box2D, but in my case I can't. I need to use Cocos2D for the gravity.
I know Cocos2D does not have any gravity API built in so I need to do something manually. The thing is there is like no tutorials or examples anywhere on the web that show this.
Can anyone show me what they have done or can some explain step by step on how to apply a non-constant gravity (One that gets slightly stronger while falling).
I think this will help a lot of people that are facing the same issue that I am having!
Thanks!
Gravity is nothing but a constant velocity applied to the body for every physics step. Have a look at this exemplary update method:
-(void) update:(ccTime)delta
{
// use a gravity velocity that "feels good" for your app
const CGPoint gravity = CGPointMake(0, -0.2);
// update sprite position after applying downward gravity velocity
CGPoint pos = sprite.position;
pos.y += gravity.y;
sprite.position = pos;
}
Every frame the sprite y position will be decreased. That's the simple approach. For a more realistic effect you will want to have a velocity vector for each moving object, and apply gravity to the velocity (which is also a CGPoint).
-(void) update:(ccTime)delta
{
// use a gravity velocity that "feels good" for your app
const CGPoint gravity = CGPointMake(0, -0.2);
// update velocity with gravitational influence
velocity.y += gravity.y;
// update sprite position with velocity
CGPoint pos = sprite.position;
pos.y += velocity.y;
sprite.position = pos;
}
This has the effect that velocity, over time, increases in the downward y direction. This will have the object accelerate faster and faster downwards, the longer it is "falling".
Yet by modifying velocity you can still change the general direction of the object. For instance to make the character jump you could set velocity.y = 2.0 and it would move upwards and come back down again due to the effect of gravity applied over time.
This is still a simplified approach but very common in games that don't use a "real" physics engine.

XNA - controlling an object with keyboard input

Ok so I have a ship which moves up and down based on the axis regardless of where the ship is facing.
How do I make the ship move in the direction it's facing? i.e. if my ship is facing east, key up makes it go north rather than east.
Your question isn't very clear - I will assume you're using models and matrices (as opposed to SpriteBatch or something else). So, making a guess - I'd say that the order of your matrix operations is incorrect.
This answer to a similar question may help.
Each matrix operation happens around the origin. So if you're doing your rotation after you move your ship into position, your rotation will also effectively "rotate" the direction of movement.
The easiest way is to make an angle and velocity variable so when you click left and right you change the angle and when you click up and down you changle the speed of your ship.
KeyboardState ks;
float speed = 0;
float angle = 0;
protected override void Update(GameTime gameTime)
{
ks = Keyboard.GetState();
if(ks.IsKeyDown(Keys.Up)) speed += 10;
if (ks.IsKeyDown(Keys.Down)) speed -= 10;
if (ks.IsKeyDown(Keys.Right)) angle += 10;
if (ks.IsKeyDown(Keys.Left)) angle -= 10;
}
You need to have direction vector like this
Vector3 direction = Vector3.Transform(Vector3.Forward, Matrix.CreateFromYawPitchRoll(yaw, pitch, roll));
Next, get your velocity vector
Vector3 velocity = direction * speed;
And move your ship
float time (float) = gameTime.ElapsedTime.TotalSeconds;
position += velocity * time;
In this example yaw is angle, pitch and roll keep 0.

Resources