Comment implémenter un joint de souris dans Sprite Kit?

J'ai travaillé l'implémentation de la fonction glisser-déposer écrite dans Cocos2d + Box2d pour iOS. J'ai besoin de le porter sur Sprite Kit. La logique est assez basique:

  • lorsque l'user touche l'écran, trouve le sprite sous le doigt
  • créer un joint de souris entre l'image-object trouvée et le corps physique de la scène, positionner la cible de l'articulation sur la position du contact
  • lorsque les touches sont déplacées, mettre à jour la cible de l'articulation vers une nouvelle position
  • Lorsque les touches sont terminées, retirer l'articulation

Tout fonctionne très bien. J'aime la façon dont la physique est simulée quand les touches se terminent – la forme traînée a une vitesse dépendante de la vitesse et de la direction, donc quand je quitte mon doigt de l'écran tout en déplaçant l'image, je continue à bouger dans la même direction. gravité et amortissement.

Malheureusement, je ne suis pas capable de reproduire le même effet en utilisant Sprite Kit. Il n'y a pas de telles articulations comme l'articulation de la souris, mais j'ai essayé d'utiliser d'autres types de joints. J'ai presque réussi avec SKPhysicsJointFixed – Je suis en train de créer un nouveau sprite et un joint entre celui-ci et l'image-object déplacée, lorsque je touche au mouvement, je déplace le sprite nouvellement créé. Malheureusement, cela ne fonctionne pas comme un joint de souris dans Cocos2d + Box2d – tout en faisant glisser le sprite, sa vélocité est toujours égale à zéro. Ainsi, chaque fois que j'ai laissé mon doigt sur l'écran, le sprite traîné s'arrête immédiatement et commence à tomber affecté par la gravité. Peu importe la rapidité avec laquelle je bouge le doigt en tirant, après avoir relâché la forme traînée, il se comporte exactement de la même manière.

Ma question est de savoir comment implémenter un joint de souris dans Sprite Kit, ou comment implémenter une fonctionnalité glisser-déposer qui fonctionne comme décrit ci-dessus?

Mise à jour: Ceci est un exemple de souris commune box2d qui pourrait vous donner une vision plus claire de ce que j'essaie de mettre en œuvre en utilisant Sprite Kit: http://blog.allanbishop.com/wp-content/uploads/2010/09/Box2DJointTutorial1.swf

Je suis assez nouveau dans le développement iOS, donc je suppose que ce n'est peut-être pas le meilleur moyen, mais c'est comme ça que je l'ai résolu et ça semble fonctionner plutôt bien.

J'utilise un UIPanGestureRecognizer pour gérer l'événement tactile. J'ai mis ceci dans mon didMoveToView: avec ce code:

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

Un UIPanGestureRecognizer est passé à handlePan: et je vérifie avec recognizer.state == UIGestureRecognizerStateEnded si le touché s'est arrêté. C'est là que je veux "relâcher" l'object et "le laisser s'envoler". Pour ce faire, j'avais besoin de calculer quelques choses, tout d'abord, je reçois la vitesse du doigt / toucher avec ce code:

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

(J'utilise la même méthode ( handlePan: avec d'autres instructions pour get le bon object quand le toucher commence, et laisser l'object sous le doigt tout le time en réglant la position de l'object à l'endroit du toucher quand on bouge)

Maintenant, je connais la vélocité, mais je ne sais toujours pas quelle force j'ai besoin d'appliquer à l'object. Vous devriez être capable de calculer la force par cette formule: Force = masse * accélération. Nous connaissons la masse (object.physicsBody.mass) et nous connaissons la vitesse. Pour get l'accélération, nous avons aussi besoin du time car accélération = vitesse / time.

Dans ma update: méthode qui est appelée chaque fois qu'une nouvelle image doit être rendue, je calcule la différence entre la dernière fois qu'une image était sur le point d'être rendue en faisant quelque chose comme ceci:

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

Je peux maintenant calculer quelle force est nécessaire pour faire bouger l'object dans la vélocité que je suis en train de "faire glisser". Pour ce faire, je fais ce qui suit:

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

Je prends la vitesse divisée avec la différence de time depuis la dernière image ( self.delta ) pour get l'accélération, puis la multiplie avec la masse de l'object pour get la force nécessaire pour garder (ou get) l'object en mouvement dans le même direction et dans la même vitesse qu'il a été déplacé par mon doigt.

Cela fonctionne pour moi en ce moment et j'espère que cela aidera d'autres personnes aussi, et dites-moi s'il y a quelque chose qui ne va pas ou s'il y a une meilleure solution. Jusqu'à présent, je n'ai trouvé aucune "solution native".

Si le seul problème est la vélocité, alors c'est simple à réparer.

Soustrayez la position tactile actuelle de la position tactile précédente pour get la vélocité entre le dernier contact et le toucher actuel. Utilisez applyForce: pour appliquer cette vélocité au corps.

Afin d'empêcher le corps de se déplacer tout seul en faisant glisser, lisez la nouvelle vélocité du corps après avoir appelé applyForce: et gardez-la dans un ivar et réglez la vitesse du corps à zéro.

Lorsque le toucher se termine, réglez la vélocité du corps sur celle que vous gardez comme ivar.

Si cela ne fonctionne pas, essayez d'utiliser applyImpulse: et / ou en définissant la vélocité avant d'appeler l'une des deux methods, c'est-à-dire:

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

De cette façon, vous pouvez garder la vélocité du corps sans perdre le contrôle de celui-ci pendant le déplacement.