Sprite kit and colorWithPatternImage

后端 未结 3 1725
傲寒
傲寒 2020-11-29 11:32

Do we have any way of repeating an image across an area, like a SKSpriteNode? SKColor colorWithPatternImage doesn\'t work unfortunately.

Edit:

I

相关标签:
3条回答
  • 2020-11-29 12:10

    Yes, it is possible to implement that with a call to CGContextDrawTiledImage(), but that wastes a lot of memory for medium and large size nodes. A significantly improved approach is provided at spritekit_repeat_shader. This blog post provides example GLSL code and BSD licensed source is provided.

    0 讨论(0)
  • 2020-11-29 12:23

    I found that the above linked sprite kit shader did not work with Xcode 10, so I rolled my own. Here is the shader code:

    void main(void) {
        vec2 offset = sprite_size - fmod(node_size, sprite_size) / 2;
        vec2 pixel = v_tex_coord * node_size + offset;
        vec2 target = fmod(pixel, sprite_size) / sprite_size;
        vec4 px = texture2D(u_texture, target);
        gl_FragColor = px;
    }
    

    Note that the offset variable is only required if you want the pattern centralised - you can omit it, and its addition in the following line, if you want your tile pattern to start with the tile texture's bottom left corner.

    Also note that you will need to manually add the node_size and sprite_size variables to the shader (and update them if they change) as neither of these have standard representations any more.

    // The sprite node's texture will be used as a single tile
    let node = SKSpriteNode(imageNamed: "TestTile")
    let tileShader = SKShader(fileNamed: "TileShader.fsh")
    
    // The shader needs to know the tile size and the node's final size.
    tileShader.attributes = [
        SKAttribute(name: "sprite_size", type: .vectorFloat2),
        SKAttribute(name: "node_size", type: .vectorFloat2)
    ]
    
    // At this point, the node's size is equal to its texture's size.
    // We can therefore use it as the sprite size in the shader.
    let spriteSize = vector_float2(
        Float(node.size.width),
        Float(node.size.height)
    )
    
    // Replace this with the desired size of the node.
    // We will set this as the size of the node later.
    let size = CGSize(x: 512, y: 256)
    let nodeSize = vector_float2(
        Float(size.width),
        Float(size.height)
    )
    
    newBackground.setValue(
        SKAttributeValue(vectorFloat2: spriteSize),
        forAttribute: "sprite_size"
    )
    
    newBackground.setValue(
        SKAttributeValue(vectorFloat2: nodeSize),
        forAttribute: "node_size"
    )
    
    node.shader = tileShader
    node.size = size
    
    0 讨论(0)
  • 2020-11-29 12:24

    iOS working code:

    CGRect textureSize = CGRectMake(0, 0, 488, 650);
    CGImageRef backgroundCGImage = [UIImage imageNamed:@"background.png"].CGImage;
    
    UIGraphicsBeginImageContext(self.level.worldSize); // use WithOptions to set scale for retina display
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawTiledImage(context, textureSize, backgroundCGImage);
    UIImage *tiledBackground = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    SKTexture *backgroundTexture = [SKTexture textureWithCGImage:tiledBackground.CGImage];
    SKSpriteNode *backgroundNode = [SKSpriteNode spriteNodeWithTexture:backgroundTexture];
    [self addChild:backgroundNode];
    
    0 讨论(0)
提交回复
热议问题