我正在尝试在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
的值。不幸的是,它不是那样工作的。
答案 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