2009-10-13 11 views
0

J'ai créé le jeu "Breakout". Un petit side-project amusant.Gestion des collisions de billes et de briques

Maintenant, je ne fais pas de jeux, donc la gestion des collisions n'est pas quelque chose à laquelle je pense normalement. J'ai une pagaie, une balle et quelques briques. Pour l'instant, en cas de collision (je dessine des rectangles autour de chacun des objets mentionnés), je change simplement la valeur Y de la boule en -Y.

Cela fonctionne très bien, SAUF si la balle frappe une brique sur le côté (soit à l'est ou à l'ouest). L'effet de bord n'est pas joli et gâche le gameplay.

Je pense que je peux sans risque supposer qu'au lieu de la technique ci-dessus, j'ai besoin de changer la valeur X à -X quand cela se produit.

Jusqu'à présent, j'ai: if (ballRect.IntersectsWith(brickRect))

ballRect et brickRect étant des rectangles autour de chaque objet. Maintenant, et si j'ai créé un rectangle autour de la frontière est de la brique, de la frontière ouest, etc? Je suppose que la largeur serait d'environ un pixel.

Si la collision se produit avec le rectangle ouest ou est, alors la valeur des balles X doit être -X. Et vice versa.

Mais qu'en est-il des coins? Devrais-je choisir au hasard quel rectangle contrôler x corner? Ou peut-être devrais-je faire un rectangle autour de chaque coin? le rectangle étant 1 * 1 dans le côté. S'il y a une collision => -x ET -y valeurs de la balle?

S'il vous plaît partagez votre opinion.

Voici le processus jusqu'à présent:

foreach (var brick in Bricks) 
    { 
     if (brick.IsAlive) 
     { 
      var brickRect = new Rectangle(brick.X, brick.Y, BrickWidth, BrickHeight); 
      if (ballRect.IntersectsWith(brickRect)) //Ball has hit brick. lets find out which side of the brick 
      { 
       var brickRectNorth = new Rectangle(brick.X, brick.Y + BrickHeight, BrickWidth, 1); 
       var brickRectSouth = new Rectangle(brick.X, brick.Y, BrickWidth, 1); 

       var brickRectEast = new Rectangle(brick.X, brick.Y, 1, BrickHeight); 
       var brickRectWest = new Rectangle(brick.X + BrickWidth, brick.Y, 1, BrickHeight); 

       if (ballRect.IntersectsWith(brickRectNorth) || ballRect.IntersectsWith(brickRectSouth)) 
       { 
        //STUFF that makes ball.y = -ball.y 
       } 
       if (ballRect.IntersectsWith(brickRectWest) || ballRect.IntersectsWith(brickRectEast)) 
       { 
        //STUFF that makes ball.x = -ball.x 
       } 
      } 
     } 
    } 

Répondre

2

Plutôt que de chercher des intersections de rectangle, j'entrecoupent les bords réels. Au coin, votre balle touche simultanément deux bords, donc son vecteur de mouvement devrait être affecté par les deux. Je garderais le rectangle unique pour la détection de collision, puisque cela réduit le nombre de rectangles que vous devez tester dans votre boucle externe, mais une fois qu'une collision avec une brique a été détectée, entrez dans une boucle interne pour détecter bord c'était ce qui a été frappé. Si vous testez simplement chaque arête et ajustez le vecteur en conséquence pour chacun d'entre eux, le coin viendra gratuitement (tant que vous ne sortirez pas de la boucle lorsque vous rencontrerez le premier arête d'intersection).

Modifier: En réponse à votre question mise à jour:

En fait, voici comment je le ferais (compte tenu de votre code, cela semble être C# 3.0, de sorte que ce que j'ai supposais ci-dessous):

foreach(var brick in Bricks) { 
    if(brick.IsAlive) { 
     var brickRect = new Rectangle(brick.X, brick.Y, BrickWidth, BrickHeight); 
     if(ballRect.IntersectsWith(brickRect)) { 
      // Ball has hit brick. Now let's adjust the ball's vector accordingly 

      // Convenience variables. Compiler will probably inline. 
      var brickLeft = brick.X; 
      var brickRight = brick.X + BrickWidth; 
      var brickTop = brick.Y; 
      var brickBottom = brick.Y + BrickHeight; 

      var ballLeft = ball.X - ball.Radius; 
      var ballRight = ball.X + ball.Radius; 
      var ballTop = ball.Y - ball.Radius; 
      var ballBottom = ball.Y + ball.Radius; 

      // Test which vector(s) we need to flip 
      bool flipX = (ballRight >= brickLeft || ballLeft <= brickRight); 
      bool flipY = (ballTop >= brickBottom || ballBottom <= brickTop); 

      // Flip the vectors (there are probably ways to optimize this, 
      // too, but without seeing your code I can't tell). 
      if(flipY) { 
       // Stuff that makes ball.y = -ball.y 
      } 

      if(flipX) { 
       // Stuff that makes ball.x = -ball.x 
      } 
     } 
    } 
} 

en fait, le point est que, puisque vous savez déjà la balle croise effectivement la brique, vous pouvez simplifier à un simple test de la boîte, ce qui est beaucoup plus rapide. En outre, il n'est pas nécessaire de créer des rectangles supplémentaires pour les bords - utilisez simplement les bords du rectangle que vous avez déjà.

+0

Merci pour vos commentaires. Je n'avais pas pensé à ça – CasperT

+0

J'ai mis à jour mon post. Est-ce que c'est ce que vous vouliez dire? – CasperT

+0

Bonjour. La balle est un rectangle (bien que dessiné comme une éclipse). Donc rayon est: int ballRadius = BallSize/2; À propos du // truc ... Je fais simplement beaucoup de choses, comme donner des points au joueur, tuer la brique et ainsi de suite. À la fin, il écrit littéralement: BallDirection = new Point (-BallDirection.X, BallDirection.Y); // x = -x Votre code me donne des résultats très bizarres, mais je vais y regarder un peu plus – CasperT