Как вырезать случайные отверстия в SKSpriteNodes

Помимо того, что здесь задан вопрос: нарисовать отверстие в прямоугольнике с помощью SpriteKit? на этот вопрос не было получено удовлетворительного ответа, самое существенное различие между ними заключается в том, что этот вопрос требует отсутствия обходных путей и, в частности, требует отмены функциональности SKCropNodes.

Основные проблемы в этом вопросе не могут быть решены типом хакерских способов, на которые можно было ответить на вышеупомянутый вопрос из-за случайности отверстий, количества отверстий и изменения в объектах, к которым должны быть применены отверстия.

Отсюда и пример швейцарского сыра:

Представьте себе кучу прямоугольных SKSpriteNode узлов произвольного размера, наполненных различными оттенками сыроподобных цветов.

Как сделать швейцарский сыр из каждого, вырезав случайные кружочки из каждого кусочка сыра?

Если узлы SKCropNode являются кружками, они оставляют только круглые кусочки сыра, а не вырезают отверстия из кусочков сыра. Есть ли способ инвертировать поведение SKCropNodes, чтобы они вместо этого вырезали отверстия?

1 ответ

Если честно, я не совсем понимаю, чего вы хотите достичь, но я могу попытаться ответить на этот вопрос:

... вырезать случайные круги из каждого кусочка сыра?

В этом проекте я пытаюсь воссоздать типичный прямоугольник (кусок сыра) со случайными отверстиями, затем я извлекаю эти отверстия и собираю их в массив.

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<Int> = 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..<totHoles {
            let radius = randomCGFloat(min:20.0, max:50.0)
            let circle = SKShapeNode(circleOfRadius: radius)
            circle.position = CGPoint(x:randomCGFloat(min:-size.width/2, max:size.width/2),y:randomCGFloat(min:-size.height/2, max:size.height/2))
            circle.fillColor = color
            circle.blendMode = .subtract
            circle.name = "hole\(i)"
            cheese.addChild(circle)
        }
        cropNode.addChild(cheese)
        cropNode.maskNode = cheese
        return cropNode
    }
}

Результат:

PS Не обращайте внимания на красные прямоугольники, это просто чтобы показать вам отверстия:

Если вы хотите точно перевернутое отверстие (негативное изображение), вы можете использовать SKCropNode с hole.blendMode, например:

Подставьте эту часть кода:

// -- 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

с этой частью:

// -- 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

Результат (другой пример):

Надеюсь, что этот пример и этот код помогут вам в достижении ваших целей. Я использовал прямоугольники для создания масок, но вы можете создавать CGPaths, если вам нужно.

Другие вопросы по тегам