Cocos2d-iPhone:视网膜和非视网膜屏幕之间的CCSprite位置不同



我有一个使用cocos2d-iPhone构建的相当简单的应用程序,但是一个奇怪的定位问题我一直无法解决。该应用程序使用精灵表,并且应用程序中有一个Retina和非Retina精灵表,它们使用完全相同的艺术品(当然,分辨率除外)。应用程序中还有其他用于CCSprites的插图,这些插图既是标准,又是 -hd 后缀。

在应用中,应用启动时会创建一组精灵。这些最初创建的CCSprites始终在视网膜和非视网膜屏幕上相同(且正确)的位置。

// In method called to setup sprites when app launches
// Cache & setup app sprites
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: @"sprites.plist"];
sprites = [CCSpriteBatchNode batchNodeWithFile: @"sprites.png"];
hill = [CCSprite spriteWithSpriteFrameName: @"hill.png"];
hill.position = ccp( 160, 75 );
[sprites addChild: hill z: 1];
// ... [create more sprites in same fashion]
// NOTE: All sprites created here have correct positioning on Retina & non-Retina screens

当用户以某种方式点击屏幕时,将调用一个方法,该方法创建另一组CCSprites(屏幕内和屏幕外),并将它们全部放入动画中。其中一个精灵,hand,总是在视网膜和非视网膜屏幕上相同(且正确)地定位。其他云(一组云)成功地创建和制作动画,但它们的位置仅在Retina显示屏上是正确的。在非 Retina 显示器上,每个云的起始位置不正确(对于xy或有时两者都不正确),并且它们在动画后的结束位置也是错误的。

我在下面包含了来自触摸方法的负责代码,该方法可以创建新精灵并对其进行动画处理。同样,它在 Retina 显示屏上按预期工作,但在非 Retina 屏幕上不正确。所使用的CCSprites在 app-start 时以相同的方式创建,以设置应用程序中的所有初始精灵,这些精灵始终具有正确的位置。

// Elsewhere, in a method called on touch
// Create clouds
cloud1 = [CCSprite spriteWithSpriteFrameName: @"cloud_1.png"];
cloud1.position = ccp(-150, 320);
cloud1.scale = 1.2f;
cloud2 = [CCSprite spriteWithSpriteFrameName: @"cloud_2.png"];
cloud2.position = ccp(-150, 335);
cloud2.scale = 1.3f;
cloud3 = [CCSprite spriteWithSpriteFrameName: @"cloud_4.png"];
cloud3.position = ccp(-150, 400);
cloud4 = [CCSprite spriteWithSpriteFrameName: @"cloud_5.png"];
cloud4.position = ccp(-150, 420);
cloud5 = [CCSprite spriteWithSpriteFrameName: @"cloud_3.png"];
cloud5.position = ccp(400, 350);
cloud6 = [CCSprite spriteWithSpriteFrameName: @"cloud_1.png"];
cloud6.position = ccp(400, 335);
cloud6.scale = 1.1f;
cloud7 = [CCSprite spriteWithSpriteFrameName: @"cloud_2.png"];
cloud7.flipY = YES;
cloud7.flipX = YES;
cloud7.position = ccp(400, 380);
// Create hand
hand = [CCSprite spriteWithSpriteFrameName:@"hand.png"];
hand.position = ccp(160, 650);
[sprites addChild: cloud1 z: 10];
[sprites addChild: cloud2 z: 9];
[sprites addChild: cloud3 z: 8];
[sprites addChild: cloud4 z: 7];
[sprites addChild: cloud5 z: 6];
[sprites addChild: cloud6 z: 10];
[sprites addChild: cloud7 z: 8];
[sprites addChild: hand z: 10];

// ACTION!!
[cloud1 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(70, 320)]];
[cloud2 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(60, 335)]];
[cloud3 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(100, 400)]];
[cloud4 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(80, 420)]];
[cloud5 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(250, 350)]];
[cloud6 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(250, 335)]];
[cloud7 runAction:[CCMoveTo actionWithDuration: 1.0f position: ccp(270, 380)]];
[hand runAction: handIn];

值得一提的是,在运行应用程序并在标准iPhone和iPhone(视网膜)硬件选项之间切换时,我在iOS模拟器中看到这种不正确的定位行为。我无法验证这种情况在实际的非视网膜 iPhone 上发生或未发生,因为我没有。

