在SKNode上挖一个洞并在Swift中更新它的physicsBody

时间:2016-07-12 23:10:05

标签: swift cut skphysicsbody

我正在创建一个应用程序,其中包含图像上的一些洞。 由于代码非常大,我创建了这个具有相同想法的简单代码。 这段代码的图像已经设置了物理实体。

我想要的是touchesBegan功能在触摸位置绘制一些透明圆圈并更新图像physicsBody(在图像上打洞)。

我在目标C和UIImage中找到了几个代码,有人可以帮助Swift和SKSpriteNode吗?

import SpriteKit

class GameScene: SKScene {
    override func didMoveToView(view: SKView) {
        let texture = SKTexture(imageNamed: "Icon.png")
        let node = SKSpriteNode(texture: texture)
        node.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
        addChild(node)

        node.physicsBody = SKPhysicsBody(rectangleOfSize: texture.size())
        node.physicsBody?.dynamic = false

    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {



    }

}

1 个答案:

答案 0 :(得分:2)

一个选项是应用蒙版并将其渲染到图像并更新SKSpriteNode's纹理。然后使用该纹理来确定物理体。然而,这个过程不会很有效。

例如在touchesBegan中,你可以这样说:

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        guard let touch = touches.first else { return }
        if let node = self.nodeAtPoint(touch.locationInNode(self.scene!)) as? SKSpriteNode{

            let layer = self.layerFor(touch, node: node) // We'll use a helper function to create the layer

            let image = self.snapShotLayer(layer) // Helper function to snapshot the layer
            let texture = SKTexture(image:image)
            node.texture = texture

            // This will map the physical bounds of the body to alpha channel of texture. Hit in performance
            node.physicsBody = SKPhysicsBody(texture: node.texture!, size: node.size) 
        }
    }

这里我们只是获取节点并查看第一次触摸,您可以推广以允许多点触摸,但我们然后创建一个具有透明度的新图像的图层,然后从中创建纹理,然后更新节点的物理体。

要创建图层,您可以说:

    func layerFor(touch: UITouch, node: SKSpriteNode) -> CALayer
    {
        let touchDiameter:CGFloat = 20.0

        let layer = CALayer()
        layer.frame = CGRect(origin: CGPointZero, size: node.size)
        layer.contents = node.texture?.CGImage()

        let locationInNode = touch.locationInNode(node)

        // Convert touch to layer coordinate system from node coordinates
        let touchInLayerX = locationInNode.x + node.size.width * 0.5 - touchDiameter * 0.5 
        let touchInLayerY = node.size.height - (locationInNode.y + node.size.height * 0.5) - touchDiameter * 0.5

        let circleRect = CGRect(x: touchInLayerX, y: touchInLayerY, width: touchDiameter, height: touchDiameter)
        let circle = UIBezierPath(ovalInRect: circleRect)

        let shapeLayer = CAShapeLayer()
        shapeLayer.frame = CGRect(x: 0.0, y: 0.0, width: node.size.width, height: node.size.height)
        let path = UIBezierPath(rect: shapeLayer.frame)
        path.appendPath(circle)
        shapeLayer.path = path.CGPath
        shapeLayer.fillRule = kCAFillRuleEvenOdd

        layer.mask = shapeLayer
        return layer
    }

这里我们只将当前纹理设置为CALayer的内容,然后为我们想要创建的蒙版创建CAShapeLayer。我们希望遮罩对于大部分图层都是不透明的,但我们想要一个透明的圆圈,所以我们创建一个矩形的路径,然后为它添加一个圆圈。我们将fillRule设置为kCAFillRuleEvenOdd以填充除我们圈子以外的所有内容。

最后,我们将该图层渲染为可用于更新纹理的UIImage。

    func snapShotLayer(layer: CALayer) -> UIImage
    {
        UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, 0.0)
        let context = UIGraphicsGetCurrentContext()
        layer.renderInContext(context!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }

也许某人会提供更高效的方法来实现这一目标,但我认为这会适用于很多情况。