I have a UIView that I want to rotate when I move my finger across the screen (like in a circle). I want the UIView to rotate so that it faces my touchpoint. I then want to shoot something from my UIView (like a bullet) in the direction that the UIView is facing. Any Ideas???
Glad I remember triginometry
-(void)degreesToRotateObjectWithPosition:(CGPoint)objPos andTouchPoint:(CGPoint)touchPoint{
float dX = touchPoint.x-objPos.x; // distance along X
float dY = touchPoint.y-objPos.y; // distance along Y
float radians = atan2(dY, dX); // tan = opp / adj
//Now we have to convert radians to degrees:
float degrees = radians*M_PI/360;
return degrees;
}
Once you have your nice method, just do this:
CGAffineTransform current = view.transform;
[view setTransform:CGAffineTransformRotate(current, [view degreesTorotateObjectWithPosition:view.frame.origin andTouchPoint:[touch locationInView:parentView]]
//Note: parentView = The view that your object to rotate is sitting in.
This is pretty much all the code that you'll need.The math is right, but I'm not sure about the setTransform stuff. I'm at school writing this in a browser. You should be able to figure it out from here.
Good luck,
Aurum Aquila
Related
I've been reading a book on the cocos2d framework for ios5 for a few days and have developed a small game that the book walks you through. To control the sprite in this game you use the accelerometer:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 0.4f;
float sensitivity = 6.0f;
float maxVelocity = 100;
// adjust velocity based on current accelerometer acceleration
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
// we must limit the maximum velocity of the player sprite, in both directions (positive & negative values)
if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
else if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
// Alternatively, the above if/else if block can be rewritten using fminf and fmaxf more neatly like so:
// playerVelocity.x = fmaxf(fminf(playerVelocity.x, maxVelocity), -maxVelocity);
}
Now I'm wondering if I can change this code to allow the sprite to still accelerate/decelerate along the x axis, but to use touch input rather than the accelerometer, and to go faster the longer the touch is held down for? So a touch to the right would move the sprite to that spot slowly, if the touch is released, it stops moving to that spot. The longer a touch is held down, the faster the sprite moves.
is there anything in the framework to allow me to implement a rotation mechanism that allows my sprite to rotate to the position that the touch was in, so it looks like its facing the point thats been touched?
Well, afaik theres no method that will determine the angle to the touch and then rotate the sprite accordingly, but if you have the x and y coordinates of the sprite and the touch you can calculate it yourself fairly easily.
CGPoint spriteCenter; // this should represent the center position of the sprite
CGPoint touchPoint; //location of touch
float distanceX = touchPoint.x - spriteCenter.x;
float distanceY = touchPoint.y - spriteCenter.y;
float angle = atan2f(distanceY,distanceX); // returns angle in radians
// do whatever you need to with the angle
Once you have the angle you can set the rotation of the sprite.
I am rotating main view with 360 degrees, and I have subviews added inside main view, everything works correctly, but with one issue.
What I want to do is when I rotate main view, inner views should not lost their frames/position. Right now, when I rotate main view with infinte repeat count and dynamically if I add subview inside main view, it goes into proper position, but it does not retain its frame.
For example, I am implementing orbit, and for that, I have used entire transparent view as orbit and orbit is rotated from center point to 360 degree infinite times, and User can add many planets as he wants onto orbit, so when planets added on orbit, planets do not retain its frame. Can you suggest any idea?
Thanks in advance.
Well it sounds like you need to add a rotating animation for every subview that you add in your main view. If the main view rotates clockwise your subviews will need to rotate around their center in a counter-clockwise direction.
I guess you're trying to keep the subviews' orientations while rotating.
If I were you, I'd use CAAnimation instead of using a view to rotate.
You may add the animation to every subview, try this:
CAKeyframeAnimation* animation;
animation = [CAKeyframeAnimation animation];
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL,imgview.layer.position.x,imgview.layer.position.y);
int p = [self getblank:tag];
float f = 2.0*M_PI - 2.0*M_PI *p/PHOTONUM;
float h = f + 2.0*M_PI *num/PHOTONUM;
float centery = self.view.center.y;
float centerx = self.view.center.x;
float tmpy = centery + RADIUS*cos(h);
float tmpx = centerx - RADIUS*sin(h);
imgview.center = CGPointMake(tmpx,tmpy);
CGPathAddArc(path,nil,self.view.center.x, self.view.center.y,RADIUS,f+ M_PI/2,f+ M_PI/2 + 2.0*M_PI *num/PHOTONUM,0);
animation.path = path;
CGPathRelease(path);
animation.duration = TIME;
animation.repeatCount = 1;
animation.calculationMode = #"paced";
return animation;
I assume you have a stored variable that represents the rotation of the "world", correct? If not, you should.
Then, for each image you add, also store a variable with it that represents its rotation to the world.
For example, if your world is rotated 180°, and you added a cup (which you want to appear right-side up when the world is upside-down) the cup's "offset" to the world rotation would be -180°.
Then, if the world is at 180° and you rotate your world by adding 90°, then the cup's new rotation value would be cup_rotate_offset + world_rotation, or 180°+270°, which is the same as saying 90°, and the top of the world would be facing left and the cup's top would be facing right.
You have to independently track the offset values for each added object.
Me again. I have a simple question. I have an UIImageView like the one shown below.
alt text http://img683.imageshack.us/img683/1999/volumen.png
That UIimageView is supposed to be the knob to control the volume of my iphone project. My question is, how to know the positions of bar on the UIImageView when it is rotated? Because the volume needs to be 0.5 when the little bar on the cercle is vertical.
I got a piece of code which is (in the touchMoved method):
float dx = locationT.x - imgVVolume.center.x;
float dy = locationT.y - imgVVolume.center.y;
CGFloat angleDif = 0.0f;
movedRotationAngle = atan2(dy,dx);
if (beganRotationAngle == 0.0) {
beganRotationAngle = movedRotationAngle;
initialTransform = imgVVolume.transform;
}
else {
angleDif = beganRotationAngle - movedRotationAngle;
CGAffineTransform newTrans = CGAffineTransformRotate(initialTransform, -angleDif);
imgVVolume.transform = newTrans;
}
Help please.
It depends on what input mechanism you want to use to control the rotation.
If the knob is to rotate based on a single finger touch dragging from side to side then you can create a UIPanGestureRecognizer and attach it to the knob UIImageView. The translationInView: method returns a CGPoint which is the amount of X and Y movement from the touch-down point. You can feed that into a formula like the one you post to get an angle of rotation. You'll want to keep track of delta from last position and also check for stop limits (like 0..360) to prevent over-rotation.
OTOH, if you're going to use two finger rotation then you'll want to use a UIRotationGestureRecognizer and look for the rotation value. Just feed that into a CGAffineTransformRotate and set it to the UIImageView transform. That takes care of all of the above for you. Again, you'll want to check for stop limits.
I'm developing a line drawing game, similar to Flight Control, Harbor Master, and others in the appstore, using Cocos2D.
For this game, I need a CCSprite to follow a line that the user has drawn. I'm storing a sequence of CGPoint structs in an NSArray, based on the points I get in the touchesBegin and touchesMoved messages. I now have the problem of how to make my sprite follow them.
I have a tick method, that is called at the framerate speed. In that tick method, based on the speed and current position of the sprite, I need to calculate its next position. Is there any standard way to achieve this?
My current approach is calculate the line between the last "reference point" and the next one, and calculate the next point in that line. The problem I have is when the sprite "turns" (moves from one segment of the line to another).
Any hint will be greatly appreciated.
Why do you code your own tick method? Why don't you just use the built-in CCMoveTo method?
(void) gotoNextWayPoint {
// You would need to code these functions:
CGPoint point1 = [self popCurrentWayPoint];
CGPoint point2 = [self getCurrentWayPoint];
// Calculate distance from last way point to next way point
CGFloat dx = point2.x - point1.x;
CGFloat dy = point2.y - point1.y;
float distance = sqrt( dx*dx + dy*dy );
// Calculate angle of segment
float angle = atan2(dy, dx);
// Rotate sprite to angle of next segment
// You could also do this as part of the sequence (or CCSpawn actually) below
// gradually as it approaches the next way point, but you would need the
// angle of the line between the next and next next way point
[mySprite setRotation: angle];
CCTime segmentDuration = distance/speed;
// Animate this segment, and afterward, call this function again
CCAction *myAction = [CCSequence actions:
[CCMoveTo actionWithDuration: segmentDuration position: nextWayPoint],
[CCCallFunc actionWithTarget: self selector: #selector(gotoNextWayPoint)],
nil];
[mySprite runAction: myAction];
}
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.