似乎从纹理图集中提取纹理时,我现在正在生成新纹理,而不是使用iOS 10在不同精灵上使用相同纹理。在iOS 9上,这可以按预期工作。还有其他人遇到过这个问题吗?也许有一个我错过的步骤,现在是iOS 10的一部分。
注意:我创建了一个示例项目并创建了一个新的图集,然后在@ 1x中拖动了太空船,我也尝试了预加载,并且没有做任何事情。
代码:
let atlas = SKTexturAtlas(named:"Sprites")
var texture = atlas.textureNamed("Spaceship")
print("\(Unmanaged.passUnretained(texture)),\(Unmanaged.passUnretained(texture).toOpaque())")
texture = atlas.textureNamed("Spaceship")
print("\(Unmanaged.passUnretained(texture)),\(Unmanaged.passUnretained(texture).toOpaque())")
编辑:为了解决比较问题,我使用description属性来比较2个纹理是否相等。为了使其工作,您无法使用2个地图集,每个地图集包含具有确切名称和大小的纹理。我永远不会遇到这种情况,但对于那里寻求帮助的人,请记住这一点。
答案 0 :(得分:3)
我进行了同样的测试并得到了相同的结果。
我不确定100%,但似乎在开发Swift 3期间有一个提案here要更改非托管以使用 UnsafePointer
但如果你试图做:
func address<T: AnyObject>(o: T) -> String{
let addr = unsafeBitCast(o, to: Int.self)
return NSString(format: "%p", addr) as String
}
<强>用法强>:
print(address(o: texture))
在 iOS9 中,您有正确的值, iOS10 错误的结果。
我认为你是对的,我们正面临着一个错误(另一个......)
答案 1 :(得分:1)
对于引用&#34;相同纹理的纹理具有不同的物理地址&#34;真的有问题吗?
我已经运行了默认的示例游戏项目,但是设置了Obj-C。我有一个纹理图集,如下图所示。但是,请注意我通过TexturePacker运行它。所以Xcode实际生成的图集是不同的。
我按照你说的做,并创建了2个同名的纹理。
self.myTextureAtlas = [SKTextureAtlas atlasNamed:@"MyTexture"];
self.tex0 = [self.myTextureAtlas textureNamed:@"tex0"];
self.tex1 = [self.myTextureAtlas textureNamed:@"tex0"];
正如您所说,tex0
和tex1
的指针不同。所以至少Swift和Obj-C之间存在一致性。
但是,我不认为这是一个问题/错误。我怀疑他们改变了实现,所以返回的SKTexture
是一个新的&#34;实例&#34;但是底层纹理仍然是相同的。
我会谈谈OpenGL,因为这就是我编写引擎的原因.Metal仍然会有相似之处。基本的子纹理实际上只有两个重要的属性:纹理名称(这是OpenGL纹理名称)和UV。如果你正在考虑什么将被视为&#34;平等&#34;为了符合Equatable
,它很可能会测试这两个项目的平等性。纹理名称是atlas纹理名称,UV是atlas中的UV,表示特定子纹理的区域。
为了测试这个假设,我对此进行了GPU帧捕获。使用Xcode 8,这似乎很不错。使用Metal,它100%的时间都崩溃了。我强迫它使用OpenGL并设法获得帧捕获。正如预期的那样,当我查看所有纹理资源时,我只看到了一个纹理图集。
纹理#3是MyTexture。
如果我转储看起来像UV的textureRect,我可以看到它们是相同的:
Tex0 Rect 0.001618 0.793765 0.139159 0.203837
Tex1 Rect 0.001618 0.793765 0.139159 0.203837
基于此,似乎self.tex0
和self.tex1
虽然具有不同的物理地址,但仍然指向相同的子纹理。
请注意,我不再使用SpriteKit。我当前的渲染器使用纹理句柄,但是,在检索时,您可以获得具有不同物理地址的句柄对象。它们仍然都取消引用真正的纹理,因为它们仍然引用相同的底层纹理实例。
我想,如果差异指针仍然引用相同的底层纹理(即不再分配纹理内存),我也不会真正看到问题指针。
答案 2 :(得分:1)
为了解决这个问题,我不得不想出一种缓存纹理的方法,以便它不会重复:
private var textureCache = [String: SKTexture]()
extension SKTextureAtlas
{
func texturesWithNames(_ names:[String]) -> [SKTexture]
{
var textures = [SKTexture]()
names.forEach({textures.append(textureNamed($0))})
return textures
}
func cachedTextureWithName(_ name:String) -> SKTexture
{
if textureCache[name] == nil
{
textureCache[name] = textureNamed(name)
}
return textureCache[name]!
}
func cachedTexturesWithNames(_ names:[String]) -> [SKTexture]
{
var textures = [SKTexture]()
names.forEach({textures.append(cachedTextureWithName($0))})
return textures
}
func clearCache()
{
textureCache = [String: SKTexture]()
}
}
extension SKTexture
{
var name : String
{
return self.description.slice(start: "'",to: "'")!
}
}