package com.angrykings;
import android.hardware.SensorManager;
import com.angrykings.maps.BasicMap;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.util.Vector2Pool;
import org.andengine.extension.physics.box2d.util.constants.PhysicsConstants;
import org.andengine.ui.activity.BaseGameActivity;
import org.andengine.util.debug.Debug;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Iterator;
/**
* PhysicsManager
*
* Manages all physically simulated game objects.
*
* @author Shivan Taher <zn31415926535@gmail.com>
* @date 31.05.13
*/
public class PhysicsManager implements IUpdateHandler {
private static PhysicsManager instance = null;
private boolean ready;
private boolean freezed;
FixedStepPhysicsWorld physicsWorld;
public static PhysicsManager getInstance() {
if(instance == null)
instance = new PhysicsManager();
return instance;
}
public static void clear(){
instance = null;
}
private static final float MIN_LINEAR_VELOCITY = 1e-2f;
private static final float MIN_ANGULAR_VELOCITY = 1e-1f;
private ArrayList<PhysicalEntity> physicalEntities;
private PhysicsManager() {
this.ready = true;
this.physicalEntities = new ArrayList<PhysicalEntity>();
this.physicsWorld = new FixedStepPhysicsWorld(
GameConfig.PHYSICS_STEPS_PER_SEC,
GameConfig.PHYSICS_MAX_STEPS_PER_UPDATE,
new Vector2(0, SensorManager.GRAVITY_EARTH),
false,
GameConfig.PHYSICS_VELOCITY_ITERATION,
GameConfig.PHYSICS_POSITION_ITERATION
);
physicsWorld.setAutoClearForces(true);
GameContext.getInstance().setPhysicsWorld(physicsWorld);
}
public void addPhysicalEntity(PhysicalEntity entity) {
this.physicalEntities.add(entity);
}
@Override
public void onUpdate(float pSecondsElapsed) {
this.ready = true;
Iterator<PhysicalEntity> it = this.physicalEntities.iterator();
while(it.hasNext()) {
PhysicalEntity entity = it.next();
Body b = entity.getBody();
if(!entity.isAutoRemoveEnabled())
continue;
float linearVelocity = b.getLinearVelocity().len();
float angularVelocity = b.getAngularVelocity();
if(linearVelocity > 0 && linearVelocity < 2.5 && angularVelocity < 3){
b.setAngularVelocity(0.0f);
}
if(linearVelocity < PhysicsManager.MIN_LINEAR_VELOCITY && angularVelocity < PhysicsManager.MIN_ANGULAR_VELOCITY) {
Debug.d("remove physical entity: lin: " + b.getLinearVelocity().len() + " angular: " + b.getAngularVelocity());
entity.remove();
it.remove();
}else{
Debug.d("not ready: lin="+linearVelocity+", ang="+angularVelocity);
this.ready = false;
}
if(entity.getAreaShape().getY() > BasicMap.GROUND_Y + 100) {
Debug.d("remove physical entity (seems to have fallen down of the 'ground'): y " + entity.getAreaShape().getY());
entity.remove();
it.remove();
}
}
}
/**
* @param ignoreAutoRemovables If true the entities with autoRemove enabled will be ignored
* @return Returns a list of physical entities.
*/
public ArrayList<PhysicalEntity> getPhysicalEntities(boolean ignoreAutoRemovables) {
ArrayList<PhysicalEntity> entities = new ArrayList<PhysicalEntity>();
Iterator<PhysicalEntity> it = this.physicalEntities.iterator();
int count =0;
while(it.hasNext()) {
PhysicalEntity entity = it.next();
if(ignoreAutoRemovables && entity.isAutoRemoveEnabled())
continue;
entities.add(entity);
}
return entities;
}
/**
* @return Returns a list of all physical entities except of the ones where autoRemove ist enabled
*/
public ArrayList<PhysicalEntity> getPhysicalEntities() {
return this.getPhysicalEntities(true);
}
/**
* @param id Id of the entity.
* @return Returns the physical entity or null if not found.
*/
public PhysicalEntity getEntityById(final int id) {
for(PhysicalEntity e : this.physicalEntities)
if(e.getId() == id)
return e;
Debug.d("Warning: entity with id=" + id + " not found!");
return null;
}
public void updateEntities(final JSONArray jsonEntities) {
BaseGameActivity gameActivity = GameContext.getInstance().getGameActivity();
gameActivity.runOnUpdateThread(new Runnable() {
@Override
public void run() {
try {
for(int i=0; i < jsonEntities.length(); i++) {
JSONObject jsonEntity = jsonEntities.getJSONObject(i);
final int id = jsonEntity.getInt("id");
final float x = (float) jsonEntity.getDouble("x");
final float y = (float) jsonEntity.getDouble("y");
final float rotation = (float) jsonEntity.getDouble("rotation");
PhysicalEntity e = PhysicsManager.this.getEntityById(id);
if(e != null){
final float widthD2 = e.getAreaShape().getWidth() / 2;
final float heightD2 = e.getAreaShape().getHeight() / 2;
final Vector2 v2 = Vector2Pool.obtain(
(x + widthD2) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT,
(y + heightD2) / PhysicsConstants.PIXEL_TO_METER_RATIO_DEFAULT
);
e.getBody().setTransform(v2, rotation);
Vector2Pool.recycle(v2);
}
}
} catch (JSONException e) {
}
}
});
}
public void clearEntities() {
this.physicalEntities.clear();
PhysicalEntity.CURRENT_ID = 0;
}
@Override
public void reset() {
}
public FixedStepPhysicsWorld getPhysicsWorld() {
return physicsWorld;
}
}