在被光线投射击中时将SKSpriteNode.isHidden更改为false,否则将其设置为true

时间:2019-03-27 10:12:23

标签: ios swift sprite-kit

我正在尝试在2d游戏中创建视线/视野,并且遇到一些问题。我目前正在尝试使用raycast作为解决方案。这个想法是默认情况下,我所有的敌人节点都具有isHidden = true。当射线投射击中它们时,应将其值更改为false,而当射线投射不再击中它们时,应将其更改回true

我在这里搞了很多不同的选择。我尝试跟踪建议的here这样的raycast命中变量。

我目前在if-else语句中设置了它来处理它,但是如果光线投射被击中,最终会导致精灵闪烁进出,如果原来是isHidden = false,它将离开。

 scene?.physicsWorld.enumerateBodies(alongRayStart: rayStart, end: rayEnd) { (body, point, normal, stop) in
    let sprite = body.node as? SKSpriteNode
    if body.categoryBitMask == 2 {
        sprite?.isHidden = true
    }else if body.categoryBitMask == 1 {

    } else { sprite?.isHidden = true }
}

我将上面的代码作为函数的一部分,然后在update()函数中调用。

我希望仅当当前被射线广播击中时,子画面才具有isHidden = false的值。不幸的是,它不是那样工作的。

2 个答案:

答案 0 :(得分:1)

我首先将所有敌人放在场景中的特殊节点容器中,然后在投射射线之前,使用forloop重置敌人isHidden属性。

enemyContainer.children.forEach{$0.isHidden = false}
scene?.physicsWorld.enumerateBodies(alongRayStart: rayStart, end: rayEnd) { (body, point, normal, stop) in
    if let sprite = body.node as? SKSpriteNode,sprite.categoryBitMask & ~0b1 \\Replace 0b1 with your category bit mask constant if you created one
        sprite.isHidden = true
    }
}

与E.Coms的答案相反,这将使您立即确定灯光是否正在触摸敌人,而E.Coms的答案只会告诉您何时在物理更新阶段击中了敌人

如果您不希望将敌人放在特殊的容器中,则可以创建一个数组,并仅存储上次投射射线时接触过的数组

//Global to class
var nodesInLight = [SKNode]()

.......

//in func

nodesInLight.forEach{$0.isHidden = false}
nodesInLight = [SKNode]() //Allow ARC to remove the previous container, instead of calling clear on it
scene?.physicsWorld.enumerateBodies(alongRayStart: rayStart, end: rayEnd) { (body, point, normal, stop) in
    if let sprite = body.node as? SKSpriteNode,sprite.categoryBitMask & ~0b1 \\Replace 0b1 with your category bit mask constant if you created one
        sprite.isHidden = true
        nodesInLight.append(sprite)
    }
}

我会做的一项高级技术是创建一个弱引用数组,这样您就不会偶然创建一个保留周期

答案 1 :(得分:0)

在这种情况下,您可以给射线一个真实的物理体,并实现接触委托。在DidBegin功能中,将敌人打开。和DidEnd func,关闭敌人。

func didBegin(_ contact: SKPhysicsContact) {
    print("begin")

}

func didEnd(_ contact: SKPhysicsContact) {
     print("end")
}

override func didMove(to view: SKView) {
    view.showsPhysics = true

    let ray = SKShapeNode()

    ray.path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 1000, height: 20)).cgPath
    ray.fillColor = UIColor.red
    addChild(ray)
    ray.physicsBody = SKPhysicsBody(rectangleOf:(ray.path?.boundingBoxOfPath)!.size)
    ray.physicsBody?.affectedByGravity = false
    ray.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(Float.pi * 2), duration: 3)))
    ray.physicsBody?.contactTestBitMask = 1
      ray.physicsBody?.collisionBitMask = 0

    let enemy = SKSpriteNode(color: UIColor.green, size: CGSize.init(width: 100, height: 100))
     enemy.physicsBody = SKPhysicsBody(rectangleOf: enemy.frame.size)
     enemy.physicsBody?.affectedByGravity = false
     enemy.position = CGPoint(x: 200, y: 200)
     enemy.physicsBody?.contactTestBitMask = 1
     enemy.physicsBody?.collisionBitMask = 0
     addChild(enemy)
     enemy.isHidden = true
     physicsWorld.contactDelegate = self