package com.indignado.logicbricks.systems.sensors;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.EntityListener;
import com.badlogic.gdx.physics.box2d.*;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectSet;
import com.indignado.logicbricks.components.BlackBoardComponent;
import com.indignado.logicbricks.components.IdentityComponent;
import com.indignado.logicbricks.components.RigidBodiesComponents;
import com.indignado.logicbricks.components.sensors.NearSensorComponent;
import com.indignado.logicbricks.core.LogicBricksException;
import com.indignado.logicbricks.core.data.Property;
import com.indignado.logicbricks.core.sensors.NearSensor;
import com.indignado.logicbricks.utils.Log;
import com.indignado.logicbricks.utils.builders.FixtureDefBuilder;
/**
* @author Rubentxu
*/
public class NearSensorSystem extends SensorSystem<NearSensor, NearSensorComponent> implements ContactListener, EntityListener {
public NearSensorSystem() {
super(NearSensorComponent.class);
}
@Override
public boolean query(NearSensor sensor, float deltaTime) {
boolean isActive = false;
if (sensor.distanceContactList.size > 0) {
isActive = true;
if (!sensor.initContact) sensor.initContact = true;
} else if (sensor.initContact && sensor.resetDistanceContactList.size > 0) {
isActive = true;
} else if (sensor.initContact) {
sensor.initContact = false;
}
return isActive;
}
@Override
public void beginContact(Contact contact) {
Object propertyA = contact.getFixtureA().getUserData();
Object propertyB = contact.getFixtureB().getUserData();
Log.debug(tag, "Begin contact %b A %s B %s Apos %s Bpos %s", contact.isTouching(), propertyA, propertyB,
contact.getFixtureA().getBody().getPosition(), contact.getFixtureB().getBody().getPosition());
if (propertyA != null && propertyA instanceof Property) {
Entity entityB = (Entity) contact.getFixtureB().getBody().getUserData();
processAddNearSensors(entityB, contact, (Property) propertyA);
} else if (propertyB != null && propertyB instanceof Property) {
Entity entityA = (Entity) contact.getFixtureA().getBody().getUserData();
processAddNearSensors(entityA, contact, (Property) propertyB);
}
}
@Override
public void endContact(Contact contact) {
Log.debug(tag, "End contact sensor contact %b", contact.isTouching());
Object propertyA = contact.getFixtureA().getUserData();
Object propertyB = contact.getFixtureB().getUserData();
Log.debug(tag, "End contact %b A %s B %s Apos %s Bpos %s", contact.isTouching(), propertyA, propertyB,
contact.getFixtureA().getBody().getPosition(), contact.getFixtureB().getBody().getPosition());
if (propertyA != null && propertyA instanceof Property) {
processRemoveNearSensors(contact, (Property) propertyA);
} else if (propertyB != null && propertyB instanceof Property) {
processRemoveNearSensors(contact, (Property) propertyB);
}
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
private void processAddNearSensors(Entity entity, Contact contact, Property property) {
NearSensor nearSensor = (NearSensor) property.getValue();
if (nearSensor.targetPropertyName != null) {
BlackBoardComponent blackBoard = entity.getComponent(BlackBoardComponent.class);
if (blackBoard.hasProperty(nearSensor.targetPropertyName)) {
if (property.getName().equals("NearSensor")) {
nearSensor.distanceContactList.add(contact);
} else if (property.getName().equals("ResetNearSensor")) {
nearSensor.resetDistanceContactList.add(contact);
}
Log.debug(tag, "Add Contact targetPropertyName");
}
} else if (nearSensor.targetTag != null) {
IdentityComponent identity = entity.getComponent(IdentityComponent.class);
if (identity.tag.equals(nearSensor.targetTag)) {
if (property.getName().equals("NearSensor")) {
nearSensor.distanceContactList.add(contact);
} else if (property.getName().equals("ResetNearSensor")) {
nearSensor.resetDistanceContactList.add(contact);
}
Log.debug(tag, "Add Contact targetTag");
}
} else if (nearSensor.targetTag == null && nearSensor.targetPropertyName == null) {
if (property.getName().equals("NearSensor")) {
nearSensor.distanceContactList.add(contact);
} else if (property.getName().equals("ResetNearSensor")) {
nearSensor.resetDistanceContactList.add(contact);
}
Log.debug(tag, "Add Contact");
}
Log.debug(tag, "distanceContactList size %d resetDistanceContactList %d", nearSensor.distanceContactList.size,
nearSensor.resetDistanceContactList.size);
}
private void processRemoveNearSensors(Contact contact, Property property) {
NearSensor nearSensor = (NearSensor) property.getValue();
if (property.getName().equals("NearSensor") && nearSensor.distanceContactList.contains(contact)) {
nearSensor.distanceContactList.remove(contact);
} else if (property.getName().equals("ResetNearSensor") && nearSensor.resetDistanceContactList.contains(contact)) {
nearSensor.resetDistanceContactList.remove(contact);
}
Log.debug(tag, "Remove NearSensor distanceContactList size %d resetDistanceContactList %d", nearSensor.distanceContactList.size,
nearSensor.resetDistanceContactList.size);
}
@Override
public void entityAdded(Entity entity) {
Log.debug(tag, "EntityAdded add nearSensors");
ObjectSet<NearSensor> nearSensors = getNearSensors(entity);
if (nearSensors.size > 0) {
Log.debug(tag, "Create Near");
createNear(entity, nearSensors);
}
}
@Override
public void entityRemoved(Entity entity) {
}
private void createNear(Entity entity, ObjectSet<NearSensor> nearSensors) {
FixtureDefBuilder fixtureBuilder = new FixtureDefBuilder();
RigidBodiesComponents rigidBodiesComponent = entity.getComponent(RigidBodiesComponents.class);
if (rigidBodiesComponent == null)
throw new LogicBricksException(tag, "Failed to create near sensor, there is no rigidBody");
for (NearSensor sensor : nearSensors) {
if (sensor.distance == 0)
throw new LogicBricksException(tag, "nearSensor distance can not be zero");
if (sensor.attachedRigidBody == null) sensor.attachedRigidBody = rigidBodiesComponent.rigidBodies.first();
FixtureDef nearFixture = fixtureBuilder
.circleShape(sensor.distance)
.sensor()
.build();
sensor.attachedRigidBody.createFixture(nearFixture).setUserData(new Property<NearSensor>("NearSensor", sensor));
if (sensor.resetDistance != 0) {
if (sensor.resetDistance <= sensor.distance)
throw new LogicBricksException(tag, "ResetDistance can not be less than or equal to the distance");
FixtureDef nearResetFixture = fixtureBuilder
.circleShape(sensor.resetDistance)
.sensor()
.build();
sensor.attachedRigidBody.createFixture(nearResetFixture).setUserData(new Property<NearSensor>("ResetNearSensor", sensor));
}
Log.debug(tag, "Create Fixture nearSensor");
}
}
private ObjectSet<NearSensor> getNearSensors(Entity entity) {
ObjectSet<NearSensor> nearSensors = new ObjectSet<NearSensor>();
NearSensorComponent nearSensorComponent = entity.getComponent(NearSensorComponent.class);
if (nearSensorComponent != null) {
IntMap.Values<ObjectSet<NearSensor>> values = nearSensorComponent.sensors.values();
while (values.hasNext()) {
for (NearSensor sensor : values.next()) {
nearSensors.add(sensor);
}
}
}
return nearSensors;
}
}