I know that this question has been "asked" here but it was not helpful, nor did it cover what I am asking.
That being said, I want to know how to achieve the following:
node
that has 2 physics bodies: 1) a smaller body (200x200) that represents the node's frame, and 2) a larger body (500x500) that represents an outer perimeter of an area that will act as a "detection" boundary. The outer body will not physically impact colliding objects, it just needs to register that an object has encountered that boundary line. Below is a simple idea of what I am describing:My initial approach was to use SKPhysicsBody bodyWithBodies:<NSArray>
but that would have just created the overlap body as the smaller rect.
So I figured I would have to create an SKSpriteNode
for the smaller body (the black square), and another SKSpriteNode
for the larger body (the blue square), and add it as a child to the smaller square (or vice versa).
My problem is that I can't seem to get the outer boundary to allow another object to pass through while registering that interaction. The closest I have come is getting a movable node to hit the boundary, then continually get pushed back and forth along the line of the 500x500 boundary as long as I attempt to pass through the boundary. I have been able to make the moving node UNABLE to pass through the 500x500, but this is quite the opposite of what I need.
Here is the code that I am using, perhaps someone can see something I am doing wrong:
/// TESTING
// Detection body - 500x500
SKSpriteNode *dbody = [SKSpriteNode spriteNodeWithImageNamed:@"object500"];
dbody.position = CGPointMake(500, 100);
dbody.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:dbody.frame];
dbody.physicsBody.categoryBitMask = detection;
dbody.physicsBody.collisionBitMask = 0;
dbody.physicsBody.contactTestBitMask = player;
// Node body - 200x200
SKSpriteNode *testBoundary = [SKSpriteNode spriteNodeWithImageNamed:@"object"];
testBoundary.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:testBoundary.frame];
testBoundary.physicsBody.categoryBitMask = object;
testBoundary.physicsBody.contactTestBitMask = player;
testBoundary.position = dbody.position;
// Add boundary as child to main node
[testBoundary addChild:dbody];
// Add to scene
[chapterScene addChild:dbody];
All of this is inside LevelScene.m, an SKScene
set with <SKPhysicsContactDelegate>
in the header. Also, I have defined chapterScene
as such:
// Set up main chapter scene
self.anchorPoint = CGPointMake(0.5, 0.5); //0,0 to 1,1
chapterScene = [SKNode node];
[self addChild:chapterScene];
, with chapterScene
defined at the top of LevelScene.
@interface LevelScene () {
#pragma 1 Scene objects
SKNode *chapterScene;
}
If someone can help me figure out what I am doing wrong, or perhaps an alternative approach that would give me what I am looking for I would appreciate it.
NOTE: My backup solution would be seemingly expensive in terms of CPU and memory, but I believe it would work nonetheless. I would have a BOOL isDetected
to represent if the moving player node IS within the 500x500 area, then in update
I would monitor the distance to a smaller 200x200 rect boundary of the center of the 500x500 node. But I would much rather use the 2 SKPhysicsBody
's as I am sure it can be done and would be much easier to implement.
UPDATE:
here is my moving character (a separate SKNode
class called Character.m)
- (void)createCharacterWithName:(NSString *)charName {
character = [SKSpriteNode spriteNodeWithImageNamed:charName];
[self addChild:character];
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:character.frame.size.width/2.0];
self.physicsBody.dynamic = YES;
self.physicsBody.allowsRotation = YES;
// Define physics body relationships
self.physicsBody.categoryBitMask = player;
self.physicsBody.collisionBitMask = player;
self.physicsBody.contactTestBitMask = detection;
}
Here is an image of my simulator (it is a little different, in terms of sizes, as my description. My description was for ease of understanding not the exact scaling of the nodes)
this is working for me. sorry i didnt write it on obj c. just a lot faster for me in swift
import SpriteKit
let CategoryOuter:UInt32 = 1 << 0
let CategoryInner:UInt32 = 1 << 1
let CategoryTester:UInt32 = 1 << 2
class GameScene: SKScene, SKPhysicsContactDelegate {
let outerSprite = SKSpriteNode(color: SKColor.redColor(), size: CGSizeMake(100, 100))
let innerSprite = SKSpriteNode(color: SKColor.blueColor(), size: CGSizeMake(40, 40))
let tester = SKSpriteNode(color: SKColor.greenColor(), size: CGSizeMake(10, 10))
override init(size: CGSize) {
super.init(size: size)
physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVectorMake(0, 0)
outerSprite.position = CGPointMake(size.width/2, size.height/2)
outerSprite.physicsBody = SKPhysicsBody(rectangleOfSize: outerSprite.size)
outerSprite.physicsBody!.dynamic = false
outerSprite.physicsBody!.categoryBitMask = CategoryOuter
outerSprite.physicsBody!.collisionBitMask = 0
outerSprite.physicsBody!.contactTestBitMask = CategoryTester
innerSprite.physicsBody = SKPhysicsBody(rectangleOfSize: innerSprite.size)
innerSprite.physicsBody!.dynamic = false
innerSprite.physicsBody!.categoryBitMask = CategoryInner
innerSprite.physicsBody!.collisionBitMask = CategoryTester
innerSprite.physicsBody!.contactTestBitMask = CategoryTester
outerSprite.addChild(innerSprite)
addChild(outerSprite)
tester.physicsBody = SKPhysicsBody(rectangleOfSize: tester.size)
tester.physicsBody!.categoryBitMask = CategoryTester
tester.physicsBody!.collisionBitMask = CategoryInner
addChild(tester)
}
func didBeginContact(contact: SKPhysicsContact) {
let collision:UInt32 = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask)
if collision == (CategoryOuter | CategoryTester) {
print("outer collision")
}
else if collision == (CategoryInner | CategoryTester) {
print("inner collision")
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
let location = touch.locationInNode(self)
tester.position = location
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}