Move CCSprite based on users touch - Cocos2d - ios

I have an object that I wish to move 50 pixels in the direction the the touch event occurs. It is a fixed CCSprite called _eyeObject.
I know I need to use
- (void)touchBegan:(UITouch *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [touches locationInNode:self];
//Not sure what to do now
}
How would I calculate the CCSprite to move 50 pixels towards the users touch? Then move back to the original position when the touch ends?
A starting point would be great....I don't need to know how to animate or anything, just the calculation.

Whenever a touch happens you want to move 50 pixels in that direction you can do (based on your desire to do it based on a statically positioned eye object sprite):
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPos = [touch locationInNode:self];
CGPoint delta = ccpSub(touchPos, self.eyeObject.position);
float moveAmount = 50.0f;
CGPoint moveVec;
if (delta.x > 0.0f)
{
moveVec.x = moveAmount;
}
else
{
moveVec.x = -moveAmount;
}
if (delta.y > 0.0f)
{
moveVec.y = moveAmount;
}
else
{
moveVec.y = -moveAmount;
}
self.spriteStartPosition = self.sprite.position;
self.sprite.position = ccpAdd(self.sprite.position, moveVec);
}
- (void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
self.sprite.position = self.spriteStartPosition;
}
If the object you are moving IS that eyeObject then it would be:
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPos = [touch locationInNode:self];
CGPoint delta = ccpSub(touchPos, self.eyeObject.position);
float moveAmount = 50.0f;
CGPoint moveVec;
if (delta.x > 0.0f)
{
moveVec.x = moveAmount;
}
else
{
moveVec.x = -moveAmount;
}
if (delta.y > 0.0f)
{
moveVec.y = moveAmount;
}
else
{
moveVec.y = -moveAmount;
}
self.eyeObjStartPosition = self.eyeObject.position;
self.eyeObject.position = ccpAdd(self.eyeObject.position, moveVec);
}
- (void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
self.eyeObject.position = self.eyeObjStartPosition;
}
To move in general if the static object was representing a joystick or gamepad (would do the same in touch began so I'd separate this into its own method):
- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchPos = [touch locationInNode:self];
CGPoint delta = ccpSub(touchPos, self.dPad.position);
float moveAmount = 50.0f;
if (delta.x > 0.0f)
{
self.sprite.position.x += moveAmount;
}
else
{
self.sprite.position.x -= moveAmount;
}
if (delta.y > 0.0f)
{
self.sprite.position.y += moveAmount;
}
else
{
self.sprite.position.y -= moveAmount;
}
}

Here's a simple solution - get the unit vector between the two points, multiply it by 50, and add it to the current position. AKA this:
- (void)touchBegan:(UITouch *)touches withEvent:(UIEvent *)event {
CGPoint touchLocation = [touches locationInNode:self];
//Not sure what to do now
CGPoint destinationVector = ccpSub(touchPos, self.eyeObject.position);
CGPoint movementVector = ccpNormalize(destinationVector);
movementVector = ccpMult(movementVector, 50);
[_eyeObject runAction:[CCActionMoveTo actionWithDuration:1.0 position:ccpAdd(_eyeObject, movementVector)]];
}
If you want to have it move back on touchEnded, just save the position in a variable before you move it the first time, and send it back to that spot on touchEnded.

Related

Speed of touch varies with number of objects on Scene

