【问题标题】:Sprite kit and colorWithPatternImageSprite 套件和 colorWithPatternImage
【发布时间】:2013-10-21 09:39:42
【问题描述】:

我们有没有办法在一个区域内重复图像,比如 SKSpriteNode?不幸的是,SKColor colorWithPatternImage 不起作用。

编辑:

我做了以下分类,到目前为止似乎有效。使用 Mac,未在 iOS 上测试。可能需要对 iOS 进行一些修复。

// Add to SKSpriteNode category or something.
+(SKSpriteNode*)patternWithImage:(NSImage*)image size:(const CGSize)SIZE;

// Add to SKTexture category or something.
+(SKTexture*)patternWithSize:(const CGSize)SIZE image:(NSImage*)image;

以及实现。放入各自的文件。

+(SKSpriteNode*)patternWithImage:(NSImage*)imagePattern size:(const CGSize)SIZE {
    SKTexture* texturePattern = [SKTexture patternWithSize:SIZE image:imagePattern];
    SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithTexture:texturePattern];
    return sprite;
}

+(SKTexture*)patternWithSize:(const CGSize)SIZE image:(NSImage*)image {
    // Hopefully this function would be platform independent one day.
    SKColor* colorPattern = [SKColor colorWithPatternImage:image];

    // Correct way to find scale?
    DLog(@"backingScaleFactor: %f", [[NSScreen mainScreen] backingScaleFactor]);
    const CGFloat SCALE = [[NSScreen mainScreen] backingScaleFactor];
    const size_t WIDTH_PIXELS = SIZE.width * SCALE;
    const size_t HEIGHT_PIXELS = SIZE.height * SCALE;
    CGContextRef cgcontextref = MyCreateBitmapContext(WIDTH_PIXELS, HEIGHT_PIXELS);
    NSAssert(cgcontextref != NULL, @"Failed creating context!");
    //  CGBitmapContextCreate(
    //                                                    NULL, // let the OS handle the memory
    //                                                    WIDTH_PIXELS,
    //                                                    HEIGHT_PIXELS,

    CALayer* layer = CALayer.layer;
    layer.frame = CGRectMake(0, 0, SIZE.width, SIZE.height);

    layer.backgroundColor = colorPattern.CGColor;

    [layer renderInContext:cgcontextref];

    CGImageRef imageref = CGBitmapContextCreateImage(cgcontextref);

    SKTexture* texture1 = [SKTexture textureWithCGImage:imageref];
    DLog(@"size of pattern texture: %@", NSStringFromSize(texture1.size));

    CGImageRelease(imageref);

    CGContextRelease(cgcontextref);

    return texture1;
}

好的,这也是需要的。这可能仅适用于 Mac。

CGContextRef MyCreateBitmapContext(const size_t pixelsWide, const size_t pixelsHigh) {
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    //int             bitmapByteCount;
    size_t             bitmapBytesPerRow;

    bitmapBytesPerRow   = (pixelsWide * 4);// 1
    //bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);// 2
    bitmapData = NULL;

#define kBitmapInfo     kCGImageAlphaPremultipliedLast
//#define kBitmapInfo       kCGImageAlphaPremultipliedFirst
//#define kBitmapInfo       kCGImageAlphaNoneSkipFirst
    // According to http://stackoverflow.com/a/18921840/129202 it should be safe to just cast
    CGBitmapInfo bitmapinfo = (CGBitmapInfo)kBitmapInfo; //kCGImageAlphaNoneSkipFirst; //0; //kCGBitmapAlphaInfoMask; //kCGImageAlphaNone; //kCGImageAlphaNoneSkipFirst;
    context = CGBitmapContextCreate (bitmapData,// 4
                                     pixelsWide,
                                     pixelsHigh,
                                     8,      // bits per component
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     bitmapinfo
                                     );
    if (context== NULL)
    {
        free (bitmapData);// 5
        fprintf (stderr, "Context not created!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace );// 6

    return context;// 7
}

【问题讨论】:

  • 我试图让它工作.. 一定是 colorWithPatternImage 和 initWithPatternImage 的错误,一点运气都没有。
  • 为 Mac 编写,未在 iOS 上测试。只是说
  • 我在 iOS 上进行了测试,但没有运气使用这些方法。
  • 这就是为什么我在帖子中写道,它没有针对 iOS 进行测试,可能需要针对 iOS 进行修复。需要以 iOS 方式创建上下文。替换MyCreateBitmapContext
  • 为IOS使用图像上下文

标签: sprite-kit


【解决方案1】:

iOS 工作代码:

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];

【讨论】:

    【解决方案2】:

    我发现上面链接的 sprite kit 着色器不适用于 Xcode 10,所以我推出了自己的。这是着色器代码:

    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;
    }
    

    请注意,offset 变量仅在您希望图案集中时才需要 - 如果您希望平铺图案从平铺纹理的左下角开始,您可以省略它,并在下一行添加它。

    另外请注意,您需要手动将 node_sizesprite_size 变量添加到着色器(如果它们发生变化,请更新它们),因为它们都不再具有标准表示。

    // 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
    

    【讨论】:

      【解决方案3】:

      是的,可以通过调用 CGContextDrawTiledImage() 来实现,但是对于中型和大型节点来说这会浪费大量内存。 spritekit_repeat_shader 提供了一种显着改进的方法。这篇博文提供了示例 GLSL 代码并提供了 BSD 许可源。

      【讨论】:

        猜你喜欢
        • 2011-04-22
        • 1970-01-01
        • 2017-03-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-15
        • 1970-01-01
        • 2011-11-28
        • 1970-01-01
        相关资源
        最近更新 更多