package com.uwsoft.editor.renderer.systems;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.ashley.utils.ImmutableArray;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.World;
import com.uwsoft.editor.renderer.components.DimensionsComponent;
import com.uwsoft.editor.renderer.components.PolygonComponent;
import com.uwsoft.editor.renderer.components.TransformComponent;
import com.uwsoft.editor.renderer.components.physics.PhysicsBodyComponent;
import com.uwsoft.editor.renderer.physics.PhysicsBodyLoader;
import com.uwsoft.editor.renderer.utils.ComponentRetriever;
import com.uwsoft.editor.renderer.utils.TransformMathUtils;
public class PhysicsSystem extends IteratingSystem {
protected ComponentMapper<TransformComponent> transformComponentMapper = ComponentMapper.getFor(TransformComponent.class);
private final float TIME_STEP = 1f/60;
private World world;
private boolean isPhysicsOn = true;
private float accumulator = 0;
public PhysicsSystem(World world) {
super(Family.all(PhysicsBodyComponent.class).get());
this.world = world;
}
@Override
public void update (float deltaTime) {
for (int i = 0; i < getEntities().size(); ++i) {
processEntity(getEntities().get(i), deltaTime);
}
if (world != null && isPhysicsOn) {
doPhysicsStep(deltaTime);
}
}
@Override
protected void processEntity(Entity entity, float deltaTime) {
TransformComponent transformComponent = transformComponentMapper.get(entity);
processBody(entity);
PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class);
Body body = physicsBodyComponent.body;
transformComponent.x = 0;
transformComponent.y = 0;
transformComponent.rotation = 0;
Vector2 localCoords = TransformMathUtils.sceneToLocalCoordinates(entity, body.getPosition().cpy().scl(1 / PhysicsBodyLoader.getScale()));
transformComponent.x = localCoords.x - transformComponent.originX;
transformComponent.y = localCoords.y - transformComponent.originY;
transformComponent.rotation = body.getAngle() * MathUtils.radiansToDegrees;
}
protected void processBody(Entity entity) {
PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class);
PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class);
TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class);
if(polygonComponent == null && physicsBodyComponent.body != null) {
world.destroyBody(physicsBodyComponent.body);
physicsBodyComponent.body = null;
}
if(physicsBodyComponent.body == null && polygonComponent != null) {
if(polygonComponent.vertices == null) return;
DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class);
physicsBodyComponent.centerX = dimensionsComponent.width/2;
physicsBodyComponent.centerY = dimensionsComponent.height/2;
PhysicsBodyComponent bodyPropertiesComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class);
physicsBodyComponent.body = PhysicsBodyLoader.getInstance().createBody(world, entity, bodyPropertiesComponent, polygonComponent.vertices, transformComponent);
physicsBodyComponent.body.setUserData(entity);
}
}
private void doPhysicsStep(float deltaTime) {
// fixed time step
// max frame time to avoid spiral of death (on slow devices)
float frameTime = Math.min(deltaTime, 0.25f);
accumulator += frameTime;
while (accumulator >= TIME_STEP) {
world.step(TIME_STEP, 6, 2);
accumulator -= TIME_STEP;
}
}
public void setPhysicsOn(boolean isPhysicsOn) {
this.isPhysicsOn = isPhysicsOn;
}
}