Cocos2D Rotation and Anchor point - iphone

The problem that I have is that when ever I change the anchor point sprite automatically rotates with respect to the current anchor point. And I don't want that to happen.
The steps that I followed
create a sprite with anchor point (0.5, 0.5)
Changed the anchor point to (0,1)
Rotated the sprite to 90 degree. (Using CCRotateBy. Sprite rotated correctly)
Changed the anchor point to (0.5, 0.5) (Every thing is fine till now. And this is the position that I need to keep). Now sprite.rotation is 90.
I changed the anchor point to (1,0) (Sprite automatically rotates to 90 degree with respect to the given anchor point - I need to stop this behavior)
Is there any way to reset the rotation of sprite to 0, without actually rotating the texture(ie., to keep the texture in its current form - actual texture rotated to 90 degrees) and changing anchor point or position along with step 4, so that I can continue from point 5.

As Lukman says, the anchor point will always affect rotation, since your goal is to be able to specify the sprite position with a different anchor point from the rotation I would suggest making an empty CCNode as a parent of your sprite.
This way, you can set the position on sprite to be relative to this parent node to compensate for your anchor point change and then keep the anchor point for rotation on the sprite but use the parent node for position.

anchorPoint affects both position and rotation. You cannot stop it from affecting either one of them.
But from reading your question, since you want to prevent anchorPoint from affecting the rotation, I'm assuming here that the reason you change the anchorPoint is for the position, for example you are setting it to be ccp(1, 0) because you want to the sprite bottom right corner, instead of the sprite center, to be where you set the position is.
My suggestion is: don't change the anchorPoint at all, but change the way you set the sprite position. You can use this small function to adjust the position:
CGPoint adjustedPosition(const CGPoint position, const CGPoint anchor, const CGSize size) {
return CGPointMake(position.x - (anchor.x - 0.5) * size.width, position.y - (anchor.y - 0.5) * size.height);
}
Now, assuming you wanted to use anchorPoint of (1,0) when doing the positioning, instead of sprite.position = ccp(200, 300), you just need to do:
sprite.position = adjustedPosition(ccp(200, 300), ccp(1.0, 0.0), sprite.contentSize);
If you want, I'll post the logic behind the math later. Otherwise, I hope this will help.

Maybe it will help you to install an anchor for the sprites in the correct coordinate.
void SetAnchorPosition(CCSprite * sprite, const CCPoint & point)
{
static CCSize winSize = CCDirector::sharedDirector()->getWinSize();
double x = ((double)1/(double)winSize.width)*(double)point.x;
double y = ((double)1/(double)winSize.height)*(double)point.y;
sprite->setAnchorPoint(ccp(x,y));
sprite->setPosition(point);
}

