5

在我的应用程序中,我有一个有脚的角色,我想制作它,以便在我的应用程序中它看起来像站在另一个 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

当我 NSLog 字符 Y 坐标时,我还注意到它在几个交互中保持在同一点附近(即使它应该发生碰撞,因此它会与上面 NSLog 中的一堆 cocosGameLoop 调用重合),然后当它实际上碰撞(以编程方式),它从之前的 Y 坐标向上移动了大约 14 个点。所以有大约 14 个点的上下抖动。

所以底线是,我如何才能使碰撞代码在每次迭代中都被调用并且不会抖动大约 14 点?我不想更改锚点,因为这会弄乱我的动画定位等等。无论如何,你有什么推荐的?另外请记住,我只使用 Box2D 进行碰撞检测,所以我必须将所有内容保存在 Cocos2D 代码中。

最后,我认为由于重力,我的应用程序中存在舍入点错误,但即使我弄乱了诸如将重力更改为整数之类的值,它也没有解决闪烁问题,所以这是我上面提到的 100% 的问题.

无论如何,这是问题的核心,我认为你可以看到一些我看不到的东西!让我知道你的想法 :)

非常感谢!

4

1 回答 1

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))
...

即,这假设您正在测试的碰撞接触可以以任一顺序为您提供两个身体 - 例如,对于两个碰撞的物体,比如角色和地面,接触侦听器可以将地面作为身体 A,将脚作为身体 B,或者将脚作为主体 A 和地面作为主体 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)

if (spriteB.position.x - spriteB.boundingBox.size.height*.5 <= spriteA.position.x + spriteA.boundingBox.size.height*.5)

您是否尝试过删除这两个语句,以便每帧设置一个新位置,而不是等待位置中的一些错误在几帧上累积?如果您正在移动一个对象,并且您希望另一个对象像牢固地连接一样四处移动,那么您需要每帧更新位置。可能是你只通过了这个有条件的说每 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 像素的区域内,那么很值得研究世界位置与屏幕位置。

于 2012-05-20T13:33:24.577 回答