package components;
import gl.GLCamera;
import gl.HasPosition;
import gl.scenegraph.MeshComponent;
import util.Vec;
import worldData.Entity;
import worldData.Obj;
import worldData.UpdateTimer;
import worldData.Updateable;
import worldData.Visitor;
import android.util.Log;
public abstract class TooFarAwayComp implements Entity {
private static final float DEFAULT_GRAYZONE_SIZE = 30; // TODO
private static final float DEFAULT_UPDATE_SPEED = 0.4f;
private static final String LOG_TAG = "TooFarAwayComp";
private static final int IS_TO_FAR_AWAY = 2;
private static final int IS_CLOSE = 1;
private float myMaxDistance;
private GLCamera myCamera;
private UpdateTimer timer;
private float myGrayZoneDist;
private int currentState;
/**
*
* obj->|--------|max dist.-------|gray.dist--------|measured dist.-----
*
* @param maxDistance
* @param grayZoneDist
* has to be larger then the max. distance!
* @param camera
* @param updateSpeed
*/
public TooFarAwayComp(float maxDistance, float grayZoneDist,
GLCamera camera, float updateSpeed) {
myMaxDistance = maxDistance;
myCamera = camera;
myGrayZoneDist = grayZoneDist;
timer = new UpdateTimer(updateSpeed, null);
}
public TooFarAwayComp(float maxDistance, GLCamera camera) {
this(maxDistance, maxDistance + DEFAULT_GRAYZONE_SIZE, camera,
DEFAULT_UPDATE_SPEED);
}
@Override
public Updateable getMyParent() {
Log.e(LOG_TAG, "Get parent called which is not "
+ "implemented for this component!");
return null;
}
@Override
public void setMyParent(Updateable parent) {
// can't have children so the parent does not have to be stored
Log.e(LOG_TAG, "Set parent called which is not "
+ "implemented for this component!");
}
@Override
public boolean update(float timeDelta, Updateable parent) {
/*
* as long as the parent is not a HasPosition subclass object the timer
* wont be updated
*/
if (parent instanceof HasPosition) {
if (timer.update(timeDelta, parent)) {
Vec pos = ((HasPosition) parent).getPosition();
if (pos != null) {
return usePosition(parent, pos);
}
}
return true;
}
Log.e(LOG_TAG, "Could not extract position from parent! " + parent
+ "(Class=" + parent.getClass() + "). "
+ "The comp cant be used in this context.");
return false;
}
private boolean usePosition(Updateable parent, Vec pos) {
MeshComponent parentsMesh = tryToGetTheParentsMesh(parent);
Vec direction = pos.copy().sub(myCamera.getPosition());
float length = direction.getLength();
direction.mult(-1);
if (length > myMaxDistance) {
/*
* the object is too faar away so inform the component
*/
if (currentState != IS_TO_FAR_AWAY) {
currentState = IS_TO_FAR_AWAY;
isNowToFarAway(parent, parentsMesh, direction);
}
onFarAwayEvent(parent, parentsMesh, direction);
/*
* if the distance is in the grayzone additionially fire the
* onGrayZoneEvent event
*/
if (length < myGrayZoneDist) {
float grayZonePercent = (length
/ (myGrayZoneDist - myMaxDistance) - 1) * 100;
onGrayZoneEvent(parent, parentsMesh, direction, grayZonePercent);
}
} else if (currentState != IS_CLOSE) {
currentState = IS_CLOSE;
isNowCloseEnough(parent, parentsMesh, direction);
}
return true;
}
private MeshComponent tryToGetTheParentsMesh(Updateable parent) {
if (parent instanceof Obj)
return ((Obj) parent).getGraphicsComponent();
return null;
}
/**
* This will be called ONCE when the user gets close enough to the object
* (use this method to hide the arrow pointing towards the object e.g.)
*
* @param parent
* Normally this will be the {@link MeshComponent} of the target
* {@link Obj} and if the object does not have one it will be the
* object itself
* @param direction
* The direction points from the object TO the user! If a
* {@link MeshComponent} is added to the parentMesh with
* subMesh.setPosition(direction) it will be at the location of
* the camera. Because of this reduce the length of the direction
* {@link Vec} to move it away from the users position and
* towards the target object
*/
public abstract void isNowCloseEnough(Updateable parent,
MeshComponent parentsMesh, Vec direction);
/**
* This will be called when ONCE when the target object is getting to faar
* away from the user (Use this method to display an arrow in the object
* direction e.g.)
*
* @param parent
* the parent where the {@link TooFarAwayComp} was added to. Will
* also be a subclass of {@link HasPosition}.
* @param parentsMesh
* the {@link MeshComponent} of the parent. If it is null the
* parent does not have a meshComp jet.
* @param direction
* The direction points from the object TO the user! If a
* {@link MeshComponent} is added to the parentMesh with
* subMesh.setPosition(direction) it will be at the location of
* the camera. Because of this reduce the length of the direction
* {@link Vec} to move it away from the users position and
* towards the target object
*/
public abstract void isNowToFarAway(Updateable parent,
MeshComponent parentsMesh, Vec direction);
/**
* This method is called frequently with the updated position of the target
* (e.g. to update the position of the arrow pointing to the target)
*
* @param parent
* the parent where the {@link TooFarAwayComp} was added to. Will
* also be a subclass of {@link HasPosition}.
* @param parentsMesh
* the {@link MeshComponent} of the parent. If it is null the
* parent does not have a meshComp jet.
* @param direction
* The direction points from the object TO the user! If a
* {@link MeshComponent} is added to the parentMesh with
* subMesh.setPosition(direction) it will be at the location of
* the camera. Because of this reduce the length of the direction
* {@link Vec} to move it away from the users position and
* towards the target object
*/
public abstract void onFarAwayEvent(Updateable parent,
MeshComponent parentsMesh, Vec direction);
/**
* This method will be called frequently when the user is in the defined
* gray zone (so nearly too far away to still see the object)
*
* @param parent
* the parent where the {@link TooFarAwayComp} was added to. Will
* also be a subclass of {@link HasPosition}.
* @param parentsMesh
* the {@link MeshComponent} of the parent. If it is null the
* parent does not have a meshComp jet.
* @param direction
* The direction points from the object TO the user! If a
* {@link MeshComponent} is added to the parentMesh with
* subMesh.setPosition(direction) it will be at the location of
* the camera. Because of this reduce the length of the direction
* {@link Vec} to move it away from the users position and
* towards the target object
* @param grayZonePercent
* from 0 to 100. 0 means entered grayzone but still far away and
* 100 means that the user is getting close enough to the object
* so that this {@link TooFarAwayComp} is not needed anymore
*
*/
public abstract void onGrayZoneEvent(Updateable parent,
MeshComponent parentsMesh, Vec direction, float grayZonePercent);
@Override
public boolean accept(Visitor visitor) {
// TODO Auto-generated method stub
return false;
}
public GLCamera getMyCamera() {
return myCamera;
}
}