3

我有使用 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

4

2 回答 2

3

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

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

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

AnUIPanGestureRecognizer被传递给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(与我的手指移动的速度相同。

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

于 2013-11-03T17:04:40.603 回答
1

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

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

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

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

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

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

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

于 2013-10-13T19:19:33.547 回答