具有两个物理体的节点
Node with Two Physics Bodies
我知道这个问题已经 "asked" here 但它没有帮助,也没有涵盖我的问题。
话虽如此,我想知道如何实现以下目标:
- 我需要一个具有 2 个物理体的
node
:1) 较小的 body (200x200) 代表节点的框架,以及 2) 较大的 body (500x500)表示将充当 "detection" 边界的区域的外周长。外层 body 不会对碰撞的 object 产生物理影响,它只需要记录一个 object 已经遇到了那条边界线。以下是我所描述内容的简单概念:
我最初的方法是使用 SKPhysicsBody bodyWithBodies:<NSArray>
,但这只会创建重叠 body 作为较小的矩形。
所以我想我必须为较小的 body(黑色方块)创建一个 SKSpriteNode
,为较大的 body(黑色方块)创建另一个 SKSpriteNode
蓝色方块),并将其作为 child 添加到较小的方块(反之亦然)。
我的问题是,在注册该交互时,我似乎无法获得允许另一个 object 通过的外边界。我最接近的是让一个可移动节点撞到边界,然后只要我试图穿过边界,就会沿着 500x500 边界线不断地来回推动。我已经能够使移动节点无法通过 500x500,但这与我需要的完全相反。
这是我正在使用的代码,也许有人能看出我做错了什么:
/// 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];
所有这些都在 LevelScene.m 中,SKScene
集 header 中的 <SKPhysicsContactDelegate>
。另外,我这样定义 chapterScene
:
// Set up main chapter scene
self.anchorPoint = CGPointMake(0.5, 0.5); //0,0 to 1,1
chapterScene = [SKNode node];
[self addChild:chapterScene];
,在 LevelScene 的顶部定义了 chapterScene
。
@interface LevelScene () {
#pragma 1 Scene objects
SKNode *chapterScene;
}
如果有人可以帮助我弄清楚我做错了什么,或者可以提供一种替代方法来满足我的需求,我将不胜感激。
注意: 我的备份解决方案在 CPU 和内存方面似乎很昂贵,但我相信它仍然有效。我将有一个 BOOL isDetected
来表示移动玩家节点是否在 500x500 区域内,然后在 update
中我将监视到 500x500 节点中心的较小 200x200 矩形边界的距离。但我更愿意使用 2 SKPhysicsBody
,因为我确信它可以完成并且更容易实现。
更新:
这是我的移动角色(一个单独的 SKNode
class 称为 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;
}
这是我的模拟器的图片(就尺寸而言,它与我的描述略有不同。我的描述是为了便于理解,而不是节点的精确缩放)
这对我有用。对不起,我没有把它写在 objc 上。 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")
}
}
我知道这个问题已经 "asked" here 但它没有帮助,也没有涵盖我的问题。
话虽如此,我想知道如何实现以下目标:
- 我需要一个具有 2 个物理体的
node
:1) 较小的 body (200x200) 代表节点的框架,以及 2) 较大的 body (500x500)表示将充当 "detection" 边界的区域的外周长。外层 body 不会对碰撞的 object 产生物理影响,它只需要记录一个 object 已经遇到了那条边界线。以下是我所描述内容的简单概念:
我最初的方法是使用 SKPhysicsBody bodyWithBodies:<NSArray>
,但这只会创建重叠 body 作为较小的矩形。
所以我想我必须为较小的 body(黑色方块)创建一个 SKSpriteNode
,为较大的 body(黑色方块)创建另一个 SKSpriteNode
蓝色方块),并将其作为 child 添加到较小的方块(反之亦然)。
我的问题是,在注册该交互时,我似乎无法获得允许另一个 object 通过的外边界。我最接近的是让一个可移动节点撞到边界,然后只要我试图穿过边界,就会沿着 500x500 边界线不断地来回推动。我已经能够使移动节点无法通过 500x500,但这与我需要的完全相反。
这是我正在使用的代码,也许有人能看出我做错了什么:
/// 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];
所有这些都在 LevelScene.m 中,SKScene
集 header 中的 <SKPhysicsContactDelegate>
。另外,我这样定义 chapterScene
:
// Set up main chapter scene
self.anchorPoint = CGPointMake(0.5, 0.5); //0,0 to 1,1
chapterScene = [SKNode node];
[self addChild:chapterScene];
,在 LevelScene 的顶部定义了 chapterScene
。
@interface LevelScene () {
#pragma 1 Scene objects
SKNode *chapterScene;
}
如果有人可以帮助我弄清楚我做错了什么,或者可以提供一种替代方法来满足我的需求,我将不胜感激。
注意: 我的备份解决方案在 CPU 和内存方面似乎很昂贵,但我相信它仍然有效。我将有一个 BOOL isDetected
来表示移动玩家节点是否在 500x500 区域内,然后在 update
中我将监视到 500x500 节点中心的较小 200x200 矩形边界的距离。但我更愿意使用 2 SKPhysicsBody
,因为我确信它可以完成并且更容易实现。
更新:
这是我的移动角色(一个单独的 SKNode
class 称为 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;
}
这是我的模拟器的图片(就尺寸而言,它与我的描述略有不同。我的描述是为了便于理解,而不是节点的精确缩放)
这对我有用。对不起,我没有把它写在 objc 上。 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")
}
}