如何在Sprite Kit中实现鼠标关节?

时间:2013-10-13 18:00:46

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

我正在使用Cocos2d + Box2d为iOS编写拖放功能。我需要将它移植到Sprite Kit。逻辑是非常基本的:

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

一切都很顺利。我喜欢当触摸结束时物理模拟的方式 - 拖动的形状具有取决于拖动速度和方向的速度,因此当我在移动精灵时将手指从屏幕上移开时,它将继续沿同一方向移动,但是现在受到影响重力和阻尼。

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

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

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

2 个答案:

答案 0 :(得分:3)

我对iOS开发很陌生,所以我想这可能不是最好的方法,但这就是我解决它的方式,它实际上看起来非常流畅。

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

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

UIPanGestureRecognizer传递给handlePan:,如果触摸停止,我会与recognizer.state == UIGestureRecognizerStateEnded核对。这就是我想要发布的#34;对象和"让它飞走"。为此,我需要计算一些东西,首先我用这段代码得到手指/触摸的速度:

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

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

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

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

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

我现在可以计算使物体以速度I' m"在"中拖动所需的力。为此,我执行以下操作:

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

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

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

答案 1 :(得分:1)

如果唯一的问题是速度,那么这很容易解决。

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

为了防止身体在拖动时自行移动,请在调用applyForce:后从身体中读出新的速度并将其保持在ivar中并将身体的速度设置为零。

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

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

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

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