我已成功将大图像 (640 x 6000) 分割成 20 block ,但不知道使用这些图像的最佳方式是什么。
我唯一的想法是创建 20 个 Sprite ,并使用相同的移动 Action 将它们全部添加到屏幕上,以便它们看起来在滚动。
但这不会使用与将整个图像加载到内存中相同的内存量吗?
我浏览了 sprite 套件文档,但不明白它是如何完成的。
有人可以帮忙吗?
谢谢
最佳答案
我建议跳过滚动操作并使用更新方法。还有一种方法可以同时只显示几个背景部分。
首先,您需要创建纹理图集并在其中添加所有这些图像。 其次,您需要在场景中创建两个属性:
SKSpriteNode *firstNode;
SKSpriteNode *secondNode;
我还建议添加所述图集作为实例变量,例如
SKTextureAtlas *atlas;
在场景的 init 方法或您的其他设置方法中,您需要创建并定位这些节点。另外,不要忘记在此之前创建纹理图集变量。
self.firstNode = [[SKSpriteNode alloc] initWithTexture:[self.atlas textureNamed:@"texture1"]];
self.secondNode = [[SKSpriteNode alloc] initWithTexture:[self.atlas textureNamed:@"texture2"]];
通常在这种情况下,我会将这些 Sprite 的 anchor 更改为 CGPointMakeZero,以简化定位计算。这可以像这样完成:
self.firstNode.anchorPoint = CGPointZero;
self.secondNode.anchorPoint = CGPointZero;
它在某种程度上有帮助, Sprite 的 (0,0) 点是 Sprite 的左下角。
现在我们可以根据需要将 Sprite 添加到我们的世界中,可以直接添加到场景中,也可以添加到中间世界节点中。
self.firstNode.position = CGPointMake(0, 0); // or CGPointZero
self.secondNode.position = CGPointMake(self.firstNode.size.width, 0);
现在我们有两个相互跟随的节点。
我们如何滚动?我们需要改变更新方法。我们需要创建新属性 CFTimeInterval lastUpdate,我们需要它来存储自上次更新以来耗时,并从中计算出移动节点所需的像素量。
-(void)update:(CFTimeInterval)currentTime {
if (!self.lastUpdate) {
self.lastUpdate = currentTime;
self.secondsCounter = 0;
return;
}
double delta = currentTime - self.lastUpdate;
self.lastUpdate = currentTime;
[self updateGroundScrollingWithDelta:delta];
}
这是实际滚动节点的方法(您需要在其他地方定义一些 moveSpeed 或者只是将其更改为某个常量):
- (void)updateGroundScrollingWithDelta:(double)delta
{
self.firstNode.position = CGPointMake(self.firstNode.position.x - delta * moveSpeed, self.firstNode.position.y);
self.secondNode.position = CGPointMake(self.secondNode.position.x - delta * moveSpeed, self.secondNode.position.y);
if (self.firstNode.position.x < -self.firstNode.size.width) {
self.firstNode.position = CGPointMake(self.secondNode.position.x + self.secondNode.size.width - 1, self.firstNode.position.y);
// here you need to change the texture of your node
}
if (self.secondNode.position.x < -self.secondNode.size.width) {
self.secondNode.position = CGPointMake(self.firstNode.position.x + self.firstNode.size.width - 1, self.secondNode.position.y);
// here you need to change the texture of your node
}
}
在此方法中,我们将节点移动一定数量的像素,然后检查 - 如果该节点距离左侧太远并且不可见,我们将该节点附加到另一个节点的末尾,因此我们的滚动似乎无缝。
在某个地方,您将需要更改 Sprite 的纹理,如评论中所述。
为了跟踪纹理,我建议创建一个实例变量int counter
。显然它应该从 2 开始,因为我们已经在两个节点上安排了编号 0 和 1 的纹理。
您可以使用它来查看接下来的纹理。所以在这里我建议一种获取下一个纹理的方法:
- (SKTexture *)nextBackgroundTexture
{
NSString *nextName = [NSString stringWithFormat:@"myTexture%d", self.counter];
self.counter++;
return [self.atlas textureNamed:nextName];
}
所以现在您只需要在需要时更新计数器并交换纹理。 正如我所说,您可以将这些行放在方法的注释部分中以滚动节点:
self.firstNode.texture = [self nextBackgroundTexture];
和
self.secondNode.texture = [self nextBackgroundTexture];
这样你的内存中就只有两个纹理,并且滚动可以正常工作。 (实际上这不是真的,因为 Sprite Kit 缓存了使用过的纹理,但希望它能在将来的某个时候释放它们)。
希望这有帮助。
附注实际上,在重新阅读你的问题后,我发现你需要垂直滚动,改变这一点相当简单,你需要以不同的方式在开始时定位节点,使用 y 坐标和节点高度而不是宽度来查找位置。
还在滚动时更改 Y 值而不是 X 值。
我把这个作为练习留给你。
关于ios - SpriteKit - 从非常大的图像(640 x 6000)创建滚动背景,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24231865/