简体   繁体   中英

Weird collision detection with SKShapeNode (SpriteKit)

I am trying to detect collision between a square SkShapeNode and a circle SkShapeNode . It basically works, but it seems the hitbox/physics body is not really aligned to the node shape. It seems to be randomly off 10-20 points.

This is my code:

SKShapeNode* circle= [SKShapeNode shapeNodeWithCircleOfRadius:7.0];
circle.physicsBody= [SKPhysicsBody bodyWithCircleOfRadius:7.0];
circle.physicsBody.usesPreciseCollisionDetection= YES;
circle.physicsBody.categoryBitMask= catCircle;
circle.physicsBody.contactTestBitMask= catSquare;

circle.position= CGPointMake(x, y);
[self addChild:circle];

SKShapeNode* square= [SKShapeNode shapeNodeWithRect:rect];
square.position= position;
square.physicsBody= [SKPhysicsBody bodyWithRectangleOfSize:rect.size];
square.physicsBody.categoryBitMask= catSquare;
square.physicsBody.contactTestBitMask= catCircle;
square.physicsBody.dynamic= YES;
square.physicsBody.usesPreciseCollisionDetection= YES;

[self addChild:square];

I am triggering the collision by moving the square shape (circle remains in position):

[square runAction:[SKAction moveTo:somePoint duration:2]];

I'm canceling the action via removeAllActions in didBeginContact as soon as collision is detected.

This is how it looks like:

在此处输入图片说明

As you can see, the square does not stop once it touches the circle, but some points before/after that.

What am I doing wrong?

I am not sure how the CD works with IOS but this could be normal behaviour, normally with collision detection when you have detected that a collision has happened your object would be inside the other object as you are seeing above. once a collision occurs you need to move the object back a frame to when it hadn't collided.

You can do this by storing the position from the previous frame each time and when collision occurs set the object back to the previous position.

I had the exact same issue (Xcode 7, iOS 9), however in my case the issue seemed to be isolated only to the simulator. When I ran the same code on a device it worked as expected.

UPDATE :

It appears that the issue that I was experiencing was different from yours. However, I figured out why you were experiencing the offset in your physics body. To understand better in your code, add the following line (preferably someplace in the view controller):

    skView.showsPhysics = YES;

The above code will show you the outline of the physics body and this is what you will see (the blue outline represents the physics body).

在此处输入图片说明

The class method that you chose to instantiate your square was causing this side effect, namely:

    SKShapeNode* square= [SKShapeNode shapeNodeWithRect:rect];

Creates a shape node with a rectangular path. (According to Apple's Docs)

Parameters rect
A rectangle, relative to the node's origin

Instead use this method to create your square and things will behave as expected:

    SKShapeNode* square= [SKShapeNode shapeNodeWithRectOfSize:rect.size];

Creates a shape node with a rectangular path centered on the node's origin.

If you still intend to use:

        SKShapeNode* square= [SKShapeNode shapeNodeWithRect:rect];

then you'll have to make sure you set 'rect' according to the following:

rect = CGRectMake(-someWidth/2, -someHeight/2, someWidth, someHeight)

The above will make sure that the physicsBody lines up with the shape node's path.

As for understanding why this is happening... When you create the square shape node using:

SKShapeNode* square = [SKShapeNode shapeNodeWithRect:rect];

if rect = CGRectMake(50.0, 50.0, 100.0, 100.0), then you are creating a SKShapeNode and giving it a rectangular shape that has its bottom left corner positioned at point (50.0, 50.0), relative to the SKShapeNode.

When you later create the physicsBody using:

square.physicsBody= [SKPhysicsBody bodyWithRectangleOfSize:rect.size];

The position of the physicsBody is being set by default relative to the origin of its node (SKShapeNode) and NOT the shape (which is a CGPathRef). I know it sounds a bit confusing however I hope it shed some light.

The position of the node is relative to its parent node (in your case it's the scene), while the position of the shape belonging to a SKShapeNode is relative to its node. By Instantiating your square shape node using:

SKShapeNode* square= [SKShapeNode shapeNodeWithRectOfSize:rect.size]

you're ensuring that your shape lines up with your node.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM