Collision Test With Sliding : Behaviour « Game « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Collections Data Structure
8. Database SQL JDBC
9. Design Pattern
10. Development Class
11. Email
12. Event
13. File Input Output
14. Game
15. Hibernate
16. J2EE
17. J2ME
18. JDK 6
19. JSP
20. JSTL
21. Language Basics
22. Network Protocol
23. PDF RTF
24. Regular Expressions
25. Security
26. Servlets
27. Spring
28. Swing Components
29. Swing JFC
30. SWT JFace Eclipse
31. Threads
32. Tiny Application
33. Velocity
34. Web Services SOA
35. XML
Microsoft Office Word 2007 Tutorial
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
C# / C Sharp
C# / CSharp Tutorial
ASP.Net
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
PHP
Python
SQL Server / T-SQL
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Java » Game » BehaviourScreenshots 
Collision Test With Sliding

       /*
DEVELOPING GAME IN JAVA 

Caracteristiques

Editeur : NEW RIDERS 
Auteur : BRACKEEN 
Parution : 09 2003 
Pages : 972 
Isbn : 1-59273-005-1 
Reliure : Paperback 
Disponibilite : Disponible a la librairie 
*/


import java.awt.AWTException;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferUShort;
import java.awt.image.IndexColorModel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import java.awt.Graphics2D;
import java.awt.Color;
import java.io.IOException;
import java.util.*;

public class CollisionTestWithSliding extends ShooterCore {

  public static void main(String[] args) {
    new CollisionTestWithSliding(args).run();
  }

  protected BSPTree bspTree;

  protected String mapFile;

  public CollisionTestWithSliding(String[] args) {
    super(args);
    for (int i = 0; mapFile == null && i < args.length; i++) {
      if (mapFile == null && !args[i].startsWith("-")) {
        mapFile = args[i];
      }
    }
    if (mapFile == null) {
      mapFile = "../images/sample.map";
    }
  }

