CCSprite定位问题在其他CCSprite之上,因为它动画屏幕?

Sim*_*iwi 5 position box2d cocos2d-iphone ios ccsprite

在我的应用程序中,我有一个有脚的角色,我想让它在我的应用程序中看起来它站在另一个CCSprite的顶部,因为它向上移动屏幕(动画).一切都工作正常除了有一点定位问题,我无法搞清楚!让我再解释一下这个问题,当角色位于CCSprite之上时,似乎角色在非常快的时间间隔内上下移动约10个点.

有谁知道为什么会这样?

谢谢!

最终编辑:我再次感谢你帮助我完成所有这些工作.首先,我删除了所有其他编辑,因为帖子太长了,如果您因任何原因需要引用旧编辑,请查看我的编辑历史记录!

所以经过大约一个小时的测试后,我把它缩小到你前面提到过的一个问题,if语句检查角色和地板块是否发生碰撞是不是在游戏循环中每次迭代都被调用(当它们应该是的时候)(只要他们看到UI).

我的cocosGameLoop日志在所有碰撞检测代码之外,但仍然在游戏loop.f中

我也注意到我的NSLogs中有一个模式,如下所示:

2012-05-27 17:00:54.791 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.811 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.825 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.841 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.858 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.874 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.891 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.908 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.924 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.928 App[2769:707] collisiontwo
2012-05-27 17:00:54.929 App[2769:707] two
2012-05-27 17:00:54.941 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.944 App[2769:707] collisiontwo
2012-05-27 17:00:54.945 App[2769:707] two
2012-05-27 17:00:54.958 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.974 App[2769:707] cocosGameLoop
2012-05-27 17:00:54.991 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.008 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.025 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.043 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.058 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.076 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.078 App[2769:707] collisiontwo
2012-05-27 17:00:55.078 App[2769:707] two
2012-05-27 17:00:55.091 App[2769:707] cocosGameLoop
2012-05-27 17:00:55.094 App[2769:707] collisiontwo
Run Code Online (Sandbox Code Playgroud)

当我NSLog字符Y坐标时,我也注意到它在一些交互中保持在同一点附近(即使它应该发生碰撞,所以它会与上面NSLog中的一堆cocosGameLoop调用一致),然后当它实际上碰撞(编程),它从之前的Y坐标向上移动大约14个点.所以抖动大约为14点上/下.

所以最重要的是,如何使冲突代码被称为每次迭代并且不会抖动大约14个点?我不想改变锚点,因为这会弄乱我的动画定位等等.无论如何,你推荐什么?另外请记住,我只使用Box2D进行碰撞检测,因此我必须将所有内容保存在Cocos2D代码中.

最后,我认为我的应用程序中存在圆点错误,因为重力,但即使我搞砸了诸如将重力更改为整数的值,它也没有修复闪烁因此它是100%我上面提到的问题.

无论如何,这是问题的核心,我认为你可以看到我不能做的事情!让我知道你的想法 :)

非常感谢!

Rob*_*b B 3

首先看起来奇怪的是你在评论后检查标签Some other tag collision checking before。这会更有意义:

else if ((spriteA.tag == 1 && spriteB.tag == 5) || (spriteB.tag == 1 && spriteA.tag == 5))
...
else if ((spriteA.tag == 6 && spriteB.tag == 1) || (spriteB.tag == 6 && spriteA.tag == 1))
...
Run Code Online (Sandbox Code Playgroud)

也就是说,假设您正在测试的碰撞接触可以以任一顺序为您提供两个身体 - 例如,对于两个碰撞的物体,例如角色和地面,接触侦听器可以将地面作为身体 A,将脚作为身体 B,或者将脚作为身体 B body A 和 ground 作为 body B。上面的语句将保证无论顺序如何,您都会执行相同的条件块。您的执行路径是否有可能在两个else if块之间振荡,因此当进入错误的块时设置了错误的位置?

好的,所以假设这些条件都是正确的(我只是看不到这一点,因为我不知道标签引用了什么主体,如何设置接触侦听器等),那么振荡一定是由物理模拟。当你在 Cocos2d 中使用 Box2D 设置 CCSprite 的位置时会发生什么?设置精灵的位置是否也会改变物理体的位置,或者两者是独立的(精灵通常在物理体的位置渲染)?自从我使用 Cocos2d 以来已经有一段时间了,它与早期相比已经发生了很大的变化,所以在没有打开最新版本并查看之前我不确定这一点。如果改变 CCSprite 的位置也会改变物理体的位置,那么这是一件坏事 - 所有运动都应该由物理模拟控制(所以如果你想移动物理体,你应该对其施加力或脉冲,而不是直接设置位置)。当物理模拟的下一步运行时,在物理之外改变身体的位置可能会导致振荡或施加到身体的不正确的脉冲。如果您想在不扰乱物理模拟的情况下更改精灵的位置,请考虑在您想要直接设置位置的所有时间内从物理模拟中删除与该精灵关联的物理主体,然后在稍后重新添加它如果你想让它在物理作用下起作用。如果没有干净的方法从物理世界中添加/删除物理体,这可能意味着删除物理体并稍后重新创建它。

另一种解决方案是在要一起移动的主体之间创建一个关节。距离连接或焊接接头是最合适的。这将使它们连接起来,因此当您移动一个物体时,另一个物体也会移动,从而保持两个物体之间的距离相同。在这种情况下,它们都将在物理模拟下起作用。

