I have a SKSpriteNode, which is a ball. My view don't have gravity. I'm able to move the ball by applying an impulse over it in the start and I want to make it to move to the user touch point which we can get in -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method without affecting its motion.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInView:self.view];
SKAction *moveToPoint = [SKAction moveByX:location.x y:location.y duration:2];
[ball runAction:moveToPoint];
}
}
Its not seems to be working. Help me guys.
If you want to send the node directly to a point use the method:
[SKAction moveTo:location duration:2];
The SKAction moveBy: method moves the node by the x and y values provided, whereas the moveTo method to the point in the node's parent.
EDIT:
Also, change the line:
CGPoint location = [touch locationInView:self.view];
to
CGPoint location = [touch locationInNode:self];
A UIView has a different coordinate system than a SKScene.
EDIT 2: You can remove affect of physics while touch exists
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
{
ball.physicsBody.dynamic = NO;
CGPoint location = [touch locationInNode: self];
SKAction *moveToPoint = [SKAction moveTo:location duration:2];
[ball runAction:moveToPoint];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
ball.physicsBody.dynamic = YES;
}
Related
I'm attempting to change the parent node of a sprite after it is dropped, but I'm getting a nil error.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKSpriteNode *gamePiece = [self pickObject];
gamePiece.position = location;
gamePiece.physicsBody.dynamic = NO;
[self addChild:gamePiece];
_currentTouch = touch;
currentGamePiece = gamePiece;
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y > 350)
{
_bg.position = CGPointMake(_bg.position.x, _bg.position.y-2);
}
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
if ([touch isEqual:_currentTouch])
{
currentGamePiece.position = location;
}
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y > 350)
{
_bg.position = CGPointMake(_bg.position.x, _bg.position.y-2);
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
if ([touch isEqual:_currentTouch])
{
currentGamePiece.position = location;
currentGamePiece.physicsBody.dynamic = YES;
SKAction *removeNode = [SKAction removeFromParent];
[gamePiece runAction: removeNode];
[_bg addChild:gamePiece];
}
}
}
Maybe it has something to do with the switch to "currentGamePiece", but when I try to remove "currentGamePiece" from its parent, I get an error like "attempting to add node that already has a parent". I may just not be going about it the right way. What's the problem?
Try replacing this code...
SKAction *removeNode = [SKAction removeFromParent];
[gamePiece runAction: removeNode];
[_bg addChild:gamePiece];
with this...
[gamePiece removeFromParent];
[_bg addChild:gamePiece];
The issue is gamePiece is added to the _gb before the SKAction has a chance to remove it from its parent. The app crashes because a node can't have two parents.
I did create SKSpriteNode using this code and physicsBody is circle. How I could check that user did touch eare in the physicsBody?
self = [super initWithColor:[SKColor clearColor] size:CGSizeMake(200, 200)];
//...
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.size.width/2.0f];
self.userInteractionEnabled = YES;
I did found solution for my problem using this code:
CGMutablePathRef pathRef;
// Fill pathRef with points and create phisycs body using pathRef.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
if (CGPathContainsPoint(pathRef, nil, touchLocation, NO)) {
// If we are here it means user did touche physic body.
}
}
The easiest solution would be to create a second invisible sprite, with the size you need, and place it directly over the area you want to record touches on.
The other option is to store ALL the coordinates which trigger a valid touch and compare them against the actual touch coordinate in your touch method, like this:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
NSLog(#"%#", NSStringFromCGPoint(touchLocation));
// Compare the touchLocation coordinate against your list of acceptable coordinates...
}
I'm currently programming a small game with SpriteKit in Xcode for the iOS platform. I wrote a code which adds some SpriteNodes on 2 different "lines", so half of the nodes are moving with the y-coordinate 100 and the others with y = 200, and they're all moving from the left side to the right which an infinity loop. Now I want that the user can touch on one SpriteNode, then moves his finger to another SpriteNode, but it has to be located on another line, then removes his finger and the SpriteNode with the TOUCHBEGAN should change its y-coordinate with the TOUCHEND Node. How can I accomplish this?
-(void)add
{
SKSpriteNode *sprite2 = [SKSpriteNode spriteNodeWithImageNamed:#"test1.png"];
sprite2.position = CGPointMake(-40, self.frame.size.height / 2);
sprite2.size = CGSizeMake(100, 32);
SKSpriteNode *sprite3 = [SKSpriteNode spriteNodeWithImageNamed:#"test.png"];
sprite3.position = CGPointMake(-40, (self.frame.size.height / 2) + 90);
sprite3.size = CGSizeMake(32, 100);
[self addChild:sprite1];
[self addChild:sprite2];
SKAction *actionMove1 = [SKAction moveTo:CGPointMake(400, (self.frame.size.height / 2) - 90) duration:12];
SKAction *actionMove2 = [SKAction moveTo:CGPointMake(200, (self.frame.size.height / 2)) duration:12];
SKAction *actionMoveDone = [SKAction removeFromParent];
[sprite1 runAction:[SKAction sequence:#[actionMove1, actionMoveDone]]];
[sprite2 runAction:[SKAction sequence:#[actionMove2, actionMoveDone]]];
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast
{
self.lastSpawnTime += timeSinceLast;
if (self.lastSpawnTime > 2)
{
self.lastSpawnTime = 0;
[self add];
}
}
- (void)update:(CFTimeInterval)currentTime
{
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTime;
self.lastUpdateTime = currentTime;
if (timeSinceLast > 2)
{
timeSinceLast = 1.0 /60.0;
self.lastUpdateTime = currentTime;
}
[self updateWithTimeSinceLastUpdate:timeSinceLast];
}
You have to subclass SkSpriteNode:
to detect TouchEvents you have to set "userInteractionEnabled" to "YES"
to react on TouchEvents implement the touch method which fits for you needs:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{}
In this method you can change the coordinates of your sprite
add these function like that in your sksence
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent )event {
/ Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if([node.name isEqualToString:#"plane"])
{
NSLog(#"_______touch ended");
//x and y position of object at Scene
NSLog(#"%f",node.position.x);
NSLog(#"%f",node.position.y);
NSLog(#"%#",node);
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if([node.name isEqualToString:#"plane"])
{
NSLog(#"_______touch mobing");
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if([node.name isEqualToString:#"plane"])
{
NSLog(#"______touch begin");
//x and y position of object at Scene
NSLog(#"%f",node.position.x);
NSLog(#"%f",node.position.y);
NSLog(#"%#",node);
}
}
i am moving a sprite using the touches moved method. currently the sprite jumps to the point on which the screen is touched but I want the sprite only to move when it is touched directly.
my code:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
CGPoint newPosition = CGPointMake(location.x, self.size.height/2);
self.sprite.position = newPosition;
}
}
check if the touch location is inside the sprite, like this:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
if(CGRectContainsPoint(self.sprite.boundingBox,positionInScene)) {
CGPoint newPosition = CGPointMake(positionInScene.x, self.size.height/2);
self.sprite.position = newPosition;
}
}
Im using Spritekit to create a game for iOS 7. The game has circles moving across the screen using this code
_enemy = [SKSpriteNode spriteNodeWithImageNamed:#"greeny"];
_enemy.position = CGPointMake(CGRectGetMidX(self.frame)+300,
CGRectGetMidY(self.frame));
_enemy.size = CGSizeMake(70, 70);
_enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:35];
_enemy.physicsBody.mass = 0;
_enemy.physicsBody.categoryBitMask = Collisiongreen;
[_enemies addObject:_enemy];
NSLog(#"Enemies%lu",(unsigned long)_enemies.count);
[self addChild:_enemy];
[_enemy runAction:[SKAction moveByX:-900 y:0 duration:4]];
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:1.4],
[SKAction performSelector:#selector(move)
onTarget:self],
]]];
I would like to have it that when the user touches one of the objects moving across the screen that they can move it with their finger either up or down (thats why I'm using touches moved)
The code i have set up right now is
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_dead)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_enemy.frame, location)){
[_enemy runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:0.01]];
}
My problem is that if i touch it the object will move a few pixels but will stop right after. How can I get it to move with my finger and if i let go it will continue moving left like programed before? Thanks!!
So the trick here is that in the touchesMoved method, you want the enemy's postion set to the location of your touch. Use the touchesEnded method to execute a method that makes the enemy continue in the direction of your last touch. This is a rough non-tested example.
You need to store the difference of the current location with the previous location.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_dead)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_enemy.frame, location)){
someBool = False;
[_enemy setPosition:location];
changeInX = location.x - lastX;
changeInY = location.y - lastY;
lastX = location.x;
lastY = location.y;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
someBool = True;
}
- (void)update:(NSTimeInterval)currentTime
{
...
if (someBool) {
enemy.position = CGPointMake((enemy.position.x + changeInX), (enemy.position.y + changeInY));
}
...
}