View is rotating "Ugly" - ios

I'm creating a car driving game for iOS, but there's a problem:
I added these lines to my ViewController.m:
_carView.transform = CGAffineTransformMakeRotation(steeringTemp-45);
steeringTemp is a float variable wich is changed by the left and right steering buttons.
But when I run the app and press the steering button, the car is rotating in an ugly way. It seems like the center point is changing everytime and the car is rotating like a triangle. I tried to set the origin to the center of the _carView, which is an image view, but it didn't work.

First of all let me tell you that you should be using radians, and not degrees. You can use this macro:
#define DEGREES_TO_RADIANS(angle) (angle * M_PI / 180.0)
And wrap it around your values:
CGAffineTransformMakeRotation(DEGRESS_TO_RADIANS(steeringTemp-45));
Second usually transforms go wrong if you:
Are rotating with the wrong anchorPoint (usually happens with clock pointers)
Don't pay attention to the order of transforms
Anchor Point
You need to make sure that your anchor point to the place you wanted. The anchorPoint defaults to the center, but you can set it to any point you like in the layer that is backed by the view. The anchor point has relative coordinates, so it goes from 0 to 1. (0,0) is your left top corner and (1,1) is your bottom right corner.
You can set it like this:
_carView.layer.anchorPoint = CGPointMake(0, 0);
Transforms order is important
Additionally, be careful if you apply more transforms you should pay attention to the order of those transforms. The previous transforms will always affect the next transforms. A rotation followed by a translation is way different than a translation followed by a rotation.

Related

IOS - using SCNLookAtConstraint does not seem to work the way I expected

I am learning SceneKit and trying to get the tip of a cone to point at the another node (a capsule) that is bouncing. Regardless of using the .orient on the cone, as soon as the SCNLookAtConstraint call gets made it re-orients the cone to the standard upright position so that the cone tip point straight up along the Y axis again and rock left and right as opposed to pointing its tip to the moving capsule which is to the rightof the cone. I tried changing the .pivot of the cone as well but that just seems to change the anchor point of the pivot but does not change the orientation of the cone.I need something like a SCNLookAtConstraint that indicates what point of the cone looks at the capsule?
Thanks
the pivot property is the way to go. It allows you to change the anchor point, but also its orientation since its a transform.

SpriteKit and combining multiple drags for a single rotation

