How to force SKTextureAtlas created from a dictionary to not modify textures size?

 ̄綄美尐妖づ 提交于 2019-12-08 06:32:33

问题


In my project, textures are procedurally generated from method provided by PaintCode (paint-code).

I then create a SKTextureAtlas from a dictionary filed with UIImage generated by these methods :
myAtlas = SKTextureAtlas(dictionary: myTextures)

At last, textures are retrieve from atlas using textureNamed: var sprite1 = SKSpriteNode(texture:myAtlas.textureNamed("texture1"))

But displayed nodes are double sized on iPhone4S simulator. And triple sized on iPhone 6 Plus simulator.

It seems that at init, atlas compute images at the device resolution. But generated images already have the correct size and do not need to be changed. See Drawing Method below.

Here is the description of the generated image:
<UIImage: 0x7f86cae56cd0>, {52, 52}

And the description of the corresponding texture in atlas:
<SKTexture> 'image1' (156 x 156)

This for iPhone 6 Plus, using @3x images, that's why size is x3.

And for iPhone 4S, using @2x images, as expected:
<UIImage: 0x7d55dde0>, {52, 52}
<SKTexture> 'image1' (156 x 156)

At last, the scaleproperty for generated UIImage is set to the right device resolution: 2.0 for @2x (iPhone 4S) and 3.0 for @3x (iPhone 6 Plus).

The Question

So what can I do to avoid atlas resizing the pictures?

Drawing method

PaintCode generate drawing methods as the following:

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

    let imageOfCell = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return imageOfCell
}

Update 1

Comparing two approaches to generate 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)

It seems that the problem lie on SKTextureAtlas from a dictionary as as SKSpriteNode initialization does not use scale property from UIImage to correctly size the node.

Here are descriptions on console: - texture1: '' (84 x 84) - texture2: 'texture1' (84 x 84)

texture2 miss some data! That could explain the lack of scale information to properly size the node as:

node's size = texture's size divide by texture's scale.

Update 2

The problem occur when the scale property of UIImage is different than one.

So you can use the following method to generate picture:

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

    }


回答1:


The problem come from the use of SKTextureAtlas(dictionary:) to initialize atlas.

SKTexture created using this method does not embed data related to image's scale property. So during the creation of SKSpriteNode by init(texture:) the lack of scale information in texture leads to choose texture's size in place of image's size.

One way to correct it is to provide node's size during SKSpriteNode creation: init(texture:size:)




回答2:


From the documentation for the scale parameter for UIGraphicsBeginImageContextWithOptions,

The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.

Therefore, if you want the textures to be the same "size" across all devices, set this value to 1.0.

EDIT:

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
}


来源:https://stackoverflow.com/questions/31557305/how-to-force-sktextureatlas-created-from-a-dictionary-to-not-modify-textures-siz

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!