iOS 8 检测 SKSpriteNode 是不是被 SKLightNode 点亮

Posted

技术标签:

【中文标题】iOS 8 检测 SKSpriteNode 是不是被 SKLightNode 点亮【英文标题】:iOS 8 detect if SKSpriteNode is lit by SKLightNodeiOS 8 检测 SKSpriteNode 是否被 SKLightNode 点亮 【发布时间】:2015-06-10 16:30:52 【问题描述】:

我的场景中有几个精灵节点正在投射阴影。我还有一个位于其中一个阴影中的精灵。我希望能够判断用户是否将精灵从阴影中移到光中。无论如何要迅速做到这一点?谢谢。

【问题讨论】:

【参考方案1】:

不幸的是,SpriteKit 中仍然不包含此功能,但是可以通过一些注意事项实现一个体面的解决方案。

为了确定一个精灵是否投射阴影,它的shadowCastBitMask 属性“通过执行逻辑与运算针对灯光的categoryBitMask 属性进行测试”。根据SKLightNode 上定义的shadowColor 属性的文档中给出的描述,SpriteKit 似乎为光照和物理体计算生成完全相同的掩码数据:

在计算光照时,会像投射光线一样创建阴影 从灯光节点的位置出来。如果精灵投下阴影, 射线与精灵的物理体相交时会被阻挡。 否则,精灵的纹理用于生成遮罩,并且任何 精灵节点纹理中具有 alpha 值的像素 非零挡住了光。

SKPhysicsWorld 有一个方法,enumerateBodies(alongRayStart:end:using:),可以高效地执行这种光线相交测试。这意味着我们可以测试一个精灵是否被任何具有物理体的精灵所遮蔽。所以我们可以写一个这样的方法来扩展SKSpriteNode

func isLit(by light: SKLightNode) -> Bool 
    guard light.isEnabled else 
        return false
    

    var shadowed = false

    scene?.physicsWorld.enumerateBodies(alongRayStart: light.position, end: position)  (body, _, _, stop) in
        if let sprite = body.node as? SKSpriteNode, light.categoryBitMask & sprite.shadowCastBitMask != 0 
            shadowed = true

            stop.pointee = true
        
    

    if shadowed 
        return false
     else 
        return true
    

我们还可以检索场景中的哪些灯光正在照亮特定的精灵:

func lights(affecting sprite: SKSpriteNode) -> [SKLightNode] 
    let lights = sprite.scene?.children.flatMap  (node) -> SKLightNode? in
        node as? SKLightNode
     ?? []

    return lights.filter  (light) -> Bool in
        sprite.isLit(by: light)
    

如果 SpriteKit 提供了一种方法来检索此信息而不将其耦合到物理 API,或者要求开发人员滚动他们自己的光线投射实现,那就太好了。

【讨论】:

以上是关于iOS 8 检测 SKSpriteNode 是不是被 SKLightNode 点亮的主要内容,如果未能解决你的问题,请参考以下文章

无法点击 SKSpriteNode - 未检测到触摸 ios

未检测到 SKSpriteNode 触摸

iOS 8 中的 SKSpriteNode 池似乎分配给了重叠的内存

快速检测到 SKSpriteNode 触摸

检测 CGPoint 是不是在正方形(菱形)内的问题

如何检测 SKSpriteNode 接触但不反应?