package com.igorcrevar.rolloverchuck.physics;
import com.badlogic.gdx.math.Vector3;
public class CollisionSolver {
private static final float ZERO = 0.00001f;
//HOW MUCH WE CHANGE indipendant value in EVERY ITERATION
private float step = 0.1f;
private Vector3 tmp = new Vector3();
/**
* Set step for every iteration of interpolation
* @param s
*/
public void setStep(float s) {
step = s;
}
private boolean isZero(float v) {
return Math.abs(v) < ZERO;
}
private int getNumberOfSteps(float diff, float step) {
float stepsHelper = Math.abs(diff) / step;
//round on greater number
if (isZero(stepsHelper - (float)Math.floor(stepsHelper))) {
return (int)stepsHelper;
}
return (int)stepsHelper + 1;
}
/**
* Interpolate over X and call handler for every iteration. Must not x2 == x1!!!
* @param handler
* @param tag
* @param start
* @param end
*/
private void iterateOverX(ICollisionIterationHandler handler, Object tag, Vector3 start, Vector3 end){
float diff = end.x - start.x;
int steps = getNumberOfSteps(diff, step);
float dx = Math.signum(diff) * step;
float dy = (end.y - start.y) / steps;
float dz = (end.z - start.z) / steps;
// use clone
Vector3 position = tmp;
position.set(start);
for (int i = 0; i < steps; ++i) {
if (handler.iterationHandler(position, (float)i / steps, tag)){ //callback
return;
}
position.x += dx;
position.y += dy;
position.z += dz;
}
//solve once more for end position
position.set(end);
handler.iterationHandler(position, 1.0f, tag); //callback
}
/**
* Interpolate over Z and call handler for every iteration. z2 must not be equal to z1!!!
* @param handler
* @param tag
* @param start
* @param end
*/
private void iterateOverZ(ICollisionIterationHandler handler, Object tag, Vector3 start, Vector3 end){
float diff = end.z - start.z;
int steps = getNumberOfSteps(diff, step);
float dx = (end.x - start.x) / steps;
float dy = (end.y - start.y) / steps;
float dz = Math.signum(diff) * step;
// use clone
Vector3 position = tmp;
position.set(start);
for (int i = 0; i < steps; ++i) {
if (handler.iterationHandler(position, (float)i / steps, tag)){ //callback
return;
}
position.x += dx;
position.y += dy;
position.z += dz;
}
//solve once more for end position
position.set(end);
handler.iterationHandler(position, 1.0f, tag); //callback
}
/**
* Iterate from posStart to posEnd and pass control on every iteration to handler
* @param handler
* @param posStart
* @param posEnd
* @param will be passed to handler
*/
public void iterateOver(ICollisionIterationHandler handler, Vector3 posStart, Vector3 posEnd, Object tag){
float diffx = Math.abs(posEnd.x - posStart.x);
float diffz = Math.abs(posEnd.z - posStart.z);
if (diffx > diffz) {
iterateOverX(handler, tag, posStart, posEnd);
}
else if (isZero(diffz)) { // didnt move at all
tmp.set(posStart);
handler.iterationHandler(tmp, 1.0f, tag); //callback
}
else {
iterateOverZ(handler, tag, posStart, posEnd);
}
}
}