用 SKPhysics(碰撞)拖动一个 SKSpriteNode(跟随你的手指动作)
Posted
技术标签:
【中文标题】用 SKPhysics(碰撞)拖动一个 SKSpriteNode(跟随你的手指动作)【英文标题】:Drag a SKSpriteNode (follow your finger movements) with SKPhysics (collision) 【发布时间】:2014-07-15 15:45:27 【问题描述】:想要使用 SKPhysics(启用碰撞)拖动 SKSpriteNode(跟随您的手指移动)
2 个失败的解决方案:
1)
a) 解决方法:改变SKSpriteNode的位置
b) 问题:当用户快速拖动 spriteNode 穿过墙壁时,SKSpriteNode 会“神奇地”意外穿过墙壁(物理似乎不起作用)
c) 代码:
@property (nonatomic) CGPoint translationBy;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self selectNodeForTouch:positionInScene];
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGPoint previousPosition = [touch previousLocationInNode:self];
CGPoint translation = CGPointMake(positionInScene.x - previousPosition.x, positionInScene.y - previousPosition.y);
[self panForTranslation:translation];
- (void)panForTranslation:(CGPoint)translation
CGPoint position = [_selectedNode position];
if([[_selectedNode name] isEqualToString:PLAYER_NAME])
[_selectedNode setPosition:CGPointMake(position.x + translation.x, position.y + translation.y)];
2) 在这里搜索后发现@LearnCocos2D 的advice“当你使用物理时,坚持通过力、脉冲或直接改变体速度来移动物理体。”所以我尝试了:
a) 解决方案:在精灵节点上应用脉冲。
b) 问题:即使我没有拖动精灵节点,精灵节点也会继续移动。 (表现得像一艘漂浮的船。一旦停止拖动,精灵节点将停止;一旦开始拖动,它将跟随手指。
c) 代码:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self selectNodeForTouch:positionInScene];
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGPoint previousPosition = [touch previousLocationInNode:self];
CGPoint translation = CGPointMake(positionInScene.x - previousPosition.x, positionInScene.y - previousPosition.y);
CGVector forceVector = CGVectorMake(translation.x, translation.y);
[self.player.physicsBody applyImpulse:forceVector];
//[self.player.physicsBody setVelocity:CGVectorMake(0, 0)];
-->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
更新:
来自评论: “i)您可以确定节点到手指位置的距离,然后设置每次更新的速度:以便下一帧它将完全位于手指的位置。ii)如果手指和节点位置相同,这将取消阻止任何移动,否则节点会在执行所有物理碰撞时粘在你的手指上,并且在被阻挡的情况下会继续在自身和手指之间推动物体。”
a) 问题:如何禁用轻弹?
b) 问题:精灵节点会随着轻微的(意外)轻弹移动到很远的地方。
c) 代码:
@property (nonatomic) CGPoint translationBy;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGPoint previousPosition = [touch previousLocationInNode:self];
// 1) You could determine the distance of the node to the finger location,
CGPoint xyTranslation = CGPointMake(positionInScene.x - previousPosition.x, positionInScene.y - previousPosition.y);
if (fabsf(positionInScene.x - previousPosition.x) < kPlayerMovementThreshold)
xyTranslation.x = 0;
if (fabsf(positionInScene.y - previousPosition.y) < kPlayerMovementThreshold)
xyTranslation.y = 0;
self.translationBy = xyTranslation;
static const CGFloat kPlayerMovementSpeed = 55.0f;
static const CGFloat kPlayerMovementThreshold = 1.0f;
-(void)update:(CFTimeInterval)currentTime
// ii) then set the velocity every update: so that it will exactly be on the finger's position the next frame.
CGFloat dx = self.translationBy.x*kPlayerMovementSpeed;
CGFloat dy = self.translationBy.y*kPlayerMovementSpeed;
CGVector velocityVector = CGVectorMake(dx,dy);
[self.player.physicsBody setVelocity:velocityVector];
【问题讨论】:
你可以添加一个 bool should_move,在 touchesBegan 内部设置 should_move 为 true,在 touchesEnded 内部设置 should_move 为 false,现在在更新类型 if (!should_move) [self.player.physicsBody setVelocity:CGVectorMake(0 , 0)];,现在您的播放器只有在您将手指放在屏幕上时才会响应。 Opps... 我忘了说 touchesEnded 方法没有被调用,因为我的手指还在屏幕上。 (但是精灵节点仍然移动-->由冲动引起) 现在你应该处理位置之间的差异,如果 (fabsf(positionInScene.x - previousPosition.x) 您可以确定节点到手指位置的距离,然后设置每次更新的速度:以便下一帧准确位于手指位置。如果手指和节点的位置相同,这将抵消任何移动,否则节点将在执行所有物理碰撞时粘在您的手指上,并在被阻挡的情况下继续在自己和手指之间推动物体。 @JulioMontoya 你能详细说明一下吗?如在哪里设置 if (fabsf(positionInScene.x - previousPosition.x) 【参考方案1】:我所做的是制作一个 SKNode,我们称之为“a”,并附有一个非常小的物理体。这个新节点通过 SKPhysicsJointSpring 连接到我要移动的节点,我们称之为“b”。新节点 a 跟踪我的手指运动,弹簧确保目标节点 b 跟随。因为节点 b 是使用物理定位的,所以碰撞检测按预期工作。
【讨论】:
如何移动节点a
?我试图通过设置a.position
来做到这一点,但这会使a
远离b
而不会移动b
。然后弹簧将通过将a
移回b
来放松,而不是像我们想要的那样将b
引导到a
的方向。似乎设置position
以某种方式绕过了物理模型。或者我弄错了。以上是关于用 SKPhysics(碰撞)拖动一个 SKSpriteNode(跟随你的手指动作)的主要内容,如果未能解决你的问题,请参考以下文章