How to cut random holes in SKSpriteNodes

前端 未结 1 1558
广开言路
广开言路 2021-01-04 03:17

Aside from the fact that the question asked here : Draw a hole in a rectangle with SpriteKit? has not satisfactorily been answered in its own right, the most significant dif

1条回答
  •  -上瘾入骨i
    2021-01-04 03:33

    In my total honesty, I'm not really sure to understand deeply what do you want to achieve, but I can try to answer to this question:

    ..cutting random circles out of each slice of cheese?

    In this project I've try to re-build a typical rectangle (the piece of cheese) with random holes, then I've extract these holes and collect them to an array.

    import SpriteKit
    class GameScene: SKScene {
        struct Cheese
        {
            static let color1 = SKColor(red: 255/255, green: 241/255, blue: 173/255, alpha: 1)
            static let color2 = SKColor(red: 255/255, green: 212/255, blue: 0/255, alpha: 1)
            static let color3 = SKColor(red: 204/255, green: 170/255, blue: 0/255, alpha: 1)
            static let color4 = SKColor(red: 140/255, green: 116/255, blue: 0/255, alpha: 1)
        }
        let cheeseColor = [Cheese.color1,Cheese.color2,Cheese.color3,Cheese.color4]
        override func didMove(to view: SKView) {        
            let totHoles = randomNumber(range:4...8)
            let color = randomNumber(range:0...3)
            let cheeseCropNode = makeCheese(size: CGSize(width:400,height:200),color: cheeseColor[color], totHoles:totHoles)
            cheeseCropNode.position = CGPoint(x:0,y:-50)
            addChild(cheeseCropNode)
            // Start to collect and show holes
            var holes = [SKNode]()
            var counter = 1
            let _ = cheeseCropNode.enumerateChildNodes(withName: "//hole*", using:{ node, stop in
                // node is the hole
                let pos = self.convert(node.position, from: cheeseCropNode)
                let sprite = SKSpriteNode.init(color: .red, size: node.frame.size)
                sprite.position = pos
    
                //Remove these shapes, it's just to debug
                let shape = SKShapeNode.init(rect: sprite.frame)
                shape.strokeColor = .red
                self.addChild(shape)
                // -- end to remove
    
                let holeTxt = SKView().texture(from: cheeseCropNode, crop: sprite.frame)
                let hole = SKSpriteNode.init(texture: holeTxt)
                hole.position = CGPoint(x:-(self.frame.maxX)+(100*CGFloat(counter)),y:150)
                hole.name = node.name
                self.addChild(hole)
                holes.append(hole)
                counter += 1
            })
        }
    
        func randomNumber(range: ClosedRange = 1...6) -> Int {
            let min = range.lowerBound
            let max = range.upperBound
            return Int(arc4random_uniform(UInt32(1 + max - min))) + min
        }
        func randomCGFloat(min: CGFloat, max: CGFloat) -> CGFloat {
            return (CGFloat(arc4random()) / CGFloat(UINT32_MAX)) * (max - min) + min
        }
        func makeCheese(size:CGSize , color:SKColor, totHoles:Int)->SKCropNode {
            let cropNode = SKCropNode()
            let cheese = SKSpriteNode.init(color: color, size: size)
            for i in 0..

    Result:

    P.S. Don't pay attention to red rectangles, it's just to show you the holes:

    If you want the exactly reversed hole, (the negative image), you could use SKCropNode with the hole.blendMode, for example:

    Substitute this part of the code:

    // -- end to remove
    
                    let holeTxt = SKView().texture(from: cheeseCropNode, crop: sprite.frame)
                    let hole = SKSpriteNode.init(texture: holeTxt)
                    hole.position = CGPoint(x:-(self.frame.maxX)+(100*CGFloat(counter)),y:150)
                    hole.name = node.name
                    self.addChild(hole)
                    holes.append(hole)
                    counter += 1
    

    with this part:

    // -- end to remove
    
                let holeTxt = SKView().texture(from: cheeseCropNode, crop: sprite.frame)
                let hole = SKSpriteNode.init(texture: holeTxt)
                hole.position = CGPoint(x:-(self.frame.maxX)+(100*CGFloat(counter)),y:150)
                hole.name = node.name
    
                let negativeCropHole = SKCropNode()
                let shadow = SKShapeNode.init(rect: hole.frame)
                shadow.fillColor = (node as! SKShapeNode).fillColor
                shadow.strokeColor = SKColor.clear
                hole.blendMode = .subtract
                negativeCropHole.addChild(shadow)
                negativeCropHole.maskNode = shadow
                negativeCropHole.addChild(hole)
                negativeCropHole.name = hole.name
                self.addChild(negativeCropHole)
                holes.append(negativeCropHole)
                counter += 1
    

    Result (another example):

    Hope these example and this code help you to obtain your objectives, I've used rectangles to make masks but your could create CGPaths if you need.

    0 讨论(0)
提交回复
热议问题