I am creating game in which user can hit the object falling from the top of the screen with the racket. user can continuously move the racket but if it is at minimal speed or is at rest it should not hit the object, but if it above the minimal speed user should hit them. I have achieved that but the issue is when user start touching the racket which continously move with the user touch, the speed varition is their it does not start with the same speed and while touch is moving at that time also some times speed is very less even though the movement is fast. Here is my piece of code
-(void)didMoveToView:(SKView *)view {
self.physicsWorld.contactDelegate = (id)self;
racketNode = [SKSpriteNode spriteNodeWithImageNamed:#"racket"];
racketNode.size = CGSizeMake(50,50);
racketNode.position = CGPointMake(self.frame.origin.x + self.frame.size.width - 50,50);
racketNode.name = #"racket";
[self addChild:racketNode];
}
-(void) didBeginContact:(SKPhysicsContact *)contact {
SKSpriteNode *nodeA = (SKSpriteNode *)contact.bodyA.node ;
SKSpriteNode *nodeB = (SKSpriteNode *) contact.bodyB.node;
if (([nodeA.name isEqualToString:#"racket"] && [nodeB.name isEqualToString:#"fallingObject"])) {
if (racketNode.speed > kMinSpeed)
[nodeB removeFromParent];
else {
nodeB.physicsBody.contactTestBitMask = 0;
[self performSelector:#selector(providingCollsion:) withObject:nodeB afterDelay:0.1];
}
}
}
-(void) providingCollsion:(SKSpriteNode *) node {
node.physicsBody.contactTestBitMask = racketHit;
}
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
start = location;
startTime = touch.timestamp;
racketNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:racketNode.frame.size];
racketNode.physicsBody.categoryBitMask = racket;
racketNode.physicsBody.contactTestBitMask = HitIt;
racketNode.physicsBody.dynamic = NO;
racketNode.physicsBody.affectedByGravity = NO;
[racketNode runAction:[SKAction moveTo:location duration:0.01]];
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
racketNode.physicsBody = nil;
racketNode.speed = 0;
}
-(void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
CGFloat dx = location.x - start.x;
CGFloat dy = location.y - start.y;
CGFloat magnitude = sqrt(dx*dx+dy*dy);
// Determine time difference from start of the gesture
CGFloat dt = touch.timestamp - startTime;
// Determine gesture speed in points/sec
CGFloat speed = magnitude/dt;
racketNode.speed = speed;
[handNode runAction:[SKAction moveTo:[touch locationInNode:self] duration:0.01]];
}
Please tell me which part my code is wrong so as to make same object collide with high speed only not on slow speed and also no collision on stable state.
Instead of doing it manually, use UIPanGestureRecognizer to handle your swipes. With it, there is a velocity property that you can use to check if the speed is greater than a given value.
Here is a great tutorial to do it:
https://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial

Drag SKSpriteNode based on touch location

I am trying to drag a sprite in the y axis but make the sprite "stick" to the users finger depending on where the touches began on the node.
The sprite is currently dragging but it seems to be snapping the anchorpoint of the sprite to the touch location within the node.
Im assuming it has something to do with getting the location within the node by doing [touch locationInNode:selectedNode]; but I am unsure where to go from there.
Here is my current code.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
CGPoint newPosition = CGPointMake(node.position.x, location.y);
if ([node.name isEqualToString:self.selectedNode] ) {
if (newPosition.y > 230) {
newPosition.y = 230;
}
node.position = newPosition;
}
}
}
You need to offset the newPosition based on the current touch position on the node.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:self.selectedNode] )
{
CGPoint previousLocation = [touch previousLocationInNode:self];
float diff = location.y - previousLocation.y;
CGPoint newPosition = CGPointMake(node.position.x, node.position.y + diff);
if (newPosition.y > 230) {
newPosition.y = 230;
}
node.position = newPosition;
}
}
}
There are a couple of ways of doing this. The sample code below tracks the user's touch location and moves the sprite towards that position during the update method. You can modify the code to only move on the y axis or x axis.
#implementation MyScene
{
SKSpriteNode *object1;
CGPoint destinationLocation;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
[self createObject];
destinationLocation = CGPointMake(300, 150);
}
return self;
}
-(void)createObject
{
object1 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
object1.position = CGPointMake(300, 150);
[self addChild:object1];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
destinationLocation = [touch locationInNode:self.scene];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
destinationLocation = [touch locationInNode:self.scene];
}
-(void)update:(CFTimeInterval)currentTime
{
float x = fabs(object1.position.x - destinationLocation.x);
float y = fabs(object1.position.y - destinationLocation.y);
float divider = 0;
if(x > y)
{
divider = x;
} else
{
divider = y;
}
float xMove = (x/divider)*8; // change number to increase or decrease speed
float yMove = (y/divider)*8; // change number to increase or decrease speed
if(object1.position.x > destinationLocation.x)
object1.position = CGPointMake(object1.position.x-xMove, object1.position.y);
if(object1.position.x < destinationLocation.x)
object1.position = CGPointMake(object1.position.x+xMove, object1.position.y);
if(object1.position.y > destinationLocation.y)
object1.position = CGPointMake(object1.position.x, object1.position.y-yMove);
if(object1.position.y < destinationLocation.y)
object1.position = CGPointMake(object1.position.x, object1.position.y+yMove);
}
#end

how can I fix this turret so that it moves smoothly

