【问题标题】:How to implement mouse joint in Sprite Kit?如何在 Sprite Kit 中实现鼠标关节?
【发布时间】:2013-10-13 18:00:46
【问题描述】:

我已经在 Cocos2d + Box2d for iOS 中实现了拖放功能。我需要将它移植到 Sprite Kit。逻辑非常基本:

  • 当用户触摸屏幕时,找到手指下的精灵
  • 在找到的精灵和场景的物理主体之间创建鼠标关节,将关节的目标设置为触摸位置
  • 当触摸移动时,将关节的目标更新到新位置
  • 触摸结束时,移除关节

一切运行良好。我喜欢触摸结束时模拟物理的方式 - 拖动的形状的速度取决于拖动速度和方向,所以当我在移动精灵时将手指从屏幕上移开时,它将继续沿相同方向移动,但现在受重力和阻尼。

很遗憾,我无法使用 Sprite Kit 重现相同的效果。没有像鼠标关节这样的关节,但我尝试过使用其他关节类型。我几乎成功地使用了 SKPhysicsJointFixed - 我正在创建新的精灵和它与拖动精灵之间的关节,当触摸移动时我正在移动新创建的精灵。不幸的是,它不像 Cocos2d + Box2d 中的鼠标关节那样工作——在拖动精灵时,它的速度总是为零。因此,每次我将手指从屏幕上移开时,拖动的精灵都会立即停止并开始受到重力影响而下落。无论我在拖动时移动手指的速度有多快,在释放拖动的形状后,它的行为方式完全相同。

我的问题是如何在 Sprite Kit 中实现鼠标关节,或者如何实现如上所述的拖放功能?

更新: 这是一个 box2d 鼠标关节示例,可以让您更清楚地了解我尝试使用 Sprite Kit 实现的内容: http://blog.allanbishop.com/wp-content/uploads/2010/09/Box2DJointTutorial1.swf

【问题讨论】:

  • Box2D 是开源的,鼠标关节只有几百行代码。这是有点神秘的代码,但在你的应用中实现它是你可以考虑获得你正在寻找的确切行为的一种可能性。
  • @iforce2d 好主意,我什至查看了 Box2d 代码,希望能够了解鼠标关节如何在引擎盖下工作,并为 Sprite Kit 编写自己的实现,但是它似乎比我复杂得多。基于Box2d开源代码我无法实现鼠标关节,所以在这里寻求帮助:-)

标签: ios drag-and-drop box2d sprite-kit


【解决方案1】:

我对 iOS 开发还很陌生,所以我想这可能不是最好的方法,但这就是我解决它的方法,实际上它似乎工作得非常顺利。

我正在使用UIPanGestureRecognizer 来处理触摸事件。我用这个代码在我的didMoveToView: 中设置了这个:

UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];

UIPanGestureRecognizer 被传递给handlePan:,如果触摸停止,我会检查recognizer.state == UIGestureRecognizerStateEnded。这就是我想要“释放”对象并“让它飞走”的地方。为此,我需要计算一些东西,首先我使用以下代码获得手指/触摸的速度:

CGPoint velocity = [recognizer velocityInView:recognizer.view];

(我使用与其他语句相同的方法(handlePan:)在触摸开始时获取正确的对象,并通过将对象的位置设置为触摸的位置让对象始终位于手指下方移动时)

现在我知道了速度,但我仍然不知道我需要对物体施加多大的力。您应该能够通过以下公式计算力:力 = 质量 * 加速度。我们知道质量(object.physicsBody.mass)并且我们知道速度。要获得加速度,我们还需要时间,因为加速度 = 速度 / 时间。

在每次要渲染新帧时调用的 update: 方法中,我通过执行以下操作来计算上次要渲染帧的时间之间的差异:

self.delta = currentTime - self.lastTime;
self.lastTime = currentTime;

我现在可以计算出使物体以我“拖入”的速度移动所需的力。为此,我执行以下操作:

[self.currentNode.physicsBody applyForce:CGVectorMake(velocity.x/self.delta * self.currentNode.physicsBody.mass, -velocity.y/self.delta * self.currentNode.physicsBody.mass)];

我将速度除以自上一帧 (self.delta) 以来的时间差以获得加速度,然后将其乘以物体的质量以获得保持(或实际获得)物体移动所需的力以与我的手指移动相同的方向和相同的速度。

目前这对我有用,我希望它也可以帮助其他人,如果我有什么问题或者是否有更好的解决方案,请告诉我。到目前为止,我还没有找到任何“原生解决方案”。

【讨论】:

  • 看起来很有希望!我稍后会尝试您的解决方案,目前我正忙于另一个项目。同时:这是一个使用 box2d 的鼠标关节物理示例:blog.allanbishop.com/wp-content/uploads/2010/09/… 您能否确认您使用所描述的手势识别器获得了类似的行为?
  • 我想到了其他事情:@LearnCocos2D 接缝提供的解决方案在节点从触摸中释放后的行为方面工作得很好,但问题是移动对象并不完全就像使用 box2d 鼠标关节一样自然。据我了解,您是通过直接设置节点位置来移动节点,而手势识别器的东西仅用于在释放时施加力,对吗?
  • 释放后的行为与我要说的示例相同,但如果对象在拖动时平滑移动很重要,那么我的解决方案可能不是最好的,因为正如你所说,我直接设置了位置,这与您链接到的示例不同。在我的情况下,重要的部分是释放时,并且在移动它时看起来不太难看(无论如何手指几乎总是会覆盖我的物体),所以我担心这可能不是你想要的解决方案.
【解决方案2】:

如果唯一的问题是速度,那么解决起来很简单。

从上一个触摸位置减去当前触摸位置,得到最后一次和当前触摸之间的速度。使用applyForce: 将此速度应用于身体。

为了防止body在拖拽的时候自己移动,调用applyForce:后从body中读出新的速度,保存在ivar中,设置body的速度为零。

当触摸结束时,将身体的速度设置为您作为 ivar 保留的速度。

如果这不起作用,请尝试使用 applyImpulse: 和/或在调用这两种方法中的任何一种之前设置速度,即:

sprite.physicsBody.velocity = bodyVelocity;
[sprite.physicsBody applyForce:touchVelocity];
bodyVelocity = sprite.physicsBody.velocity;
sprite.physicsBody.velocity = CGVectorMake(0, 0);

这样你可以在拖动时保持身体的速度而不会失去对它的控制。

【讨论】:

  • 好的,我试过你的解决方案,我能够根据触摸位置的变化计算速度。不幸的是,我不知道如何在“释放”触摸后将计算出的速度应用于拖动的身体。当触摸结束时,我只需将关节从世界中移除,然后我可以设置速度或对拖动的身体施加力或冲量,但它不起作用。无论我使用多大的矢量,看起来身体的速度都会立即重置为零。
  • 不知何故,我成功地在触摸结束后应用了冲动。现在物理行为更像 Cocos2d+Box2d。不幸的是,这仍然不像在 Cocos2d+Box2d 中那样自然。我将在真实设备上玩这两个项目并尝试调整 Sprite Kit 中的参数,但我相信必须有更好的解决方案。这样的逻辑应该由物理引擎计算。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多