Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (580)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Collision Correction Too Large  (Read 1469 times)
0 Members and 1 Guest are viewing this topic.
Offline fletchergames

Senior Member





« Posted 2007-03-20 19:03:48 »

I'm programming a game that's a cross between Arkanoid and Space Invaders.  You have a bat which you use to hit a ball.  The ball destroys bricks, except that in this case the bricks are germs.  The germs move all the way left (or right) and then switch direction.  Whenever they're in the middle, they drop down a little bit.

The problem is when the ball hits the germs.  Sometimes, the ball shifts farther away than it should when it bounces off.  This is better than the bug I used to have (the ball going right through the germs - which only occurs very rarely now) but still annoying.

In Developing Games in Java, it explains how to slide a sprite off of a tile.  I basically did the same thing except sliding a sprite (the ball) of another sprite (a germ).  I've tried several other methods, but all caused the ball to go right through the germs at times.

Although my code is excessively complicated, I see no way to obtain help but to post it here.  Here's my code for moving the balls:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
//if the ball is moving horizontally, move it
if(horizontalDirection != Direction.NONE) {
   //determine its horizontal velocity
  double xVelocity = ((horizontalDirection == Direction.NEGATIVE) ? -1 : 1) *
      horizontalSpeed;
         
   double oldX = ball.getX();
   double newX = oldX + xVelocity * elapsedSeconds;
         
   ball.setPosition(newX, ball.getY());

   SelfIterableBag<Sprite> bGermHitByBall =
      GamePlayGermUtil.getGermsCollidingWithSprite(ball);
   if(bGermHitByBall.size() > 0) {
      hitGermsWithBall(ball, bGermHitByBall);
      Direction newDirection =
         ballMover.getHorizontalMovementDirection().getReverse();
      Sprite germ = bGermHitByBall.getAny();
      horizontalCorrection =
         correctBallGermCollisionHelper(ball, germ, true, newDirection);
      changeBallDirection(ball, true, newDirection);
   } //end if there were germ to ball collisions
} //end if the ball is moving horizontally

//if the ball is moving vertically, move it
if(verticalDirection != Direction.NONE) {
   //determine its vertical velocity
  double yVelocity = ((verticalDirection == Direction.NEGATIVE) ? -1 : 1) *
      verticalSpeed;
         
   double oldY = ball.getY();
   double newY = oldY + yVelocity * elapsedSeconds;
     
   ball.setPosition(ball.getX(), newY);

   SelfIterableBag<Sprite> bGermHitByBall =
      GamePlayGermUtil.getGermsCollidingWithSprite(ball);
   if(bGermHitByBall.size() > 0) {
      hitGermsWithBall(ball, bGermHitByBall);
      Direction newDirection =
         ballMover.getVerticalMovementDirection().getReverse();
      Sprite germ = bGermHitByBall.getAny();
      verticalCorrection =
         correctBallGermCollisionHelper(ball, germ, false, newDirection);
      changeBallDirection(ball, false, newDirection);
   } //end if there were germ to ball collisions
} //end if the ball is moving vertically


The SelfIterableBag class is my version of the Bag class discussed elsewhere on this forum.  It's basically an array.  The Direction class is the direction for one axis only - it's either NEGATIVE, NONE, or POSITIVE to specify which direction the Sprite is moving in that axis.

The "getGermsCollidingWithSprite" method is not a problem.  Here is the code of the 2 main methods used here:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
/**Corrects the specified ball's direction.
 * @param ball the ball Sprite
 * @param shouldChangeHorizontally whether to change the ball's direction horizontally
 * @param correctionDirection the direction to move the ball in for the correction*/

private static void changeBallDirection(final Sprite ball,
   final boolean shouldChangeHorizontally, final Direction correctionDirection)
{
   SpriteMover ballMover = ball.getMover();
   if(shouldChangeHorizontally)
      ballMover.setHorizontalMovementDirection(correctionDirection);
   else
      ballMover.setVerticalMovementDirection(correctionDirection);
} //end changeBallDirection

/**Corrects a collision where the germ collided with the ball.
 * @param ball the ball colliding
 * @param germ the germ that was collided with
 * @param horizontalGermMovementDirection the Direction the germ moved in horizontally
 * @param didGermMoveDown whether the germ moved down*/

