No colision detection with edges when panning node fast - ios

Im freaking out with this collision issue:
panned ball breaks out edgeloop body when panned fast. Anyone had simillar problem?
Here is scene code ilustrating the issue.
(Replacement MyScene in xcode sample - spritekitgame)
#import "SAMyScene.h"
/* Bitmask for the different entities with physics bodies. */
typedef enum : uint32_t {
SAColliderTypeBall = 0x1 << 1
,SAColliderTypeEdge = 0x1 << 3
} SAColliderType;
NSString * const SABallName = #"ballNode";
#interface SAMyScene()
#property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer;
#property (nonatomic, strong) SKShapeNode *ball;
#end
#implementation SAMyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
NSLog(#"Ball categorie bitmask =%d", SAColliderTypeBall);
NSLog(#"Edges categorie bitmask =%d", SAColliderTypeEdge);
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.categoryBitMask = SAColliderTypeEdge;
self.physicsBody.usesPreciseCollisionDetection = YES;
self.ball = [self newBallNode];
[self addChild:self.ball];
}
return self;
}
- (SKShapeNode *)newBallNode {
SKShapeNode *ball = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGFloat radius = 60.0;
CGPathAddArc(myPath, NULL, 0,0, radius, 0, M_PI*2, YES);
ball.path = myPath;
ball.fillColor = [SKColor yellowColor];
ball.name = SABallName;
ball.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:radius];
ball.physicsBody.affectedByGravity = NO;
ball.physicsBody.dynamic = YES;
ball.physicsBody.categoryBitMask = SAColliderTypeBall;
ball.physicsBody.contactTestBitMask = SAColliderTypeEdge;
ball.physicsBody.collisionBitMask = SAColliderTypeEdge;
ball.physicsBody.usesPreciseCollisionDetection = YES;
return ball;
}
-(void)update:(CFTimeInterval)currentTime {
//Called before each frame is rendered
}
- (UIPanGestureRecognizer *)panGestureRecognizer {
if (!_panGestureRecognizer) {
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:#selector(handlePanFrom:)];
}
return _panGestureRecognizer;
}
- (void)didMoveToView:(SKView *)view {
if (![[self view].gestureRecognizers containsObject:self.panGestureRecognizer]) {
[[self view] addGestureRecognizer:self.panGestureRecognizer];
}
}
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
} else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:recognizer.view];
translation = CGPointMake(translation.x, - translation.y);
[self panForTranslation:translation];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
}
}
- (void)panForTranslation:(CGPoint)translation {
CGPoint position = self.ball.position;
CGPoint newPos = CGPointMake(position.x + translation.x, position.y);
self.ball.position = newPos;
}
#end

Related

Objective C - SpriteKit - Unable to detect contact between ball and paddle node

