I am using Sprite Kit in Xcode and having problem with position.
I want to drag the node and drop to target area.If not the right target than send the node back to old position.
My code is working but when I touch node (except the center of node) anywhere will be holding center point of old position.So if target is wrong the node going back as little moved because of touched point was different than center of node.
Therefore If I can get center position of touched node than I can send back with absolute position!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self selectNodeForTouch:positionInScene];}
Than
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGPoint previousPosition = [touch previousLocationInNode:self];
CGPoint translation = CGPointMake(positionInScene.x - previousPosition.x, positionInScene.y - previousPosition.y);
[self panForTranslation:translation];
}
//
-(void)selectNodeForTouch:(CGPoint)touchLocation{
SKSpriteNode *touchedNode = (SKSpriteNode *)[self nodeAtPoint: touchLocation];
if (![_selectedNode isEqual:touchedNode.name]) {
_selectedNode =touchedNode;
if ((newPositionStone.x-28)<5 || (newPositionStone.x-28)>(5*(-1))){
NSLog(#"Great! you drop node to target ");
}
else{
NSLog(#"Didn't drop node to target");//Send back to old position
_selectedNode.position = oldPositionStone;
}
}}
Thanks in advance!
You need to store the object's position at the moment of touch so you can revert back to it if your drag destination fails.
Create a CGPoint variable in your #implementation like so:
#implementation MyScene
{
CGPoint objectStartPosition;
}
In the touchesBegan: set the object's current position:
objectStartPosition = newPositionStone.position;
Then in your touchesEnded: check if the node's destination is valid:
if(whatever x and y positions you need to check for in here)
{
// do whatever you need to
} else {
newPositionStone.position = objectStartPosition;
}
The only solution I founded fixing the node on specific position.
But wondering does Sprite Kit has method to find position of touched node?
Here is my solution
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
if (positionInScene.x>400.0 && positionInScene.x<430.0) {
//Fix the position to original
oldPositionStone.x = 414;
oldPositionStone.y = 25;
}
[self selectNodeForTouch:positionInScene];}
//Than
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
NSLog(#"Touches END %f %f",positionInScene.x,positionInScene.y);
if (positionInScene.x>15 && positionInScene.x<40) {
newPositionStone.x=28;
newPositionStone.y = 25;
if ([_selectedNode.name isEqualToString:#"stone"]) {
_selectedNode.position=newPositionStone;
}
}
else{
positionInScene = oldPositionStone;
_selectedNode.position = positionInScene;
}
[self selectNodeForTouch:positionInScene];}
Related
I'm trying to move SKSpritenode in an array like a scrollbar where all objects move together according to the move location:
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
NSEnumerator *e = [_blockStream objectEnumerator];
PBAIceBlock *block;
while (block = [e nextObject])
{
//this says the expresion is not assignable
block.position.y += location.y;
}
}
Where the comments says, I get an error, could some one please point me in the right direction on how to implement something like this?
Using Sprite kit in xcode 5?
A solution is to create a CGPoint to store a value. set that value in touchesBegan, then:
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
int yOFFSET = location.y - _touchLocation.y ;
NSLog(#"yOFFSET : %d", yOFFSET);
NSEnumerator *e = [_blockStream objectEnumerator];
PBAIceBlock *block;
while (block = [e nextObject]) {
CGPoint _center = block.position;
_center.y += yOFFSET;
block.position = _center;
}
_touchLocation = location;
}
This problem happened because you cannot call the position.y specifically.
I'm trying to figure out how to reposition the MKMap region programmatically so that my annotation (automatically selected when the map loads) will all fit centered.
Current Result: https://www.evernote.com/shard/s46/sh/7c7d2ed8-203c-4878-af8c-83ff77ad7b21/ce7786acdf66b0782fc689b72d1b67e7
Desired Result: https://www.evernote.com/shard/s46/sh/21fb0eab-d5c4-4e6d-b05b-322e7dcce8ab/ab816f2a24f11b9c9e15bf55ac648f72
I have tried to reposition everything in - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views but that didn't work. Is there a better approach?
// here is viewWillAppear logic
[self.mapView removeAnnotations:self.mapView.annotations];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLGeocodeCompletionHandler completionHandler = ^(NSArray *placemarks, NSError *error) {
if (error) {
EPBLog(#"error finding placemarks: %#", [error localizedDescription]);
} else {
if (placemarks) {
[placemarks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
CLPlacemark *placemark = (CLPlacemark *)obj;
if ([placemark.country isEqualToString:#"United States"]) {
EPBAnnotation *annotation = [EPBAnnotation annotationWithCoordinate:placemark.location.coordinate];
annotation.title = self.locationObj.locationName;
annotation.subtitle = self.locationObj.locationAddress;
[self.mapView addAnnotation:annotation];
self.mapView.selectedAnnotations = #[annotation];
[self.mapView setCenterCoordinate:placemark.location.coordinate];
/**
* #todo
* MOVE THIS OUTTA HERE
*/
MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}};
region.center = placemark.location.coordinate;
region.span.longitudeDelta = 0.003f;
region.span.latitudeDelta = 0.003f;
[self.mapView setRegion:region animated:YES];
[self.mapView regionThatFits:region];
*stop = YES;
}
}];
}
}
};
[geocoder geocodeAddressString:self.locationObj.locationAddress completionHandler:completionHandler];
Following method will fit the map on region to show all annotations. You can call this method in Map's didAddAnnotations method.
- (void)zoomToFitMapAnnotations {
if ([mMapView.annotations count] == 0) return;
int i = 0;
MKMapPoint points[[mMapView.annotations count]];
//build array of annotation points
for (id<MKAnnotation> annotation in [mMapView annotations]){
points[i++] = MKMapPointForCoordinate(annotation.coordinate);
}
MKPolygon *poly = [MKPolygon polygonWithPoints:points count:i];
[mMapView setRegion:MKCoordinateRegionForMapRect([poly boundingMapRect]) animated:YES];
}
Howevcer you should see if you want to add user location annotation in visible area also. If you don't then in loop check if current annotation is MkUserLocation and don't add it's points in points array.
if ([annotation isKindOfClass:[MKUserLocation class]]) {
continue:
}
Now if you wanted an Annotation to be in center and selected automatically then do this
annotation.coordinate=mMapView.centerCoordinate;
[mMapView selectAnnotation:annotation animated:YES];
I need to implement a simple pinch gesture in my cocos2d project with two or more sprites. Would you be so kind to tell me, how can I handle pitch gesture?
I need something like this:
-(void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer
{
if (recognizer.state != UIGestureRecognizerStateCancelled)
{
if (recognizer.numberOfTouches == 3)
{
CGPoint firstPoint = [recognizer locationOfTouch:0 inView:recognizer.view];
CGPoint secondPoint = [recognizer locationOfTouch:1 inView:recognizer.view];
CGPoint thirdPoint = [recognizer locationOfTouch:2 inView:recognizer.view];
CGPoint fourthPoint = [recognizer locationOfTouch:3 inView:recognizer.view];
ball1.position=firstPoint;
ball2.position=secondPoint;
ball3.position=thirdPoint;
ball4.position=fourthPoint;
}
}
}
Here what I did (it took me quite a lot of googling)
In implementation file
-(id)init
{
self = [super init];
self.isTouchEnabled=YES;
if (self != nil)
{
}
return self;
}
//pinch recognising
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allUserTouches=[event allTouches];
if(allUserTouches.count==2)
{
UITouch* touch1=[[allUserTouches allObjects] objectAtIndex:0];
UITouch* touch2=[[allUserTouches allObjects] objectAtIndex:1];
CGPoint touch1location=[touch1 locationInView:[touch1 view]];
CGPoint touch2location=[touch2 locationInView:[touch2 view]];
touch1location=[[CCDirector sharedDirector] convertToGL:touch1location];
touch2location=[[CCDirector sharedDirector] convertToGL:touch2location];
ball.position=touch1location;
newBall.position=touch2location;
float currentdist=ccpDistance(touch1location, touch2location);
oldDist=currentdist;
}
}
-(void)ccTouchesMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
NSSet *allUserTouches=[event allTouches];
if(allUserTouches.count==2)
{
UITouch* touch1=[[allUserTouches allObjects] objectAtIndex:0];
UITouch* touch2=[[allUserTouches allObjects] objectAtIndex:1];
CGPoint touch1location=[touch1 locationInView:[touch1 view]];
CGPoint touch2location=[touch2 locationInView:[touch2 view]];
touch1location=[[CCDirector sharedDirector] convertToGL:touch1location];
touch2location=[[CCDirector sharedDirector] convertToGL:touch2location];
float currentdist=ccpDistance(touch1location, touch2location);
if (oldDist>=currentdist)
{
//[spriteToZoom setScale:spriteToZoom.scale-fabs((oldDist-currentdist)/100)];
[ball setPosition:touch1location];
[newBall setPosition:touch2location];
NSLog(#"pinch out");
}
else
{
//[spriteToZoom setScale:spriteToZoom.scale+fabs((oldDist-currentdist)/100)];
[ball setPosition:touch1location];
[newBall setPosition:touch2location];
NSLog(#"pinch in");
}
}
}
I'm trying to create a drawing view by drawing the line(s) using an Array of CGPoints.
I'm currently able to draw more than one line but the problem is that I don't know how to break each line when touch is ended.
The current status is -
line1 is drawn until touchended
When touchbegan again, line2 is drawn as well, BUT, line1 endpoint is connected with line2 starting point.
Implementation as follows:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger tapCount = [[touches anyObject] tapCount];
if (tapCount == 2)
{
[pointArray removeAllObjects];
[self setNeedsDisplay];
}
else
{
if ([pointArray count] == 0)
pointArray = [[NSMutableArray alloc] init];
UITouch *touch = [touches anyObject];
start_location = [touch locationInView:self];
[pointArray addObject:[NSValue valueWithCGPoint:start_location]];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
current_location = [touch locationInView:self];
[pointArray addObject:[NSValue valueWithCGPoint:current_location]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
-(void)drawRect:(CGRect)rect
{
if ([pointArray count] > 0)
{
int i;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
for (i=0; i < ([pointArray count] -1); i++)
{
CGPoint p1 = [[pointArray objectAtIndex:i]CGPointValue];
CGPoint p2 = [[pointArray objectAtIndex:i+1]CGPointValue];
CGContextMoveToPoint(context, p1.x, p1.y);
CGContextAddLineToPoint(context, p2.x, p2.y);
CGContextStrokePath(context);
}
}
}
Please advise :-))
Thank you in advance,
Dudi Shani-Gabay
In this case, I think its better for you to keep separate arrays for separate lines. Let the "pointArray" be an array having number of arrays for each line drawn.
In "touchesBegan" method, you need to add new array object to pointArray as follows:
start_location = [touch locationInView:self];
NSMutableArray *newLineArray = [[NSMutableArray alloc] init];
[pointArray addObject:newLineArray];
[[pointArray lastObject] addObject:[NSValue valueWithCGPoint:start_location]];
In "touchesMoved", you have to replace
[pointArray addObject:[NSValue valueWithCGPoint:current_location]];
with the following:
[[pointArray lastObject] addObject:[NSValue valueWithCGPoint:current_location]];
In the "drawRect" method, the 'for' loop should be like this:
for (i=0; i < [pointArray count]; i++)
{
for (int j=0; j < ([[pointArray objectAtIndex:i] count] -1); j++)
{
CGPoint p1 = [[[pointArray objectAtIndex:i] objectAtIndex:j]CGPointValue];
CGPoint p2 = [[[pointArray objectAtIndex:i] objectAtIndex:j+1]CGPointValue];
CGContextMoveToPoint(context, p1.x, p1.y);
CGContextAddLineToPoint(context, p2.x, p2.y);
CGContextStrokePath(context);
}
}
I am working on an application in which I am adding the same image again and again on a button click on random positions and moving those images.
But on moving those images, images can move in whole view inspite of moving in UIView i want my image to move only in subview(UIImage view) on which i am adding it.
here is my code of TouchesMoved
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
UIImageView *imgPimple;// = [[UIImageView alloc]init];
imgPimple = (UIImageView*)[touch view];
CGPoint touchLocation = [touch locationInView:imgPimple superview];
if ([touch.view isKindOfClass:[UIImageView class]])
{
imgPimple.center = touchLocation;
}
}
What you should be doing is:
CGPoint touchLocation = [touch locationInView:[imgPimple superview]];
I think.
It seems to me that if you're deciding where to move it in its superview, and you get the touch location in the imgPimple view, it will behave incorrectly.