但是,这是我唯一一次看到这种奇怪的定位行为发生(用户触摸后获得的错误结果),并且由于我以完全相同的方式创建所有精灵(即[CCSprite spriteWithSpriteFrameName:]然后用cpp()设置position),我将特别感激任何帮助来追踪为什么这组精灵在非 Retina 屏幕上总是不正确。

编辑/更新我添加了一些额外的日志记录来准确调查创建的精灵发生了什么。下面是其中一个云的示例:

// Non-Retina
cloud1 position -- x: 70.000000 y: 320.000000
cloud1 anchor -- x: 0.500000 y: 0.500000
cloud1 size -- w: 384.000000 h: 576.000000
cloud1 origin -- x: -122.000008 y: 31.999989
// Retina
cloud1 position -- x: 70.000000 y: 320.000000
cloud1 anchor -- x: 0.500000 y: 0.500000
cloud1 size -- w: 172.800003 h: 121.800003
cloud1 origin -- x: -16.400003 y: 259.100006

必须说我对此感到非常困惑。我也没有混淆这些日志。非视网膜上的边界框比视网膜上的边界框大?这些宽度/高度值甚至与它们引用的图像的大小都不匹配。也许精灵表/纹理内部发生了一些奇怪的事情?我还注意到起源不匹配。也许这也影响了输出?很奇怪,它只发生在这些精灵身上,而没有发生在其他精灵身上。

任何想法和建议不胜感激。

我可以想象两个原因:

  1. 标清图像的大小并不完全是高清图像的一半
  2. plist 中的图像命名不正确

验证您的高清图像的宽度和高度是否恰好是标清图像的两倍(反之亦然)。由于您是从高清缩小的,因此请确保您的高清图像尺寸可以被两整除。

一个常见的命名错误发生在 plist 中。通常你会有图像.png和图像高清.png。但是,对于纹理图集,情况略有不同。您应该有 atlas.png 和 atlas-hd.png 文件以及相关的 plist 文件,但纹理图集中的图像应该引用 image.png 对于这两个版本。一个典型的错误是将 image-hd.png 添加到 atlas-hd.png 纹理图集。

不确定这些问题是否适用。当然,听起来您可能希望将日志记录添加到精灵位置,然后比较视网膜与标准分辨率位置。如果这些位置正好偏移了另一个版本位置的一半或两倍,您就知道您有一个视网膜与非视网膜定位错误。如果没有,则更有可能是您的定位或移动代码中存在错误。

虽然

问题已经消失了,但对此没有可行的答案。

我再次将所有图像修剪为2的幂,在此过程中减少了一些额外的空间。我将纹理/精灵表创建工具从Zwoptex交换到TexturePacker,并使用新的.plist文件创建了两个新的精灵表作为PVR而不是PNG。

我还决定将 cocos2d libs 升级到最新的稳定版(我之前使用的是 1.0.1 稳定版之前的旧 RC 版本)。

问题消失了,没有进行任何代码更改。奇怪。

我的猜测是替换精灵表是诀窍,但在模拟器完全覆盖应用程序的原始版本之前,您没有看到任何区别。我遇到了图像在模拟器中缓存的问题,我不得不删除应用程序(摆动它,按 X),然后神奇地出现了更新的图像。

如有疑问,请在设备上进行测试。模拟器是很多"高奇怪"的原因。不值得。

我刚刚创建了一个测试应用程序并进行了测试。

因此,对于没有视网膜的设备:图像名称.png - 适用于 iPhone/iPod图片名称~ipad.png -- 适用于 iPad

对于带有视网膜显示屏的设备:ImageName@2x.png - 适用于 iPhone/iPodImageName@2x~iPad.png -- 适用于 iPad

如果您的iPhone高分辨率图像和iPad高分辨率图像具有相同的大小,您仍然可以使用@2x。 要加载图像,只需使用 [UIImage imageNamed:@"ImageName.png"]; 我刚刚在iOS 5.1,5.0和4.3的iOS模拟器上对其进行了测试。 顺便说一下,为什么你应该使用@2x,仅此而已。

最主要的是,您不应该在iPhone和iPad上使用相同的图形,因为iPhone和iPad的尺寸不同。如果您将使用相同的尺寸,则图形已经为您的iPad视网膜显示器完成(如果您以前使用iPhone视网膜显示器)。如果您将使用不同大小的图像,那么您将为iPhone和iPad使用不同的图像名称。所以在这一边,你只需要添加@2x后缀。这就是为什么你应该只使用@2x后缀。- 这些是我的想法。

最新更新