I am trying to detect the collision between the ball node and either one of the paddle nodes but the message to confirm the collision is not being fired.
Could somebody help me understand where I am going wrong?
//categories for detecting contacts between nodes
static const uint32_t ballCategory = 0x1 << 0;
static const uint32_t paddleCategory = 0x1 << 1;
#interface GameScene ()
#property BOOL contentCreated;
#property(nonatomic) UITouch *playerOnePaddleControlTouch;
#property(nonatomic, weak) UITouch *paddleTouch;
#property(nonatomic) SKSpriteNode *paddleOneNode;
#property(nonatomic) SKSpriteNode *paddleTwoNode;
#property(nonatomic) SKSpriteNode *ballNode;
#property(nonatomic) SKLabelNode *playerOneScoreNode;
#property(nonatomic) SKLabelNode *playerTwoScoreNode;
#property(nonatomic) NSInteger playerOneScore;
#property(nonatomic) NSInteger playerTwoScore;
#end
#implementation GameScene
- (void)didMoveToView:(SKView *)view
{
if (!self.contentCreated)
{
[self createSceneContents];
self.contentCreated = YES;
}
}
- (void) createSceneContents
{
self.backgroundColor = [SKColor blackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
[self addChild: [self newGameNode]];
self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;
// Create border around screen
SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody = borderBody;
self.physicsBody.friction = 0;
// Create Paddle One
SKSpriteNode *paddleOne = [self newPaddle];
paddleOne.position = CGPointMake(CGRectGetMidX(self.frame)/8, CGRectGetMidY(self.frame));
paddleOne.name = #"paddleOne";
paddleOne.physicsBody.categoryBitMask = paddleCategory;
paddleOne.physicsBody.contactTestBitMask = ballCategory;
[self addChild:paddleOne];
// Create Paddle Two
SKSpriteNode *paddleTwo = [self newPaddle];
paddleTwo.position = CGPointMake((CGRectGetMaxX(self.frame) - CGRectGetMidX(self.frame) / 8), CGRectGetMidY(self.frame));
paddleTwo.name = #"paddleTwo";
paddleTwo.physicsBody.categoryBitMask = paddleCategory;
paddleTwo.physicsBody.contactTestBitMask = ballCategory;
[self addChild:paddleTwo];
// Create ball
SKSpriteNode *ball = [self newBall];
ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:ball];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
ball.physicsBody.friction = 1.0f; //normally 1.0f
ball.physicsBody.restitution = 1.0f; //normally 1.0f
ball.physicsBody.linearDamping = 0.0f; //normally 0.0f
ball.physicsBody.allowsRotation = NO;
ball.physicsBody.categoryBitMask = ballCategory;
ball.physicsBody.contactTestBitMask = paddleCategory;
[ball.physicsBody applyImpulse:CGVectorMake(1.0f, -1.0f)];
// Create score labels
self.playerOneScoreNode = [SKLabelNode labelNodeWithFontNamed:#"Helvetica"];
self.playerTwoScoreNode = [SKLabelNode labelNodeWithFontNamed:#"Helvetica"];
self.playerOneScoreNode.fontColor = self.playerOneScoreNode.fontColor = [SKColor whiteColor];
self.playerOneScoreNode.fontSize = self.playerTwoScoreNode.fontSize = 90;
self.playerOneScoreNode.position = CGPointMake((CGRectGetWidth(self.frame))* 0.25, (CGRectGetHeight(self.frame)) - 80);
self.playerTwoScoreNode.position = CGPointMake((CGRectGetWidth(self.frame)) * 0.75, (CGRectGetHeight(self.frame)) - 80);
[self addChild:self.playerOneScoreNode];
[self addChild:self.playerTwoScoreNode];
// Set Scores to 0
self.playerOneScore = 7;
self.playerTwoScore = 0;
self.playerOneScoreNode.text = [NSString stringWithFormat:#"%ld",self.playerOneScore];
self.playerTwoScoreNode.text = [NSString stringWithFormat:#"%ld",self.playerTwoScore];
}
- (SKSpriteNode *)newPaddle
{
SKSpriteNode *paddle = [[SKSpriteNode alloc]initWithColor:[SKColor whiteColor] size:CGSizeMake(16,64)];
return paddle;
}
- (SKSpriteNode *)newBall
{
SKSpriteNode *ball = [[SKSpriteNode alloc]initWithColor:[SKColor redColor] size:CGSizeMake(16, 16)];
return ball;
}
- (SKLabelNode *) newGameNode
{
SKLabelNode *gameNode = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
gameNode.text = #" Pong";
gameNode.fontSize = 50;
gameNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
gameNode.fontColor = [SKColor blueColor];
return gameNode;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.paddleTouch = [touches anyObject];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInNode:self];
SKNode *paddleOne = [self childNodeWithName:#"paddleOne"];
SKNode *paddleTwo = [self childNodeWithName:#"paddleTwo"];
if (touchPoint.x < CGRectGetMidX(self.frame)) {
paddleOne.position = CGPointMake(paddleOne.position.x, touchPoint.y);
}
else
{
paddleTwo.position = CGPointMake(paddleTwo.position.x, touchPoint.y);
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if (self.paddleTouch) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInNode:self];
CGPoint previousPoint = [touch previousLocationInNode:self];
SKSpriteNode *paddleOne = (SKSpriteNode*)[self childNodeWithName:#"paddleOne"];
SKSpriteNode *paddleTwo = (SKSpriteNode*)[self childNodeWithName:#"paddleTwo"];
int paddleOneY = paddleOne.position.y + (touchPoint.y - previousPoint.y);
int paddleTwoY = paddleTwo.position.y + (touchPoint.y - previousPoint.y);
if (touchPoint.x < CGRectGetMidX(self.frame)) {
paddleOne.position = CGPointMake(paddleOne.position.x, paddleOneY);
}
else
{
paddleTwo.position = CGPointMake(paddleTwo.position.x, paddleTwoY);
}
}
}
// React to collision's between nodes/bodies
// Currently not working....need to understand this set of code.
-(void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody;
SKPhysicsBody *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if (firstBody.categoryBitMask == ballCategory && secondBody.categoryBitMask == paddleCategory)
{
NSLog(#"Ball has touched Paddle");
}
}
#end
Your paddleOne and paddleTwo does not have SKPhysicsBody.
Add these (change size of physics body if needed)
paddleOne.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: paddleOne.size];
paddleTwo.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: paddleTwo.size];

iOS SpriteKit - ray(line) is reflected from bounds

We have line(ray) which moves to bounds and reflects when bound is reached. These images demonstrates the dynamic of movement and reflections.
And i'd like to implement it in SpriteKit(obj-c is prefer) but don't understand from which point I should start.
I found how to implement it. Hope it'll be useful for others
#import "GameScene.h"
static const float GUIDE_MASS = .0015;
static const int SEGMENTS_COUNT = 10;
static const int SEGMENT_LENGTH = 5;
#interface GameScene(private)
-(void) createGuidesAndShot;
#end
#implementation GameScene
SKShapeNode *shot;
NSMutableArray* shotSegments;
-(void)didMoveToView:(SKView *)view {
[self setBackgroundColor:[SKColor whiteColor]];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
}
-(void)update:(CFTimeInterval)currentTime {
CGMutablePathRef pathToDraw = CGPathCreateMutable();
if (shotSegments!=nil) {
bool isFirst = YES;
for (SKNode* segment in shotSegments) {
if(isFirst){
CGPathMoveToPoint(pathToDraw, NULL,
segment.position.x,
segment.position.y);
isFirst =NO;
} else {
CGPathAddLineToPoint(pathToDraw, NULL,
segment.position.x,
segment.position.y);
}
}
shot.path = pathToDraw;
}
}
-(void)didBeginContact:(SKPhysicsContact *)contact {
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (shotCategory|screenBoundsCategory)){
}
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
shotSegments = [NSMutableArray new];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody = borderBody;
self.physicsBody.friction = 0.0f;
self.physicsBody.categoryBitMask = screenBoundsCategory;
self.physicsBody.contactTestBitMask = shotCategory;
self.physicsWorld.contactDelegate = self;
[self createGuidesAndShot];
}
return self;
}
-(void) createGuidesAndShot{
for (int i = 0; i<SEGMENTS_COUNT*SEGMENT_LENGTH; i+=SEGMENT_LENGTH) {
SKShapeNode* guide = [SKShapeNode shapeNodeWithCircleOfRadius:1];
guide.position = CGPointMake(self.frame.size.width/2+i,
self.frame.size.height/2-i);
// guide.fillColor = [SKColor blackColor];
guide.name = [NSString stringWithFormat:#"guide%i", i];
[self addChild:guide];
[shotSegments addObject:guide];
guide.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:guide.frame.size.width/2];
guide.physicsBody.friction = 0.0f;
guide.physicsBody.restitution = 1.0f;
guide.physicsBody.linearDamping = 0.0f;
guide.physicsBody.allowsRotation = NO;
guide.physicsBody.categoryBitMask = shotCategory;
guide.physicsBody.contactTestBitMask = screenBoundsCategory;
guide.physicsBody.collisionBitMask = screenBoundsCategory;
guide.physicsBody.mass = GUIDE_MASS;
[guide.physicsBody applyImpulse:CGVectorMake(0.1f, -0.1f)];
}
shot = [SKShapeNode node];
[shot setStrokeColor:[UIColor redColor]];
[self addChild:shot];
}
#end

SpriteKit drag and drop through wall

I did simple drag and drop in SpriteKit with physics. It works as expected, but when I use fast drag, element goes through wall.
self.runner is wall
self.runner2 is square
Wall have dynamic set to NO.
Movie shows everything: https://www.dropbox.com/s/ozncf9i16o1z80o/spritekit_sample.mov?dl=0
Tested on simulator and real device, both iOS 7.
I want to prevent square from going through wall. Any ideas?
#import "MMMyScene.h"
static NSString * const kRunnerImg = #"wall.png";
static NSString * const kRunnerName = #"runner";
static NSString * const kRunnerImg2 = #"zebraRunner.png";
static NSString * const kRunnerName2 = #"runner";
static const int kRunnerCategory = 1;
static const int kRunner2Category = 2;
static const int kEdgeCategory = 3;
#interface MMMyScene () <SKPhysicsContactDelegate>
#property (nonatomic, weak) SKNode *draggedNode;
#property (nonatomic, strong) SKSpriteNode *runner;
#property (nonatomic, strong) SKSpriteNode *runner2;
#end
#implementation MMMyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.runner = [SKSpriteNode spriteNodeWithImageNamed:kRunnerImg];
self.runner.texture = [SKTexture textureWithImageNamed:kRunnerImg];
[self.runner setName:kRunnerName];
[self.runner setPosition:CGPointMake(160, 300)];
[self.runner setSize:CGSizeMake(320, 75)];
[self addChild:self.runner];
self.runner.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(320, 75)];
self.runner.physicsBody.categoryBitMask = kRunnerCategory;
self.runner.physicsBody.contactTestBitMask = kRunner2Category;
self.runner.physicsBody.collisionBitMask = kRunner2Category;
self.runner.physicsBody.dynamic = NO;
self.runner.physicsBody.allowsRotation = NO;
self.runner2 = [SKSpriteNode spriteNodeWithImageNamed:kRunnerImg2];
[self.runner2 setName:kRunnerName2];
[self.runner2 setPosition:CGPointMake(100, 100)];
[self.runner2 setSize:CGSizeMake(75, 75)];
self.runner2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(75, 75)];
self.runner2.physicsBody.categoryBitMask = kRunner2Category;
self.runner2.physicsBody.contactTestBitMask = kRunnerCategory;
self.runner2.physicsBody.collisionBitMask = kRunnerCategory;
self.runner2.physicsBody.dynamic = YES;
self.runner2.physicsBody.allowsRotation = NO;
[self addChild:self.runner2];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.categoryBitMask = kEdgeCategory;
self.physicsBody.collisionBitMask = 0;
self.physicsBody.contactTestBitMask = 0;
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
}
return self;
}
- (void)didBeginContact:(SKPhysicsContact *)contact {
SKPhysicsBody *firstBody, *secondBody;
firstBody = contact.bodyA;
secondBody = contact.bodyB;
if(firstBody.categoryBitMask == kRunnerCategory )
{
NSLog(#"collision");
//self.draggedNode = nil;
}
}
- (void)didMoveToView:(SKView *)view {
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanFrom:)];
[[self view] addGestureRecognizer:gestureRecognizer];
}
- (void)panForTranslation:(CGPoint)translation {
CGPoint position = [self.draggedNode position];
if([[self.draggedNode name] isEqualToString:kRunnerName]) {
[self.draggedNode setPosition:CGPointMake(position.x + translation.x, position.y + translation.y)];
}
}
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
[self selectNodeForTouch:touchLocation];
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:recognizer.view];
translation = CGPointMake(translation.x, -translation.y);
[self panForTranslation:translation];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
}
- (void)selectNodeForTouch:(CGPoint)touchLocation {
SKSpriteNode *touchedNode = (SKSpriteNode *)[self nodeAtPoint:touchLocation];
if(![self.draggedNode isEqual:touchedNode]) {
self.draggedNode = touchedNode;
// self.draggedNode.physicsBody.affectedByGravity = NO;
}
}
#end
You're setting the position of the node directly, this bypasses collision detection. If you move fast, the next position can be on the other side of the wall (or close enough so that physics will resolve the collision by moving the dragged node outside and above the wall).
Enabling usesPreciseCollisionDetection on the dynamic body may improve the situation but may not entirely prevent it. Actually it may not make any difference due to setting the node position directly instead of moving the body using force/impulse.
To fix this behavior you can't rely on contact events. Instead use bodyAlongRayStart:end: to determine if there's a blocking body between the node's current and the next position. Even so this will only work with your current setup, but couldn't prevent the ray successfully passing through small gaps in the wall where the dynamic body wouldn't be able to fit through.
While dragging nodes, if you change their position in the following ways,
draggedNode.position = CGPoint(x: position.x + translation.x, y: position.y + translation.y)
and
SKAction.move(to: CGPoint(x: 100, y: sprite.position.y), duration: 1))
nodes will lose their physics properties. That's why they pass through walls or other nodes. Therefore you need to change their velocity or apply force or impulse.
I created an example project in Github. And the video is here

