How can you detect if SKShapeNode is touched? - sprite-kit

I created a sknodeshape. How can I detect if the shape I made was touched(clicked)?
Here is the code: (I solved it already)
//metung_babi is the name of the SKShapeNode
UITouch *touch = [touches anyObject];
CGPoint nokarin = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:nokarin];
if ([node.name isEqualToString:#"metung_babi"]) {
NSlog(#"touch me not");
}
my mistake was when I created the shape I put the SKShapeNode name before initializing it.

Implement the touch delegate methods. Then, in the -touchesBegan: method, extract the point of touch and retrieve the node using the [self nodeAtPoint:] method

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *yourNode = ....;
CGRect yourNodeFrame = bowlNode.frame;
if (CGRectContainsPoint(yourNodeFrame, location)) {
//your node may be touched, check if it's your node
SKNode *theNode = [self nodeAtPoint:location];
if ([theNode.name isEqualTo:yourNode.name]) {
//it's your node touched
}
}
}
the method nodeAtPoint return value is complicated. you can check the document to find different situations

Related

intersectsNode not working?

I'm trying to detect when one node overlaps another. I am teaching myself sprite kit and cannot get intersectsNodes to give any output. I've loaded 2 nodes that can be moved around on the screen and then added intersectsNodes in the update section.
-(void)update:(CFTimeInterval)currentTime {
SKSpriteNode* playerShip1;
SKSpriteNode* playerShip2;
if ([playerShip1 intersectsNode: playerShip2]) {
NSLog(#"your ships overlap");
}
Any thoughts on why no intersection is found?
here is the whole m file.
#import "MyScene.h"
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode* playerShip1 = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
playerShip1.position = CGPointMake(self.frame.size.width/2, playerShip1.frame.size.height);
playerShip1.name = #"PLAYER_SHIP_1";
[self addChild:playerShip1];
SKSpriteNode* playerShip2 = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
playerShip2.position = CGPointMake(self.frame.size.width/2, self.frame.size.height-playerShip2.frame.size.height);
playerShip2.name = #"PLAYER_SHIP_2";
[self addChild:playerShip2];
SKSpriteNode* playerShip3 = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
playerShip3.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
playerShip3.name = #"PLAYER_SHIP_3";
[self addChild:playerShip3];
activeDragNode = nil;
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
// Identify where this touch is on the scene
CGPoint scenePosition = [touch locationInNode:self];
// Find the child node that contains this touch
SKNode* checkNode = [self nodeAtPoint:scenePosition];
// Make sure it is a player ship and not another node like the parent SKScene
if (checkNode && [checkNode.name hasPrefix:#"PLAYER_SHIP"]) {
activeDragNode = (SKSpriteNode*)checkNode;
SKAction *zoomAction = [SKAction scaleTo:1.5 duration:.2];
[checkNode runAction:zoomAction];
//NSLog(#"your ship has been hit!");
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Remove reference to which object we are dragging
activeDragNode=nil;
UITouch *touch = [touches anyObject];
CGPoint scenePosition = [touch locationInNode:self];
SKNode* checkNode = [self nodeAtPoint:scenePosition];
SKAction *shrinkAction = [SKAction scaleTo:1.0 duration:.2];
[checkNode runAction:shrinkAction];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// Be sure we have a reference to an object to drag
if (activeDragNode==nil) return;
UITouch *touch = [touches anyObject];
CGPoint scenePosition = [touch locationInNode:self];
CGPoint lastPosition = [touch previousLocationInNode:self];
// Calculate the new location of the dragged node
CGPoint newLoc = CGPointMake(activeDragNode.position.x + (scenePosition.x - lastPosition.x), activeDragNode.position.y + (scenePosition.y - lastPosition.y));
// Update this location
activeDragNode.position = newLoc;
}
-(void)update:(CFTimeInterval)currentTime {
SKSpriteNode* playerShip1;
SKSpriteNode* playerShip2;
if ([playerShip1 intersectsNode: playerShip2]) {
NSLog(#"your ships overlap");
}
/* Called before each frame is rendered */
}
#end
First you need to set a position for each node:
playerShip1.position = CGPointMake(0,0);
Second you need to add each node to the view:
[self addChild:playerShip1];
Also, you are adding the nodes in your update method which is the wrong place. As your code is now, you will continuously add each node 60 times a second.
I see you adding additional code. You are creating 3 SKSpriteNodes in your init method which is fine and works. However, you are not keeping a reference to these 3 nodes. This means once they are created, you have no way to access them again. To resolve this, you should create 3 SKSpriteNode class properties or add all 3 nodes into an array (class property for the array). If you don't know what I mean, that's ok, it just means you have a ways to learn.
I suggest you do a couple of tutorials as this will teach some additional fundamentals and prevent a ton of "why isn't this working" frustration in the future.

Dpad for sprite kit

I an interested in trying to create a few games, namely in the new sprite kit. However, for the game that I have in mind I would rather use a directional pad vs a joy stick. Since I shall be moving over from Cocos, my old program no longer works (so neither will that dpad). Sadly, I have not come accross any tutorial that may help with implementing one in the new sprite kit (only joy sticks). I was wondering and hoping if anyone came across a simple dpad class from github or something or a helpful link that they would like to share. Thanks
Here's one way:
//Joystick node
- (SKSpriteNode *)controlPadNode
{
SKSpriteNode *controlPadNode = [SKSpriteNode spriteNodeWithImageNamed:#"game-controller-front"];
controlPadNode.position = CGPointMake(controlPadX,controlPadY);
controlPadNode.name = #"controlPadNode";
controlPadNode.zPosition = 1.0;
return controlPadNode;
}
//handle touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
touchX = location.x;
touchY = location.y;
controlButtonDown = true;
}
}
//when touch moves
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
touchX = location.x;
touchY = location.y;
controlButtonDown = true;
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
controlButtonDown = false;
}
}
//update method
-(void)update:(NSTimeInterval)currentTime {
if (controlButtonDown) {
//the control pad
SKNode *controlNode = [self childNodeWithName:#"controlPadNode"];
//the node you want to move
SKNode *node = [self childNodeWithName:#"spaceShipNode"];
//compute the angle between parameters pad and the horizontal
float angle = atan2f (touchY - controlPadY, touchX - controlPadX) ;
//move the control pad for the player to have a sense of movement
SKAction *moveControlPad = [SKAction moveTo:CGPointMake(touchX, touchY) duration:0.00001];
double distance = sqrt(pow((touchX - controlPadX), 2.0) + pow((touchY - controlPadY), 2.0));
//make sure the control pad only moves 40 pixels
if( distance < 40 ){
[controlNode runAction:moveControlPad];
}
//move the ship
SKAction *moveShip = [SKAction moveByX: 6*cosf(angle) y:6*sinf(angle) duration:0.005];
[node runAction: moveShip];
}
}
EDIT:
Also can use this to move the control pad back when touch ends:
if (!controlButtonDown) {
SKNode *controlNode = [self childNodeWithName:#"controlPadNode"];
SKAction *moveControlPad = [SKAction moveTo:CGPointMake(controlPadX, controlPadY) duration:0.00001];
[controlNode runAction:moveControlPad];
}
I've built a small UIKit based game engine before the introduction of SpriteKit. My engine loads cocos2d compatible maps from Tiled, sprites from TexturePacker, and it comes with a joystick that I ported from cocos2d to UIKit. (Mine is based on sneaky-joystick.)
You can grab the whole library on GitHub and pull out the parts you need. It's fairly modular.

draw line using finger and an object will follow that path?

I m new to game devloping in ios. Now I want made a game similar like "Control Air Flight" and "Air Traffic Controller" ,
where a user can draw line using their finger and an object will
follow that path
so ,anyone can guide me which is best for developing like this.Can Cocos2d is best for it? Or any thing else i have to use for this.
Also If anyone knows of a tutorial already out there or any reference link please suggest me.
Thanks in Advance.
To simply let the object follow your finger, implement touches (and just one of its methods):
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint toPoint = [touch locationInView:self.view];
[yourObjectOutlet setCenter:toPoint];
}
Here, your object's center will follow your path, but you can adjust its anchor point by editing "toPoint" accordingly to object's frame.
EDIT
If you want to draw the path, then make the object follow that path, do like this:
//define an NSMutableArray in your header file (do not forget to alloc and init it in viewDidLoad), then:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//you begin a new path, clear the array
[yourPathArray removeAllObjects];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint toPoint = [touch locationInView:self.view];
//now, save each point in order to make the path
[yourPathArray addObject:[NSValue valueWithCGPoint:toPoint]];
}
Now you want to start the move:
- (IBAction)startMoving{
[self goToPointWithIndex:[NSNumber numberWithInt:0]];
}
- (void)goToPointWithIndex:(NSNumber)indexer{
int toIndex = [indexer intValue];
//extract the value from array
CGPoint toPoint = [(NSValue *)[yourPathArray objectAtIndex:toIndex] CGPointValue];
//you will repeat this method so make sure you do not get out of array's bounds
if(indexer < yourPathArray.count){
[yourObject setCenter:toPoint];
toIndex++;
//repeat the method with a new index
//this method will stop repeating as soon as this "if" gets FALSE
[self performSelector:#selector(goToPointWithIndex:) with object:[NSNumber numberWithInt:toIndex] afterDelay:0.2];
}
}
That's all!

Handling touches on Iphone

Im having a little problem on handling touches in my apps.
I set my touchesBegan like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *currentTouch = [[event allTouches] anyObject];
touchPoint = [currentTouch locationInView:self.view];
if (CGRectContainsPoint(image1.frame, touchPoint)) {
image1IsTouched = YES;
}
}
Then i set my touch move like this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *currentTouch = [[event allTouches] anyObject];
currentPoint = [currentTouch locationInView:currentTouch.view];
if(image1IsTouched == YES) {
image1.center = CGPointMake(currentPoint.x,currentPoint.y);
.....
}
}
Now i tried my app on actual unit and thats where i notice my problem. While im touching the image1 with 1 finger the app is doing ok and its checking for collision everytime i drag my finger. The problem occurs when i touch the screen with another finger while touching/dragging the image. The image im currently touching will jump to the other finger. I've tried [myView setMultipleTouchEnable:NO]; & using NSArray on touches and comparing the [touches count] with the touch but its not working. Can someone show me how to set a uiimageview to act on single touch only. Thanks.
First, you should use UITouch *currentTouch = [touches anyObject]; to get the current touch.
Second, you should check that touches.count == 1 to make sure there's only one finger on the screen, and ignore touch input if there's more than one, unless you wanted to support multitouch.

iPhone drag/drop

Trying to get some basic drag/drop functionality happening for an iPhone application.
My current code for trying to do this is as follows:
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
self.center = location;
}
This code has the result of a the touched UIView flickering while it follows the touch around. After playing around with it a bit, I also noticed that the UIView seemed to flicker from the 0,0 position on the screen to the currently touched location.
Any ideas what I'm doing wrong?
The center property needs to be specified in the coordinate system of the superview, but you've asked the touch event for the location in terms of your subview. Instead ask for them based on the superview's coordinates, like this:
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.superview]; // <--- note self.superview
self.center = location;
}