What I'm attempting to recreate is the draggable arrow that's used in the popular iOS game called "Fragger", complete with both adjusting the rotation AND the strength of the pull all at the same time based on a finger drag but using SpriteKit - I believe they did it in Cocos2D.
I'll start by saying that I've honestly spent many weeks relearning trigonometry (http://www.mathsisfun.com/ is a great resource) and combing through Ray Wenderlich's tutorials (http://www.raywenderlich.com/35866/trigonometry-for-game-programming-part-1) but I can't find a solution for executing a "collective" drag rotation AND strength on a SpriteKit object.
Yes, it's relatively easy to set an anchor point and rotate that object (I'm using an arrow) so that it's pointing at your finger and thanks to Ray, I've got a really smooth action utilizing the following:
float angleRadians = atan2f(firstFingerTouchY - _arrow.position.y, firstFingerTouchX - _arrow.position.x);
float angleDegrees = RADIANS_TO_DEGREES(angleRadians);
float rotateDegreesPerSecond = 180 / 0.5; // Would take 0.5 seconds to rotate 180 degrees, or half a circle
float degreesDiff = (angleCurrent - angleDegrees) * 1.0;
float rotateDuration = fabs(degreesDiff / rotateDegreesPerSecond);
however, that's only part of the equation ...
Again, the first drag is fine as the angle of rotation is derived from the fulcrum of the arrow (it's anchor point) and where ever my finger ends up. However, let's say due to the limit of the screen size I can't get the angle I desire in a single drag, so I lift up my finger and then place it back down to continue the drag? Well I can't use the above mentioned code because as soon as I place my finger down for the second time, the arrow's rotation jumps over to where my finger now starts - again ending the same way.
So I thought the solution would be to not use the anchor point of the arrow at all, but instead use the initial finger touchpoint (as the new anchor) and calculate the arrow's angle based on that touchpoint and where ever my finger moves to? That works in theory, however when you then try to factor in the "strength draw" aspect that's represented in "Fragger" (where pulling the finger closer or farther away from the arrow adjusts the strength of the grenade throw), then you're not moving your finger towards the arrow to weaken the pull, but instead towards where ever you initially touched - which is not only visually difficult but as a bonus creates a lot of rotational jerky-ness as you get your finger closer to the origin.
I've been working on it for about a month now (did I mention that I hate math) trying to create a homogenized method (SIN ... COS ... TAN ... I hate you all!) to do the following:
First pull will rotate the arrow based on the direction of the pull but NOT automatically point to your finger (initial angle)
The ability to lift my finger up, place it back down and drag to ADD TO or SUBTRACT FROM the current rotation of the arrow. (delta angle)
The drag of my finger towards or away from the anchor of the arrow (relative to the current angle of the arrow) will adjust the strength of the "pull" accordingly. For example, if the arrow is already pointing straight up, then continuing the drag straight up would increase the strength and down would decrease the strength respectively. (hypotenuse derived from arrow anchor point).
I also need to be able to use another finger (2 finger touch) to assist in the rotation/strength calculation, so that adds even more chaos into my cluster ...
If you've ever played the 'Fragger' game, you'll recognize the complexity of this single finger action which is also it's functional beauty. I can get pieces of it working - I can rotate it, I can adjust a color mask to indicate strength - but not all of it working together. Perhaps I'm going about it completely wrong, however every example I find online stops at simply rotating an object to point to your finger with every new touch drag ending with the same results.

Can SKPhysicsJoints be used in a scrolling SpriteKit game?

This seems to be a major oversight by Apple, but since SKPhysicsJoints have their anchor points set in Scene coordinates, this makes doing any kind of scrolling game impossible.
To simulate a camera in SpriteKit you create a WorldNode which contains all of the gameplay elements, and then pan that around the scene. Unfortunately, doing this causes the Scene coordinates of every object in the game to change on every frame as you pan the world around. In turn, this breaks the joint anchor points, and things go berserk.
There isn't even a way to change the joint's anchor point, so I don't even have a way of just updating the coordinate every frame. It would seem that using SKPhysicsJoint in a scrolling game is not an option.
Does anyone know of a way around this?
Ok, I think I figured out what was going on, and I was totally incorrect in my original assumption. The reason my anchor points looked incorrect is because the [convertPoint toNode] call was returning me Scene coordinates that were incorrect. After several hours I realized it was off by exactly half the screen dimensions. My Scene has an anchorPoint of (0.5, 0.5), but this screws up the conversion values. So, if I simply offset the point by width/2, height/2 it's correct:
GPoint pt = CGPointMake(anchorWorldX, anchorWorldY);
pt = [gGameScene convertPoint:pt fromNode:gGameWorld]; // convert to scene coords, but it's WRONG
pt.x += scene.size.width * scene.anchorPoint.x; // this properly adjusts the value to be correct
pt.y += scene.size.height * scene.anchorPoint.y;
SKPhysicsJointPin* pin =[SKPhysicsJointPin jointWithBodyA:hinge.physicsBody bodyB:door.physicsBody anchor:pt];

What's the relationship between scaleX and anchorPoint

I'm trying to flip a sprite horizontally i.e.
sprite.scaleX = -1;
What I notice is that the sprite is flipped around its bottom left corner. However since I don't want to mess up my positioning of the sprite (I'd like the sprite to stay in the original place), so I tried to set its anchor point to (1,0)
sprite.anchorPoint = ccp(1,0);
My reasoning is this:
Since the sprite should be flipped around the anchorPoint, if I set the anchorPoint to its bottom right corner then that corner will then become the 'left bottom' corner of the changed sprite; and I should be able to move the sprite using that new anchorPoint just as I do with a normal sprite of anchorPoint (0,0).
However apparently it's not working as I expected. What am I missing?
Edit
What I really want to do is to flip a sprite and then be able to control its position via the left bottom corner - well the left bottom corner of the sprite that I see. I don't think I fully understand how scaleX = -1 is applied relating to the anchorPoint. If somebody can explain to me the concepts behind these parameters then that will greatly help me.
I have to correct myself on making the assertion that setting anchorPoint doesn't help. In fact, setting anchorPoint to (1,0) is exactly the solution to the problem, only that somehow some bug prevented me from recognizing it in my test.

anchorpoint issues with CCUIViewWrapper

I am having some issues understanding and using anchorPoint. As I understand it, the default anchor is (.5,.5) which applies transforms about the center of objects. However, when I placed a UIButton into a CCUIViewWrapper, I noticed that scaling it would scale about the right side of the object (i.e. if I scaled from 0 to 1, it would grow from right to left).
I wasn't sure what to make of this, but with tinkering found that I had to adjust the anchor point to (0,0) in order to make scaling occur about the center of the object. Why would this happen?
Further more, while I expect that to make the anchor be the bottom left of the object because Cocos2d is bottom left oriented for (0,0), it did not and in fact aligned the top left with my wrapper's position value.
In the end, what worked to scale about the center was to make the anchor point (0,0) and position the wrapper using the top left of the object, almost as if it were using the UIView coordinates to place the object. I'm not certain if this behavior is something occurring strictly with wrapped UIViews in CCUIViewWrappers nor do I know if this is simply correct behavior and I'm completely misunderstanding it.
Can someone clarify and explain?
I've had a similar problem with the wrapper. One of the issue here is that the wrapper attaches the view to the root window instead of the director's OpenGL view, which means it wont respect whatever autorotation the OpenGL view is using. The code looks like it is trying compensate for the difference between UIView and Cocos2d coordinates but doesn't seem to do it properly when it comes to anchor points. I ended up just using UIView coordinates in the end but I did experiment with an alternate method for setting the anchor point by using:
uiItem.center = ccp((self.anchorPoint.x - 0.5f) * self.contentSize.width, (self.anchorPoint.y - 0.5f) * self.contentSize.height);
At the start of the updateUIViewTransform method in CCUIViewWrappers before setting the view's transform. This makes anchor points behave as expected, at least for views attached directly to a layer.
Instead of using:
uiItem.center = ccp((self.anchorPoint.x - 0.5f) * self.contentSize.width, (self.anchorPoint.y - 0.5f) * self.contentSize.height);
which set the anchor point to the bottom right, I used:
uiItem.center = ccp(-uiItem.bounds.size.height/2, uiItem.bounds.size.width/2);
which set it to the center.
The reason the x and y are flipped, I'm guessing it's because my item is rotated by 90.

Resources