【问题标题】:Collision between two objects not detected after performing a move action on one of them对其中一个执行移动操作后未检测到两个对象之间的碰撞
【发布时间】:2016-06-24 21:16:06
【问题描述】:

我似乎对SpriteKit 中与碰撞检测、动作或位置相关的内容了解甚少。

我有一个玩家和积木,当一个玩家落在任何积木上时,他会跳过积木,然后所有积木都会向下移动一段距离。我将玩家添加为场景的子节点,将砖块添加为包含它们的节点 (SKNode) 的子节点。当我想改变它们的 y 位置时,我只需在该节点上使用 moveBy 操作,砖块确实会按照我想要的方式移动。

问题是,当他们移动甚至停止时,玩家不能再降落在他们身上(他们和玩家之间的碰撞不再被检测到),所以玩家只是从他们身上掉下来。

这是我在GameScene.swift中的代码:

func moveBricksDownFor(movedForY: CGFloat) {
    let moveAction = SKAction.moveBy(CGVectorMake(0, -movedForY), duration: 1.0)
    brickNode.runAction(moveAction)
    for _ in 0...4 {addBrick(0.7)}
}

func playerCollidedWithBrick(brick: Brick) {
    if player.position.y > brick.position.y {
        player.physicsBody?.velocity.dy = player.maxVelocityY
    }
    if player.yChangedFor() > 70 {moveBricksDownFor(player.yChangedFor())}
}

物理体是否可能没有附加到砖块的视觉表示或类似的东西上?

这里也是Player类(上面代码中用到的部分):

let maxVelocityY: CGFloat = 900
var startPositionY: CGFloat!

init(position: CGPoint) {
    let texture = SKTexture(imageNamed: "doodler.png")
    super.init(texture: texture, color: UIColor.blackColor(), size: CGSizeMake(60, 60))
    self.zPosition = Layer.player.rawValue
    self.position = position
    self.startPositionY = position.y
    self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
    self.physicsBody?.affectedByGravity = true
    self.physicsBody?.allowsRotation = false
    self.physicsBody?.dynamic = true
    self.physicsBody?.categoryBitMask = PhysicsCategory.Player
    self.physicsBody?.contactTestBitMask = PhysicsCategory.Brick
    self.physicsBody?.collisionBitMask = PhysicsCategory.None
    self.physicsBody?.usesPreciseCollisionDetection = true
}

func yChangedFor() -> CGFloat {
    return (self.position.y - startPositionY)
}

我在谷歌上搜索了类似的主题,但没有发现任何类似的问题,所以我想我在这里遗漏了一些基本的东西,或者犯了一个愚蠢的错误。

更新(添加Brick类和worldNode的初始化(SKNode)):

class Brick: SKSpriteNode { 
    init(position:CGPoint) {
        let texture = SKTexture(imageNamed: "brick.png")
        super.init(texture: texture, color: UIColor.clearColor(), size: CGSizeMake(70, 10))
        self.position = position
        self.zPosition = Layer.brick.rawValue
        self.physicsBody = SKPhysicsBody(rectangleOfSize: self.size)
        self.physicsBody?.affectedByGravity = false
        self.physicsBody?.allowsRotation = true
        self.physicsBody?.dynamic = false
        self.physicsBody?.categoryBitMask = PhysicsCategory.Brick
        self.physicsBody?.contactTestBitMask = PhysicsCategory.Player
        self.physicsBody?.collisionBitMask = PhysicsCategory.None
        self.physicsBody?.usesPreciseCollisionDetection = true
    }
}

设置brickNode 并将砖块添加到它的子代:

func setupBrickNode() {
    brickNode.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
    brickNode.physicsBody?.affectedByGravity = false
}

func addBrick(minXPercantage: CGFloat) {
    let randomX = random(min: size.width*0.25, max: size.width - 100)
    let randomY = random(min: size.height*minXPercantage, max: size.height)
    let brick = Brick(position: CGPointMake(randomX, randomY))
    brickNode.addChild(brick)
}

func setupBricks() {
    for _ in 0...10 {addBrick(0.25)}
}

更新了我移动 brickNode 的部分(现在设置了它的速度):