Sprite Kit player can still leave screen

I've been trying to prevent my sprite that is controlled by a UIPanGestureRecognizer from leaving the screen. I've tried creating this with this code but the player is still able to leave the screen.
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.categoryBitMask = wallCategory;
player = [SKSpriteNode spriteNodeWithImageNamed:#"thePlayer.png"];
player.size = CGSizeMake(35, 35);
player.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
player.name = kPlayerName;
player.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:player.size.width/2];
player.physicsBody.dynamic = NO;
player.physicsBody.usesPreciseCollisionDetection = YES;
player.physicsBody.categoryBitMask = playerCategory;
player.physicsBody.restitution = 0;
player.physicsBody.collisionBitMask = enemyCategory | wallCategory;
player.physicsBody.contactTestBitMask = enemyCategory | bonusCategory;
[self addChild:player];
}
- (void)didMoveToView:(SKView *)view
{
[super didMoveToView:view];
if (!pan) {
pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(dragPlayer:)];
pan.minimumNumberOfTouches = 1;
pan.delegate = self;
[self.view addGestureRecognizer:pan];
}
}
-(void)dragPlayer: (UIPanGestureRecognizer *)gesture {
CGPoint trans = [gesture translationInView:self.view];
SKAction *moveAction = [SKAction moveByX:trans.x y:-trans.y duration:0];
[player runAction:moveAction];
[gesture setTranslation:CGPointMake(0, 0) inView:self.view];
}
Any ideas?

