How to rotate something using spritekit relative to user touch coordinates - ios

I want to rotate a gun based on the user dragging their finger on the screen. I figure i will need my cartesian points in polar coordinates and that i will need a long press gesture which is both things that i have. I am just wondering how i would go about programming this? sorry i'm really new to sprite kit i have read all of apple's documentation and i'm having a hard time finding this. My anchor point is 0,0.
-(void)shootBullets:(UILongPressGestureRecognizer *) gestureRecognizer
{
double radius;
double angle;
SKSpriteNode *gun = [self newGun];
}
i figured out how to get the angle but now my zrotation wont work. Like i nslog and the angles are right but when i click gun.zrotation and i tap nothing happens? please help i'm getting uber mad.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
SKSpriteNode *gun = [self newGun];
self.gunRotation = atanf(location.y/location.x)/0.0174532925;
gun.zRotation = self.gunRotation;
NSLog(#"%f",gun.zRotation);
}

This is a very old question, but here is what I did - hopefully it will help someone out there:
#import "MyScene.h"
#define SK_DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) * 0.01745329252f) // PI / 180
Then add this:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint positionInScene = [touch locationInNode:self];
float deltaX = positionInScene.x - gun.position.x;
float deltaY = positionInScene.y - gun.position.y;
float angle = atan2f(deltaY, deltaX);
gun.zRotation = angle - SK_DEGREES_TO_RADIANS(90.0f);
}
}

Check out the answers I got to this question about how to implement a rotary knob, people have already figured out all the geometry, all you need to do is implement a transparent rotary knob, get its angle and pass it to your sprite kit object, using action rotate

Related

touch and move sprite doesn't track well

I'm building a game using Sprite Kit that needs quick precise movements following the user's touch. I need to detect if the user has touched on the "Player" in the view, and if they have, when they move, the player sprite needs to move with the touch accordingly.
I have this working now, however, it's not very precise... the more movement input (without lifting your finger), the more offset the sprite gets from the touch location.
Here's the code I'm using right now.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.isFingerOnPlayer) {
UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
CGPoint previousLocation = [touch previousLocationInNode:self];
// Calculate new position for player
int playerX = player.position.x + (touchLocation.x - previousLocation.x);
int playerY = player.position.y + (touchLocation.y - previousLocation.y);
// Limit x and y so that the player will not leave the screen any
playerX = MAX(playerX, player.size.width/2);
playerX = MIN(playerX, self.size.width - player.size.width/2);
playerY = MAX(playerY, (player.size.width/2)-3+inBoundsOffset);
playerY = MIN(playerY, (self.size.height - ((player.size.width/2)-3) - inBoundsOffset));
// Update position of player
player.position = CGPointMake(playerX, playerY);
}
}
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch* touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
SKPhysicsBody* body = [self.physicsWorld bodyAtPoint:touchLocation];
if (body && [body.node.name isEqualToString: #"player"]) {
NSLog(#"Began touch on player");
self.isFingerOnPlayer = YES;
}
}
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
self.isFingerOnPlayer = NO;
}
It detects the touch location, checks to make sure that you're touching the player sprite, if you are, then when you move, so does the sprite... but it can get off quite quickly if you're slinging your finger around (as playing this game will cause the player to do).
Can anybody suggest a more accurate way of accomplishing this, that will keep the sprite under the user's finger even when moving around a lot without lifting your finger?
You have to keep in mind that -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event ONLY gets called when the moving finger writes (sorry couldn't help the Inspector Clouseau reference).
In effect what happens is that the user can very quickly move his/her finger from one location to the next and as soon the the finger is lifted, your position updates stops.
What I suggest you do is create a CGPoint property and have -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event store the location in the CGPoint property.
Then in your -(void)update:(CFTimeInterval)currentTime you add the code that actually moves the player to the finger coordinates. This should make things a lot smoother.

SKAction moveTo goes up when should go down

I was following the SpriteKit tutorial here to create a simple sprite kit shooter, where you make a space ship that shoots lasers at asteroids.
I want to make the lasers (each laser is an SKSpriteNode) move to the point where I click. I am getting the touch correctly within the method touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event. However when I setup an SKAction on the SKSpriteNode, it moves in the y direction OPPOSITE of where I click. Ie image the window has width (x) 500 and height (y) 400. When I touch the screen at the coordinate (300, 100), the lazer appears to move to the coordinate (300, 300).
I've verified that the coordinates in touchLocation are correct.
FYI I have only used the iPhone simulator for this - but that shouldn't matter, should it?
Relevant code snippet:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
SKSpriteNode *shipLaser = [_shipLasers objectAtIndex:_nextShipLaser];
shipLaser.position = CGPointMake(_ship.position.x+shipLaser.size.width,_ship.position.y+0);
shipLaser.hidden = NO;
[shipLaser removeAllActions];
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
SKAction *laserMoveAction = [SKAction moveTo:touchLocation duration:0.5];
SKAction *laserDoneAction = [SKAction runBlock:(dispatch_block_t)^() {
shipLaser.hidden = YES;
}];
SKAction *moveLaserActionWithDone = [SKAction sequence:#[laserMoveAction,laserDoneAction]];
[shipLaser runAction:moveLaserActionWithDone withKey:#"laserFired"];
}
EDIT: I wonder if it might have to do with the fact that SprikeKit's coordinate system originates from the bottom left, while UIKit originates from the top left??
You want the touchLocation in the SKScene, not the UIView.
change :
CGPoint touchLocation = [touch locationInView:self.view];
to :
CGPoint touchLocation = [touch locationInNode:self];
The problem was that SprikeKit's coordinate system originates from the bottom left, unlike UIKit's coordinate system which originates in the top right. So the coordinates for the touch event were in the UIkit's coord system, and the SKNode was moving in SpriteKit's system. Once I understood this difference it was pretty easy to fix.

read x,y pixel touched ipad/iphone?

Is there anyway to detect which pixels you are touching while keeping your hand/finger on the screen (iphone/ipad)? Essentially drawing a shape of my hand (not as detailed like a fingerprint).
Thanks.
What you want to achieve is sadly not possible. The current devices can only detect up to 11 touches as points (more info in this post). There is no way to get the real touch area or the true touched pixels.
If you are looking for the coordinate point of touch use following code.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.view];
NSLog(#"%f,%f",currentTouchPosition.x,currentTouchPosition.y);
}

iPad app - touchesBegan double tapping not correct

I have a UIViewController that has a touchesBegan function and outputs the positions.
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"in");
NSArray *touchesArray = [touches allObjects];
for(int i=0; i<1; i++)
{
UITouch *touch = (UITouch *)[touchesArray objectAtIndex:i];
CGPoint point = [touch locationInView:touch.view];
NSLog(#"point = %f %f",point.x,point.y);
}
}
If I double tap quickly towards the middle of the screen, I get the following output
2012-02-12 21:47:13.522 MoreMost[479:707] in
2012-02-12 21:47:13.523 MoreMost[479:707] point = 698.000000 86.000000
2012-02-12 21:47:13.617 MoreMost[479:707] in
2012-02-12 21:47:13.619 MoreMost[479:707] point = 39.000000 22.000000
why is that second tap being registered as (39,22)...which is like the top left corner of the iPad. However, I was tapping in the middle.
So, I'd like to solve this in two ways:
1) somehow, not let the user double tap (however it seems even when I double tap fast, the touchesBegan function is called on two separate occassions)
2) figure out why that 2nd tap is being registered with the wrong coordinates.
It should be CGPoint point = [touch locationInView:self.view];...not "touch.view"

