Android Open Source - game-api-android Colliding Object






From Project

Back to project page game-api-android.

License

The source code is released under:

MIT License

If you think the Android project game-api-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package android.gameengine.icadroids.objects.collisions;
//from  w w  w  .j  av a  2  s .c o m
import java.util.List;
import java.util.Vector;

import android.gameengine.icadroids.objects.graphics.Sprite;
import android.gameengine.icadroids.tiles.GameTiles;
import android.gameengine.icadroids.tiles.Tile;

/**
 * CollidingObject holds methods to calculate tile collisions. It's also the
 * class that calls the collisionOccured() method.
 * NOTE: main method for detection is very long and complicated. This can be improved
 * by making all its local variables global and then splitting up. Now it is no use, we would
 * have loads of parameteres and problems with return values, probably.
 * <br />
 * <b>This is a utility class vor the GameEngine. Game programmers will have no need
 * of this class! (Hide it, make it an inner class?)</b>
 * 
 * @author Bas van der Zandt, Paul Bergervoet
 * 
 */
public class CollidingObject {


  /**
   * <b>This method is automatically called by a MoveableGameObject, do
   * not call this yourself!</b>
   * <br />
   * This method calculates if there has been an collision <i>with tiles</i>
   * when the object has moved. It will call the method 
   * collisionOccurred(ArrayList<TileCollision>) if there are collisions
   * 
   * It calculates its collision by adding a collision box around it. This
   * collision box includes it's current position and it's next position. This
   * has the benefit that, when a object travels very fast, it will not pass
   * through the tile.
   * 
   * This method will call collisionOccurred();
   * 
   * @param startX
   *            The current x position of the object
   * @param startY
   *            The current y position of the object
   * @param endX
   *            The next x position of the object
   * @param endY
   *            The next y position of the object
   * @param sprite
   *            The sprite of the object
   * @param gameTiles
   *            The gameTiles object to check the collision with
   * @param collisionObject
   *            An ICollision object that needs to be called when a collision
   *            has occurred
   *     
   * @see android.gameengine.icadroids.objects.collisions.ICollision#collisionOccurred(List)
   */
  public void calculateCollision(double endX, double endY, 
      double startX, double startY, Sprite sprite, GameTiles gameTiles,
      ICollision collisionObject) 
  {  // no tiles, no sprite: no tile collisions
    if (gameTiles == null || sprite == null )
    {
      return; 
    }
    List<TileCollision> collidedTiles = new Vector<TileCollision>();
    
        int xTileIndex;     // index of column of collided tiles (horizontal collision)
        int yTileIndex;     // index of row of collided tiles (vertical collision)
        int collisionX;       // Xpos of possible collision (gridline on tile grid)
        int collisionY;       // Ypos of possible collision (gridline on tile grid)
        int itemXatCollision;   // xpos of item at collision ( =collisionX, -width if collision on right side)
        int itemYatCollision;   // ypos of item at collision ( =collisionY, -height if collision at bottom)
        double xFactor;     // part of move that is done up to collision
        double yFactor;     // part of move that is done up to collision
        int xCollisionSide;    // collisionSide for horizontal collisions, will be either 1 or 3
        int yCollisionSide;    // collisionSide for vertical collisions, will be either 0 or 2
        
        boolean moveleft = ( endX < startX );
        boolean moveup = ( endY < startY );
    int gridsize = gameTiles.tileSize;
    int objwidth = sprite.getFrameWidth();
    int objheight = sprite.getFrameHeight();

        // 1: Find gridlines ( x and y ) where collision occurs (if any).
        //     Determine corresponding indexes in tilemap
        //     Note: it is assumed gameTiles start at position (0,0), ref to coordinates of map commented out
        if ( moveleft )       // find gridline for horizontal collision
        {   // find index of gridline just left of start-left side of item
            // -1: entire tile left of previous pos of object, we collide into right side
            xTileIndex = divdown(startX /*- mapStartX*/, gridsize) - 1;
            // x of collision is right side of tile (hence '+1')
            collisionX = (xTileIndex + 1) * gridsize /*+ mapStartX*/;
            // x of item equals collisionX because collision is on left side
            itemXatCollision = collisionX;
            // collision will be on right side of tile, because object is moving to the left
            xCollisionSide = 1;
        } else
        {   // find index of gridline just right of start-right side of item
            xTileIndex = divdown(Math.ceil(startX) + objwidth -1 /*- mapStartX*/, gridsize) + 1;
            // x of collision is left side of tile
            collisionX = xTileIndex * gridsize /*+ mapStartX*/;
            // x of item equals collisionX-width because collision is on right side
            itemXatCollision = collisionX - objwidth;
            // collison will be on left side of tile, because object is moving to the right
            xCollisionSide = 3;
        }
        if ( moveup ) // vertical collision?? (comments ommitted, are like horizontal)
        {
            yTileIndex = divdown(startY /*- mapStartY*/, gridsize) - 1;
            collisionY = (yTileIndex + 1) * gridsize /*+ mapStartY*/;
            itemYatCollision = collisionY;
            yCollisionSide = 2;  // moving up, so hitting bottom of tile
        } else
        {
            yTileIndex = divdown(Math.ceil(startY) + objheight -1 /*- mapStartY*/, gridsize) + 1;
            collisionY = yTileIndex * gridsize /*+ mapStartY*/;
            itemYatCollision = collisionY - objheight;
            yCollisionSide = 0;
        }
        // 2: calculate the part of move that has been done until the collision: (colx - prevx)/(newx - prevx)
        // Note: if factor >=1, the collision position is further away than the move. Therefore it has not
        // been reached and there is no collision. This property will be used as a collision test.
        xFactor = calcMoveFactor(startX, endX, itemXatCollision);
        yFactor = calcMoveFactor(startY, endY, itemYatCollision);
        // System.out.println("col6, xf: " + MathFloat.toString(xFactor, 2, 2) + ", yf: "
        //        + MathFloat.toString(yFactor, 2, 2));

        // 3. Loop through colliding gridlines, starting always with the nearest one.
        // After handling collision with one gridline, move to the next, recalculating Factor.
        while ( xFactor < 1 || yFactor < 1 )
        {  // handle collision that comes first, that is the lower factor (<1 guaranteed by loop criterion)
             if (xFactor <= yFactor)
            {   // horizontal collision occurrs earlier than vertical
               if ( (xTileIndex >= 0) && (xTileIndex < gameTiles.getMapWidth()) )
               {  // find matching ypos, then tiles in range [ypos, ypos+frameheight]
                 int ypos = (int)(startY + xFactor*(endY-startY));
                 // find corresponding tilenumebers, limit to size of map through min & max. 
                 int firsttile = Math.max(0, divdown(ypos/*-mapStartY*/, gridsize));
                 int lasttile = Math.min(gameTiles.getMapHeigth()-1, divdown(ypos + objheight-1/*-mapStartY*/, gridsize));
                 // loop through y-range
                 for (int yindex = firsttile; yindex <=lasttile; yindex++)
                 {  // see if there is a tile at the current position
                   Tile t = gameTiles.getTileOnIndex(xTileIndex, yindex);
                   if ( t != null )
                     if ( t.getTileType() != -1 )
                       collidedTiles.add(new TileCollision(t, xCollisionSide));
                 }
               }
                if ( moveleft )
                {  // move collision gridline to the left for next check
                    xTileIndex--;
                    collisionX = (xTileIndex + 1) * gridsize /*+ mapStartX*/;
                    itemXatCollision = collisionX;
                } else
                {  // move collision gridline to the right for next check
                    xTileIndex++;
                    collisionX = xTileIndex * gridsize /*+ mapStartX*/;
                    itemXatCollision = collisionX - objwidth;
                }
                // calculate new xFactor, since gridline has moved
                xFactor = calcMoveFactor(startX, endX, itemXatCollision);
            } else      
            {  // vertical collision occurs earlier (comments omitted, are like horizontal collision)
               if ( (yTileIndex >= 0) && (yTileIndex < gameTiles.getMapHeigth()) )   // nog een keer spelfout verbeteren: height :-)
               {  
                 int xpos = (int)(startX + yFactor*(endX-startX));
                 int firsttile = Math.max(0, divdown(xpos/*-mapStartX*/, gridsize));
                 int lasttile = Math.min(gameTiles.getMapWidth()-1, divdown(xpos + objwidth-1/*-mapStartX*/, gridsize));
                 for (int xindex = firsttile; xindex <= lasttile; xindex++)
                 {
                   Tile t = gameTiles.getTileOnIndex(xindex, yTileIndex);
                   if ( t != null )
                     if ( t.getTileType() != -1 )
                       collidedTiles.add(new TileCollision(t, yCollisionSide));
                 }
               }
                if ( moveup )
                {  yTileIndex--;
                    collisionY = (yTileIndex + 1) * gridsize /*+ mapStartY*/;
                    itemYatCollision = collisionY;
                } else
                {  yTileIndex++;
                    collisionY = yTileIndex * gridsize /*+ mapStartY*/;
                    itemYatCollision = collisionY - objheight;
                }
                 yFactor = calcMoveFactor(startY, endY, itemYatCollision);
            }
            // System.out.println("col6, xf: " + MathFloat.toString(xFactor, 2, 2) + ", yf: "
            //        + MathFloat.toString(yFactor, 2, 2));
        }
        // 4. call collisonOccurred with list of tileCollisions
    if (collidedTiles.size() >  0) {
      // System.out.println("=====");  // Debug feedback
      // System.out.println("startx,y: "+startX+", "+startY+" endx,y: "+endX+", "+endY);
      collisionObject.collisionOccurred(collidedTiles);
      // Tile found? collision occurred
    }
  }