Okay guys I have managed to make a sprite kit game where I have a turret that shoots candies but the problem I have is that the turret doesn't move smoothly as I point a location with my finger. It just jumps to point to the location.
so here is my code below:
- (void) rotateSprite:(SKSpriteNode *)sprite toFace:(CGPoint)velocity rotateRadiansPerSec:(CGFloat)rotateRadiansPerSec {
float targetAngle = CGPointToAngle(velocity);
float shortest = ScalarShortestAngleBetween(sprite.zRotation, targetAngle);
float amtToRotate = rotateRadiansPerSec * _dt;
if (ABS(shortest) < amtToRotate) {
amtToRotate = ABS(shortest);
}
sprite.zRotation += ScalarSign(shortest) * amtToRotate;
}
- (void) movePlayerToward:(CGPoint)location {
_lastTouchLocation = location;
CGPoint offset = CGPointSubtract(location, _Player.position);
CGPoint direction = CGPointNormalize(offset);
_velocity = CGPointMultiplyScalar(direction, PLAYER_MOVE_POINTS_PER_SEC);
}
- (void) update:(NSTimeInterval)currentTime {
if (_lastUpdateTime) {
_dt = currentTime - _lastUpdateTime;
}
else {
_dt = 0;
}
_lastUpdateTime = currentTime;
CGPoint offset = CGPointSubtract(_lastTouchLocation, _Player.position);
float distance = CGPointLength(offset);
if (distance < PLAYER_MOVE_POINTS_PER_SEC * _dt) {
_velocity = CGPointZero;
}
else
{
[self rotateSprite:_Player toFace:_velocity rotateRadiansPerSec:PLAYER_ROTATE_RADIANS_PER_SEC];
}
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
[self movePlayerToward:touchLocation];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
[self movePlayerToward:touchLocation];
}
I assume you are using the Zombie Conga code which uses static const to set fixed movement and rotation speed values.
In your code you have the line float amtToRotate = rotateRadiansPerSec * _dt;
Make sure you have the rotateRadiansPerSec value set properly as this controls the speed of your rotation.
In the Conga code, the value was:
static const float ZOMBIE_ROTATE_RADIANS_PER_SEC = 4 * M_PI;

Rotate imageView as per touch

I am rotating imageView which is minuit hand of a clock, with
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch view] == _imgViewMinuit)
{
NSLog(#"Touched");
_imgMinuitHand.transform = CGAffineTransformRotate(_imgMinuitHand.transform,DEGREES_RADIANS(6));
}
}
Now i want to rotate it as per my finger, clockwise/anticlockwise, with speed of my touch.
How I can achieve this ?
check this code
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch=[[event allTouches]anyObject];
[self transformSpinnerwithTouches:touch];
}
-(void)transformSpinnerwithTouches:(UITouch *)touchLocation
{
CGPoint touchLocationpoint = [touchLocation locationInView:self.view];
CGPoint PrevioustouchLocationpoint = [touchLocation previousLocationInView:self.view];
//origin is the respective piont from that i gonna measure the angle of the current position with respective to previous position ....
CGPoint origin;
origin.x = arrow.center.x;
origin.y = arrow.center.y;
CGPoint previousDifference = [self vectorFromPoint:origin toPoint:PrevioustouchLocationpoint];
CGAffineTransform newTransform = CGAffineTransformScale(arrow.transform, 1, 1);
CGFloat previousRotation = atan2(previousDifference.y, previousDifference.x);
CGPoint currentDifference = [self vectorFromPoint:origin toPoint:touchLocationpoint];
CGFloat currentRotation = atan2(currentDifference.y, currentDifference.x);
CGFloat newAngle = currentRotation- previousRotation;
temp1 = temp1 + newAngle;
//NSLog(#"temp1 is %f",temp1);
//NSLog(#"Angle:%F\n",(temp1*180)/M_PI);
newTransform = CGAffineTransformRotate(newTransform, newAngle);
[self animateView:arrow toPosition:newTransform];
}
-(void)animateView:(UIView *)theView toPosition:(CGAffineTransform) newTransform
{
arrow.transform = newTransform;
}
-(CGPoint)vectorFromPoint:(CGPoint)firstPoint toPoint:(CGPoint)secondPoint
{
CGFloat x = secondPoint.x - firstPoint.x;
CGFloat y = secondPoint.y - firstPoint.y;
CGPoint result = CGPointMake(x, y);
//NSLog(#"%f %f",x,y);
return result;
}

Detect diagonal swipe gestures in a UIView

