The collisionData class is a type that i defined to handle collision detection. It is mainly used in my Physics_Handler class seen below:
package slick;
import java.util.ArrayList;
import java.util.List;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;
public class Physics_Handler{
static Player play;
Physics_Handler(){
}
//Adds a player to the physics simulation. Currently not fully implemented.
static void AddPlayer(Player player) {play = player;}
//This is where the collision detection process takes place.
static public CollisionData Collision(Entity entity, Vector2f position, int delta){
Vector2f OldPosition = new Vector2f(entity.getPhysics().position);
Rectangle rect = new Rectangle(0,0,0,0);
rect = entity.getPhysics().boundary;
CollisionData collision = new CollisionData(position);
//Check for Collision along the Y Axis
rect.setLocation(new Vector2f(OldPosition.x, position.y));
for(Entity obj : Map.tileMap)
{
if(rect.intersects(obj.getBounds()) && obj.getBounds() != entity.getPhysics().Self()
&& obj.getName() != "Player"){
collision.setActive(obj);
if(obj.isPassable()){
} else {
collision.setValidY(OldPosition.y);
collision.collideType = obj.getName();
collision.setCollision(true);
collision.setCollisionY(true);
rect.setLocation(collision.getValidPosition());
break;
}
} else {
collision.setValidY(position.y);
}
}
//Check for Collision along the X Axis
rect.setLocation(new Vector2f(position.x, OldPosition.y));
for(Entity obj : Map.tileMap)
{
if(rect.intersects(obj.getBounds()) && obj.getBounds() != entity.getPhysics().Self()
&& obj.getName() != "Player"){
collision.setActive(obj);
if(obj.isPassable()){
} else {
collision.setValidX(OldPosition.x);
collision.setCollision(true);
collision.setCollisionX(true);
entity.setPosition(collision.getValidX(), entity.getPosition().y);
entity.getPhysics().setAcceleration("collide", 0 , 0);
break;
}
} else {
collision.setValidX(position.x);
}
}
return collision;
}
//Used for Calculation Gravity within the "physics simulation". Only partly implemented
static public void calcGrav(Entity entity, Vector2f pos, int delta){
Vector2f tempPosition = new Vector2f(pos);
tempPosition.y += delta * 0.3f;
if(Collision(entity, tempPosition, delta).getCollisionY()){
entity.setFallingState(false);
} else {
entity.setFallingState(true);
entity.setPosition(tempPosition.x, tempPosition.y);
Level.spr.setAction(1);
}
}
}
To make use of this code, i have another class PBody that handles all physics for any object that it is "attached to". For example: If i want to add collision detection or gravity to a block, or the ability for a block to detect collisions i add a PBody to it. The PBody class is listed below:
package slick;
import org.newdawn.slick.geom.Vector2f;
import org.newdawn.slick.geom.Rectangle;
import java.text.*;
public class PBody{
Rectangle boundary;
Vector2f position;
Vector2f acceleration;
Entity entity;
int width, height;
int weigth = 1;
float scale = 1;
String type;
String currentdirection;
CollisionData collide;
Timer timer;
final float ACCEL_MAX = 5;
public void setAcceleration(String x, float mod, int delta){
currentdirection = x;
switch(x)
{
case "left":
acceleration.x -= (acceleration.x >= -ACCEL_MAX) ? mod*delta : 0;
this.TestCollision(new Vector2f(entity.getPosition().x + acceleration.x, entity.getPosition().y), delta);
break;
case "right":
acceleration.x += (acceleration.x <= ACCEL_MAX) ? mod*delta : 0;
this.TestCollision(new Vector2f(entity.getPosition().x + acceleration.x, entity.getPosition().y), delta);
break;
case "collide":
acceleration.x = 0;
return;
default:
acceleration.x += (acceleration.x > 0) ? -(delta * mod) : (acceleration.x < 0) ? delta * mod : 0;
if(acceleration.x < 1.0 && acceleration.x > -1.0)acceleration.x = 0;
this.TestCollision(new Vector2f(entity.getPosition().x + acceleration.x, entity.getPosition().y), delta);
}
if(acceleration.x >= 5)
acceleration.x = ACCEL_MAX;
else if(acceleration.x <= -5)
acceleration.x = -ACCEL_MAX;
timer.Update(delta);
}
final public Vector2f getAcceleration(){return acceleration;}
final public String getDirection(){return currentdirection;}
public PBody(Entity entity, Vector2f position, String type, int width, int height, float scale)
{
this.width = width;
this.height = height;
this.scale = scale;
this.entity = entity;
this.boundary = new Rectangle(position.x, position.y , width * scale, height * scale);
this.position = new Vector2f(position);
this.type = type;
this.collide = new CollisionData(position);
this.timer = new Timer();
acceleration = new Vector2f(0, 0);
currentdirection = " ";
this.boundary.closed();
timer.enableTargetInterval(true);
timer.setTargetInterval(300.0f, 0);
}
public PBody(Vector2f position)
{
this.boundary = new Rectangle(position.x, position.y, 32, 32);
}
public CollisionData getCollisionInfo()
{
return collide;
}
public void SetBoundary(Vector2f pos)
{
this.position = pos;
this.boundary.setLocation(pos);
boundary.setCenterX(position.x + (boundary.getWidth() / 2));
boundary.setCenterY(position.y + (boundary.getHeight() / 2));
}
public void Update(Entity en)
{
this.position = en.getPosition();
boundary.setLocation(position);
boundary.setCenterX(position.x + (boundary.getWidth() / 2));
boundary.setCenterY(position.y + (boundary.getHeight() / 2));
this.boundary.setBounds(position.x, position.y, height * scale, height * scale);
entity.setPosition(this.position.x + acceleration.x, this.position.y + acceleration.y);
}
public Rectangle Self(){return boundary;}
public void TestCollision(Vector2f position, int delta)
{
DecimalFormat df = new DecimalFormat("#.#");
this.position.x = Float.parseFloat(df.format(this.position.x));
this.position.y = Float.parseFloat(df.format(this.position.y));
position.x = Float.parseFloat(df.format(position.x));
position.y = Float.parseFloat(df.format(position.y));
float oldX = this.position.x;
float oldY = this.position.y;
float tempX = position.x;
float tempY = position.y;
Vector2f tempPosition = new Vector2f(tempX, tempY);
collide = Physics_Handler.Collision(entity, tempPosition,delta);
if(tempY != oldY)
{
if(collide.getCollision())
{
entity.setPosition(collide.getValidPosition());
}
else
{
entity.setPosition(tempPosition);
}
}
else
{
return;
}
tempPosition.x = tempX;
tempPosition.y = tempY;
if(tempX!= oldX)
{
if(collide.getCollision())
{
entity.setPosition(collide.getValidPosition());
}
else
{
entity.setPosition(tempX, tempY);
}
}
else
return;
}
public CollisionData cfPlayer(int x, int y){
CollisionData collide = new CollisionData(position);
Rectangle border = new Rectangle(this.position.x, this.position.y, x + 1, y + 1);
if(border.intersects(Level.player.getBounds())){
collide.setActive(this.entity);
collide.setCollideType(this.entity.getName());
collide.setCollision(true);
}
return collide;
}
public boolean CheckForPlayer(int x, int y){
boolean result = false;
Rectangle border = new Rectangle(this.position.x, this.position.y, x + 1, y + 1);
if(border.intersects(Level.player.getBounds())) result = true;
return result;
}
public boolean CheckForPlayerY(float y){
boolean result = false;
Rectangle check = new Rectangle (this.position.x + 8, this.position.y + y, 24, -y);
if(check.intersects(Level.player.getBounds()))
result = true;
return result;
}
public boolean CheckPosition(float x, float y)
{
boolean result = false;
Rectangle check = new Rectangle(x, y, 32, 32);
for(Entity e : Level.currentLevel.tileMap)
{
if(e == entity) continue;
if(check.intersects(e.getBounds()))
{
result = true;
break;
}
}
return result;
}
}
Effectively, within my code for my Item class for example all i need to do is create an instance of collisionData then i can do something like below:
CollisionData collision;
collision = this.getPhysics().cfPlayer(sprite.Render().getWidth(), sprite.Render().getHeight());
if(collision.getCollision()){
do something...
}
the "this" in the code is a particular instance of an implementation of an entity (Entity is made as an Interface. Object is an abstract implementation of Entity. Items is an extension (extends) of the Object abstract class) in this case the Items class. Since it is an entity it has a PBody attached to it. getPhysics() returns a handle to the specific instance of Items' specific instance of PBody.
My code is currently set up to test for collision on the Y axis then collision on the X axis. If there is a collision, collisionX and collisionY are set to true. However i have detection split between the X axis and the Y axis. It checks for Y collisions first, then X collisions. So i can easily implement realistic slope traversal or have a block push me of something without any issues.
What you see in that constructor spinet is me setting everything to a default state. By default, the object will be considered passable because by default no entity (something containing a PBody) is passed to the class.
pDataType is the type of PBody, be it static, dynamic or hybrid. I have this difference set for updating purposes. It currently does not have a use but it is there for when i update the order that collisions are handled by in the future.
As for the Valid X and the Valid Y, that is used for the collision detection i described earlier. Since i detect X and Y collisions separate, it allows my to continue moving along my X axis if my Y axis is blocked. I.E: Valid X and Valid Y are the last know X and Y values where collision have not taken place.
GetValidPosition does return what was set by valid position, however as i mentioned earlier X and Y collisions are tested separately, therefore i cannot just pass it the position that i went into the code using.
The code (CollisionData) was only posted here as an example of a helper class (in this case i guess a helper type) that i made so that i can do things like what was listed earlier in this post.
I apologize about the wall of text, and i greatly appreciate your feedback thus far.