    /**
     * This method solves the problem that (int) (a/b)*b works as a round down to multiples of b for positive ints
     * a, and as a round up for negative ints. 
     * 
     * @param pos
     *                a number, usually an X- or Y-position
     * @param deler
     *                the divisor, usually tilesize
     * @return pos/deler, one down if pos is negative (i.e. divdown( -6, 10) yields -1)
     */
    private int divdown(double pos, int deler)
    {
        int res = (int)(pos/deler);
        if (res<0) res--;
        return res;
    }
    
    /**
     * Gets the fraction of the move that has been done up to a collision with a tile.
     * Utility method for collision detection, to find out if vertical collision happens before horizontal
     * Example: if object moves from pos 5 (start) to 25 (end) and gridline is at 10 (pos), collision
     * occurs at (10-5)/(25-5) = 0.25, that is after one quarter of the move.
     * Factors will be calculated in both x and y directions and will determine which collision is first.
     * 
     * @return the fraction of the move, a number between 0 and 1
     */
    private double calcMoveFactor(double start, double end, int pos)
    {
        if (end == start )
        {  // the calculation is not quite right (since (colx-prevx)/0 is not equal to 1.... 
            // but it is ok for collision detection, because >=1 means 'no collision'
            return 1;
        } else
        {
            return ( (double)pos - start)/(end - start);
        }
      
    }

/*  public Tile getTileOnIndex(int xPosition, int yPosition,
      GameTiles gameTiles) {

    if (gameTiles.tileArray != null) {

      if (yPosition >= 0 && yPosition < gameTiles.tileArray.length) {
        if (xPosition >= 0 && xPosition < gameTiles.tileArray[yPosition].length) {
          return gameTiles.tileArray[yPosition][xPosition];
        }
      }
    }
    return null;
  }
  *//**
   * Get a tile on a specific x and y position in the game world
   * 
   * @param xPosition
   *            x position of the tile
   * @param yPosition
   *            y position of the tile
   * @param gameTiles
   * @return The Tile object at the given x and y position
   *//*
  public Tile getTileOnPosition(int xPosition, int yPosition,
      GameTiles gameTiles) {

    if (gameTiles.tileArray != null) {

      int tiley = yPosition / gameTiles.tileSize;
      int tilex = xPosition / gameTiles.tileSize;

      if (tiley >= 0 && tiley < gameTiles.tileArray.length) {
        if (tilex >= 0 && tilex < gameTiles.tileArray[tiley].length) {
          return gameTiles.tileArray[tiley][tilex];
        }
      }
    }
    return null;
  }*/
}