private static void correctGermToBallCollision(final Sprite ball,
   final Sprite germ, final Direction horizontalGermMovementDirection,
   final boolean didGermMoveDown)
{
   //determine how to fix ball Sprite's coordinates based upon how the germ is moving
  boolean shouldFixHorizontally = true;
   if(didGermMoveDown) {
      //get the intersection between the 2 Sprites
     Rectangle ballGermIntersection = ball.getIntersection(germ);
         
      //fix the smallest distance possible
     shouldFixHorizontally = ballGermIntersection.width < ballGermIntersection.height;
   }
   
   //correct the ball's position
  Direction newDirection = (shouldFixHorizontally ? horizontalGermMovementDirection :
      Direction.POSITIVE);
   correctBallGermCollisionHelper(ball, germ, shouldFixHorizontally, newDirection);
} //end correctGermToBallCollision


And here's the helper method:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
/**Corrects the position of the ball after a collision with a germ.
 * @param ball the ball Sprite
 * @param germ the germ Sprite
 * @param shouldFixHorizontally whether to fix the collision horizontally
 * @param correctionDirection the direction to move the ball in for the correction
 * @return the amount of the correction.  This amount is always positive, giving no
 * information about direction.*/

private static double correctBallGermCollisionHelper(final Sprite ball,
   final Sprite germ, final boolean shouldFixHorizontally,
   final Direction correctionDirection)
{
   double correction = 0.0;
   
   //determine the position to move to horizontally
  if(shouldFixHorizontally) {
      double xNew = ball.getX();

      switch(correctionDirection) {
      case NEGATIVE:
         //shove the germ left
        if(ball.getX2() >= germ.getX())
            xNew = germ.getX() - ball.getWidth();
         break;
      case POSITIVE:
         //shove the germ right
        if(ball.getX() <= germ.getX2())
            xNew = germ.getX2() + 1;
         break;
      //ignore the approaching vertically case
     } //end switch movement direction

      correction = xNew - ball.getX();
      ball.setPosition(xNew, ball.getY());
   } else { //else determine the position to move to vertically
     double yNew = ball.getY();

      switch(correctionDirection) {
      case NEGATIVE:
         //shove the germ up
        if(ball.getY2() >= germ.getY())
            yNew = germ.getY() - ball.getHeight();
         break;
      case POSITIVE:
         //shove the germ down
        if(ball.getY() <= germ.getY2())
            yNew = germ.getY2() + 1;
         break;
      //ignore the approaching horizontally case
     } //end switch movement direction

      correction = yNew - ball.getY();
      ball.setPosition(ball.getX(), yNew);
   } //end else determine the position to move to vertically
 
   return Math.abs(correction);
} //end correctBallGermCollisionHelper


Minor changes, such as using the horizontal/vertical correction values to only change the ball's direction along one axis, cause the ball to go through the germs again, which is unacceptable.  I considered sliding the ball once after the germs move and then again after the ball moves, but that would just make the correction even greater.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2007-03-21 00:02:24 »

Isn't it easier to represent the germs as circles? Colliding moving circles in 2D is pretty easy. If a circle doesn't accurately describe the germ's shape, you could make it a set of circles, and collide against each of them. Use a bounding circle to prevent doing too much collision-checks.

HTH

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline fletchergames

Senior Member





« Reply #2 - Posted 2007-03-21 15:06:37 »

Checking for collisions isn't the problem.  It's where to move the ball to after the collision occurs.  Using circles, I would be completely lost on collision correction.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #3 - Posted 2007-03-21 15:21:42 »

Me: "Colliding moving circles in 2D is pretty easy"

So not only detecting, but also the response. There are numerous articles on circle-circle collision.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline fletchergames

Senior Member





« Reply #4 - Posted 2007-03-21 20:34:53 »

I will look it up, but I think it's too late in the development cycle to make that much of a change.

I reduced the magnitude of the problem by setting a maximum correction amount for the horizontal correction.  This seems to work, though still has slight overcorrections.
Offline fletchergames

Senior Member





« Reply #5 - Posted 2007-03-22 01:09:17 »

I figured out the problem.  Or, at least, I figured out how to fix it.  It had nothing to do with the shape used by collision detection (rectangle versus circle).

I just had to add an if statement for each axis preventing the correction for that axis from exceeding the number of pixels the ball actually moved.  It seems like a lame solution, but it works perfectly so far as I can tell.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (50 views)
2014-04-15 18:08:23

BurntPizza (46 views)
2014-04-15 03:46:01

UprightPath (62 views)
2014-04-14 17:39:50

UprightPath (44 views)
2014-04-14 17:35:47

Porlus (60 views)
2014-04-14 15:48:38

tom_mai78101 (84 views)
2014-04-10 04:04:31

BurntPizza (142 views)
2014-04-08 23:06:04

tom_mai78101 (242 views)
2014-04-05 13:34:39

trollwarrior1 (201 views)
2014-04-04 12:06:45

CJLetsGame (208 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!