2016-07-12 52 views
0

我正在創建一個應用程序,它將在圖像上包含一些洞。 由於代碼非常大,我創建了這個具有相同想法的簡單代碼。 這段代碼有一個圖像,它已經設置了physicsBody。在SKNode上挖一個洞並在Swift中更新它的physicsBody

我想在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?) { 



    } 

} 
+0

物理體對節點的視覺外觀沒有影響。你是否試圖削減節點中的視覺洞,物理體中的物理洞或兩者? – andyvn22

+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 
    } 

也許有人會提供實現這個更高性能的方式,但我認爲這會爲很多的情況下工作。

+0

beyowulf您的解決方案完美工作,雖然我認爲它會更小,也許更簡單。我想可能有更簡單的方法來做到這一點?儘管如此,我會等一會兒,看看別人或者你是否有更簡單的方法,否則我會將其標記爲正確的!非常感激! –