事实上,我刚刚想到你可能会改变角色和它所在的 CCSprite 的物理体的位置。在这种情况下,这不仅很糟糕,因为物理模拟不受控制,而且您的位置计算也可能导致两个物体稍微重叠,因此当物理模拟下次运行时,它会对两个物体施加很大的力迫使它们分开,但随后您将位置更改回重叠,因此下一次更新会再次产生很大的力。

如果您更改 CCSprite 的位置实际上并没有更改物理体的位置,并且您基本上只是将玩家的渲染位置设置为与物理体在世界中的位置不同,那么您需要考虑物理体正在发生什么。它是在滚动、从世界上掉下来、在其他物体或其他东西之间摇摆吗?如果不了解更多关于你的游戏的信息,我很难判断它可能会发生什么。但它所发生的事情可能会影响您的头寸计算。如果您想在精灵周围移动而不让它们受到物理模拟的影响,请考虑从物理世界中删除物理对象。在处理物理实体时,进行某种调试绘制是非常宝贵的,因此您可以看到每个实体的确切形状和位置以及它正在与什么交互,而不管您自己的精灵或其他艺术品如何。不确定 Cocos2D/Box2D 组合是否提供了开箱即用的功能,但如果没有,请强烈考虑实现它,并通过一种简单的方法来打开/关闭它。

还需要考虑的一件事是以下两个陈述:

if (spriteA.position.x - spriteA.boundingBox.size.height*.5 <= spriteB.position.x + spriteB.boundingBox.size.height*.5)
Run Code Online (Sandbox Code Playgroud)

if (spriteB.position.x - spriteB.boundingBox.size.height*.5 <= spriteA.position.x + spriteA.boundingBox.size.height*.5)
Run Code Online (Sandbox Code Playgroud)

您是否尝试过删除这两个语句,以便每帧设置一个新位置,而不是等待位置中的一些错误在几帧上累积?如果您正在移动一个对象,并且希望另一个对象也像牢固连接一样移动,那么您需要每帧更新位置。可能您只通过了这个条件,例如每 30 帧中有 10 帧,因此假设 30 fps,这将产生非常明显的抖动运动,而不是您想要的平滑运动。

希望上述内容可以解决您的问题,或者至少让您更好地了解从哪里开始寻找。在您的问题中提供更多信息 - 也许回应我提到的一些假设/未知因素 - 应该有助于我们深入了解您的问题:)

编辑1

感谢您向我们提供额外的详细信息,这让事情变得更加清晰。既然我知道您只是使用 Box2D 进行碰撞检测,那么您所做的事情就完全有意义了。

我想说,为了解决你的问题,在for你查看联系人的循环中,当你检测到已进行接触时,你应该设置一个标志,而不是改变此时字符的位置,例如BOOL characterOnPlatform- 将其设置为YES当检测到接触时。在该循环之外for(但不一定采用相同的方法 - 它可以在每帧调用的任何地方,以及最有意义的地方),您将检查该标志和 if characterOnPlatfom == YES,然后将字符的位置设置为您正在计算的位置当前正在联系侦听器for循环中进行。即,除了更改您将在其他地方引用的某些状态之外,不要在联系侦听器for循环中执行任何操作。

这种变化将使你的角色完全随着平台移动。如果您仍然希望角色能够跳下平台,则需要在NO玩家进行跳跃等输入时将该标志设置回 ,否则他们所需的移动将被我们强迫他们进入某个位置而覆盖。该平台。

编辑2

实际上不可能确切地看到新代码发生了什么。例如,您的方法发生了什么resetgravity?如何设置hasCollided为NO(即如何检测角色不再在平台上)?您的角色是否仍然上下抖动,或者您提到的闪烁与之前有所不同?

假设您仍然进行上下运动,我仍然认为这是由于您发布的代码没有在每一帧中被调用,或者它正在与其他一些定位代码(例如,无论您移动到哪里)周围的角色响应玩家的输入,在其中应用重力等)。

确保将角色保留在平台上的代码不会将位置设置得太高,导致角色被检测为不在平台上,否则您将陷入以下恶性循环:

  • 角色与平台碰撞
  • 角色位置设置为平台上方
  • 角色不再与平台碰撞,因此定位代码不会运行以将其重新定位在平台上
  • 由于重力的影响,角色向下坠落(或者无论您如何模拟)
  • 角色与平台碰撞
  • ...

如果是这种情况,那么您需要改进对角色何时不与平台碰撞的检测,或者偏移您的定位代码,以便角色保持与平台稍微相交(如果这在视觉上看起来很糟糕,您可能想要将精灵从 Box2D 形状稍微偏移,以便物理体与平台稍微相交,但角色的脚看起来正好在平台上。

编辑3

听起来您已经排除了很多可能导致抖动的因素!我问了另一位游戏开发者,他建议你的问题可能是由世界空间到屏幕空间的转换引起的。因此,您可以尝试注销角色的世界位置,以及渲染角色的屏幕位置(这可能意味着更改 Cocos2D 中完成此转换的代码)。至少查看注销的值可能有助于缩小一些抖动/振荡的值的范围。您还可以查找可能引入的任何舍入点错误,例如将浮点精度截断为整数。如果您的抖动看起来仅在 + 或 - 1 像素区域内,那么很值得研究一下世界位置与屏幕位置。记录这些值比每帧停止调试器更容易检查。