func moveBricks() {
    brickNode.physicsBody?.velocity = CGVectorMake(0, -player.maxVelocityY/4)
    let waitAction = SKAction.waitForDuration(1.0)
    let setBrickNodeVelocityToZero = SKAction.runBlock({self.brickNode.physicsBody?.velocity = CGVectorMake(0, 0)})
    runAction(SKAction.sequence([waitAction, setBrickNodeVelocityToZero]))
}

func playerCollidedWithBrick(brick: Brick) {
    if player.position.y > brick.position.y {
        player.physicsBody?.velocity.dy = player.maxVelocityY
        moveBricks()
    }
}

【问题讨论】:

  • 看我的第二个回答。希望对您有所帮助。

标签: swift sprite-kit


【解决方案1】:

示例代码

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {
    var world: SKNode!
    var player: SKSpriteNode!

    override func didMoveToView(view: SKView) {
        physicsWorld.contactDelegate = self
        physicsWorld.gravity = CGVector(dx: 0, dy: -10)

        // World
        world = SKNode()
        addChild(world)

        // Player
        player = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 50, height: 50))
        player.position.x = size.width / 2

        player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
        player.physicsBody!.categoryBitMask = 2
        player.physicsBody!.contactTestBitMask = 4
        player.physicsBody!.collisionBitMask = 0
        player.physicsBody!.mass = 1
        player.physicsBody!.velocity = CGVector(dx: 0, dy: 2000)
        player.physicsBody!.usesPreciseCollisionDetection = true

        world.addChild(player)

        // Bricks
        for index in 0...50 {
            // Player
            let brick = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 100, height: 25))
            brick.position = CGPoint(x: size.width / 2, y: 300 + CGFloat(index) * 200)
            brick.zPosition = -1

            brick.physicsBody = SKPhysicsBody(rectangleOfSize: brick.size)
            brick.physicsBody!.categoryBitMask = 4
            brick.physicsBody!.contactTestBitMask = 2
            brick.physicsBody!.collisionBitMask = 0
            brick.physicsBody!.dynamic = false

            world.addChild(brick)
        }
    }

    func didBeginContact(contact: SKPhysicsContact) {
        // Is the player falling?
        guard player.physicsBody!.velocity.dy <= 0 else {
            return
        }

        player.physicsBody!.velocity = CGVector(dx: 0, dy: 1000)
    }

    override func didFinishUpdate() {
        guard player.position.y > 200 else {
            return
        }

        world.position.y = -player.position.y + 200
    }
}

【讨论】:

    【解决方案2】:

    如果你想降落到一个动态涉及的对象,你可能必须设置这个。

    self.physicsBody!.restitution = 0
    

    此外,使用 SKAction 的 moveBy 而非通过速度或力矢量进行正确运动并不是最好的姿态,这可能会改变您的物理对象值并且您会失去方向。

    【讨论】:

    • 我不知道,谢谢。你能解释一下为什么我应该将恢复原状设为零吗?除了在碰撞发生时使它们反弹之外,这是否会以其他方式影响物理体?
    【解决方案3】:

    因为特定的砖块位置总是相同的。您正在移动它的父级而不是砖块本身。

    let realBrickPosition = convertPoint(brick.position, toNode: self)  
    

    【讨论】:

    • 您确定这是问题所在吗?那么玩家不是会在错误的地方发生碰撞,但仍然会碰撞并跳跃一些东西吗?在移动之前,他会从落地的每一块砖上跳下来,但如果我试图移动它们,他就无法落在其中任何一块上,只会从它们身上掉下来。
    • 不看游戏很难判断。我只会使用 didBeginContact / didEndContact 来检测...砖块和玩家之间的接触。
    • 砖有物理体吗?
    • 是的,我确实使用 didBeginContact 来检测碰撞。它们被设置为不会与砖块发生碰撞,但在接触时会联系 SKPhysicsContact,然后调用 playerCollidedWithBrick 函数,这会使玩家跳跃并移动brickNode,这是一个包含所有砖块的SKNode。
    • 我尝试通过设置它的速度来移动brickNode,但同样的事情发生了——没有检测到玩家和砖块之间的碰撞。使用有子节点的 SKNode 并移动它而不是单独移动每个子节点是错误的方法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-19
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多