You can add a line in the touchEnded method as a forceful alternative:
-(void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event{
_yourSprite.rotation = 90;
}

Related

bodyWithEdgeLoopFromRect doesn't match SKSpriteNode

I have in my scene playing board (for Tetris) - smaller then scene (750x510px). I need to frame it with bodyWithEdgeLoopFromRect. Here is a code :
SKSpriteNode *herniPlocha = [[SKSpriteNode alloc]initWithImageNamed:#"Plocha"];
herniPlocha.anchorPoint = CGPointMake(0, 0);
herniPlocha.position = CGPointMake(10, self.size.height-450);
herniPlocha.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:herniPlocha.frame];
[self addChild:herniPlocha];
but when I try to put block inside this board, the physicsBody doesn't match my board, it is about 40px moved to the right and up. Can you help me solve this problem, please?
Don't change the anchorPoint. The anchorPoint shifts the texture relative to the node's position and does nothing else. It certainly does not change where the physics shape is relative to the node.

Need help in understanding the positions of sprite in cocos2d?

I am new in cocos2d i have created a simple example
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *player = [CCSprite spriteWithFile:#"Player.jpg"
rect:CGRectMake(0, 0, 27, 40)];
player.position = ccp(player.contentSize.width/2, winSize.height/2);
[self addChild:player];
but I am not clear about the position of sprite how to manager it
Your code will create a sprite and position it within the parent node so that its lower-left corner is at ccp(player.contentSize.width/2, winSize.height/2).
If you wonder why your sprite is not centered respect to the coordinate you provide, the answer is that it is the lower-left corner which is positioned, not the sprite center.
You can tweak this behavior by defining the anchorPoint property of the sprite, like this:
player.anchorPoint = ccp(0.5,0.5);
player.position = ...
EDIT:
You can think of the anchor point as the "center of gravity" of the sprite: the texture is centered around it, any scaling or other kind of transformation will be relative to it.
If the anchor point is set at (0,0), then it coincides with the lower-left corner (default); if it is (0.5, 0.5) then it is exactly in the middle of the sprite (50% width, 50% height). Its coordinates are not point, but the relative displacement within the sprite; the coordinates can go from 0.0 to 1.0.

Anchor Point in CALayer

Looking at the Touches example from Apple's documentation, there is this method:
// scale and rotation transforms are applied relative to the layer's anchor point
// this method moves a gesture recognizer's view's anchor point between the user's fingers
- (void)adjustAnchorPointForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
UIView *piece = gestureRecognizer.view;
CGPoint locationInView = [gestureRecognizer locationInView:piece];
CGPoint locationInSuperview = [gestureRecognizer locationInView:piece.superview];
piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width, locationInView.y / piece.bounds.size.height);
piece.center = locationInSuperview;
}
}
First question, can someone explain the logic of setting the anchor point in the subview, and changing the center of the superview (like why this is done)?
Lastly, how does the math work for the anchorPoint statement? If you have a view that has a bounds of 500, 500, and say you touch at 100, 100 with one finger, 500, 500 with the other. In this box your normal anchor point is (250, 250). Now it's ???? (have no clue)
Thanks!
The center property of a view is a mere reflection of the position property of its backing layer. Surprisingly what this means is that the center need not be at the center of your view. Where position is situated within its bounds is based on the anchorPoint which takes in values anywhere between (0,0) and (1,1). Think of it as a normalized indicator of whether the position lies within its bounds. If you were to change either the anchorPoint or the position, the bounds will adjust itself rather than the position shifting w.r.t to its superlayer/superview. So to readjust position so that the frame of the view doesn't shift one can manipulate the center.
piece.layer.anchorPoint = CGPointMake(locationInView.x / piece.bounds.size.width, locationInView.y / piece.bounds.size.height);
Imagine the original thing being where O is the touch point,
+++++++++++
+ O + +++++++++++
+ X + --> + X +
+ + + +
+++++++++++ + +
+++++++++++
Now we want this X to be at the point where the user has touched. We do this because all scaling and rotations are done based on the position/anchorPoint. To adjust the frame back to its original position, we set the "center" of the view to the touch location.
piece.center = locationInSuperview;
So this reflects in the view readjusting its frame back,
+++++++++++
+++++++++++ + X +
+ X + --> + +
+ + + +
+ + +++++++++++
+++++++++++
Now when the user rotates or scales, it will happen as if the axis were at the touch point rather than the true center of the view.
In your example, the location of view might end up being the average i.e. (300, 300) which means the anchorPoint would be (0.6, 0.6) and in response the frame will move up. To readjust we move the center to the touch location will move the frame back down.
First question, can someone explain
the logic of setting the anchor point
in the subview, and changing the
center of the superview (like why this
is done)?
This code isn't changing the center of the superview. It's changing the center of the gesture recognizer's view to be the location of the gesture (coordinates specified in the superview's frame). That statement is simply moving the view around in its superview while following the location of the gesture. Setting center can be thought of as a shorthand way of setting frame.
As for the anchor point, it affects how scale and rotation transforms are applied to the layer. For example, a layer will rotate using that anchor point as its axis of rotation. When scaling, all points are offset around the anchor point, which doesn't move itself.
Lastly, how does the math work for the
anchorPoint statement? If you have a
view that has a bounds of 500, 500,
and say you touch at 100, 100 with one
finger, 500, 500 with the other. In
this box your normal anchor point is
(250, 250). Now it's ???? (have no
clue)
The key concept to note on the anchorPoint property is that the range of the values in the point is declared to be from [0, 1], no matter what that actual size of the layer is. So, if you have a view with bounds (500, 500) and you touch twice at (100, 100) and (500, 500), the location in the view of the gesture as a whole will be (300, 300), and the anchor point will be (300/500, 300/500) = (0.6, 0.6).

Check UIButton position after rotating UIView

