diff --git a/core/src/com/group/golf/Ball.java b/core/src/com/group/golf/Ball.java index a925e22..b70f98a 100644 --- a/core/src/com/group/golf/Ball.java +++ b/core/src/com/group/golf/Ball.java @@ -1,23 +1,28 @@ package com.group.golf; import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.math.Circle; +import com.group.golf.Physics.Queue; import com.group.golf.math.MathLib; import com.group.golf.screens.CourseScreen; + /** * A class to save the data of the ball */ -public class Ball { +public class Ball extends Queue{ public static final float RADIUS = 10; + private double mass; private double x; private double y; private double velocityX; private double velocityY; + private double accelerationX; + private double accelerationY; + private Texture texture; private CourseScreen courseScreen; @@ -51,6 +56,17 @@ public Ball(double mass) { this.collisionCircle = new Circle((float) this.x, (float) this.y, RADIUS); } + public double[] dequeue() { + double[] coord = super.dequeue(); + setX(coord[0]); + setY(coord[1]); + return coord; + } + + public void addCoord(double[] coord) { + super.enqueue(coord); + } + /** * Create a new Ball using another one as a template * @param other the template ball @@ -137,8 +153,7 @@ public double calcVelocity() { * Get access to the x-component of the velocity * @return the x-component of the velocity */ - public double getVelocityX() { - return velocityX; + public double getVelocityX() {return velocityX; } /** @@ -186,10 +201,14 @@ public void setMass(double mass) { * @return the x-coordinate for position */ public double getX() { - return x; +// if (super.tail == null) + return x; +// return super.last()[0]; } + + /** * Set a new x-position * @param x the new x-position @@ -204,7 +223,9 @@ public void setX(double x) { * @return the y-coordinate for position */ public double getY() { - return y; +// if (super.tail == null) + return y; +// return super.last()[1]; } /** @@ -226,4 +247,20 @@ public void setPosition(double x, double y) { this.y = y; this.updateCollisionCircle(); } + + public void setAccelerationX(double accelerationX) { + this.accelerationX = accelerationX; + } + + public void setAccelerationY(double accelerationY) { + this.accelerationY = accelerationY; + } + + public double getAccelerationX() { + return accelerationX; + } + + public double getAccelerationY() { + return accelerationY; + } } diff --git a/core/src/com/group/golf/Physics/Collision.java b/core/src/com/group/golf/Physics/Collision.java index 8e0a064..bee22b5 100644 --- a/core/src/com/group/golf/Physics/Collision.java +++ b/core/src/com/group/golf/Physics/Collision.java @@ -18,39 +18,28 @@ public class Collision { private Ball ball; private final Course course; - private double[] offsets; - private double[] scales; - private double lastX; private double lastY; + + /** * Create a new instace of Collision * @param ball the ball to evaluate * @param course the course in which the ball rolls - * @param offsets the offsets of the course - * @param scales the scales of the course */ - public Collision(Ball ball, Course course, double[] offsets, double[] scales) { + public Collision(Ball ball, Course course) { this.ball = ball; this.course = course; - this.offsets = offsets; - this.scales = scales; this.lastX = this.course.getStart()[0]; this.lastX = this.course.getStart()[1]; } - /** - * Create a new instance of Collision from a template - * @param other the template - */ public Collision(Collision other) { - this.ball = other.ball; this.course = other.course; - this.offsets = other.offsets; - this.scales = other.scales; + this.ball = other.ball; this.lastX = other.lastX; - this.lastX = other.lastY; + this.lastY = other.lastY; } /** @@ -66,16 +55,17 @@ public boolean isGoalAchieved() { /** * React when the ball hits a wall + * @param ballX the pixel-x position of the ball + * @param ballY the pixel-y position of the ball */ - public void checkForWalls() { - double[] real = MathLib.toPixel(new double[]{this.ball.getX(), this.ball.getY()}, this.offsets, this.scales); + public void checkForWalls(double ballX, double ballY) { double vx = this.ball.getVelocityX(); double vy = this.ball.getVelocityY(); - if ((real[0] < Ball.RADIUS && vx < 0) || (real[0] > Golf.VIRTUAL_WIDTH - Ball.RADIUS && vx > 0)) { + if ((ballX < Ball.RADIUS && vx < 0) || (ballX > Golf.VIRTUAL_WIDTH - Ball.RADIUS && vx > 0)) { this.ball.setVelocityX(-this.ball.getVelocityX()); } - if ((real[1] < Ball.RADIUS && vy < 0) || (real[1] > Golf.VIRTUAL_HEIGHT - Ball.RADIUS && vy > 0)) { + if ((ballY < Ball.RADIUS && vy < 0) || (ballY > Golf.VIRTUAL_HEIGHT - Ball.RADIUS && vy > 0)) { this.ball.setVelocityY(-this.ball.getVelocityY()); } } @@ -87,8 +77,8 @@ public void checkForWalls() { public boolean ballInWater() { boolean water = false; - double ballX = this.ball.getX(); - double ballY = this.ball.getY(); + double ballX = this.ball.last()[0]; + double ballY = this.ball.last()[1]; Line2D path = new Line2D(this.lastX, this.lastY, ballX, ballY); // Evaluate the line @@ -106,9 +96,15 @@ public boolean ballInWater() { } } - // Make the current position of the ball the last - this.lastX = ballX; - this.lastY = ballY; + + if (water) { + // Make the current position of the ball the last + this.lastX = Physics.hitCoord[0]; + this.lastY = Physics.hitCoord[1]; + } else { + this.lastX = ballX; + this.lastY = ballY; + } return water; } @@ -145,24 +141,4 @@ public Ball getBall() { public void setBall(Ball ball) { this.ball = ball; } - - public Course getCourse() { - return course; - } - - public double[] getOffsets() { - return offsets; - } - - public void setOffsets(double[] offsets) { - this.offsets = offsets; - } - - public double[] getScales() { - return scales; - } - - public void setScales(double[] scales) { - this.scales = scales; - } } diff --git a/core/src/com/group/golf/Physics/Physics.java b/core/src/com/group/golf/Physics/Physics.java index 1796d2b..78273ea 100644 --- a/core/src/com/group/golf/Physics/Physics.java +++ b/core/src/com/group/golf/Physics/Physics.java @@ -1,10 +1,10 @@ package com.group.golf.Physics; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.math.Vector2; import com.group.golf.Ball; import com.group.golf.Course; -import com.group.golf.math.Computable; +import com.group.golf.Golf; +import com.group.golf.math.MathLib; import java.util.ArrayList; @@ -17,7 +17,12 @@ public class Physics { private Course course; private Ball ball; - private double[] hitCoord; + private Collision collision; + private double[] offsets; + private double[] scales; + private boolean water; + + public static double[] hitCoord; /** * Construct a Physics engine @@ -29,83 +34,113 @@ public Physics(Course course, Ball ball) { this.course = course; this.ball = ball; this.hitCoord = new double[2]; + this.collision = new Collision(this.ball, this.course); + } + /** + * Sets the acceleration , velocity and position + * after an h time-step using runge-kutta 4th order + * @param h time step + */ //https://www.haroldserrano.com/blog/visualizing-the-runge-kutta-method - public double[] RK4(double h){ + public void RK4(double h){ + double[][] accel = new double[4][2]; + accel[0] = new double[]{ball.getAccelerationX(),ball.getAccelerationY()}; - double[] grav = gravForce(ball, new double[]{ball.getX(),ball.getY()}); - double[] friction = frictionForce(ball,ball.getVelocityX(),ball.getVelocityY()); + double[][] velo = new double[4][2]; + velo[0] = new double[]{ball.getVelocityX(),ball.getVelocityY()}; + for (int i = 1; i < 4; i++) { + double[] v = updateRKStep(velo[0],accel[i-1],h,i); + velo[i] = v; - double v1x = ball.getVelocityX(); double v1y = ball.getVelocityY(); + double[] p = updateRKStep(ball.last(),v,h,i); - double a1x = grav[0] + friction[0]; double a1y = grav[1] + friction[1]; - double v2x = v1x + a1x * h/2; double v2y = v1y + a1y * h/2; + double[] grav = gravForce(p); + double[] friction = frictionForce(v[0],v[1]); - friction = frictionForce(ball,v2x,v2y); - double a2x = grav[0] + friction[0]; double a2y = grav[1] + friction[1]; - double v3x = v1x + a2x * h/2; double v3y = v1y + a2y * h/2; + accel[i] = new double[]{grav[0] + friction[0], grav[1] + friction[1]}; + } - friction = frictionForce(ball,v3x,v3y); - double a3x = grav[0] + friction[0]; double a3y = grav[1] + friction[1]; - double v4x = v1x + h * a3x; double v4y = v1y + h * a3y; - friction = frictionForce(ball,v4x,v4y); - double a4x = grav[0] + friction[0]; double a4y = grav[1] + friction[1]; + ball.setAccelerationX((accel[0][0] + 2 * accel[1][0] + 2 * accel[2][0] + accel[3][0])/6); + ball.setAccelerationY((accel[0][1] + 2 * accel[1][1] + 2 * accel[2][1] + accel[3][1])/6); + + ball.setVelocityX(velo[0][0] + h * ball.getAccelerationX()); + ball.setVelocityY(velo[0][1] + h * ball.getAccelerationY()); + + ball.limit(this.course.getVmax()); + + + double[] coord = new double[]{ball.last()[0] + h/6 * (velo[0][0] + 2 * velo[1][0] + 2 * velo[2][0] + velo[3][0]), + ball.last()[1] + h/6 * (velo[0][1] + 2 * velo[1][1] + 2 * velo[2][1] + velo[3][1])}; + ball.addCoord(coord); + + double[] ballCoords = MathLib.toPixel(coord,offsets,scales); + this.collision.checkForWalls(ballCoords[0], ballCoords[1]); + + if (this.collision.ballInWater()) { + ball.reset(); + water = true; + } + + + if (Math.abs(this.ball.getVelocityX()) < 0.07 && Math.abs(this.ball.getVelocityY()) < 0.07) { + this.ball.reset(); + } - double[] resV = {v1x + h/6 * (a1x + 2*a2x + 2*a3x + a4x), v1y + h/6 * (a1y + 2*a2y + 2*a3y + a4y)}; - return resV; - } + } + private double[] updateRKStep(double[] startPos, double[] prev, double h, double k) { + if (k < 3) { + return new double[]{startPos[0] + prev[0] * h/2,startPos[1] + prev[1] * h/2}; + } else { + return new double[]{startPos[0] + prev[0] * h, startPos[1] + prev[1] * h}; + } + } /** * Hit the ball - * @param forceX the velocityX done to the ball - * @param forceY the velocityY done to the ball + * @param xLength the length that the mouse was dragged horizontally + * @param yLength the length that the mouse was dragged vertically */ - public void hit(double forceX, double forceY) { + public void hit(double xLength, double yLength) { + water = false; hitCoord[0] = ball.getX(); hitCoord[1] = ball.getY(); - ball.setVelocityX(Gdx.graphics.getDeltaTime() * forceX / ball.getMass()); - ball.setVelocityY(Gdx.graphics.getDeltaTime() * forceY / ball.getMass()); - } + ball.addCoord(hitCoord); - /** - * Update the ball state to the following instance of time - * @param delta delta time - */ - public void movement(float delta, boolean debug) { + double frameRate = 0.04; // - ball.setX(ball.getX() + delta * ball.getVelocityX()); - ball.setY(ball.getY() + delta * ball.getVelocityY()); + xLength *= 90; + yLength *= 90; - double[] vel = RK4(delta); - ball.setVelocityX(vel[0]); - ball.setVelocityY(vel[1]); + ball.setAccelerationX(xLength/ball.getMass()); + ball.setAccelerationY(yLength/ball.getMass()); - if (debug) System.out.println("VelocityX: " + ball.getVelocityX() + " VelocityY: " + ball.getVelocityY()); - if (Math.abs(this.ball.getVelocityX()) < 0.0776 && Math.abs(this.ball.getVelocityY()) < 0.0776) { - this.ball.reset(); + RK4(frameRate); + while (this.ball.isMoving() && !water) { + RK4(frameRate); } } /** * Compute the friction force that oposes to the movement of the ball - * @param ball the ball rolling * @param velocityX the x-component of the velocity of the ball * @param velocityY the y-component of the velocity of the ball * @return a Vector2 instace containig the friction force */ - public double[] frictionForce(Ball ball,double velocityX, double velocityY) { + public double[] frictionForce(double velocityX, double velocityY) { double multiplier = - this.course.getMu() * this.course.getG() / normalLength(velocityX,velocityY); +// System.out.println(multiplier * velocityX); return new double[]{(multiplier * velocityX) ,(multiplier * velocityY)}; } @@ -121,11 +156,10 @@ public double normalLength(double velocityX, double velocityY) { /** * Compute the gravitational force that the ball suffers - * @param ball the ball rolling * @param coord the Vector2 containing the actual position of the ball * @return a Vector2 instance containing the gravity force */ - public double[] gravForce(Ball ball, double[] coord) { + public double[] gravForce(double[] coord) { double multiplier = - this.course.getG(); double[] slopeMultiplier = calculateSlope(coord); return new double[] {multiplier * slopeMultiplier[0],multiplier * slopeMultiplier[1]}; @@ -143,6 +177,7 @@ public double[] calculateSlope(double[] coord) { slope[0] = (this.course.getHeight(coord[0]+step,coord[1]) - this.course.getHeight(coord[0]-step,coord[1]))/(2*step); slope[1] = ((this.course.getHeight(coord[0],coord[1]+step) - this.course.getHeight(coord[0],coord[1]-step))/(2*step)); + return slope; } @@ -193,4 +228,21 @@ public double[] getHitCoord() { public void setHitCoord(double[] hitCoord) { this.hitCoord = hitCoord; } + + + public void setOffsets(double[] offsets) { + this.offsets = offsets; + } + + public void setScales(double[] scales) { + this.scales = scales; + } + + public boolean isWater() { + return water; + } + + public void setWater(boolean water) { + this.water = water; + } } diff --git a/core/src/com/group/golf/Physics/Queue.java b/core/src/com/group/golf/Physics/Queue.java new file mode 100644 index 0000000..6c0f4c4 --- /dev/null +++ b/core/src/com/group/golf/Physics/Queue.java @@ -0,0 +1,52 @@ +package com.group.golf.Physics; + +/** + * Created by alex_ on 23-May-18. + */ + +public class Queue { + protected node head; + protected node tail; + private int size; + + public Queue() { + head = null; + tail = null; + size = 0; + } + + public void enqueue(E element) { + if (head == null) { + head = new node(element); + tail = head; + } else { + node newTail = new node(element); + node temp = tail; + temp.next = newTail; + newTail.prev = temp; + tail = newTail; + } + size++; + } + + public E dequeue() { + E temp = head.element; + head = head.next; + size--; + return temp; + } + + public E last() { + return tail.element; + } + + public void clear() { + head = null; + tail = null; + size = 0; + } + + public int getSize() { + return size; + } +} diff --git a/core/src/com/group/golf/Physics/node.java b/core/src/com/group/golf/Physics/node.java new file mode 100644 index 0000000..7db5cb4 --- /dev/null +++ b/core/src/com/group/golf/Physics/node.java @@ -0,0 +1,15 @@ +package com.group.golf.Physics; + +/** + * Created by alex_ on 23-May-18. + */ +public class node { + E element; + node next; + node prev; + + public node(E element) { + this.element = element; + next = null; + } +} diff --git a/core/src/com/group/golf/ai/GeneticBot.java b/core/src/com/group/golf/ai/GeneticBot.java index 15b1447..73a4a32 100644 --- a/core/src/com/group/golf/ai/GeneticBot.java +++ b/core/src/com/group/golf/ai/GeneticBot.java @@ -81,7 +81,6 @@ public void setPhysics(Physics physics) { public void setCollision(Collision collision) { this.collision = collision; this.virtualCollision = new Collision(collision); - this.virtualCollision.setBall(this.virtualBall); this.startEvolution(); } @@ -224,7 +223,7 @@ public void fillLandings(JVector2[] forces, JVector2[] landings) { this.virtualBall.reset(); this.virtualBall.setPosition(landings[0].getX(), landings[0].getY()); for (int i = 1; i < landings.length; i++) { - this.simulateShot(forces[i-1], landings[i-1]); + this.simulateShot(forces[i-1]); landings[i] = new JVector2(this.virtualBall.getX(), this.virtualBall.getY()); } } @@ -232,15 +231,14 @@ public void fillLandings(JVector2[] forces, JVector2[] landings) { /** * Simulate a shot */ - private void simulateShot(JVector2 force, JVector2 last) { + private void simulateShot(JVector2 force) { this.virtualEngine.hit(force.getX(), force.getY()); - while (this.virtualBall.isMoving()) { - this.virtualCollision.checkForWalls(); - this.virtualEngine.movement(Gdx.graphics.getDeltaTime(), false); - this.virtualBall.limit(this.course.getVmax()); - if (this.virtualCollision.ballInWater()) { - this.virtualBall.reset(); - this.virtualBall.setPosition(last.getX(), last.getY()); + while (this.virtualBall.getSize() != 0) { + this.virtualBall.dequeue(); + if (this.virtualEngine.isWater() && this.virtualBall.getSize() == 0) { + this.virtualBall.clear(); + this.virtualBall.setX(this.engine.getHitCoord()[0]); + this.virtualBall.setY(this.engine.getHitCoord()[1]); } } } diff --git a/core/src/com/group/golf/ai/botMartijn.java b/core/src/com/group/golf/ai/botMartijn.java index cd98b52..e9a8580 100644 --- a/core/src/com/group/golf/ai/botMartijn.java +++ b/core/src/com/group/golf/ai/botMartijn.java @@ -140,27 +140,17 @@ private double[] Point3Dto2D(Point3D point){ return p; } - private void simulateShot(JVector2 force, JVector2 last) { - this.virtualEngine.hit(force.getX(),force.getY()); - while (this.virtualBall.isMoving()) { - this.virtualEngine.movement(Gdx.graphics.getDeltaTime(), false); - this.virtualBall.limit(this.course.getVmax()); - this.virtualCollision.checkForWalls(); - if (this.virtualCollision.ballInWater()) { - this.virtualBall.reset(); - this.virtualBall.setPosition(last.getX(), last.getY()); - } - } - } - private void simulateShot(JVector2 force) { - this.virtualEngine.hit(force.getX(),force.getY()); - while (this.virtualBall.isMoving()) { - this.virtualEngine.movement(Gdx.graphics.getDeltaTime(), false); - this.virtualBall.limit(this.course.getVmax()); - this.virtualCollision.checkForWalls(); + this.virtualEngine.hit(force.getX(), force.getY()); + while (this.virtualBall.getSize() != 0) { + this.virtualBall.dequeue(); + if (this.virtualEngine.isWater() && this.virtualBall.getSize() == 0) { + this.virtualBall.clear(); + this.virtualBall.setX(this.engine.getHitCoord()[0]); + this.virtualBall.setY(this.engine.getHitCoord()[1]); + } + } } - } diff --git a/core/src/com/group/golf/listeners/RandomBotListener.java b/core/src/com/group/golf/listeners/RandomBotListener.java deleted file mode 100644 index e69de29..0000000 diff --git a/core/src/com/group/golf/screens/CourseScreen.java b/core/src/com/group/golf/screens/CourseScreen.java index 2500e44..7bb4787 100644 --- a/core/src/com/group/golf/screens/CourseScreen.java +++ b/core/src/com/group/golf/screens/CourseScreen.java @@ -49,30 +49,27 @@ public class CourseScreen implements Screen { private List moves; private int counter; - // Ball stuff - double[] lastStop; - // Graphing things private int goalSize; - private double scaleX; - private double scaleY; - private static final double SCALE_MULTIPLIER = 100; - private double xoffset; - private double yoffset; private double[][] heights; private double maximum; private double minimum; private Color[][] colors; - private double ballX; - private double ballY; // Gaming stuff - boolean touchFlag; + private boolean touchFlag; private int firstX; private int firstY; private int lastX; private int lastY; + private double scaleX; + private double scaleY; + private double xoffset; + private double yoffset; + private double ballX; + private double ballY; + // Bot private Bot bot; private boolean landed = true; @@ -158,9 +155,6 @@ public CourseScreen(final Golf game, Course course, Ball ball, Bot bot) { */ private void setupCommon() { - // Setup lastStop - this.lastStop = MathLib.copyDoubleArr(this.course.getStart()); - // Setup sounds this.hitSound = Gdx.audio.newSound(Gdx.files.internal("golf_hit_1.wav")); this.loseSound = Gdx.audio.newSound(Gdx.files.internal("defeat_2.wav")); @@ -175,27 +169,27 @@ private void setupCommon() { this.music.setVolume(0.2f); this.music.setLooping(true); + // Setup engine and collision system + this.engine = new Physics(this.course, this.ball); + this.collision = new Collision(this.ball, this.course); + // Setup Course this.setUpCourse(); + this.engine.setOffsets(new double[]{this.xoffset,this.yoffset}); + this.engine.setScales(new double[]{this.scaleX,this.scaleY}); + + // Setup Goal this.goalSize = 20; this.flag = new Texture(Gdx.files.internal("golf_flag.png")); // Setup engine and collision system this.engine = new Physics(this.course, this.ball); - this.collision = new Collision(this.ball, this.course, new double[]{this.xoffset, this.yoffset}, - new double[]{this.scaleX, this.scaleY}); - } + this.collision = new Collision(this.ball, this.course); + this.engine.setOffsets(new double[]{this.xoffset, this.yoffset}); + this.engine.setScales(new double[]{this.scaleX, this.scaleY}); - /** - * Compute the pixel coordinates of the ball - */ - private void computeBallPixels() { - double[] ballPixels = MathLib.toPixel(new double[]{this.ball.getX(), this.ball.getY()}, - new double[]{this.xoffset, this.yoffset}, new double[]{this.scaleX, this.scaleY}); - this.ballX = ballPixels[0]; - this.ballY = ballPixels[1]; } /** @@ -215,33 +209,6 @@ private void setUpCourse() { this.calcColorsMatrix(); } - /** - * Compute the scale - */ - private void calcScale() { - double dist = this.course.getDistance(); - double limitDist = 0.40625; - this.scaleX = 0.000625; - while (dist > limitDist) { - this.scaleX *= 2; - limitDist *= 2; - } - this.scaleY = scaleX; - } - - /** - * Compute the screen offsets - */ - private void calcOffsets() { - double x1 = this.course.getStart()[0]; - double x2 = this.course.getGoal()[0]; - double xUnits = Golf.VIRTUAL_WIDTH / (1/this.scaleX); - this.xoffset = (x1 + x2 - xUnits) / 2.0; - double y1 = this.course.getStart()[1]; - double y2 = this.course.getGoal()[1]; - double yUnits = Golf.VIRTUAL_HEIGHT / (1/this.scaleY); - this.yoffset = (y1 + y2 - yUnits) / 2.0; - } /** * Compute the heights matrix @@ -252,8 +219,8 @@ private void calcHeightsMatrix() { this.minimum = Double.MAX_VALUE; for (int x = 0; x < this.heights.length; x++) { for (int y = 0; y < this.heights[x].length; y++) { - double value = this.course.getHeight(this.xoffset + x*this.scaleX, - this.yoffset + y*this.scaleY); + double value = this.course.getHeight(this.getXoffset() + x*this.getScaleX(), + this.getYoffset() + y*this.getScaleY()); if (value > this.maximum) this.maximum = value; else if (value < this.minimum) this.minimum = value; this.heights[x][y] = value; @@ -295,8 +262,8 @@ private void splineSetup() { // Setup Offsets BicubicInterpolator botLeftInterp = (BicubicInterpolator) this.course.getFunctions()[0][0]; Point3D[][] points = botLeftInterp.getPoints(); - this.xoffset = points[0][0].getX(); - this.yoffset = points[0][0].getY(); + this.setXoffset(points[0][0].getX()); + this.setYoffset(points[0][0].getY()); // Setup scales int xLength = this.course.getFunctions().length; @@ -306,13 +273,13 @@ private void splineSetup() { BicubicInterpolator botRightInterp = (BicubicInterpolator) this.course.getFunctions()[xLength - 1][0]; Point3D[][] botRightPoints = botRightInterp.getPoints(); double rightX = botRightPoints[1][0].getX(); - this.scaleX = (rightX - this.xoffset) / Golf.VIRTUAL_WIDTH; + this.setScaleX((rightX - this.getXoffset()) / Golf.VIRTUAL_WIDTH); // scaleY BicubicInterpolator topLeftInterp = (BicubicInterpolator) this.course.getFunctions()[0][yLength - 1]; Point3D[][] topLeftPoints = topLeftInterp.getPoints(); double topY = botRightPoints[0][1].getY(); - this.scaleY = (topY - this.yoffset) / Golf.VIRTUAL_HEIGHT; + this.setScaleY((topY - this.getYoffset()) / Golf.VIRTUAL_HEIGHT); } @Override @@ -336,16 +303,13 @@ public void render(float delta) { // Render the goal this.renderGoal(); - // Check the walls - this.collision.checkForWalls(); + // Update pixel position of ball + this.computeBallPixels(); + + // Check if the ball is stopped - if (!this.ball.isMoving()) { - // Print position of the ball - if (landed) { - System.out.println("Ball landed at: " + this.ball.getX() + " " + this.ball.getY()); - this.landed = false; - } + if (this.ball.getSize() == 0) { // Check if the goal is achieved if (this.collision.isGoalAchieved()) { this.winSound.play(); @@ -356,9 +320,8 @@ public void render(float delta) { return; } - // Store position - this.lastStop[0] = this.ball.getX(); - this.lastStop[1] = this.ball.getY(); + + // Make a move if (this.bot != null && Gdx.input.isKeyPressed(Input.Keys.SPACE)) { @@ -375,14 +338,17 @@ else if (this.moves != null && this.counter < this.moves.size() && this.userMoves(); } } else { - this.engine.movement(delta, false); + + this.ball.dequeue(); } - this.ball.limit(this.course.getVmax()); + + this.computeBallPixels(); // Check for water - if (this.collision.ballInWater()) { - this.ball.reset(); - this.ball.setPosition(this.lastStop[0], this.lastStop[1]); + if (this.engine.isWater() && this.ball.getSize() == 0) { + this.ball.clear(); + this.ball.setX(this.engine.getHitCoord()[0]); + this.ball.setY(this.engine.getHitCoord()[1]); this.loseSound.play(0.2f); } @@ -427,27 +393,20 @@ else if (this.touchFlag) { Vector3 secondV = new Vector3(this.lastX, this.lastY,0); this.cam.unproject(secondV); - System.out.println("firstX=" + this.firstX + ", firstY=" + this.firstY); - System.out.println("lastX=" + this.lastX + ", lastY=" + this.lastY); - double forceX = Math.abs(lastX - firstX) * 20; - double forceY = Math.abs(lastY - firstY) * 20; + double xLength = Math.abs(lastX - firstX); + double yLength = Math.abs(lastY - firstY); if (lastX < firstX ) - forceX *= -1; + xLength *= -1; if (lastY > firstY) - forceY *= -1; + yLength *= -1; double modulus = Math.sqrt(Math.pow((lastX - firstX), 2) + Math.pow((lastY - firstY), 2)); // we don't need this !! double force = MathLib.map(modulus, 0, 300, 0, 600); - // Use the scales to normalize forces - forceX *= this.scaleX * SCALE_MULTIPLIER; - forceY *= this.scaleY * SCALE_MULTIPLIER; - - this.engine.hit(forceX, forceY); - this.landed = true; + this.engine.hit(xLength, yLength); this.hitSound.play(); } @@ -455,13 +414,52 @@ else if (this.touchFlag) { } } + + /** + * Compute the pixel coordinates of the ball + */ + public void computeBallPixels() { + double[] ballPixels = MathLib.toPixel(new double[]{this.ball.getX(), this.ball.getY()}, + new double[]{this.xoffset, this.yoffset}, new double[]{this.scaleX, this.scaleY}); + this.ballX = ballPixels[0]; + this.ballY = ballPixels[1]; + } + + /** + * Compute the scale + */ + public void calcScale() { + double dist = this.course.getDistance(); + double limitDist = 0.40625; + this.scaleX = 0.000625; + while (dist > limitDist) { + this.scaleX *= 2; + limitDist *= 2; + } + this.scaleY = scaleX; + } + + /** + * Compute the screen offsets + */ + public void calcOffsets() { + double x1 = this.course.getStart()[0]; + double x2 = this.course.getGoal()[0]; + double xUnits = Golf.VIRTUAL_WIDTH / (1/this.scaleX); + this.xoffset = (x1 + x2 - xUnits) / 2.0; + double y1 = this.course.getStart()[1]; + double y2 = this.course.getGoal()[1]; + double yUnits = Golf.VIRTUAL_HEIGHT / (1/this.scaleY); + this.yoffset = (y1 + y2 - yUnits) / 2.0; + } + /** * Render the goal */ private void renderGoal() { this.game.shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); - double[] real = MathLib.toPixel(this.course.getGoal(), new double[]{this.xoffset, this.yoffset}, - new double[]{this.scaleX, this.scaleY}); + double[] real = MathLib.toPixel(this.course.getGoal(), new double[]{this.getXoffset(), this.getYoffset()}, + new double[]{this.getScaleX(), this.getScaleY()}); float realX = (float) real[0]; float realY = (float) real[1]; this.game.shapeRenderer.setColor(0, 0, 0, 1); @@ -470,8 +468,8 @@ private void renderGoal() { this.game.shapeRenderer.end(); this.game.shapeRenderer.begin(ShapeRenderer.ShapeType.Line); double tolerance = this.course.getTolerance(); - float toleranceX = (float) (tolerance * 1/(this.scaleX)); - float toleranceY = (float) (tolerance * 1/(this.scaleY)); + float toleranceX = (float) (tolerance * 1/(this.getScaleX())); + float toleranceY = (float) (tolerance * 1/(this.getScaleY())); this.game.shapeRenderer.setColor(1, 0, 0, 1); this.game.shapeRenderer.ellipse(realX - toleranceX, realY - toleranceY, toleranceX*2, toleranceY*2); @@ -576,6 +574,43 @@ public void setGoalSize(int goalSize) { this.goalSize = goalSize; } + + public double[][] getHeights() { + return heights; + } + + public void setHeights(double[][] heights) { + this.heights = heights; + } + + public double getMaximum() { + return maximum; + } + + public void setMaximum(double maximum) { + this.maximum = maximum; + } + + public double getMinimum() { + return minimum; + } + + public void setMinimum(double minimum) { + this.minimum = minimum; + } + + public Color[][] getColors() { + return colors; + } + + public void setColors(Color[][] colors) { + this.colors = colors; + } + + public Physics getEngine() { + return engine; + } + public double getScaleX() { return scaleX; } @@ -608,35 +643,19 @@ public void setYoffset(double yoffset) { this.yoffset = yoffset; } - public double[][] getHeights() { - return heights; + public double getBallX() { + return ballX; } - public void setHeights(double[][] heights) { - this.heights = heights; + public void setBallX(double ballX) { + this.ballX = ballX; } - public double getMaximum() { - return maximum; - } - - public void setMaximum(double maximum) { - this.maximum = maximum; + public double getBallY() { + return ballY; } - public double getMinimum() { - return minimum; - } - - public void setMinimum(double minimum) { - this.minimum = minimum; - } - - public Color[][] getColors() { - return colors; - } - - public void setColors(Color[][] colors) { - this.colors = colors; + public void setBallY(double ballY) { + this.ballY = ballY; } }