Java Source Code List

android.gameengine.icadroids.alarms.Alarm.java
android.gameengine.icadroids.alarms.IAlarm.java
android.gameengine.icadroids.dashboard.DashboardImageView.java
android.gameengine.icadroids.dashboard.DashboardTextView.java
android.gameengine.icadroids.engine.GameEngine.java
android.gameengine.icadroids.engine.GameFPSCounter.java
android.gameengine.icadroids.engine.GameThread.java
android.gameengine.icadroids.engine.GameView.java
android.gameengine.icadroids.engine.Viewport.java
android.gameengine.icadroids.forms.GameForm.java
android.gameengine.icadroids.forms.IFormInput.java
android.gameengine.icadroids.forms.ViewCreator.java
android.gameengine.icadroids.forms.ViewRemover.java
android.gameengine.icadroids.input.MotionSensor.java
android.gameengine.icadroids.input.OnScreenButton.java
android.gameengine.icadroids.input.OnScreenButtons.java
android.gameengine.icadroids.input.TouchInput.java
android.gameengine.icadroids.objects.GameObject.java
android.gameengine.icadroids.objects.MoveableGameObject.java
android.gameengine.icadroids.objects.collisions.CollidingObject.java
android.gameengine.icadroids.objects.collisions.ICollision.java
android.gameengine.icadroids.objects.collisions.TileCollision.java
android.gameengine.icadroids.objects.graphics.AnimatedSprite.java
android.gameengine.icadroids.objects.graphics.Sprite.java
android.gameengine.icadroids.persistence.GamePersistence.java
android.gameengine.icadroids.sound.GameSound.java
android.gameengine.icadroids.sound.MusicPlayer.java
android.gameengine.icadroids.tiles.GameTiles.java
android.gameengine.icadroids.tiles.Tile.java
com.android.vissenspel.Monster.java
com.android.vissenspel.StrawberryControler.java
com.android.vissenspel.Strawberry.java
com.android.vissenspel.Vis.java
com.android.vissenspel.Vissenkom.java
game.MyAndroidGame.java
testGames.AndroidCraft_demo.java
testGames.FormTest.java
testGames.Player.java
testGames.TestGameBas.java
testGames.TestGameLex.java
testGames.TestGameRoel.java
testGames.gameEngineTest.DebugEngine.java
testGames.gameEngineTest.GameEngineTestGame.java
testGames.gameEngineTest.TestGameObject.java
testGames.gameEngineTest.debugObject.java
testGames.gameEngineTest.randomObject.java
testGames.testGameObjectBas.java
testGames.testGame.java