rotate an image with touch

I making an app which sets the sleep timer with a clock .Basically it is clock which has a single hand which user can move to set his sleep time .I tried to rotate the image with uitouch but it rotates from middle but i want it to rotate from the tip.Secondly i want that the image only rotates when user is touching the tip of the image but in my project the image is also rotating when use touches any part of the screen.Also i want to rotate the image in both directions but in my project it moves only clockwise due to this method
image.transform = CGAffineTransformRotate(image.transform, degreesToRadians(1));
Can anybody give me hints or solutions about how can it be done?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//
touch = [[event allTouches] anyObject];
touchLocation = [touch locationInView:touch.view];
NSLog(#"began");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// get touch event
[image.layer setAnchorPoint:CGPointMake(0.0,0.0)];
if ([touch view] == image) {
image.transform = CGAffineTransformRotate(image.transform, degreesToRadians(1));
//image.center = touchLocation;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"end");
}
In detail, you can custom a rotateView,then:
1: In the delegate method of "touchesBegan", get initialPoint of finger and initialAngle.
2: During "touchesMoved",get the newPoint of finger:
CGPoint newPoint = [[touches anyObject] locationInView:self];
[self pushTouchPoint:thePoint date:[NSDate date]];
double angleDif = [self angleForPoint:newPoint] - [self angleForPoint:initialPoint];
self.angle = initialAngle + angleDif;
[[imageView layer] setTransform:CATransform3DMakeRotation(angle, 0, 0, 1)];
3: At last, in "touchesEnded" you can calculate final AngularVelocity.
If anything being confused, for more detail, you can write back.
To rotate it the other way you just use:
image.transform = CGAffineTransformRotate(image.transform, degreesToRadians(1));
And to rotate form the tip you should use setAnchorPoint (like you used in your code, but i think you should do: [image setAnchorPoint]).
more on the subject: setAnchorPoint for UIImage?
I tried to rotate the image with uitouch but it rotates from middle but i want it to rotate from the tip
I dont know any way in SDK to rotate an element on its extreme end. If you want to have that effect take the clock handle image you have twice in length with half portion transparent. It is not a direct solution, but a workaround.
Also i want to rotate the image in both directions but in my project it moves only clockwise due to this method
As per iOS developer documentation, a positive angle value specifies counterclockwise rotation and a negative value specifies clockwise rotation.

Resources