我们有没有办法在某个区域重复图像,比如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
}
答案 0 :(得分:3)
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];
答案 1 :(得分:0)
是的,可以通过调用CGContextDrawTiledImage()来实现它,但这会浪费大量内存用于中型和大型节点。 spritekit_repeat_shader提供了一种显着改进的方法。此博客文章提供了示例GLSL代码,并提供了BSD许可源。
答案 2 :(得分:0)
我发现上面链接的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_size
和sprite_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