Подтвердить что ты не робот

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

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

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

Следовательно, пример швейцарского сыра:

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

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

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

4b9b3361

Ответ 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 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
    }
}

Результат

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

введите описание изображения здесь

Если вы хотите точно обратное отверстие (отрицательное изображение), вы можете использовать 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, если вам нужно.