在我的应用程序中,我有一个有脚的角色,我想让它在我的应用程序中看起来它站在另一个CCSprite的顶部,因为它在屏幕上移动(动画)。一切都工作正常除了有一点定位问题,我无法搞清楚! 让我再解释一下这个问题,当角色位于CCSprite之上时,似乎角色在非常快的时间间隔内上下移动约10个点。
有谁知道为什么会这样?
谢谢!
最终编辑:我再次感谢您帮助我完成所有这些工作。首先,我删除了所有其他编辑,因为帖子太长了,如果您因任何原因需要引用旧编辑,请查看我的编辑历史记录!
所以经过大约一个小时的测试后,我把它缩小到你之前提到过的一个问题,if语句检查角色和地板块是否发生碰撞 NOT 被调用游戏循环中的迭代,当他们应该时(就他们在UI中看到的那样)。
我的cocosGameLoop日志在所有碰撞检测代码之外,但仍在游戏循环中.f
我也注意到了我的NSLog中的模式,如下所示:
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%的问题我在上面提到过。
无论如何,这是问题的核心,我认为你可以看到我不能做的事情!让我知道你的想法:)。
非常感谢!
答案 0 :(得分: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
块之间振荡,因此当它进入错误的块时设置错误的位置?
好的,假设这些条件都是正确的(我只是不能看到,因为我不知道标签所指的是什么样的身体,联系人听众如何设置等),那么振荡必须由物理模拟引起。使用Box2D在Cocos2d中设置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
循环之外(不一定是在同一个方法中 - 它可以是每个帧调用的任何地方,无论哪个地方最有意义)你都要检查那个标志,如果characterOnPlatfom == YES
,则设置角色的位置是您当前在联系人侦听器for
循环中进行的位置计算。即不要在联系人听众for
循环中做任何事情,除非更改您将在其他地方引用的某些州。
这一改变将使你的角色与平台完全一致。如果您仍然希望角色能够跳出平台,如果玩家进行跳跃等输入,则需要将该标志设置回NO
,否则他们所需的移动将被覆盖我们强迫他们在平台上占据一席之地。
编辑2
您无法确切了解新代码的确切情况。例如,resetgravity
方法中发生了什么?如何将hasCollided
设置为NO(即如何检测角色不再在平台上)?你的角色在上下运动中是不是仍在抖动,或者你提到的闪烁与以前有什么不同?
假设你仍在进行上下移动,我仍然希望这可能是由于你发布的代码没有被每一帧调用,或者它正在与其他一些定位代码作斗争(例如,无论你在何处移动角色以响应玩家的输入,你施加重力等)。
确保在平台上保留角色的代码不会将位置设置得太高并导致角色被检测到不在平台上,因为那样你将陷入以下恶性循环:
如果是这种情况,则需要改进角色何时不与平台发生碰撞的检测,或者偏移定位代码以使角色与平台保持轻微交叉(不是这样看视觉上很糟糕,你可能想要从Box2D形状略微偏移精灵,这样物理体与平台略微相交,但角色的脚似乎正好在平台上。
编辑3
听起来你已经排除了许多可能导致抖动的事情!我问另一位游戏开发者,他建议你的问题可能是由世界空间转换到屏幕空间造成的。因此,您可以尝试注销角色的世界位置,以及渲染它的屏幕位置(这可能意味着更改Cocos2D中完成此转换的代码)。至少看一下注销的值可能有助于缩小一些抖动/振荡的值。您还可以查找可能引入的任何舍入点错误,例如将浮点精度截断为整数。如果你的抖动看起来只是在+或 - 1像素的范围内,那么很可能值得研究世界位置与屏幕位置。记录这些值将比每帧停止调试器更容易检查。