Package com.golden.gamedev.object.collision

Source Code of com.golden.gamedev.object.collision.AdvanceCollisionGroup

/*
* Copyright (c) 2008 Golden T Studios.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.golden.gamedev.object.collision;

// JFC
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.golden.gamedev.object.Sprite;
import com.golden.gamedev.object.SpriteGroup;
import com.golden.gamedev.util.Utility;

/**
* Accurates collision check that able to check collision between one sprite
* with many sprites (one to many collision check).
* <p>
*
* This collision check is the most advance among all other collision check, it
* checking is the collision really occured or not.
* <p>
*
* For example: <br>
* A sprite is checked its collision with three other sprites, if the checking
* only based on the sprite position, the sprite is collided with the three
* other sprites. But if the sprite is collided with the first sprite and stop,
* the sprite actually only collide with the first, because the second and the
* third is right behind the first sprite.
* <p>
*
* This collision group is suitable for collision that using physics heavily,
* like in platformer game, where a sprite could collide with many blocks at one
* time.
*/
public abstract class AdvanceCollisionGroup extends PreciseCollisionGroup
        implements Comparator {
 
  private final Map storage = new HashMap();
 
  private Sprite source;
 
  /** ************************************************************************* */
  /** ***************************** CONSTRUCTOR ******************************* */
  /** ************************************************************************* */
 
  /**
   * Constructs new <code>AdvanceCollisionGroup</code>.
   */
  public AdvanceCollisionGroup() {
  }
 
  /** ************************************************************************* */
  /** ****************** MAIN-METHOD: CHECKING COLLISION ********************** */
  /** ************************************************************************* */
 
  public void checkCollision() {
    // clear previous collision event
    this.storage.clear();
   
    // the usual collision check
    SpriteGroup group1 = this.getGroup1(), group2 = this.getGroup2();
    if (!group1.isActive() || !group2.isActive()) {
      // one of the group is not active
      return;
    }
   
    Sprite[] member1 = group1.getSprites(), // members group one
    member2 = group2.getSprites();
    int size1 = group1.getSize(), // total non-null members
    size2 = group2.getSize();
   
    Sprite sprite1, sprite2; // sprite reference
    CollisionShape shape1, shape2; // sprite collision rect
   
    // sprite 1, 2 collision rectangle -> rect1, rect2
    for (int i = 0; i < size1; i++) {
      sprite1 = member1[i];
     
      if (!sprite1.isActive()
              || (shape1 = this.getCollisionShape1(sprite1)) == null) {
        // sprite do not want collision check
        continue;
      }
     
      for (int j = 0; j < size2; j++) {
        sprite2 = member2[j];
       
        if (!sprite2.isActive()
                || // !sprite1.isActive() ||
                sprite1 == sprite2
                || (shape2 = this.getCollisionShape2(sprite2)) == null) {
          // sprite do not want collision check
          continue;
        }
       
        if (this.isCollide(sprite1, sprite2, shape1, shape2)) {
          // collects all collided sprites event into
          // our storage object
         
          // store sprites collided with sprite1
          Sprite[] other = (Sprite[]) this.storage.get(sprite1);
         
          other = (Sprite[]) Utility.expand(other, 1, true,
                  Sprite.class);
          other[other.length - 1] = sprite2;
         
          this.storage.put(sprite1, other);
        }
      }
    }
   
    // now it's time to check the actual collision
    Iterator key = this.storage.keySet().iterator();
   
    while (key.hasNext()) {
      Sprite s1 = (Sprite) key.next();
      Sprite[] s2 = (Sprite[]) this.storage.get(s1);
     
      if (s2.length == 1) {
        // sprite s1 collide with only 'one' other sprite
        // so there should be no problem
       
        // need to reset revert positions- this is left at last
        // test,
        this.isCollide(s1, s2[0], this.getCollisionShape1(s1), this
                .getCollisionShape2(s2[0]));
       
        // fire collision event
        this.collided(s1, s2[0]);
       
        // continue to the next sprite
        continue;
      }
     
      // sort all collided sprites
      this.source = s1;
      if (this.sort(this.source)) {
        Arrays.sort(s2, this);
      }
     
      // in here the collision event is really fired to the listener
      for (int i = 0; i < s2.length; i++) {
        if (!s1.isActive()) {
          break;
        }
       
        // System.out.println("Start "+s2.length);
       
        if (s2[i].isActive()) {
         
          // System.out.print(s2[i]+"
          // "+s2[i].getX()+","+s2[i].getY()+"--");
         
          if (this.isCollide(s1, s2[i], this.getCollisionShape1(s1),
                  this.getCollisionShape2(s2[i]))) {
            // fire collision event
            // System.out.print("Yes");
            this.collided(s1, s2[i]);
          }
          // System.out.println();
        }
        // System.out.println("End\n");
      }
    }
  }
 
  /**
   * Determines all sprites that collided with Sprite <code>source</code>
   * should be sorted or not before checking the actual collision.
   * <p>
   *
   * By default this method return true in order to sort the collided sprites.
   *
   * @return true, collided sprites will be sorted before checking the actual
   *         collision.
   * @see #compare(Object, Object)
   */
  protected boolean sort(Sprite source) {
    return true;
  }
 
  /**
   * Sorts two sprites (<code>o1</code> and <code>o2</code>) that
   * collided with {@linkplain #getSourceSprite() the object sprite} to
   * determine which one should be checked first.
   * <p>
   *
   * By default when the {@linkplain #getSourceSprite() object sprite} is
   * falling ({@linkplain Sprite#getVerticalSpeed() vertical speed} >= 0),
   * all collided sprites are sorted by greater y at bottom, otherwise it sort
   * by greater y at top.
   */
  public int compare(Object o1, Object o2) {
    Sprite s1 = (Sprite) o1, s2 = (Sprite) o2;
   
    if (this.source.getHorizontalSpeed() != 0 && s1.getX() != s2.getX()) {
      // source not stationary and s1 x the same as s2 x
      return (this.source.getHorizontalSpeed() >= 0) ? // if source
      // heading right
      (int) Math.floor(s1.getX() - s2.getX())
              : // most lefterly
              (int) Math.floor(s2.getX() - s1.getX());// most righterly
    }
   
    // // sort by sprite y position
    // return (source.getVerticalSpeed() >= 0) ?
    // (int) Math.ceil(s1.getY() - s2.getY()) :
    // (int) Math.ceil(s2.getY() - s1.getY());
   
    // sort by sprite y position
    return (this.source.getVerticalSpeed() >= 0) ? (int) Math.floor(s1
            .getY()
            - s2.getY()) : (int) Math.floor(s2.getY() - s1.getY());
   
  }
 
  /**
   * Returns the source sprite to be checked at the moment.
   * <p>
   *
   * Source sprite is the sprite from group 1 that will be checked its actual
   * collision with sprite from group 2.
   */
  protected Sprite getSourceSprite() {
    return this.source;
  }
 
  /**
   * Returns collided sprites storage.
   * <p>
   *
   * Mapping a sprite with its collided sprites.
   */
  public Map getStorage() {
    return this.storage;
  }
 
}
TOP

Related Classes of com.golden.gamedev.object.collision.AdvanceCollisionGroup

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.