在 SKSpriteNode 上叠加两个纹理

Posted

技术标签:

【中文标题】在 SKSpriteNode 上叠加两个纹理【英文标题】:Superimpose two textures on an SKSpriteNode 【发布时间】:2018-08-04 14:44:22 【问题描述】:

我想实现这个gif所示的效果。

目前,我使用一系列 ~7 个带有红色背景和白线的 png 图像来执行此操作,这些图像通过带有 SKAction 的精灵进行动画处理。

我还想对精灵添加一些其他内容,这些内容可能会根据情况而改变,而且我想用多种颜色重复这一点。 这会产生:6 种颜色、7 种光泽效果、5 种边缘效果和 4 种角效果,从而产生了 136 种我需要创建和存储的纹理组合。

我觉得在设置精灵的纹理时必须有一种方法可以在透明背景上叠加 png,但我似乎无法在任何地方找到这样做的方法。

这是否可行,以便我可以将资产数量减少到 22 个,或者我必须全部制作 136 个并在类中构建逻辑以决定使用哪个?

【问题讨论】:

使用多个 SKSpriteNodes 和 colorBlendFactor 如果我使用这种方法并为效果添加子元素,那么额外精灵的性能与简单创建所有纹理的额外存储相比如何?最多可以有 70 个基础精灵添加这些效果。 根本不会花费太多,但您会在此过程中节省大量内存。每个方块需要 1 个精灵,眩光需要 1 个大精灵(或多个精灵合成一个大眩光以节省纹理内存,如果需要)你的灰色方块的 zPosition 为 2,你的眩光的 zPosition 为 1 ,并且您的颜色方块的 zPosition 为 0 【参考方案1】:

我希望我的游戏有这样的效果,我尝试了很多选择。我尝试使用粒子来提高性能,但甚至无法接近。我知道你可以使用 Shaders 来完成它,但我没有走那条路,而且在 ios 12 中,Shaders 无论如何都不会支持 Open GL。最后我选择了 CropNodes。

这是我的眩光图像,因为它略带透明的白色图像,所以很难看到。

这是我使用 CropNodes 获得的结果

class Glare: SKSpriteNode 

    var glare = SKSpriteNode()
    private var cropNode = SKCropNode()

    init(color: UIColor, size: CGSize) 

        super.init(texture: nil, color: color, size: size)

        alpha = 0.7
        zPosition = 10

        setupGlare()
    

    required init?(coder aDecoder: NSCoder) 
        fatalError("init(coder:) has not been implemented")
    

    func setupGlare() 

        let buffer: CGFloat = 10

        let mask = SKSpriteNode(texture: nil, color: .black, size: self.size)

        let texture = SKTextureAtlas(named: "Sprites").textureNamed("glare")
        glare = SKSpriteNode(texture: texture)
        glare.position = CGPoint(x: 0 - (self.size.width / 2 + buffer), y: self.size.height / 2 + buffer)
        glare.setScale(3.50)
        glare.zPosition = 1

        cropNode.zPosition = 2
        cropNode.maskNode = mask
        cropNode.addChild(glare)

        let random = Double(CGFloat.random(min: 0, max: 1))

        let pause = SKAction.wait(forDuration: random)
        let move = SKAction.moveBy(x: self.size.width + buffer * 2, y: 0 - (self.size.height + buffer * 2), duration: 0.5)
        let wait = SKAction.wait(forDuration: 1.0)
        let reset = SKAction.moveBy(x: 0 - (self.size.width + buffer * 2), y: self.size.height + buffer * 2, duration: 0.0)
        let seq = SKAction.sequence([move, wait, reset])
        let repeater = SKAction.repeatForever(seq)
        let repeaterSeq = SKAction.sequence([pause, repeater])

        glare.run(repeaterSeq)
    

    func showGlare(texture: SKTexture) 

        let mask = SKSpriteNode(texture: texture)

        cropNode.maskNode = mask
        glare.isHidden = false
        if cropNode.parent == nil  self.addChild(cropNode)
    

    func hideGlare() 

        glare.isHidden = true
        //remove cropnode from the node tree
        cropNode.removeFromParent()
    

然后在我的 GameScene 中...

我将眩光添加到眩光层,但这不是必需的。当游戏加载时,我也会提前为所有 15 个插槽创建眩光并将它们放在一个数组中。这样我就不必动态创建它们,我可以随时打开插槽 10,也可以将其关闭。

private var glares = [Glare]()

let glare = Glare(color: .clear, size: CGSize(width: kSymbolSize, height: kSymbolSize))
glare.position = CGPoint(x: (CGFloat(x - 1) * kSymbolSize) + (kSymbolSize / 2), y: 0 - (CGFloat(y) * kSymbolSize) + (kSymbolSize / 2))
glare.zPosition = 100
glareLayer.addChild(glare)
glares.append(glare)

当我想在插槽上显示眩光时

在此处为您编辑纹理将只是一个与您的瓷砖大小相同的空白方形纹理。

glares[index].showGlare(texture: symbol.texture!)

当我想隐藏它时

glares[index].hideGlare()

【讨论】:

看这个,你可能不需要你的裁剪节点,如果你的 zPositioning 正确,你把禁用的网格放在启用的图形上方,并将眩光放在中间 是的,但我希望眩光只出现在物体本身上,而不是背面的瓷砖上。 (即,如果樱桃后面的正方形是红色的,您将看不到背景上的高光,它只会使樱桃发光) 啊,好吧,那是有道理的 但即使我想突出显示整个正方形,我认为您仍然必须使用cropnode,因为移动时眩光会超出瓷砖边界 好吧,现在你失去了我,哈哈……我的想法是让眩光延伸到瓷砖边界之外,但是你的禁用/灰色区域的 zposition 会覆盖额外的眩光,因为它在它上面。但我想如果你有 2 个彼此相邻,这将成为一个问题(除非你使用一个巨型眩光而不是单个眩光)

以上是关于在 SKSpriteNode 上叠加两个纹理的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 使用纹理数组更改 SKSpriteNode 纹理

如何让 SKSpriteNode 不旋转纹理

SKSpriteNode 多个纹理

SKSpriteNode()纹理的大小是否有限制? (4000 x 4000)

如何防止在暂停场景上运行 SKAction(取消暂停后),节点纹理在暂停/取消暂停场景后不改变

如何在两种纹理之间交替?