package com.igorcrevar.rolloverchuck.physics; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; public class SphereMoving { private Vector3 position = new Vector3(); private Vector3 velocity = new Vector3(); private Vector3 rotationAxis = new Vector3(); private float angle; private Vector3 friction = new Vector3(); private Vector3 maxVelocity = new Vector3(); private Vector3 boundary = new Vector3(); private Vector3 bouncingFactor = new Vector3(); public void init(Vector3 boundary, Vector3 friction, Vector3 maxVelocity, Vector3 bouncingFactor) { position.set(0f, 0f, 0f); velocity.set(0f, 0f, 0f); rotationAxis.set(0f, 0f, 0f); setFriction(friction); setMaxVelocity(maxVelocity); setBoundary(boundary); setBouncingFactor(bouncingFactor); angle = 0; } public void setBouncingFactor(Vector3 bouncingFactor) { this.bouncingFactor.set(bouncingFactor); } public void setMaxVelocity(Vector3 maxVelocity) { this.maxVelocity.set(maxVelocity); } public void setFriction(Vector3 friction) { this.friction.set(friction); } public void setBoundary(Vector3 boundary) { this.boundary.set(boundary); } public Vector3 getPosition() { return position; } public void populateMatrix(Matrix4 m, float scaleFactor) { m.translate(position).scale(scaleFactor, scaleFactor, scaleFactor).rotate(rotationAxis, angle); } public void reflect(boolean rX, boolean rY) { if (rX) { velocity.x = -velocity.x; } if (rY) { velocity.y = -velocity.y; } } public void addVelocity(float incX, float incZ) { float dirX = Math.signum(velocity.x); float dirZ = Math.signum(velocity.z); float dxSign = Math.signum(incX); float dzSign = Math.signum(incZ); // direction change - zero if (Math.abs(dxSign - dirX) == 2) { velocity.x = 0; } velocity.x += incX; // check if MAX X reached if (Math.abs(velocity.x) > maxVelocity.x) { velocity.x = Math.signum(velocity.x) * maxVelocity.x; } // direction change - zero if (Math.abs(dzSign - dirZ) == 2) { velocity.z = 0.0f; } velocity.z += incZ; // check if MAX Z reached if (Math.abs(velocity.z) > maxVelocity.z) { velocity.z = Math.signum(velocity.z) * maxVelocity.z; } changeDirection(); } public void update(float deltaTime) { //update position and rotation position.x += deltaTime * velocity.x; position.z += deltaTime * velocity.z; // angle update - increment depends on intensity of velocity float velInt = velocity.set(velocity).len2(); angle = fixAngle(angle + velInt * deltaTime * 5.0f); // update velocity X float dir = Math.signum(velocity.x); velocity.x -= deltaTime * friction.x * dir; // if sign of velocity is changed then we are on zero if (Math.signum(velocity.x) != dir) { velocity.x = 0.0f; } // update velocity Z dir = Math.signum(velocity.z); velocity.z -= deltaTime * friction.z * dir; // if sign of velocity is changed then we are on zero if (Math.signum(velocity.z) != dir) { velocity.z = 0.0f; } // check if boundaries reched so we change direction boolean changeVelocity = false; float angleFix = 0.0f; // X boundaries if (position.x < -boundary.x){ position.x = -boundary.x; velocity.x = -velocity.x * bouncingFactor.x; changeVelocity = true; angleFix = 180.0f; } if (position.x > boundary.x){ position.x = boundary.x; velocity.x = -velocity.x * bouncingFactor.x; changeVelocity = true; angleFix = -180.0f; } // Z boundaries if (position.z < -boundary.z){ position.z = -boundary.z; velocity.z = -velocity.z * bouncingFactor.z; changeVelocity = true; angleFix = 180.0f; } if (position.z > boundary.z){ position.z = boundary.z; velocity.z = -velocity.z * bouncingFactor.z; changeVelocity = true; angleFix = -180.0f; } // change direction if bouncing occured if (changeVelocity) { changeDirection(); angle = fixAngle(angle + angleFix); } } private void changeDirection() { rotationAxis.set(0.0f, 1.0f, 0.0f); rotationAxis.crs(new Vector3(velocity).nor()); } /** * Fix rotation angle so it is inside 0..360 * @param value angle * @return fixed angle */ private float fixAngle(float value){ if (value > 360.0f){ return 360.0f - value; } else if (value < 0){ return value + 360.0f; } return value; } }