Sprite Kit:很多精灵 (1000+),带有位 Blitting

Posted

技术标签:

【中文标题】Sprite Kit:很多精灵 (1000+),带有位 Blitting【英文标题】:Sprite Kit: A Lot of sprites (1000+) with Bit Blitting 【发布时间】:2015-08-14 13:46:44 【问题描述】:

我正在尝试使用 SpriteKit 创建一个场景,其中包含数千个精灵(~500 - 2000)。每个精灵只是一个 1x1 的白色像素 - 甚至不需要为它们使用纹理。

一次直接将这么多精灵添加到场景中是不可能的(或者至少我认为是这样)。在 iPhone 6 上,我最终添加了大约 200 个精灵,然后系统由于内存问题结束了添加过程,其余的精灵没有添加。

我找到了一个名为Bit Blitting 的巧妙解决方案,其中所有精灵都添加到一个节点,然后使用textureFromNode: 方法将其“转换”为纹理,然后从该纹理创建一个单独的精灵,它将最终被添加到屏幕上。它工作得很好,我可以一次创建超过 10 000 个精灵,而且 fps 很好。

我的问题是之后我无法移动这些精灵(= 更改位置)。无论我做什么,质地总是保持不变。我错过了什么?

我的代码:

override func didMoveToView(view: SKView) 
    self.generateRandomSprites()


func generateRandomSprites() 

    let texture = SKTexture(imageNamed: "whitePixel")

    self.canvasNode = SKNode()

    log("started generating all sprites")

    for var i = 0;i < 1000;i++ 

        let width = self.scene!.frame.size.width
        let height = self.scene!.frame.size.height

        let x: CGFloat = CGFloat(arc4random_uniform(UInt32(width)))
        let y: CGFloat = CGFloat(arc4random_uniform(UInt32(height)))

        let cell = SKSpriteNode(texture: texture)
        cell.position = CGPointMake(x, y)

        self.arrCells.append(cell)
        self.canvasNode.addChild(cell)
    

    self.canvasTexture = self.view!.textureFromNode(self.canvasNode)
    self.canvasSprite = SKSpriteNode(texture: self.canvasTexture, size: self.frame.size)
    self.canvasSprite.anchorPoint = ccp(0,0)

    self.addChild(self.canvasSprite)



override func update(currentTime: CFTimeInterval) 
    for oneCell in self.arrCells 
        oneCell.position = CGPointMake(oneCell.position.x + 1, oneCell.position.y)
    

    self.canvasTexture = self.view!.textureFromNode(self.canvasNode)
    self.canvasSprite.texture = self.canvasTexture
 

来自应用程序的屏幕截图(这是静态的,没有任何反应):

【问题讨论】:

你的屏幕截图是黑色的,你说你的纹理是白色的。你怎么知道你的精灵在屏幕的可见侧。我在你的屏幕截图中看到的是黑色 截图中有白点...只是1px所以必须放大/有好的分辨率...点击图片就可以看到...跨度> 你是对的,点击图片后,我可以看到它们。 节点被写入纹理 - 图像。在重新渲染图像之前,移动节点将不起作用。您必须再次调用 generateRandomSprites,但不要再次添加孩子。 @Chris 不正确!从问题中阅读文章。 ...您是否尝试过循环使用self.canvasNode.children 而不是您的阵列?我无法测试它atm。所以这只是一个建议。 【参考方案1】:

这不是答案,而是我尝试过的东西的集合。

我真的很好奇那个代码。我试过了,但没有用。我将更新方法更改为仅将点放在随机位置并且它可以工作:

所以我有一个问题。为什么代码不能从它的当前位置更新,或者这是一个红鲱鱼?

override func update(currentTime: CFTimeInterval) 

    let width = self.scene!.frame.size.width
    let height = self.scene!.frame.size.height

    for oneCell in self.canvasNode.children as! [SKSpriteNode] 

        let x: CGFloat = CGFloat(arc4random_uniform(UInt32(width)))
        let y: CGFloat = CGFloat(arc4random_uniform(UInt32(height)))

        oneCell.position = CGPointMake(x, y)
    

    self.canvasTexture = self.view!.textureFromNode(self.canvasNode)
    self.canvasSprite.texture = self.canvasTexture