  public void createPolygons() {
    Graphics2D g = screen.getGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(00, screen.getWidth(), screen.getHeight());
    g.setColor(Color.WHITE);
    g.drawString("Loading..."5, screen.getHeight() 5);
    screen.update();

    float ambientLightIntensity = .2f;
    List lights = new LinkedList();
    lights.add(new PointLight3D(-100100100.3f, -1));
    lights.add(new PointLight3D(1001000.3f, -1));

    MapLoader loader = new MapLoader();
    loader.setObjectLights(lights, ambientLightIntensity);

    try {
      bspTree = loader.loadMap(mapFile);
    catch (IOException ex) {
      ex.printStackTrace();
    }

    CollisionDetection collisionDetection = new CollisionDetectionWithSliding(
        bspTree);
    gameObjectManager = new GridGameObjectManager(bspTree.calcBounds(),
        collisionDetection);
    gameObjectManager.addPlayer(new Player());

    ((BSPRendererpolygonRenderer).setGameObjectManager(gameObjectManager);

    createGameObjects(loader.getObjectsInMap());
    Transform3D start = loader.getPlayerStartLocation();
    gameObjectManager.getPlayer().getTransform().setTo(start);
  }

  private void createGameObjects(List mapObjects) {
    Iterator i = mapObjects.iterator();
    while (i.hasNext()) {
      PolygonGroup group = (PolygonGroupi.next();
      String filename = group.getFilename();
      if ("robot.obj".equals(filename)) {
        gameObjectManager.add(new Bot(group));
      else {
        // static object
        gameObjectManager.add(new GameObject(group));
      }
    }
  }

  public void drawPolygons(Graphics2D g) {

    polygonRenderer.startFrame(g);

    // draw polygons in bsp tree (set z buffer)
    ((BSPRendererpolygonRenderer).draw(g, bspTree);

    // draw game object polygons (check and set z buffer)
    gameObjectManager.draw(g, (GameObjectRendererpolygonRenderer);

    polygonRenderer.endFrame(g);

  }
}
/**
 * The CollisionDetectionWithSliding class handles collision detection between
 * the GameObjects, and between GameObjects and a BSP tree. When a collision
 * occurs, the GameObject slides to the side rather than stops.
 */

class CollisionDetectionWithSliding extends CollisionDetection {

  private Vector3D scratch = new Vector3D();

  private Vector3D originalLocation = new Vector3D();

  /**
   * Creates a new CollisionDetectionWithSliding object for the specified BSP
   * tree.
   */
  public CollisionDetectionWithSliding(BSPTree bspTree) {
    super(bspTree);
  }

  /**
   * Checks for a game object collision with the walls of the BSP tree.
   * Returns the first wall collided with, or null if there was no collision.
   * If there is a collision, the object slides along the wall and again
   * checks for a collision. If a collision occurs on the slide, the object
   * reverts back to its old location.
   */
  public BSPPolygon checkWalls(GameObject object, Vector3D oldLocation,
      long elapsedTime) {

    float goalX = object.getX();
    float goalZ = object.getZ();

    BSPPolygon wall = super.checkWalls(object, oldLocation, elapsedTime);
    // if collision found and object didn't stop itself
    if (wall != null && object.getTransform().isMoving()) {
      float actualX = object.getX();
      float actualZ = object.getZ();

      // dot product between wall's normal and line to goal
      scratch.setTo(actualX, 0, actualZ);
      scratch.subtract(goalX, 0, goalZ);
      float length = scratch.getDotProduct(wall.getNormal());

      float slideX = goalX + length * wall.getNormal().x;
      float slideZ = goalZ + length * wall.getNormal().z;

      object.getLocation().setTo(slideX, object.getY(), slideZ);
      originalLocation.setTo(oldLocation);
      oldLocation.setTo(actualX, oldLocation.y, actualZ);

      // use a smaller radius for sliding
      PolygonGroupBounds bounds = object.getBounds();
      float originalRadius = bounds.getRadius();
      bounds.setRadius(originalRadius - 1);

      // check for collision with slide position
      BSPPolygon wall2 = super.checkWalls(object, oldLocation,
          elapsedTime);

      // restore changed parameters
      oldLocation.setTo(originalLocation);
      bounds.setRadius(originalRadius);

      if (wall2 != null) {
        object.getLocation().setTo(actualX, object.getY(), actualZ);
        return wall2;
      }
    }

    return wall;
  }

  /**
   * Checks for object collisions with the floor and ceiling. Uses
   * object.getFloorHeight() and object.getCeilHeight() for the floor and
   * ceiling values. Applies gravity if the object is above the floor, and
   * scoots the object up if the player is below the floor (for smooth
   * movement up stairs).
   */
  protected void checkFloorAndCeiling(GameObject object, long elapsedTime) {
    float floorHeight = object.getFloorHeight();
    float ceilHeight = object.getCeilHeight();
    float bottomHeight = object.getBounds().getBottomHeight();
    float topHeight = object.getBounds().getTopHeight();
    Vector3D v = object.getTransform().getVelocity();
    Physics physics = Physics.getInstance();

    // check if on floor
    if (object.getY() + bottomHeight == floorHeight) {
      if (v.y < 0) {
        v.y = 0;
      }
    }
    // check if below floor
    else if (object.getY() + bottomHeight < floorHeight) {

      if (!object.isFlying()) {
        // if falling
        if (v.y < 0) {
          object.notifyFloorCollision();
          v.y = 0;
          object.getLocation().y = floorHeight - bottomHeight;
        else if (!object.isJumping()) {
          physics.scootUp(object, elapsedTime);
        }
      else {
        object.notifyFloorCollision();
        v.y = 0;
        object.getLocation().y = floorHeight - bottomHeight;
      }
    }
    // check if hitting ceiling
    else if (object.getY() + topHeight > ceilHeight) {
      object.notifyCeilingCollision();
      if (v.y > 0) {
        v.y = 0;
      }
      object.getLocation().y = ceilHeight - topHeight;
      if (!object.isFlying()) {
        physics.applyGravity(object, elapsedTime);
      }
    }
    // above floor
    else {
      if (!object.isFlying()) {
        // if scooting-up, stop the scoot
        if (v.y > && !object.isJumping()) {
          v.y = 0;
          object.getLocation().y = floorHeight - bottomHeight;
        else {
          physics.applyGravity(object, elapsedTime);
        }
      }
    }

  }

  /**
   * Handles an object collision. Object A is the moving object, and Object B
   * is the object that Object A collided with. Object A slides around or
   * steps on top of Object B if possible.
   */
  protected boolean handleObjectCollision(GameObject objectA,
      GameObject objectB, float distSq, float minDistSq,
      Vector3D oldLocation) {
    objectA.notifyObjectCollision(objectB);

    if (objectA.isFlying()) {
      return true;
    }

    float stepSize = objectA.getBounds().getTopHeight() 6;
    Vector3D velocity = objectA.getTransform().getVelocity();

    // step up on top of object if possible
    float objectABottom = objectA.getY()
        + objectA.getBounds().getBottomHeight();
    float objectBTop = objectB.getY() + objectB.getBounds().getTopHeight();
    if (objectABottom + stepSize > objectBTop
        && objectBTop + objectA.getBounds().getTopHeight() < objectA
            .getCeilHeight()) {
      objectA.getLocation().y = (objectBTop - objectA.getBounds()
          .getBottomHeight());
      if (velocity.y < 0) {
        objectA.setJumping(false);
        // don't let gravity get out of control
        velocity.y = -.01f;
      }
      return false;
    }

    if (objectA.getX() != oldLocation.x || objectA.getZ() != oldLocation.z) {
      // slide to the side
      float slideDistFactor = (floatMath.sqrt(minDistSq / distSq1;
      scratch.setTo(objectA.getX()0, objectA.getZ());
      scratch.subtract(objectB.getX()0, objectB.getZ());
      scratch.multiply(slideDistFactor);
      objectA.getLocation().add(scratch);

      // revert location if passing through a wall
      if (super.checkWalls(objectA, oldLocation, 0!= null) {
        return true;
      }

      return false;
    }

    return true;
  }

}

/**
 * A GameObject that can jump.
 */

class JumpingGameObject extends GameObject {

  public static final float DEFAULT_JUMP_HEIGHT = 64;

  protected float jumpVelocity;

  public JumpingGameObject(PolygonGroup group) {
    super(group);
    setJumpHeight(DEFAULT_JUMP_HEIGHT);
  }

  /**
   * Sets how high this GameObject can jump.
   */
  public void setJumpHeight(float jumpHeight) {
    jumpVelocity = Physics.getInstance().getJumpVelocity(jumpHeight);
  }

  /**
   * Causes this GameObject to jump if the jumping flag is set and this object
   * is not already jumping.
   */
  public void setJumping(boolean isJumping) {
    if (isJumping() != isJumping) {
      super.setJumping(isJumping);
      if (isJumping) {
        Physics.getInstance().jump(this, jumpVelocity);
      }
    }
  }

  public void notifyFloorCollision() {
    // the object has landed.
    setJumping(false);
  }

}
/**
 * The Physics class is a singleton that represents various attributes (like
 * gravity) and the functions to manipulate objects based on those physical
 * attributes. Currently, only gravity and scoot-up (acceleration when traveling
 * up stairs) are supported.
 */

class Physics {

  /**
   * Default gravity in units per millisecond squared
   */
  public static final float DEFAULT_GRAVITY_ACCEL = -.002f;

  /**
   * Default scoot-up (acceleration traveling up stairs) in units per
   * millisecond squared.
   */
  public static final float DEFAULT_SCOOT_ACCEL = .006f;

  private static Physics instance;

  private float gravityAccel;

  private float scootAccel;

  private Vector3D velocity = new Vector3D();

  /**
   * Gets the Physics instance. If a Physics instance does not yet exist, one
   * is created with the default attributes.
   */
  public static synchronized Physics getInstance() {
    if (instance == null) {
      instance = new Physics();
    }
    return instance;
  }

  protected Physics() {
    gravityAccel = DEFAULT_GRAVITY_ACCEL;
    scootAccel = DEFAULT_SCOOT_ACCEL;
  }

  /**
   * Gets the gravity acceleration in units per millisecond squared.
   */
  public float getGravityAccel() {
    return gravityAccel;
  }

  /**
   * Sets the gravity acceleration in units per millisecond squared.
   */
  public void setGravityAccel(float gravityAccel) {
    this.gravityAccel = gravityAccel;
  }

  /**
   * Gets the scoot-up acceleration in units per millisecond squared. The
   * scoot up acceleration can be used for smoothly traveling up stairs.
   */
  public float getScootAccel() {
    return scootAccel;
  }

  /**
   * Sets the scoot-up acceleration in units per millisecond squared. The
   * scoot up acceleration can be used for smoothly traveling up stairs.
   */
  public void setScootAccel(float scootAccel) {
    this.scootAccel = scootAccel;
  }

  /**
   * Applies gravity to the specified GameObject according to the amount of
   * time that has passed.
   */
  public void applyGravity(GameObject object, long elapsedTime) {
    velocity.setTo(0, gravityAccel * elapsedTime, 0);
    object.getTransform().addVelocity(velocity);
  }

  /**
   * Applies the scoot-up acceleration to the specified GameObject according
   * to the amount of time that has passed.
   */
  public void scootUp(GameObject object, long elapsedTime) {
    velocity.setTo(0, scootAccel * elapsedTime, 0);
    object.getTransform().addVelocity(velocity);
  }

  /**
   * Applies the negative scoot-up acceleration to the specified GameObject
   * according to the amount of time that has passed.
   */
  public void scootDown(GameObject object, long elapsedTime) {
    velocity.setTo(0, -scootAccel * elapsedTime, 0);
    object.getTransform().addVelocity(velocity);
  }

  /**
   * Sets the specified GameObject's vertical velocity to jump to the
   * specified height. Calls getJumpVelocity() to calculate the velocity,
   * which uses the Math.sqrt() function.
   */
  public void jumpToHeight(GameObject object, float jumpHeight) {
    jump(object, getJumpVelocity(jumpHeight));
  }

  /**
   * Sets the specified GameObject's vertical velocity to the specified jump
   * velocity.
   */
  public void jump(GameObject object, float jumpVelocity) {
    velocity.setTo(0, jumpVelocity, 0);
    object.getTransform().getVelocity().y = 0;
    object.getTransform().addVelocity(velocity);
  }

  /**
   * Returns the vertical velocity needed to jump the specified height (based
   * on current gravity). Uses the Math.sqrt() function.
   */
  public float getJumpVelocity(float jumpHeight) {
    // use velocity/acceleration formal: v*v = -2 * a(y-y0)
    // (v is jump velocity, a is accel, y-y0 is max height)
    return (floatMath.sqrt(-* gravityAccel * jumpHeight);
  }
}

/**
 * A Player object.
 */

class Player extends JumpingGameObject {

  public static final float DEFAULT_PLAYER_RADIUS = 32;

  public static final float DEFAULT_PLAYER_HEIGHT = 128;

  public Player() {
    this(new PolygonGroup("Player"));

    // set up player bounds
    PolygonGroupBounds playerBounds = getBounds();
    playerBounds.setTopHeight(DEFAULT_PLAYER_HEIGHT);
    playerBounds.setRadius(DEFAULT_PLAYER_RADIUS);
  }

  public Player(PolygonGroup group) {
    super(group);
  }

}

/**
 * The GridGameObjectManager is a GameObjectManager that integrally arranges
 * GameObjects on a 2D grid for visibility determination and to limit the number
 * of tests for collision detection.
 */

class GridGameObjectManager implements GameObjectManager {

  /**
   * Default grid size of 512. The grid size should be larger than the largest
   * object's diameter.
   */
  private static final int GRID_SIZE_BITS = 9;

  private static final int GRID_SIZE = << GRID_SIZE_BITS;

  /**
   * The Cell class represents a cell in the grid. It contains a list of game
   * objects and a visible flag.
   */
  private static class Cell {
    List objects;

    boolean visible;

    Cell() {
      objects = new ArrayList();
      visible = false;
    }
  }

  private Cell[] grid;

  private Rectangle mapBounds;

  private int gridWidth;

  private int gridHeight;

  private List allObjects;

  private GameObject player;

  private Vector3D oldLocation;

  private CollisionDetection collisionDetection;

  /**
   * Creates a new GridGameObjectManager with the specified map bounds and
   * collision detection handler. GameObjects outside the map bounds will
   * never be shown.
   */
  public GridGameObjectManager(Rectangle mapBounds,
      CollisionDetection collisionDetection) {
    this.mapBounds = mapBounds;
    this.collisionDetection = collisionDetection;
    gridWidth = (mapBounds.width >> GRID_SIZE_BITS1;
    gridHeight = (mapBounds.height >> GRID_SIZE_BITS1;
    grid = new Cell[gridWidth * gridHeight];
    for (int i = 0; i < grid.length; i++) {
      grid[inew Cell();
    }
    allObjects = new ArrayList();
    oldLocation = new Vector3D();
  }

  /**
   * Converts a map x-coordinate to a grid x-coordinate.
   */
  private int convertMapXtoGridX(int x) {
    return (x - mapBounds.x>> GRID_SIZE_BITS;
  }

  /**
   * Converts a map y-coordinate to a grid y-coordinate.
   */
  private int convertMapYtoGridY(int y) {
    return (y - mapBounds.y>> GRID_SIZE_BITS;
  }

  /**
   * Marks all objects as potentially visible (should be drawn).
   */
  public void markAllVisible() {
    for (int i = 0; i < grid.length; i++) {
      grid[i].visible = true;
    }
  }

  /**
   * Marks all objects within the specified 2D bounds as potentially visible
   * (should be drawn).
   */
  public void markVisible(Rectangle bounds) {
    int x1 = Math.max(0, convertMapXtoGridX(bounds.x));
    int y1 = Math.max(0, convertMapYtoGridY(bounds.y));
    int x2 = Math.min(gridWidth - 1, convertMapXtoGridX(bounds.x
        + bounds.width));
    int y2 = Math.min(gridHeight - 1, convertMapYtoGridY(bounds.y
        + bounds.height));

    for (int y = y1; y <= y2; y++) {
      int offset = y * gridWidth;
      for (int x = x1; x <= x2; x++) {
        grid[offset + x].visible = true;
      }
    }
  }

  /**
   * Adds a GameObject to this manager.
   */
  public void add(GameObject object) {
    if (object != null) {
      if (object == player) {
        // ensure player always moves first
        allObjects.add(0, object);
      else {
        allObjects.add(object);
      }
      Cell cell = getCell(object);
      if (cell != null) {
        cell.objects.add(object);
      }

    }
  }

  /**
   * Removes a GameObject from this manager.
   */
  public void remove(GameObject object) {
    if (object != null) {
      allObjects.remove(object);
      Cell cell = getCell(object);
      if (cell != null) {
        cell.objects.remove(object);
      }
    }
  }

  /**
   * Adds a GameObject to this manager, specifying it as the player object. An
   * existing player object, if any, is not removed.
   */
  public void addPlayer(GameObject player) {
    this.player = player;
    if (player != null) {
      player.notifyVisible(true);
      add(player);
    }
  }

  /**
   * Gets the object specified as the Player object, or null if no player
   * object was specified.
   */
  public GameObject getPlayer() {
    return player;
  }

  /**
   * Gets the cell the specified GameObject is in, or null if the GameObject
   * is not within the map bounds.
   */
  private Cell getCell(GameObject object) {
    int x = convertMapXtoGridX((intobject.getX());
    int y = convertMapYtoGridY((intobject.getZ());
    return getCell(x, y);
  }

  /**
   * Gets the cell of the specified grid location, or null if the grid