/*
* Copyright (C) 2007 The Fysix Team
*
* This file is part of Fysix.
*
* Fysix is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* Fysix 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Fysix; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.sf.fysix.engine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.contacts.ContactPoint;
import net.sf.fysix.math.Vector2d;
import net.sf.fysix.world.Environment;
import net.sf.fysix.world.World;
import net.sf.fysix.world.WorldObject;
import net.sf.fysix.world.WorldObjectState;
import net.sf.fysix.world.WorldObject.TypeE;
public class Engine implements ContactListener {
private World world;
class ObjectHistory {
public List<WorldObjectState> stateobjs = new ArrayList<WorldObjectState>();
}
private static int HistoryC = 6;
private List<ObjectHistory> objectHist = new ArrayList<ObjectHistory>();
private int currentHistory=0;
private List<ContactPoint> contacts = new ArrayList<ContactPoint>();
public Engine(){
for(int i=0;i<HistoryC;i++){
objectHist.add(i, new ObjectHistory());
}
}
public void setWorld(World world) {
this.world = world;
world.getJBox2dWorld().setListener(this);
}
private void copyHistory(){
currentHistory++;
currentHistory %= HistoryC; // make constant...
ObjectHistory current = objectHist.get(currentHistory);
current.stateobjs.clear();
for (WorldObject wo : world.getObjects()){
WorldObjectState stateCopy = new WorldObjectState(wo.getElasticity(), wo.getMass(), wo.getMomentOfInertia(), wo.getTimeToLive(), wo.getType(), wo);
stateCopy.copyState(wo);
current.stateobjs.add(stateCopy);
}
}
public void tick(double dt) {
List<WorldObject> removeLst = new ArrayList<WorldObject>();
List<Body> removeBodyLst = new ArrayList<Body>();
//
// STORE APPROX 200 ms OF GAME TICK DATA
// 30FPS => 3 frames per 100 ms => a ROUND ROBIN on 6 elements...
//
// Note 1: shall be used to adjust calculations against clients with bad throughput, however 100 ms might be
// really ba game play connection so...
// Note 2: shall be use to get values before conect/collision to calculate 'mass of movement' and energy loss
//
copyHistory();
//
// BEGIN - TEST CODE AREA FOR COLLISION...
//
for (ContactPoint cp : Collections.unmodifiableCollection(contacts))
{
Body body1 = cp.shape1.getBody();
Body body2 = cp.shape2.getBody();
float mass1 = body1.getMass();
float mass2 = body2.getMass();
WorldObject wo1 = null;
WorldObject wo2 = null;
ObjectHistory oh = objectHist.get(currentHistory);
for (WorldObjectState wos : oh.stateobjs){
if(wos.getBody().equals(body1) || wos.getBody().equals(body2)){
System.out.println("Velocity : " + wos.getVelocity().length());
System.out.println("Mass : " + wos.getMass());
System.out.println("Type : " + wos.getType());
if(wo1 == null){
wo1 = wos.getWOPtr();
} else if(wo2 == null){
wo2= wos.getWOPtr();
break;
}
}
}
// Give damage to each other depending on the opposite velocity and mass
// TODO: USCH!
if(wo1 != null && wo2 != null){
if(wo1.getType().compareTo(TypeE.GAME_MAP) != 0){
wo1.doDamage(1000);
}
if(wo1.isDestroyed()){
removeBodyLst.add(body1);
}
if(wo2.getType().compareTo(TypeE.GAME_MAP) != 0){
wo2.doDamage(1000);
}
if(wo2.isDestroyed()){
removeBodyLst.add(body2);
}
}
}
contacts.clear(); // TODO: DON'T USE CONTACTS, MAKE A COPY!
for (WorldObject wo : world.getObjects()){
for(Body b : Collections.unmodifiableCollection(removeBodyLst)){
if(wo.getBody().equals(b)){
removeLst.add(wo);
}
}
}
List<WorldObject> reSpawnLst = new ArrayList<WorldObject>();
for (WorldObject wo : Collections.unmodifiableCollection(removeLst)){
world.removeObject(wo); // TODO: !!!
if(wo.getPlayerHandler() != null){
reSpawnLst.add(wo);
}
}
removeLst.clear();
for (WorldObject wo : Collections.unmodifiableCollection(reSpawnLst)){
wo.getPlayerHandler().enterPlayDead(world);
}
reSpawnLst.clear();
//
// WorldObjects with actions that result in new WorldObjects...
//
List<WorldObject> actionLst = new ArrayList<WorldObject>();
for (WorldObject wo : world.getObjects()){
if(wo.hasGameAction()){
actionLst.add(wo);
}
}
for (WorldObject wo : Collections.unmodifiableCollection(actionLst)){
wo.doGameAction();
}
actionLst.clear();
//
// END - TEST CODE AREA FOR COLLISION...
//
for (WorldObject wo : world.getObjects()) {
for (Force force : wo.getForces()) {
Vector2d dir = force.getDirection();
Vector2d origin = force.getOrigin();
Vec2 fvect = new Vec2((float) dir.getX(), (float) dir.getY());
Vec2 point = new Vec2((float) origin.getX(), (float) origin.getY());
fvect = wo.getBody().getWorldVector(fvect);
point = wo.getBody().getWorldPoint(point);
wo.getBody().applyForce(fvect, point);
}
Vector2d p = wo.getPosition();
for (Environment env : world.getEnvironments()) {
Vector2d g = env.getGravity(p);
double fr = env.getFriction(p); // TODO Should we get rid of this?
g.scale(wo.getBody().getMass());
Vec2 point = wo.getBody().getWorldCenter();
wo.getBody().applyForce(new Vec2((float) g.getX(), (float) g.getY()), point);
}
// Time space
wo.onGameTick();
if(wo.isAlive() == false){
removeLst.add(wo);
}
}
world.getJBox2dWorld().step((float) dt, 10);
for (WorldObject wo : Collections.unmodifiableCollection(removeLst)){
world.removeObject(wo);
}
removeLst.clear();
}
public void add(ContactPoint collision) {
// System.out.println("CONTACT (ADD) : " + collision.id);
//
// TODO: MAKE HARD COPY!!!
//
contacts.add(collision);
}
public void persist(ContactPoint collision) {
// System.out.println("CONTACT (PER) : " + collision.id);
}
public void remove(ContactPoint collision) {
// System.out.println("CONTACT (REM) : " + collision.id);
}
}