如何平铺 Sprite 节点的纹理?

Posted

技术标签:

【中文标题】如何平铺 Sprite 节点的纹理?【英文标题】:How to tile a Sprite Node's Texture? 【发布时间】:2015-02-06 01:08:10 【问题描述】:

使用 SpriteKit,我将如何平铺水平重复的 SKTexture 以填充 SKSpriteNode 的宽度?这是我目前所拥有的 - 只是拉伸纹理。

var header = SKSpriteNode()
let headerTexture = SKTexture(imageNamed: "inGameHeader-1.png")
header = SKSpriteNode(texture: headerTexture)
header.position = CGPoint(x: 0, y: CGRectGetMaxY(self.frame)-39)
header.size.width = CGRectGetWidth(self.frame)
header.size.height = 150
header.anchorPoint = CGPoint(x: 0,y: 1)
addChild(header)

【问题讨论】:

我认为目前没有简单的方法来平铺纹理,但是您可以在一次绘制过程中生成许多精灵。这会给你类似的结果...... 嗯,我该怎么做呢?我真正需要做的就是重复一个 1px 宽度的渐变来填充标题背景。我只是认为这比使用 600 像素宽度的渐变(仅重复 1 像素)更有效 正如我所说,目前没有简单的方法可以做到这一点,但你不必担心,Spritekit 有它的方法来优化事情:developer.apple.com/library/ios/documentation/GraphicsAnimation/… 【参考方案1】:

这是我的解决方案:将您的图像发送到此函数,带有精灵的大小,然后是图块的大小。这将返回一个平铺的 SKTexture。

-(SKTexture *)tiledTextureImage:(UIImage *)image ForSize:(CGSize)size tileSize:(CGSize)tileSize

// First we create a new size based on the longest side of your rect
int targetDimension = (int)fmax(size.width,size.height);
CGSize targetSize = CGSizeMake(targetDimension, targetDimension);

// Create a CGImage from the input image and start a new image context.
struct CGImage *targetRef = image.CGImage;
UIGraphicsBeginImageContext(targetSize);
CGContextRef contextRef = UIGraphicsGetCurrentContext();

// Now we simply draw a tiled image
CGContextDrawTiledImage(contextRef, CGRectMake(0,0, tileSize.width,tileSize.height), targetRef);
UIImage *tiledTexture = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Finally create a texture and return it. 
return  [SKTexture textureWithImage:tiledTexture];

【讨论】:

谢谢,工作正常,但这样做的一个问题是您将 targetSize 强制为基于最大高度或宽度的正方形。虽然它填充了精灵,但实际上它“过度填充”,在屏幕外留下了额外的图块。我不需要额外的行李,所以我取出前两行并使用我传递的“大小”而不是 targetSize。【参考方案2】:

你知道你可以通过 resizableImageWithCapInsets 在 UIButton 或 UIImageView 中做到这一点,所以,这是我的解决方案:

-(SKTexture *)textureWithImage:(UIImage *)image tiledForSize:(CGSize)size withCapInsets:(UIEdgeInsets)capInsets
//get resizable image
image =  [image resizableImageWithCapInsets:capInsets];
//redraw image to target size
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
[image drawInRect:CGRectMake(0, 0, size.width-1, size.height-1)];
[[UIColor clearColor] setFill];
//get target image
UIImage *ResultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// get texture
SKTexture * texture = [SKTexture textureWithImage:ResultImage];
return texture;

【讨论】:

这个方法有效【参考方案3】:

这是 Swift 3 和 4 的静态函数。不使用扩展,因为 SKTexture 类实际上没有指定的初始化程序。

请注意,这不会非常高效。最好在使用前预加载纹理,或者深入了解自定义着色器的世界。

static func generateTiledTexture(size: CGSize, imageNamed imageName: String) -> SKTexture? 
    var texture: SKTexture?

    UIGraphicsBeginImageContext(size)
    let context = UIGraphicsGetCurrentContext()

    if let image = UIImage(named: imageName), let cgImage = image.cgImage 
        context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height), byTiling: true)

        if let tiledImage = UIGraphicsGetImageFromCurrentImageContext() 
            texture = SKTexture(image: tiledImage)
        
    

    UIGraphicsEndImageContext()

    return texture

【讨论】:

以上是关于如何平铺 Sprite 节点的纹理?的主要内容,如果未能解决你的问题,请参考以下文章

unity中Sprite内平铺

从 sprite_sheet 坐标创建纹理

cocos源码分析--Sprite绘图原理

如何防止 Sprite 节点相互推挤?

在Sprite纹理中检测触摸而不是整个框架iOS Swift SpriteKit?

OpenGL纹理不会绘制