I have a buttonsthat I add on a UIImageView. With a method when the user touch the screen
the UIImageView will rotate, I want to know if there is a way to get the new position of the button after the rotation is done.
Right now I'm getting all the time the original position with this method :
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Xposition : %f", myButton.frame.origin.x);
NSLog(#"Yposition : %f", myButton.frame.origin.y);
}
Thanks,
This is a tricky question. Referring to the UIView documentation on the frame property it states:
Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
So the trick is finding a workaround, and it depends on what exactly you need. If you just need an approximation, or if your rotation is always a multiple of 90 degrees, the CGRectApplyAffineTransform() function might work well enough. Pass it the (untransformed) frame of the UIButton of interest, along with the button's current transform and it will give you a transformed rect. Note that since a rect is defined as an origin, width and height, it can't define a rectangle with sides not parallel to the screen edges. In the case that it isn't parallel, it will return the smallest possible bounding rectangle for the rotated rect.
Now if you need to know the exact coordinates of one or all of the transformed points, I've written code to compute them before, but it's a bit more involved:
- (void)computeCornersOfTransformedView:(UIView*)transformedView relativeToView:(UIView*)parentView {
/* Computes the coordinates of each corner of transformedView in the coordinate system
* of parentView. Each is corner represented by an independent CGPoint. Doesn't do anything
* with the transformed points because this is, after all, just an example.
*/
// Cache the current transform, and restore the view to a normal position and size.
CGAffineTransform cachedTransform = transformedView.transform;
transformedView.transform = CGAffineTransformIdentity;
// Note each of the (untransformed) points of interest.
CGPoint topLeft = CGPointMake(0, 0);
CGPoint bottomLeft = CGPointMake(0, transformedView.frame.size.height);
CGPoint bottomRight = CGPointMake(transformedView.frame.size.width, transformedView.frame.size.height);
CGPoint topRight = CGPointMake(transformedView.frame.size.width, 0);
// Re-apply the transform.
transformedView.transform = cachedTransform;
// Use handy built-in UIView methods to convert the points.
topLeft = [transformedView convertPoint:topLeft toView:parentView];
bottomLeft = [transformedView convertPoint:bottomLeft toView:parentView];
bottomRight = [transformedView convertPoint:bottomRight toView:parentView];
topRight = [transformedView convertPoint:topRight toView:parentView];
// Do something with the newly acquired points.
}
Please forgive any minor errors in the code, I wrote it in the browser. Not the most helpful IDE...

How to rotate image around center point automatically with finger touch

On iPhone, how to implement rotating image around the center point using finger touch ?
Just like wheel, if you put finger on the iPhone screen , then move suddenly, then the image becoming rotating around center point just like the wheel, after a while, it becomes more and more slow , finally stop.
Who can help to give some pieces of codes (Object-C) or some suggest ?
I was working with a "spin the bottle"-app yesterday. On the window I have a ImageView with an bottle that's suppose to response to touches and rotate the way the user swipes his finger. I struggled to get my ImageView to rotate during the touch-events (TouchesBegan, Touchesoved, TouchesEnd). I used this code in TouchesMoved to find out the angle in witch to rotate the image.
public override void TouchesMoved (NSSet touches, UIEvent evt)
{
PointF pt = (touches.AnyObject as UITouch).LocationInView(this);
float x = pt.X - this.Center.X;
float y = pt.Y - this.Center.Y;
double ang = Math.Atan2(x,y);
// yada yada, rotate image using this.Transform
}
THIS IS IMPORTANT! When the ImageView rotates, even the x & y-coordinates changes. So touching the same area all the time would give me different values in the pt and prePt-points. After some thinking, googeling and reading I came up with an simple solution to the problem. The "SuperView"-property of the ImageView.
PointF pt = (touches.AnyObject as UITouch).LocationInView(this.SuperView);
Having that small change in place made it alot easier, no i can use the UITouch-metohs LocationInView and PreviousLocationInView and get the right x & y coordinates. Her is parts of my code.
float deltaAngle;
public override void TouchesMoved (NSSet touches, UIEvent evt)
{
PointF pt = (touches.AnyObject as UITouch).LocationInView(this.Superview);
float x = pt.X - this.Center.X;
float y = pt.Y - this.Center.Y;
float ang = float.Parse(Math.Atan2(dx,dy).ToString());
//do the rotation
if (deltaAngle == 0.0) {
deltaAngle = ang;
}
else
{
float angleDif = deltaAngle - ang;
this.Transform = CGAffineTransform.MakeRotation(angleDif);
}
}
Hope that helped someone from spending hours on how to figure out how to freaking rotate a bottle! :)
I would use the affine transformations - yuou can assign a transformation to any layer or UI element using the transform property.
You can create a rotation transform using CGAffineTransform CGAffineTransformMakeRotation( CGFloat angle) which will return a transformation that rotates an element. The default rotation should be around the centerpoint.
Be aware, the rotation is limited to 360 degrees, so if you want to rotate something more than that (say through 720 degrees) - you have to break the rotation into several sequences.
You may find this SO article useful as well.
The transform property of a view or layer can be used to rotate the image displayed within. As far as the spinning part goes, you just track the location and movement of touches in your view with touchesBegan, touchesMoved, and touchesEnded.
Use the distance and time between the touches updates to calculate a speed, and use that to set a rotational velocity. Once you start the image spinning, update the position periodically (with an NSTimer, maybe), and reduce the rotational velocity by some constant.