【问题标题】:Node with Two Physics Bodies具有两个物理实体的节点
【发布时间】:2016-02-08 19:45:22
【问题描述】:

我知道这个问题已被“询问”here,但它没有帮助,也没有涵盖我的问题。

话虽如此,我想知道如何实现以下目标:

  • 我需要一个node,它有 2 个物理实体:1) 一个较小的实体 (200x200),代表节点的框架,2) 一个较大的实体 (500x500),代表一个区域的外围,它将充当“检测”边界。外体不会物理地撞击碰撞的物体,它只需要记录一个物体已经遇到了那个边界线。以下是我所描述内容的一个简单概念:

我最初的方法是使用SKPhysicsBody bodyWithBodies:<NSArray>,但这只会将重叠主体创建为较小的矩形。

所以我想我必须为较小的主体(黑色方块)创建一个SKSpriteNode,为较大的主体(蓝色方块)创建另一个SKSpriteNode,并将其作为子对象添加到较小的方块中(或相反亦然)。

我的问题是我似乎无法在注册该交互时获得外边界以允许另一个对象通过。我最接近的是让一个可移动节点到达边界,然后只要我试图穿过边界,就会不断地沿着 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 集,标题中带有 <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];

chapterScene 定义在 LevelScene 的顶部。

@interface LevelScene () {

#pragma 1 Scene objects
    SKNode *chapterScene;

}

如果有人可以帮助我找出我做错了什么,或者也许可以提供一种替代方法来满足我的需求,我将不胜感激。

注意:我的备份解决方案在 CPU 和内存方面似乎很昂贵,但我相信它仍然可以工作。我将有一个BOOL isDetected 来表示移动的玩家节点是否在 500x500 区域内,然后在update 中,我将监控到 500x500 节点中心的较小 200x200 矩形边界的距离。但我更愿意使用 2 个SKPhysicsBody,因为我确信它可以完成并且更容易实现。

更新: 这是我的移动角色(一个名为 Character.m 的单独 SKNode 类)

- (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;

}

这是我的模拟器的图像(根据我的描述,它的大小有点不同。我的描述是为了便于理解,而不是节点的精确缩放)

【问题讨论】:

  • 你介意我用swift写一个答案吗?
  • 哈哈继续 - 我肯定会翻译它
  • 好的,让我自己试试。你想要一个对象通过外部区域..并注册它。并且你想与内部碰撞..对
  • 是的,正是我需要的
  • 您的 2 sprite 代码无法正常工作的原因是因为使用带循环的边意味着动态总是错误的,因此对象永远不会注册命中玩家。您需要将对象添加到玩家接触测试中

标签: ios sprite-kit skspritenode skphysicsbody


【解决方案1】:

这对我有用。抱歉,我没有在 obj c 上写它。对我来说很快就快了很多

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")
    }
}

【讨论】:

  • 我仍然无法通过outerSprite body..我不知道为什么它不起作用
  • 穿过内外边界的精灵是什么样子的?
  • 现在是一个带有地球 (PNG) 图像的圆圈。我没有使用您提供的那个,但是无论如何我的设置方式完全相同。我很困惑为什么它不起作用 - 我完全理解为什么你发布的内容会起作用,以及我的应该如何工作。它只是行为不正确
  • 你能展示一下你的三个物理体吗?它应该工作。如果你愿意,我可以提供我的工作视频
  • 比较我的和你的……他们真的很不一样。你需要这个:testBoundary.physicsBody.collisionBitmask = player;使玩家collisionBitmask =对象,并删除那个人的contactTestBitmask ..你没有按照我的例子:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多