I want to detect a two-finger diagonal swipe that starts from the bottom right of the screen to the middle. I tried adding UISwipeGestureRecognizer with direction set as "UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionLeft" but to no vail as the handler is getting invoked even if I start the swipe from the middle of the screen to the top left.
Do I need to sub-class UIGestureRecognizer or can I handle this using touchesBegan and touchesMoved ?
You need to subclass it to use touchesBegan and touchesMoved anyway. I'd do UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionLeft like you said, then set up two CGRects, one for acceptable starting points, one for acceptable end points. Then use the UIGestureRecognizerDelegate method gestureRecognizer:shouldReceiveTouch:, and check if the touch point is in the acceptable start rect by using CGRectContainsPoint(). Then (I think) in your UISwipeGestureRecognizer subclass, override touchesEnded:withEvent:, and check if the end touch is in the acceptable rect. If it's not, set the state to UIGestureRecognizerStateCancelled (or however you're supposed to cancel a gesture). Also make sure the view it's attached to has its multipleTouchEnabled property set. I haven't actually tried this, but something of the sort should do it. Good luck!
EDIT
Actually, if you didn't want to have to worry about specific rect values for the acceptable start/end points, and make it device independent, you could do this:
//swap in whatever percentage of the screen's width/height you want in place of ".75f"
//set the origin for acceptable start points
CGFloat startRect_x = self.view.frame.size.width * .75f;
CGFloat startRect_y = self.view.frame.size.height * .75f;
//set the size
CGFloat rectWidth = self.view.frame.size.width - startRect_x;
CGFloat rectHeight = self.view.frame.size.height - startRect_y;
//make the acceptable start point rect
CGRect startRect = CGRectMake(startRect_x, startRect_y, rectWidth, rectHeight);
//set the origin for the accepable end points
CGFloat endRect_x = self.view.center.x - rectWidth/2;
CGFloat endRect_y = self.view.center.y - rectHeight/2;
//make the acceptable end point rect
CGRect endRect = CGRectMake(endRect_x, endRect_y, rectWidth, rectHeight);
the touches method of cause can do every Gesture, the Gesture is supported since ios3.2.
i can give you a simple code , you maybe modify by yourself.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
isTwoFingersBegin = NO;
isTwoFingersEnd = NO;
UITouch *touch = [touches anyObject];
UIView *touchView = [touch view];
if ([touches count] == 2)
{
isTwoFingersBegin = YES;
}
touchStartPoint = [touch locationInView:self.view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
isSwip = YES;
}
#define TOUCH_MOVE_EFFECT_DIST 30
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
UIView *touchView = [touch view];
touchEndPoint = [touch locationInView:self.view];
if ([touches count] == 2)
{
isTwoFingersEnd = YES;
}
CGPoint deltaVector = CGPointMake(touchEndPoint.x - touchStartPoint.x, touchEndPoint.y - touchStartPoint.y);
if (fabsf(deltaVector.x) > TOUCH_MOVE_EFFECT_DIST
&&fabsf(deltaVector.y) > TOUCH_MOVE_EFFECT_DIST
&& isSwip &&isTwoFingersBegin&&isTwoFingersEnd) {
theSwipGesture=RightUpGesture;
}
else if (fabsf(deltaVector.x) <- TOUCH_MOVE_EFFECT_DIST
&& fabsf(deltaVector.y) <- TOUCH_MOVE_EFFECT_DIST
&& isSwip&&isTwoFingersBegin&&isTwoFingersEnd) {
theSwipGesture=LeftDownGesture;
}
isSwip = NO;
}
You can use a UIPanGestureRecognizer
- (void)viewPanned:(UIPanGestureRecognizer *)panGR
{
CGPoint translation = [panGR translationInView:self];
CGFloat threshold = self.bounds.size.width/2;
// Detect
Direction direction = DirectionUnknown;
if (translation.x > threshold) {
if (translation.y > threshold) {
direction = DirectionBottomRight;
} else if (translation.y < -threshold) {
direction = DirectionTopRight;
} else {
direction = DirectionRight;
}
} else if (translation.x < -threshold) {
if (translation.y > threshold) {
direction = DirectionBottomLeft;
} else if (translation.y < -threshold) {
direction = DirectionTopLeft;
} else {
direction = DirectionLeft;
}
} else {
if (translation.y > threshold) {
direction = DirectionBottom;
} else if (translation.y < -threshold) {
direction = DirectionTop;
}
}
}
One possible solution would be to map off a group of coordinates on the iPhone's screen where the swipe could potentially start, and another where it could potentially end. Then in the touchesBegan: and touchesMoved: methods, you could compare the starting and ending points of the swipe and determine whether it qualified as diagonal.
Thanks Guys!
I ended up writing custom code in touchesBegan, touchesMoved and touchesEnded and ot works like charm.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count] == 2) {
CGPoint nowPoint = [[touches anyObject] locationInView:self];
if( nowPoint.x >= ALLOWED_X)
swipeUp = YES;
}
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if ([touches count] == 2 && swipeUp) {
CGPoint nowPoint = [[touches anyObject] locationInView:self];
CGPoint prevPoint = [[touches anyObject] previousLocationInView:self];
if( nowPoint.x <= prevPoint.x && nowPoint.y <= prevPoint.y){
}
else {
swipeUp = NO;
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
CGPoint nowPoint = [[touches anyObject] locationInView:self];
if ([touches count] == 2 && swipeUp && nowPoint.x <= DELTA_X && nowPoint.y <= DELTA_Y) {
NSLog(#"Invoke Method");
}
swipeUp = NO;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
swipeUp = NO;
}

Resources