I am using CALayers to make an analog clock. The real-time clock works perfect and all the hands are moving smoothly just like default clock app icon in iOS. However, when I try to move the clock hands by touch/dragging, the minute hand moves perfectly but the hour hand doesn't. I am trying to move the clock hands just as they move in a real gear-based clock. Any solutions on how to calculate the angle for hour hand with respect to the movement of minute hand both clockwise and counter-clockwise? Actually I want somewhat similar functionality to this app https://itunes.apple.com/us/app/bb-teaching-clock/id612261763?mt=8
Here is the code for minute hand rotation
float dx = touchPoint.x - minHand.position.x;
float dy = touchPoint.y - minHand.position.y;
deltaAngle = atan2f(dy,dx);
startTransform = minHand.transform;
float angleDifference;
float dx = pt.x - minHand.position.x;
float dy = pt.y - minHand.position.y;
float ang = atan2f(dy,dx);
angleDifference = deltaAngle - ang;
minHand.transform = CATransform3DRotate(startTransform, -angleDifference,0 ,0 ,1);
NSLog(#"angleDifference: %f", angleDifference);
CGFloat hourAngle = (1/12)*(angleDifference);
// hour hand should move in the same direction as minute hand but at a much slower rate
hourHand.transform = CATransform3DRotate (hourHand.transform, -hourAngle, 0, 0, 1);
Try making the following changes, where centerPoint is the center of the clock...
float dx = touchPoint.x - centerPoint.x;
float dy = touchPoint.y - centerPoint.y;
deltaAngle = atan2f(dy,dx);
startTransform = minHand.transform;
float angleDifference;
dx = minHand.position.x - centerPoint.x;
dy = minHand.position.y - centerPoint.y;
float ang = atan2f(dy,dx);
angleDifference = ang - deltaAngle;
Related
So I currently get the location of a touch by using
CGPoint location = [touch locationInView:self.view];
Now what I want to do is check the location on the next touch to see if the locations are close, say 25 points on x or y axis.
There are a few posts that show how to compare if two touches are equivalent but is there to calculate the distance between multiple points? Any info would be awesome.
To estimate the distance between two CGPoints, you can make use of simple Pythagorean formula:
CGFloat dX = (p2.x - p1.x);
CGFloat dY = (p2.y - p1.y);
CGFloat distance = sqrt((dX * dX) + (dY * dY));
I want to convert Yaw,Pitch and Roll values to CGPoint inorder to draw shapes .But the CGPoint consists of two float values don't know how to add yaw value to cgpoint.My code
float ratio = 125/25.0f;
CMQuaternion quat = self.motionManager.deviceMotion.attitude.quaternion;
CGFloat roll = radiansToDegrees(atan2(2*(quat.y*quat.w - quat.x*quat.z), 1 - 2*quat.y*quat.y - 2*quat.z*quat.z)) ;
CGFloat pitch = radiansToDegrees(atan2(2*(quat.x*quat.w + quat.y*quat.z), 1 - 2*quat.x*quat.x - 2*quat.z*quat.z));
CGFloat yaw = radiansToDegrees(2*(quat.x*quat.y + quat.w*quat.z));
CGPoint point=CGPointMake(roll*ratio,pitch*ratio);
Can anyone please provide me some information regarding this....
Thanks in Advance...
I am trying to pan and seek forwards and backwards in my AVPlayer. It is kind of working but the basic math of determining where the pan is translated to the length of the asset is wrong. Can any one offer assistance?
- (void) handlePanGesture:(UIPanGestureRecognizer*)pan{
CGPoint translate = [pan translationInView:self.view];
CGFloat xCoord = translate.x;
double diff = (xCoord);
//NSLog(#"%F",diff);
CMTime duration = self.avPlayer.currentItem.asset.duration;
float seconds = CMTimeGetSeconds(duration);
NSLog(#"duration: %.2f", seconds);
CGFloat gh = 0;
if (diff>=0) {
//If the difference is positive
NSLog(#"%f",diff);
gh = diff;
} else {
//If the difference is negative
NSLog(#"%f",diff*-1);
gh = diff*-1;
}
float minValue = 0;
float maxValue = 1024;
float value = gh;
double time = seconds * (value - minValue) / (maxValue - minValue);
[_avPlayer seekToTime:CMTimeMakeWithSeconds(time, 10) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
//[_avPlayer seekToTime:CMTimeMakeWithSeconds(seconds*(Float64)diff , 1024) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
You are not normalizing the touch location and the corresponding time values. Is there a 1:1 relationship between the two? That's not possible.
Take the minimum and maximum touch location values of the pan gesture and the minimum and maximum values of the asset's duration (obviously, from zero to the length of the video), and then apply the following formula to translate the touch location to the seek time:
// Map
#define map(x, in_min, in_max, out_min, out_max) ((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
Here's the code I wrote that uses that formula:
- (IBAction)handlePanGesture:(UIPanGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateChanged){
CGPoint location = [sender locationInView:self];
float nlx = ((location.x / ((CGRectGetMidX(self.frame) / (self.frame.size.width / 2.0)))) / (self.frame.size.width / 2.0)) - 1.0;
//float nly = ((location.y / ((CGRectGetMidY(self.view.frame) / (self.view.frame.size.width / 2.0)))) / (self.view.frame.size.width / 2.0)) - 1.0;
nlx = nlx * 2.0;
[self.delegate setRate:nlx];
}
}
I culled the label that displays the rate, and the Play icon that appears while you're scrubbing, and which changes sizes depending on how fast or slow you are panning the video. Although you didn't ask for that, if you want it, just ask.
Oh, the "times-two" factor is intended to add an acceleration curve to the pan gesture value sent to the delegate's setRate method. You can use any formula for that, even an actual curve, like pow(nlx, 2.0) or whatever...
If you want to make it more precise and useful you should implement different "levels of sensitivity".
Apple does that with their slider: if you drag away from the slider and then to the sides, that pace at which the video moves changes. The farther your are from the slider the more precise it gets/the less you can reach.
So this is my first practice game I'm developing and first time using accelerometer so apologizes in advance if the answer is obvious. Would also like answered with code and explanation.
So part of game I have a ball being rolled around no the screen. The ball moves according to the tilt. The device orientation for this app is only landscape right. When I tilt the phone up and down while holding the phone landscape right the ball moves accordingly. (tilt the top end down the ball rolls up, tilt the bottom end down the ball rolls down). So those 2 tilts are fine. Now when I tilt the screen left side down the ball rolls right and vice versa. What I want is the screen to tilt left and the ball to go left and tilt the screen right and the ball goes right. How is this fixed with my code below. I know its as simple as changing two lines probably.
//delegate method
-(void)outputAccelertionData:(CMAcceleration)acceleration
{
currentMaxAccelX = 0;
currentMaxAccelY = 0;
if(fabs(acceleration.x) > fabs(currentMaxAccelX))
{
// this needs to be currentMaxAccelY not currentMaxAccelX for those of you thinking this is the solution
currentMaxAccelY = acceleration.x;
}
if(fabs(acceleration.y) > fabs(currentMaxAccelY))
{
// this needs to be currentMaxAccelX not currentMaxAccelY for those of you thinking this is the solution
currentMaxAccelX = acceleration.y;
}
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
float maxY = 480;
float minY = 0;
float maxX = 320;
float minX = 0;
float newY = 0;
float newX = 0;
//Im pretty sure the problem is in this if statement as this is what deals with the left and right tilt
if(currentMaxAccelX > 0.05){
newX = currentMaxAccelX * 10;
}
else if(currentMaxAccelX < -0.05){
newX = currentMaxAccelX*10;
}
else{
newX = currentMaxAccelX*10;
}
newY = currentMaxAccelY *10;
newX = MIN(MAX(newX+self.ball.position.x,minY),maxY);
newY = MIN(MAX(newY+self.ball.position.y,minX),maxX);
self.ball.position = CGPointMake(newX, newY);
}
So I solved the problem. The issue was with my math. Instead of multiplying by 10 I should have been multiplying by negative 10 to get in the inverse effect.
if(currentMaxAccelX > 0.05){
newX = currentMaxAccelX * -10;
}
else if(currentMaxAccelX < -0.05){
newX = currentMaxAccelX*-10;
}
else{
newX = currentMaxAccelX*-10;
}
I am working on the basis of Ray Wenderlich's tutorial on rotating turrets in Cocos 2d (see here: http://www.raywenderlich.com/25791/rotating-turrets-how-to-make-a-simple-iphone-game-with-cocos2d-2-x-part-2). I need my game to be in portrait mode so I have managed to get the position of the turret correctly:
The turret manages to shoot right, but not left. Here is my code:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (_nextProjectile != nil) return;
// Choose one of the touches to work with
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace:touch];
// Set up initial location of projectile
CGSize winSize = [[CCDirector sharedDirector] winSize];
_nextProjectile = [[CCSprite spriteWithFile:#"projectile2.png"] retain];
_nextProjectile.position = ccp(160, 20);
// Determine offset of location to projectile
CGPoint offset = ccpSub(location, _nextProjectile.position);
// Bail out if you are shooting down or backwards
if (offset.x <= 0) return;
// Determine where you wish to shoot the projectile to
int realX = winSize.width + (_nextProjectile.contentSize.width/2);
float ratio = (float) offset.y / (float) offset.x;
int realY = (realX * ratio) + _nextProjectile.position.y;
CGPoint realDest = ccp(realX, realY);
// Determine the length of how far you're shooting
int offRealX = realX - _nextProjectile.position.x;
int offRealY = realY - _nextProjectile.position.y;
float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
// Determine angle to face
float angleRadians = atanf((float)offRealY / (float)offRealX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
float rotateDegreesPerSecond = 180 / 0.5; // Would take 0.5 seconds to rotate 180 degrees, or half a circle
float degreesDiff = _player.rotation - cocosAngle;
float rotateDuration = fabs(degreesDiff / rotateDegreesPerSecond);
[_player runAction:
[CCSequence actions:
[CCRotateTo actionWithDuration:rotateDuration angle:cocosAngle],
[CCCallBlock actionWithBlock:^{
// OK to add now - rotation is finished!
[self addChild:_nextProjectile];
[_projectiles addObject:_nextProjectile];
// Release
[_nextProjectile release];
_nextProjectile = nil;
}],
nil]];
// Move projectile to actual endpoint
[_nextProjectile runAction:
[CCSequence actions:
[CCMoveTo actionWithDuration:realMoveDuration position:realDest],
[CCCallBlockN actionWithBlock:^(CCNode *node) {
[_projectiles removeObject:node];
[node removeFromParentAndCleanup:YES];
}],
nil]];
_nextProjectile.tag = 2;
}
Thanks for the help!
You are checking x axis instead of Y
// Bail out if you are shooting down or backwards
if (offset.x <= 0) return
;
Did you actually set the application to run in portrait mode or have you just rotated the simulator and repositioned the turret?
If you didn't explicitly set the app to run in portrait your x and y coordinates will be swapped (x will run from the ios button to the top of the phone, not accross as you would expect).
If it is converted properly I have answered this question before :)
This issue here is that you've copy-pasted the math instead of editing it properly for your purposes. There are some assumptions made in Ray's code that rely on you shooting always to the right of the turret instead of up, down, or left.
Here's the math code you should be looking at:
// Determine offset of location to projectile
CGPoint offset = ccpSub(location, _nextProjectile.position);
// Bail out if you are shooting down or backwards
if (offset.x <= 0) return;
Note here that you will have an offset.x less than 0 if the tap location is to the left of the turret, so this is an assumption you took from Ray but did not revise. As gheesse said, for your purposes this should be set to offset.y as you don't want them shooting south of the projectile's original location. But this is only part of the problem here.
// Determine where you wish to shoot the projectile to
int realX = winSize.width + (_nextProjectile.contentSize.width/2);
Here's your other big issue. You did not revise Ray's math for determining where the projectile should go. In Ray's code, his projectile will always end up on a location that is off the screen to the right, so he uses the width of the screen and projectile's size to determine the real location he wants the projectile to go. This is causing your issue since you don't have the assumption that your projectile will always head right - yours will always go up (hint, code similar to this should be used for your realY)
float ratio = (float) offset.y / (float) offset.x;
int realY = (realX * ratio) + _nextProjectile.position.y;
Again, Ray makes assumptions in his math for his game and you haven't corrected it in this realY. Your code has the turret turning in ways that will effect the realX coordinate instead of the realY, which is the coordinate that Ray's always shoot right turret needed to effect.
You need to sit down and re-do the math.