Package net.javlov.world.grid

Source Code of net.javlov.world.grid.GridWorldGeneric

package net.javlov.world.grid;

import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

import net.javlov.world.Body;
import net.javlov.world.CollisionEvent;

/**
* Grid world implementation that can be used with bodies of any size and shape.
* @author matthijs
*
*/
public class GridWorldGeneric extends GridWorld {

  private List<CollisionEvent> collisionList;
 
  public GridWorldGeneric(int width, int height, double cellWidth,
      double cellHeight) {
    super(width, height, cellWidth, cellHeight);
    collisionList = new ArrayList<CollisionEvent>();
  }
 
  //TODO this only works correctly if no recursion is required, i.e. if there is
  //no collision with movable objects next to other objects. In the latter case,
  //all collision events might be fired before it can be guaranteed
  //that the move is allowed.
  /**
   * @return true if the move was completed entirely (the number of cells indicated
   * by the speed parameter), false otherwise.
   */
  @Override
  public boolean translateBody(Body b, Direction d, int speed) {
    List<GridCell> currCells = getIntersectingCellsLarge(getTransformedShape(b)),
            targetCells = new ArrayList<GridCell>(currCells.size());
           
    GridCell locCell = grid.getCell(b.getX(), b.getY()),
        targetCell;
   
    int i;
    boolean moveAllowed;
    for ( i = 0; i < speed; i++) {
      moveAllowed = true;
      for ( GridCell currCell : currCells ) {
        targetCell = currCell.go(d);
        targetCells.add(targetCell);
        if ( targetCell.isBorder() || !move(b, d, targetCell) )
          moveAllowed = false;
      }
      if ( moveAllowed ) {
        fireQueuedCollisionEvents();
        for ( int j = 0; j < currCells.size(); j++ ) {
          currCells.get(j).removeBody(b);
          targetCells.get(j).addBody(b);
          currCells.set(j, targetCells.get(j));
        }
        locCell = locCell.go(d); //track body's location
      } else {
        cleanQueuedCollisionEvents();
        break;
      }
    }
   
    b.setLocation(locCell.getCenterX(), locCell.getCenterY());
   
    if ( i < speed-1 ) //move couldn't be entirely completed
      return false;
    return true;
  }
 
  /**
   * Checks if the body can be moved to the specified target cell. If an obstacle is
   * encountered in the target cell, the move is invalidated and a CollisionEvent is
   * fired immediately.
   * If any other type of Body is encountered, a CollisionEvent is created and put in
   * a list of collision events. These events will be fired if the move as a whole (as
   * executed by {@link #translateBody(Body, Direction, int)}) is allowed (the move
   * method only checks a single cell).
   */
  @Override
  protected boolean move( Body b, Direction d, GridCell targetCell ) {
    //TODO Don't like all these fors and ifs
    List<Body> occupiers = targetCell.getOccupiers();
    //obstacles take precedence over all other bodies
    for ( Body targetBody : occupiers )
      if ( targetBody.getType() == Body.OBSTACLE ) {
        fireCollisionEvent(b, targetBody, new Point2D.Double(d.x(), d.y()));
        return false;
      }
    //next check if movables can be moved
    for ( Body targetBody : occupiers )
      if ( targetBody.getType() == Body.MOVABLE ) {
        queueCollisionEvent(b, targetBody, new Point2D.Double(d.x(), d.y()));
        if ( !translateBody(targetBody, d, 1) )
          return false;
      }
    //just queue collisionevent for the other body types
    for ( Body targetBody : occupiers )
      if ( targetBody.getType() != Body.OBSTACLE && targetBody.getType() != Body.MOVABLE )
        queueCollisionEvent(b, targetBody, new Point2D.Double(d.x(), d.y()));
       
    return true;
  }
 
  protected void queueCollisionEvent(Body b1, Body b2, Point2D.Double speed) {
    CollisionEvent e = new CollisionEvent(b1, b2, speed, (Point2D.Double)b2.getLocation());
    collisionList.add(e);
  }
 
  protected void fireQueuedCollisionEvents() {
    for ( CollisionEvent event : collisionList )
      fireCollisionEvent(event);
    cleanQueuedCollisionEvents();
  }
 
  protected void cleanQueuedCollisionEvents() {
    collisionList.clear();
  }
 
  protected Shape getTransformedShape(Body b) {
    //rotate figure
    AffineTransform at = new AffineTransform();
    //rotate around the body's center
    at.rotate(b.getBearing(), b.getX(), b.getY());
    return at.createTransformedShape(b.getFigure());
  }
 
  @Override
  protected void addToCells(Body b) {
    int count = 0;
      for ( GridCell c : getIntersectingCellsLarge(getTransformedShape(b)) ) {
        count++;
        c.addBody(b);
      }
    }
 
  @Override
  protected void removeFromCells(Body b) {
    for ( GridCell c : getIntersectingCellsLarge(getTransformedShape(b)) )
        c.removeBody(b);
    }
}
TOP

Related Classes of net.javlov.world.grid.GridWorldGeneric

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.