在 SKNode 上开一个洞并在 Swift 中更新它的 physicsBody
Cut a hole on SKNode and update its physicsBody in Swift
我正在创建一个应用程序,该应用程序将在图像上包含一些漏洞。
由于代码非常大,我创建了这个具有相同想法的简单代码。
此代码有一张图片,其中已经设置了 physicsBody。
我想要的是在touchesBegan函数中在触摸的位置绘制一些透明圆圈并更新图像physicsBody(在图像上打洞)。
我在 objective 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?) {
}
}
一种选择是应用蒙版并将其渲染到图像并更新 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
}
也许有人会提供一种更高效的方法来完成此操作,但我认为这适用于很多情况。
我正在创建一个应用程序,该应用程序将在图像上包含一些漏洞。 由于代码非常大,我创建了这个具有相同想法的简单代码。 此代码有一张图片,其中已经设置了 physicsBody。
我想要的是在touchesBegan函数中在触摸的位置绘制一些透明圆圈并更新图像physicsBody(在图像上打洞)。
我在 objective 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?) {
}
}
一种选择是应用蒙版并将其渲染到图像并更新 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
}
也许有人会提供一种更高效的方法来完成此操作,但我认为这适用于很多情况。