7
votes

Python & Pygame: Collision de balle avec intérieur du cercle

Je fais une partie dans laquelle les balles rebondissent autour des à l'intérieur d'un cercle beaucoup plus grand. Le plus grand cercle ne bouge pas.

Voici le code que je suis actuellement en train d'utiliser pour ces collisions: xxx

Il est basé sur le merveilleux tutoriel de Peter Collingridge < a href = "http://www.petercollingridge.co.uk/pygame-physics-simulation/collisions" rel = "noreferrer"> ici .

Les objets du cercle et de la balle sont Les deux classes, avec (x, y), rayon, angle et vitesse.

J'ai deux problèmes avec cette méthode, cependant:

  1. La balle rebondit de (ce que je soupçonne) est son "point d'ancrage", qui semble être dans le coin supérieur droit du cercle.
  2. Lors de la collision avec le fond de 5% du cercle, elle ne peut pas rebondir suffisamment haut et donc "évier" hors de l'écran. Je suppose que c'est parce que le rebond n'est pas assez élevé pour déplacer la balle au-dessus de son "point d'ancrage mal placé"?

    Ayant examiné des solutions possibles déjà ici, notamment "Détection de collision de cercle rapide" [Lien supprimé en raison de la limite de liaison de spam], qui, bien que, bien que dans Java utilise la même méthode, ils traitent tous des collisions externes , alors que je cherche à rebondir une balle autour de l'intérieur d'un cercle.

    Voici aussi les définitions de la classe de la balle () et du cercle (): xxx

    Merci d'avance, Nathan


0 commentaires

3 Réponses :


2
votes

La plupart des packages graphiques utilisent en haut à gauche comme Démarrer pour le code de dessin. Vous voulez très probablement 2 ensembles de coordonnées, celui qui vous collisez / bouge / etc. avec et celui pour dessiner (X-rayon, Y-rayon).

En outre, sans avoir réfléchi à cela trop, la vérification de l'intersection soit-elle Distance + Ball.Size> = Cercle.Size ? La distance des balles du centre plus son rayon devrait être inférieure au rayon du cercle, si j'ai bien compris la configuration correctement.


0 commentaires

14
votes

Sans répondre à votre question, j'aimerais commenter votre stratégie de mise en œuvre et recommander une nouvelle approche. Vous représentez la vitesse de la balle en forme de coordonnée polaire, comme ball.ange.angle et ball.speed . .

Je pense que cela va être généralement gênant pour vous. Par exemple, dans votre code de collision, vous finissez par appeler ATAN2 pour activer le vecteur ( dx , dy ) dans un angle, puis vous appelez. sin et cos pour retourner l'angle dans un vecteur à nouveau. (En outre, si vous essayez jamais de généraliser votre code à trois dimensions, vous vous retrouverez dans un monde de douleur.) Donc, à moins que vous n'ayez des exigences particulières nécessitant des coordonnées polaires, je vous recommande de faire ce que tout le monde fait, à savoir représentant La vitesse de la balle dans les coordonnées cartésiennes comme vecteur ( vx , vy ).

Je recommande également de changer votre approche de physique d'un statique one ("est un objet un élément en collision actuellement avec l'objet B?") à un dynamique un ("obtiendra un entrer en collision avec l'objet B lors de son prochain mouvement de mouvement? "). Dans un système de physique statique, vous vous retrouvez souvent avec des objets se croisant à la fin d'une étape de mouvement, puis vous devez comprendre le meilleur moyen de les amener à se séparer à nouveau, ce qui est difficile à obtenir.

Si vous faites les deux, il est simple de rebondir le ballon sans aucune trigonométrie.

Étape 1. Transformez la collision de cercle / de cercle en collision Point / Circle en utilisant Minkowski Addition :

problème d'origine à gauche montre petit cercle se déplaçant à l'intérieur d'un grand cercle. Problème transformé à droite montre le point de passage en cercle dont Le rayon est la différence entre les rayons des cercles dans le problème initial.

Étape 2. Considérez un segment de temps dans lequel la balle commence à p = (px, py) et se déplace par v = (VX, VY). Est-ce que cela se croisit avec le cercle? Vous pouvez utiliser un Test de segment de ligne / cercle standard pour cela sauf que le sens du test est inversé.

Étape 3. Trouvez le point de collision C = (CX, CY). La balle rebondit du cercle de la même manière que rebondir de la ligne t tangente au cercle à ce stade. Pour un cercle centré à l'origine, le vecteur tangent est juste (-Cy, CX) et je suis sûr que vous pouvez déterminer comment calculer pour les autres cercles.

Figure décrit ci-dessus

Voir cette réponse pour savoir comment calculer le nouveau chemin de la balle basée sur des coefficients de frottement et de restitution.

Étape 4. N'oubliez pas que la balle peut encore avoir une certaine distance pour se déplacer le long du nouveau vecteur w . Si l'étape de temps est suffisamment grande ou si la vitesse suffisamment haut, il peut se heurter à nouveau pendant le même segment de temps.


1 commentaires

Bien que ce n'était pas ce que je cherchais, merci des tas! J'y regarde.



12
votes

Je suis content que vous ayez aimé mon tutoriel. J'aime votre variation, il devrait réellement être plus simple.

Premièrement, je pense que vous avez besoin de modifier le test de collision vers: p> xxx pré>

parce que la taille de la balle plus grande, le La distance entre son centre et le centre du cercle peut être plus petite. Cela devrait faire rebondir les balles au bon endroit (à l'intérieur du cercle). P>

Puis je pense que vous devez simplement échanger les signes des x et y et tout devrait fonctionner. P>

overlap = math.hypot(dx, dy) - (circle.size - ball.size)

if overlap >= 0:
  tangent = math.atan2(dy, dx)
  ball.angle = 2 * tangent - ball.angle
  ball.speed *= elasticity

  angle = 0.5 * math.pi + tangent
  ball.x += math.sin(angle)*overlap
  ball.y -= math.cos(angle)*overlap


4 commentaires

L'axe X ne serait-il pas défini par le cosinus de l'angle et de l'axe des Y par le sinus? Ou j'ai appris faux? :X


Je pense que vous avez raison que c'est la façon standard de définir des choses, mais aussi longtemps que vous êtes cohérent, cela ne fait aucune différence. Clairement, si vous faites pivoter tout de 90 degrés, cela ne devrait pas affecter comment les choses rebondissent (en supposant que la gravité change également).


@Petercollingridge, vos articles sont incroyable ! Solutions élégantes, style pythonique, félicitations .. et merci!


@Petercollingridge: Au fait, je pense avoir repéré une erreur de physique dans votre article: Si une balle se heurte à une stationnaire (pas de gravité, de glisser et d'élasticité = 1), votre simulation finira toujours par kiking l'autre balle et faire de la première balle stationnaire. Dans la physique correcte qui ne se produira que si c'est une collision sur la collision (vélocité et la normale de contact sont parallèles)