Understanding SpriteKit : Moving Sprites

This is my first post and I am trying to use Apple's SpriteKit framework.
I believe I have a misunderstanding of how to move sprites using the framework. I have a simple example where I would like to move a hero in a simple UP, DOWN, LEFT, RIGHT direction based on the a tap location, respective to the "hero" location. Once the hero hits a block the "hero" should stop.
For testing purposes I am just trying to tap above the "hero" hit the wall of blocks on the top of the screen. Then after the collision occurs, tap below the "hero". I was expecting the "hero" to move toward the wall of blocks on the bottom row; however it seem that the "hero" continues to move UP and through the top wall. I am sure I am making a fundamental flaw, I would appreciate any help.
Thanks
Here is the sample scene I wrote:
static inline CGPoint CGPointSubtract(const CGPoint a, const CGPoint b)
{
return CGPointMake(a.x - b.x, a.y - b.y);
}
typedef enum DIRECTION_e
{
UP,
DOWN,
LEFT,
RIGHT
} DIRECTION_t;
typedef NS_OPTIONS(uint32_t, CNPhysicsCategory)
{
PhysicsCategoryBlock = 1 << 0,
PhysicsCategoryHero = 1 << 1
};
#interface LevelScene ()
#property (nonatomic) SKSpriteNode * hero;
#property (nonatomic) BOOL inMotion;
#end
#implementation LevelScene
-(id) initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
[self createLevel];
[self createHero];
self.inMotion = NO;
}
return self;
}
- (void) createHero
{
[self addHeroAtRow:5 column:2];
}
- (void) createLevel
{
self.backgroundColor = [SKColor blackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
[self addBlockAtRow:1 column:1];
[self addBlockAtRow:1 column:2];
[self addBlockAtRow:1 column:3];
[self addBlockAtRow:10 column:1];
[self addBlockAtRow:10 column:2];
[self addBlockAtRow:10 column:3];
}
- (void) addBlockAtRow:(NSInteger)row column:(NSInteger)column
{
SKSpriteNode *block = [[SKSpriteNode alloc] initWithColor:[SKColor brownColor] size:CGSizeMake(64,64)];
block.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
block.name = #"block";
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size];
block.physicsBody.dynamic = NO;
block.physicsBody.categoryBitMask = PhysicsCategoryBlock;
block.physicsBody.collisionBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
block.physicsBody.contactTestBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
[self addChild:block];
}
- (void) addHeroAtRow:(NSInteger)row column:(NSInteger)column
{
self.hero = [[SKSpriteNode alloc] initWithColor:[SKColor redColor] size:CGSizeMake(64,64)];
self.hero.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
self.hero.name = #"hero";
self.hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.hero.size.width/2, self.hero.size.height/2)];
self.hero.physicsBody.usesPreciseCollisionDetection = YES;
self.hero.physicsBody.dynamic = YES;
self.hero.physicsBody.categoryBitMask = PhysicsCategoryHero;
self.hero.physicsBody.collisionBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
self.hero.physicsBody.contactTestBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
[self addChild:self.hero];
NSLog(#"ADDING HERO: %f, %f", self.hero.position.x, self.hero.position.y);
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
if (contact.bodyA.categoryBitMask == PhysicsCategoryBlock && contact.bodyB.categoryBitMask == PhysicsCategoryHero)
{
[self.hero removeAllActions];
self.hero.position = contact.bodyB.node.position;
NSLog(#"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
}
else if (contact.bodyB.categoryBitMask == PhysicsCategoryBlock && contact.bodyA.categoryBitMask == PhysicsCategoryHero)
{
[self.hero removeAllActions];
self.hero.position = contact.bodyA.node.position;
NSLog(#"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
}
}
- (void) moveHeroTowardDirection:(DIRECTION_t)direction
{
CGPoint location;
switch (direction)
{
case UP:
{
location = CGPointMake(self.hero.position.x, self.hero.position.y + 600);
}
break;
case DOWN:
{
location = CGPointMake(self.hero.position.x, self.hero.position.y + -600);
}
break;
case LEFT:
{
location = CGPointMake(self.hero.position.x + -600, self.hero.position.y);
}
break;
case RIGHT:
{
location = CGPointMake(self.hero.position.x + 600, self.hero.position.y);
}
break;
default: return;
}
NSLog(#"MOVE POSITION: %f, %f", location.x, location.y);
SKAction *action = [SKAction moveTo:location duration:10];
[self.hero runAction:action];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.inMotion)
return;
self.inMotion = YES;
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
CGPoint diff = CGPointSubtract(self.hero.position, touchLocation);
NSLog(#"TOUCH POSITION: %f, %f", touchLocation.x, touchLocation.y);
NSLog(#"HERO POSITION: %f, %f", self.hero.position.x, self.hero.position.y);
NSLog(#"DIFF POSITION: %f, %f", diff.x, diff.y);
//
// Magnitude to find out which direction is dominate
//
if (abs(diff.x) > abs(diff.y))
{
if (touchLocation.x > self.hero.position.x)
{
NSLog(#"LEFT");
[self moveHeroTowardDirection:LEFT];
}
else
{
NSLog(#"RIGHT");
[self moveHeroTowardDirection:RIGHT];
}
}
else
{
if (touchLocation.y < self.hero.position.y)
{
NSLog(#"UP");
[self moveHeroTowardDirection:UP];
}
else
{
NSLog(#"DOWN");
[self moveHeroTowardDirection:DOWN];
}
}
}
#end
Here try this, you need to remove/disable your touches ended as well
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
CGPoint diff = CGPointMake(location.x - self.hero.position.x, location.y - self.hero.position.y);
CGFloat angleRadians = atan2f(diff.y, diff.x);
[self.hero runAction:[SKAction sequence:#[
[SKAction rotateToAngle:angleRadians duration:1.0],
[SKAction moveByX:diff.x y:diff.y duration:3.0]
]]];
}
}
}

Resources