好的,我一直在玩这个,这很有效,只是获取一个随机值并将其添加到位置......

override func update(currentTime: CFTimeInterval) 

    let width = self.scene!.frame.size.width
    let height = self.scene!.frame.size.height

    for oneCell in self.canvasNode.children as! [SKSpriteNode] 

        let x2: CGFloat = CGFloat(arc4random_uniform(UInt32(10)))
        let y2: CGFloat = CGFloat(arc4random_uniform(UInt32(10)))
        let x:CGFloat = oneCell.position.x - x2
        let y:CGFloat = oneCell.position.y - y2
        let point = CGPointMake(x, y)

        oneCell.position = point
    

    self.canvasTexture = self.view!.textureFromNode(self.canvasNode)
    self.canvasSprite.texture = self.canvasTexture


现在我认为这与编译器有关:

override func update(currentTime: CFTimeInterval) 

    let width = self.scene!.frame.size.width
    let height = self.scene!.frame.size.height


    var x3:CGFloat = 10.0
    var y3:CGFloat = 10.0
    for oneCell in self.canvasNode.children as! [SKSpriteNode] 

        let x:CGFloat = oneCell.position.x - x3
        let y:CGFloat = oneCell.position.y - y3
        let point = CGPointMake(x, y)

        oneCell.position = point
        x3 += 0.01
    


    self.canvasTexture = self.view!.textureFromNode(self.canvasNode)
    self.canvasSprite.texture = self.canvasTexture


更多调查,有趣,如果您使用值 1.3 并运行代码,您可以看到点移动一次。 (http://llvm.org/docs/LangRef.html#simple-constants)

override func update(currentTime: CFTimeInterval) 

    let width = self.scene!.frame.size.width
    let height = self.scene!.frame.size.height

    for oneCell in self.canvasNode.children as! [SKSpriteNode] 

        let x:CGFloat = oneCell.position.x - 1.3
        let y:CGFloat = oneCell.position.y - 1.3
        let point = CGPointMake(x, y)

        oneCell.position = point
    

    self.canvasTexture = self.view!.textureFromNode(self.canvasNode)
    self.canvasSprite.texture = self.canvasTexture


像 50.3333333333 这样的数字显示出明显的抖动,但随后似乎停止了。

【讨论】:

感谢您的回答,您完全正确! ......我得到了和你一样的结果,尝试了所有的选择......这真的很奇怪。就像...真的很奇怪:) 我会花一些时间在上面,如果我想出什么办法会告诉你... 很遗憾,没有。两周前我尝试了几件事(主要基于您的观察),但没有取得任何值得一提的进展。我完全同意这与编译器有关,因为它真的很奇怪,我无法以任何其他方式解释它......如果我将来发现一些东西,我会告诉你(这是一个附带项目,我只是有时在研究它)。【参考方案2】:

老实说,我认为您建议的方法效果不佳,而且看起来真的很复杂,无缘无故。例如,使用 SpriteKit,您可以只创建一个具有背景纹理颜色的节点并将其设置为 1x1,而无需执行任何 blit 操作。像这样:

SKSpriteNode *node = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor]
size:CGSizeMake(1,1)];

【讨论】:

以上是关于Sprite Kit:很多精灵 (1000+),带有位 Blitting的主要内容,如果未能解决你的问题,请参考以下文章

Sprite Kit,使多个精灵遵循相同的方法

在 Sprite Kit 中永远随机移动精灵的最佳方法

Sprite Kit 碰撞发生在精灵之外的几个点

Sprite Kit 中的单个粒子和物理

在 Sprite Kit iOS 中使用一个图像精灵表

Swift iOS Sprite Kit - 将精灵从一种颜色淡化为另一种颜色[关闭]