package com.indignado.logicbricks.systems;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntityListener;
import com.badlogic.ashley.core.Family;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.*;
import com.indignado.logicbricks.components.RadialGravityComponent;
import com.indignado.logicbricks.components.RigidBodiesComponents;
import com.indignado.logicbricks.core.LogicBricksException;
import com.indignado.logicbricks.config.Settings;
import com.indignado.logicbricks.utils.Log;
import com.indignado.logicbricks.utils.builders.FixtureDefBuilder;
/**
* @author Rubentxu
*/
public class RadialGravitySystem extends LogicBrickSystem implements ContactListener, EntityListener {
private ComponentMapper<RadialGravityComponent> rgm;
private Vector2 debris_position;
private Vector2 planet_distance;
private float force;
public RadialGravitySystem() {
super(Family.all(RadialGravityComponent.class).get(), 4);
rgm = ComponentMapper.getFor(RadialGravityComponent.class);
planet_distance = new Vector2();
}
@Override
public void processEntity(Entity entity, float deltaTime) {
if (Settings.DEBUG_ENTITY != null) tag = Log.tagEntity(this.getClass().getSimpleName(), entity);
RadialGravityComponent radialGravity = rgm.get(entity);
Vector2 planet_position = radialGravity.attachedRigidBody.getWorldCenter();
if (radialGravity.bodyList.size > 0) radialGravity.bodyList.first().getWorld().clearForces();
for (Body body : radialGravity.bodyList) {
debris_position = body.getWorldCenter();
planet_distance.set(0, 0);
planet_distance.add(debris_position);
planet_distance.sub(planet_position);
force = (float) ((radialGravity.gravity * body.getMass()) / planet_distance.len());
if (planet_distance.len() < radialGravity.radius * radialGravity.gravityFactor) {
planet_distance.scl(force);
body.applyForceToCenter(planet_distance, true);
float desiredAngle = MathUtils.atan2(-body.getLinearVelocity().x, body.getLinearVelocity().y);
while (desiredAngle < -180 * MathUtils.degreesToRadians)
desiredAngle += 360 * MathUtils.degreesToRadians;
while (desiredAngle > 180 * MathUtils.degreesToRadians)
desiredAngle -= 360 * MathUtils.degreesToRadians;
body.applyTorque(desiredAngle < 0 ? planet_distance.nor().len() / 2 : -planet_distance.nor().len() / 2, true);
}
}
}
@Override
public void beginContact(Contact contact) {
RadialGravityComponent radialGravity;
radialGravity = (RadialGravityComponent) contact.getFixtureA().getUserData();
if (radialGravity != null) {
Body body = contact.getFixtureB().getBody();
body.setGravityScale(0);
body.resetMassData();
radialGravity.bodyList.add(body);
Log.debug(tag, "Begin RadialGravity body %s", body.getPosition());
return;
}
radialGravity = (RadialGravityComponent) contact.getFixtureB().getUserData();
if (radialGravity != null) {
Body body = contact.getFixtureA().getBody();
body.setGravityScale(0);
body.resetMassData();
radialGravity.bodyList.add(body);
Log.debug(tag, "Begin RadialGravity body %s", body.getPosition());
return;
}
if (!processContactBody(contact.getFixtureA().getBody(), contact))
processContactBody(contact.getFixtureB().getBody(), contact);
}
public boolean processContactBody(Body body, Contact contact) {
Entity entity = (Entity) body.getUserData();
if (entity.getComponent(RadialGravityComponent.class) != null) {
contact.resetFriction();
return true;
}
return false;
}
@Override
public void endContact(Contact contact) {
RadialGravityComponent radialGravity;
radialGravity = (RadialGravityComponent) contact.getFixtureA().getUserData();
if (radialGravity != null) {
Body body = contact.getFixtureB().getBody();
body.setGravityScale(1);
body.resetMassData();
radialGravity.bodyList.removeValue(body, true);
Log.debug(tag, "End Contact body %s", body.getPosition());
return;
}
radialGravity = (RadialGravityComponent) contact.getFixtureB().getUserData();
if (radialGravity != null) {
Body body = contact.getFixtureA().getBody();
body.setGravityScale(1);
body.resetMassData();
radialGravity.bodyList.removeValue(body, true);
Log.debug(tag, "End Contact body %s", body.getPosition());
}
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
@Override
public void entityAdded(Entity entity) {
RadialGravityComponent radialGravity = entity.getComponent(RadialGravityComponent.class);
if (radialGravity != null) createRadialGravitySensor(entity, radialGravity);
}
@Override
public void entityRemoved(Entity entity) {
}
private void createRadialGravitySensor(Entity entity, RadialGravityComponent radialGravity) {
Log.debug(tag, "EntityAdded add RadialGravity");
FixtureDefBuilder fixtureBuilder = new FixtureDefBuilder();
RigidBodiesComponents rigidBodiesComponent = entity.getComponent(RigidBodiesComponents.class);
if (rigidBodiesComponent == null)
throw new LogicBricksException(tag, "Failed to create RadialGravitySensor, there is no rigidBody");
if (radialGravity.radius == 0)
throw new LogicBricksException(tag, "radialGravity radius can not be zero");
if (radialGravity.attachedRigidBody == null)
radialGravity.attachedRigidBody = rigidBodiesComponent.rigidBodies.first();
FixtureDef radialFixture = fixtureBuilder
.circleShape(radialGravity.radius)
.sensor()
.build();
radialGravity.attachedRigidBody.createFixture(radialFixture).setUserData(radialGravity);
Log.debug(tag, "Create Fixture RadialGravitySensor");
}
}