【问题标题】:How to force SKTextureAtlas created from a dictionary to not modify textures size?如何强制从字典创建的 SKTextureAtlas 不修改纹理大小?
【发布时间】:2015-07-22 08:03:56
【问题描述】:

在我的项目中,textures 是由 PaintCode () 提供的方法按程序生成的。

然后我从通过这些方法生成的带有UIImage 的字典中创建一个SKTextureAtlas
myAtlas = SKTextureAtlas(dictionary: myTextures)

最后,使用textureNamedatlas中检索纹理 var sprite1 = SKSpriteNode(texture:myAtlas.textureNamed("texture1"))

但显示的 节点 在 iPhone4S 模拟器上是双倍大小。并在 iPhone 6 Plus 模拟器上放大三倍。

似乎在初始化时,atlas 以设备分辨率计算图像。 但是生成的图像已经具有正确的大小,不需要更改。请参阅下面的绘图方法

这里是生成图片的说明:
<UIImage: 0x7f86cae56cd0>, {52, 52}

以及图集中对应纹理的描述:
<SKTexture> 'image1' (156 x 156)

这适用于 iPhone 6 Plus,使用 @3x 图像,这就是大小为 x3 的原因。

对于 iPhone 4S,使用 @2x 图像,正如预期的那样:
<UIImage: 0x7d55dde0>, {52, 52}
<SKTexture> 'image1' (156 x 156)

最后,生成的UIImagescale属性设置为正确的设备分辨率:@2x (iPhone 4S) 为 2.0,@3x (iPhone 6 Plus) 为 3.0。

问题

那么我该怎么做才能避免图集调整图片大小?

画法

PaintCode生成绘图方法如下:

public class func imageOfCell(#frame: CGRect) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
    StyleKit.drawCell(frame: frame)

    let imageOfCell = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return imageOfCell
}

更新 1

比较两种生成SKTextureAtlas的方法

// Some test image
let testImage:UIImage...


// Atlas creation
var myTextures = [String:UIImage]() 

myTextures["texture1"] = testImage
myAtlas = SKTextureAtlas(dictionary: myTextures)

// Create two textures from the same image 
let texture1 = myAtlas.textureNamed("texture1")
let texture2 = SKTexture(image:testImage)

// Wrong display : node is oversized
var sprite1 = SKSpriteNode(texture:texture1)

// Correct display
var sprite2 = SKSpriteNode(texture:texture2)

问题似乎出在字典中的SKTextureAtlas 上,因为SKSpriteNode 初始化不使用UIImage 中的scale 属性来正确调整节点的大小。

以下是控制台上的说明: - texture1: '' (84 x 84) - texture2: 'texture1' (84 x 84)

texture2 想念一些data!这可以解释缺乏 scale 信息来正确调整节点大小:

节点的大小 = 纹理的大小除以纹理的比例。

更新 2

UIImage 的 scale 属性不为 1 时会出现问题。

所以可以使用以下方法生成图片:

func imageOfCell(frame: CGRect, color:SKColor) -> UIImage {
     UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)

     var bezierPath = UIBezierPath(rect: frame)
     color.setFill()
     bezierPath.fill()
     let imageOfCell = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()

     return imageOfCell

    }

【问题讨论】:

  • iOS 9 / Xcode 7 中仍然存在问题...

标签: paint-code swift uiimage sprite-kit sktextureatlas paintcode


【解决方案1】:

问题来自于使用SKTextureAtlas(dictionary:)初始化图集。

使用此方法创建的SKTexture 不会嵌入与图像的scale 属性相关的数据。所以在init(texture:)init(texture:)创建SKSpriteNode的过程中,纹理中缺少比例信息导致选择纹理的大小而不是图像的大小。

纠正它的一种方法是在SKSpriteNode 创建期间提供节点的大小:init(texture:size:)

【讨论】:

  • 你不是在创建一个比它需要的更大的纹理图集吗(在 6+ 上是 3 倍)?
  • 没有。唯一的区别是创建纹理的方式。顺便说一句,谢谢你的帮助!
  • 您可以尝试通过使用相同的生成图像创建另一个精灵来获得相同的行为,但使用此图像创建的纹理没有图集。并且不要忘记调用 imageOfCell 时标度值为 0。
  • 如果您从图集中检索纹理,然后使用println (texture.size()) 打印其大小,我很确定这就是图集中纹理的大小。我怀疑您正在做的是在使用init(texture:size) 创建精灵时调整它的大小。
  • 问题是SKSpriteNode的大小,而不是纹理的大小。只需尝试我在上面为您提供的修改,您就会发现 SKSpriteNode 的渲染方式不同,具体取决于纹理的创建方式。
【解决方案2】:

来自UIGraphicsBeginImageContextWithOptionsscale 参数的文档,

应用于位图的比例因子。如果您指定的值 0.0,比例因子设置为设备主屏幕的比例因子。

因此,如果您希望纹理在所有设备上具有相同的“大小”,请将此值设置为 1.0。

编辑:

override func didMoveToView(view: SKView) {        
    let image = imageOfCell(CGRectMake(0, 0, 10, 10),scale:0)

    let dict:[String:UIImage] = ["t1":image]

    let texture = SKTextureAtlas(dictionary: dict)
    let sprite1 = SKSpriteNode(texture: texture.textureNamed("t1"))
    sprite1.position = CGPointMake (CGRectGetMidX(view.frame),CGRectGetMidY(view.frame))
    addChild(sprite1)
    println(sprite1.size)

    // prints (30.0, 30.0) if scale = 0
    // prints (10,0, 10,0) if scale = 1
}


func imageOfCell(frame: CGRect, scale:CGFloat) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(frame.size, false, scale)

    var bezierPath = UIBezierPath(rect: frame)
    UIColor.whiteColor().setFill()
    bezierPath.fill()
    let imageOfCell = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return imageOfCell
}

【讨论】:

  • 问题在于纹理生成而不是使用UIGraphicsBeginImageContextWithOptions生成图像。
  • UIGraphicsBeginImageContextWithOptions 通过设置正确的值(设备的主屏幕之一)来完成这项工作。
  • 来自UIImage 文档:如果从名称中包含@2x 修饰符的文件加载图像,则比例设置为2.0。您还可以在从 Core Graphics 图像初始化图像时指定显式比例因子。假设所有其他图像的比例因子为 1.0。...
  • 如果将图像的逻辑大小(存储在 size 属性中)乘以该属性中的值,则得到图像的尺寸(以像素为单位)
  • SKTextureAtlas 在生成纹理时使用UIImagescale 属性。如果图像为 10x10 且其比例为 3,则生成的纹理将为 30x30。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-20
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 2020-03-29
  • 2013-07-06
相关资源
最近更新 更多