Keeping Direction of a Vector Constant while Rotating Sprite - ios

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.

Related

SceneKit - Rotate object around X and Z axis

I’m using ARKit with SceneKit. When user presses a button I create an anchor and to the SCNNode corresponding to it I add a 3D object (loaded from a .scn file in the project).
The 3D object is placed facing the camera, with the same orientation the camera has. I would like to make it look like the object is laying on a plane surface and not inclined if it is that way. So, if I got it right, I’d need to apply a rotation transformation so that it’s rotation around the X and Z axis become 0.
My attempt at this is: take the node’s x and z eulerAngles, invert them, and rotate that amount around each axis
let rotationZ = rotationMatrixAroundZ(radians: -node.eulerAngles.z)
let rotationX = rotationMatrixAroundX(radians: -node.eulerAngles.x)
let rotationTransform = simd_mul(rotationTransformX, rotationTransformZ)
node.transform = SCNMatrix4(simd_mul(simd_float4x4(node.transform), rotationTransform))
This works all right for most cases, but in some the object is rotated in completely strange ways. Should I be setting the
rotation angle to anything else than just the inverse of the current Euler Angle? Setting the angles to 0 directly did not work at all.
I've come across this and figured out I was running into gimbal lock. The solution was to rotate the node around one axis, parent it to another SCNNode(), then rotate the parent around the other axis. Hope that helps.
You don't have to do the node transform on a matrix, you can simply rotate around a specific axis and that might be a bit simpler in terms of the logic of doing the rotation.
You could do something like:
node.runAction(SCNAction.rotateBy(x: x, y: y, z: z, duration: 0.0))
Not sure if this is the kind of thing you're looking for, but it is simpler than doing the rotation with the SCNMatrix4
Well, I managed a workaround, but I'm not truly happy with it, so I'll leave the question unanswered. Basically I define a threshold of 2 degrees and keep applying those rotations until both Euler Angles around X and Z are below the aforementioned threshold.
func layDownNode(_ node: SCNNode) {
let maxErrDegrees: Float = 2.0
let maxErrRadians = GLKMathDegreesToRadians(maxErrDegrees)
while (abs(node.eulerAngles.x) > maxErrRadians || abs(node.eulerAngles.z) > maxErrRadians) {
let rotationZ = -node.eulerAngles.z
let rotationX = -node.eulerAngles.x
let rotationTransformZ = rotationMatrixAroundZ(radians: rotationZ)
let rotationTransformX = rotationMatrixAroundX(radians: rotationX)
let rotationTransform = simd_mul(rotationTransformX, rotationTransformZ)
node.transform = SCNMatrix4(simd_mul(simd_float4x4(node.transform), rotationTransform))
}
}

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.

rotate camera use lookat function with pan gesture

I try use lookat function rotate camera with pan gesture. I use swift and Metal(in this case Metal work the same with OpenGLES). Here is my code
The lookat function:
let kEye = V3f(0.0, 0.0, -2.0)
var ktarget = V3f(0.0, 0.0, 0.0)
let kUp = V3f(0.0, 1.0, 0.0)
var viewMatrix = lookAt(kEye, center: ktarget, up: kUp)
The pan gesture:
func pan(panGesture: UIPanGestureRecognizer){
if panGesture.state == UIGestureRecognizerState.Changed{
let pointInView = panGesture.locationInView(self.view)
let xDelta = (lastPanLocation.x - pointInView.x)/self.view.bounds.width * panSensivity
let yDelta = (lastPanLocation.y - pointInView.y)/self.view.bounds.height * panSensivity
lastPanLocation = pointInView
var viewDirection = rotationM3f(kUp, angle: Float(-xDelta)) * viewDirection
var toRotateAround = Cross(viewDirection, b: kUp)
viewDirection = rotationM3f(toRotateAround, angle: Float(-yDelta)) * viewDirection
ktarget = kEye + viewDirection
} else if panGesture.state == UIGestureRecognizerState.Began {
lastPanLocation = panGesture.locationInView(self.view)
}
}
At the beginning, it works fine, pan the camera after a while, the viewDirection and toRotateAround vector will become -0.0,-0.0,0.0, when finger move vertically but the camera does not look up and down, Anyone knows what is wrong in the code? Thanks~~~
You only modify the view direction (ktarget in the end) but forget about kUP. Once these 2 vectors become parallel the cross product is zero and everything breaks.
The solution you are looking for is recomputing the kUp vector by using a cross product of viewDirection and toRotateAround.
When using rotations like this you need to think of your data as base vectors and a position (location=kEye, forward=ktarget-keye, up=kUp, right=cross(forward, up)). The base vectors are always perpendicular to each other (I suggest them to be normalized as well) and when you rotate you always rotate one of these vectors around another base vectors and after the rotation you need to recompute the 3rd vector by using a cross product.
So to rotate left or right you would rotate the forward around up and then use a cross product between forward and up to get the right vector. (The right vector here is optional since you do not use it)
To rotate up or down you rotate forward vector around right vector and use a cross product between the forward and right to get the new top vector.
Then for tilting left or right you rotate up around forward and get the right vector with cross product of the 2 used vectors.
If you see the logic you will find out there are always 2 ways of rotating along one axis. For instance to rotate left or right you might as well rotate the right vector around up and find the new forward vector by using a cross product of right and up.
There is a trick though. The procedure described here works great for a free movement such as a flight simulation where you can "tilt". It is not appropriate for a movement such as for a first person shooter where up is always in the center of the screen horizontally (I hope you see the difference). To create this FPS way you actually do need to keep up as (0,1,0) but then forward must never be (0,1,0) but it can be (0.001, 0.09, 0) which is pretty close to looking directly upwards. So as long as you limit the upwards angle to some value you should be fine. There are other ways as well...

Character not moving in the correct direction in Scenekit

I am making a fist person camera in Scenekit and the character is not moving relative to the rotation. Instead it is moving relative to the world axis. I want my game to be so when the player swipes forward, the character moves forward on its own x axis. Not along the x axis of the world. I tried to compensate of this with sine and cosine but it did not work. Here is my code:
func lookGestureRecognized(gesture: UIPanGestureRecognizer) {
let velocity = gesture.velocityInView(sceneView)
let rotationAngle = heroNode.presentationNode().rotation.w * heroNode.presentationNode().rotation.y
var impulse = SCNVector3Make(Float(velocity.x)/50, 0, Float(velocity.y)/50)
impulse = SCNVector3(x: impulse.x * cos(rotationAngle), y: 0, z: impulse.z * sin(rotationAngle))
heroNode.physicsBody?.applyForce(impulse, impulse: true)
}
This is still making the character move in the wrong direction of the swipe. Does anyone know how to make the character move relative to its rotation?
Thanks, please ask for clarification if needed
the rotation property is made of a rotation axis and a rotation angle. If you want to retrieve the rotation along the x axis you can use the eulerAngles property.

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