From 2e7e46514dd35006e9dde07b1959540078292691 Mon Sep 17 00:00:00 2001 From: Svjatoslav Agejenko Date: Tue, 10 Jul 2018 18:40:00 +0300 Subject: [PATCH] Refactoring. --- .../sixth/e3d/geometry/TransformPipe.java | 2 +- .../eu/svjatoslav/sixth/e3d/gui/Avatar.java | 101 ++++++++++-------- .../eu/svjatoslav/sixth/e3d/gui/View.java | 8 +- .../sixth/e3d/gui/ViewUpdateListener.java | 11 +- .../e3d/gui/humaninput/UserInputTracker.java | 2 +- .../humaninput/WorldNavigationTracker.java | 8 +- .../e3d/renderer/raster/RenderAggregator.java | 15 +-- .../e3d/renderer/raster/ShapeCollection.java | 2 +- 8 files changed, 76 insertions(+), 73 deletions(-) diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/geometry/TransformPipe.java b/src/main/java/eu/svjatoslav/sixth/e3d/geometry/TransformPipe.java index 0bf86a2..7df7991 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/geometry/TransformPipe.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/geometry/TransformPipe.java @@ -11,7 +11,7 @@ package eu.svjatoslav.sixth.e3d.geometry; public class TransformPipe { - Transform[] transforms = new Transform[100]; + private Transform[] transforms = new Transform[100]; private int transformsCount = 0; diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java index 4234593..6e4c5ec 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/Avatar.java @@ -11,6 +11,9 @@ package eu.svjatoslav.sixth.e3d.gui; import eu.svjatoslav.sixth.e3d.geometry.Point3D; +import static java.lang.Math.cos; +import static java.lang.Math.sin; + public class Avatar implements ViewUpdateListener { public static final double SPEED_LIMIT = 30; @@ -23,7 +26,7 @@ public class Avatar implements ViewUpdateListener { * are updated within the world, avatar orientation relative to the world is * taken into account. */ - private final Point3D movementDirection = new Point3D(); + private final Point3D movementVector = new Point3D(); public double avatarAcceleration = 0.1; /** * Avatar location within the 3D world. @@ -41,6 +44,11 @@ public class Avatar implements ViewUpdateListener { */ private double orientationYZ; + /** + * Determines amount of friction user experiences every millisecond while moving around in space. + */ + private static final double MILLISECOND_FRICTION = 1.005; + public Avatar() { } @@ -62,27 +70,27 @@ public class Avatar implements ViewUpdateListener { } @Override - public boolean beforeViewUpdate(final ViewContext viewContext, - final int millisecondsSinceLastFrame) { + public boolean beforeViewUpdate(final ViewContext viewContext, final int millisecondsSinceLastFrame) { final Point3D locationBeforeUpdate = new Point3D(location); - updateLocation(millisecondsSinceLastFrame); - - final double distanceMoved = location - .getDistanceTo(locationBeforeUpdate); + translateAvatarLocation(millisecondsSinceLastFrame); + applyFrictionToUserMovement(millisecondsSinceLastFrame); + return isFrameRepaintNeeded(locationBeforeUpdate); + } + private boolean isFrameRepaintNeeded(Point3D locationBeforeUpdate) { + final double distanceMoved = location.getDistanceTo(locationBeforeUpdate); return distanceMoved > 0.03; - } public void enforceSpeedLimit() { - final double currentSpeed = movementDirection + final double currentSpeed = movementVector .getDistanceTo(Point3D.ZERO); if (currentSpeed <= SPEED_LIMIT) return; - movementDirection.scaleDown(currentSpeed / SPEED_LIMIT); + movementVector.scaleDown(currentSpeed / SPEED_LIMIT); } public double getAngleXZ() { @@ -109,49 +117,48 @@ public class Avatar implements ViewUpdateListener { this.location = location; } - public Point3D getMovementDirection() { - return movementDirection; + public Point3D getMovementVector() { + return movementVector; } public double getMovementSpeed() { - return movementDirection.getDistanceTo(Point3D.ZERO); + return movementVector.getDistanceTo(Point3D.ZERO); + } + + private void applyFrictionToUserMovement(int millisecondsPassedSinceLastFrame) { + for (int i = 0; i < millisecondsPassedSinceLastFrame; i++) + applyMillisecondFrictionToUserMovementVector(); + } + + private void applyMillisecondFrictionToUserMovementVector() { + getMovementVector().x /= MILLISECOND_FRICTION; + getMovementVector().y /= MILLISECOND_FRICTION; + getMovementVector().z /= MILLISECOND_FRICTION; } /** - * Update camera location based on current speed + * Translate coordinates based on avatar movement vector and avatar orientation in the world. + * + * @param millisecondsPassedSinceLastFrame We want avatar movement to be independent of framerate. + * Therefore we take frame rendering time into account when translating + * avatar between consecutive frames. */ - public void updateLocation(final int millisecondsPassedSinceLastFrame) { - - // translate user coordinates based on avatar movement speed, and avatar - // orientation in the world - { - location.x -= (float) Math.sin(getAngleXZ()) - * getMovementDirection().z * SPEED_MULTIPLIER - * millisecondsPassedSinceLastFrame; - location.z += (float) Math.cos(getAngleXZ()) - * getMovementDirection().z * SPEED_MULTIPLIER - * millisecondsPassedSinceLastFrame; - - location.x += (float) Math.cos(getAngleXZ()) - * getMovementDirection().x * SPEED_MULTIPLIER - * millisecondsPassedSinceLastFrame; - location.z += (float) Math.sin(getAngleXZ()) - * getMovementDirection().x * SPEED_MULTIPLIER - * millisecondsPassedSinceLastFrame; - - location.y += getMovementDirection().y * SPEED_MULTIPLIER - * millisecondsPassedSinceLastFrame; - } - - final double millisecondFriction = 1.005; - // apply friction to progressively slow movement - for (int i = 0; i < millisecondsPassedSinceLastFrame; i++) { - getMovementDirection().x = getMovementDirection().x - / millisecondFriction; - getMovementDirection().y = getMovementDirection().y - / millisecondFriction; - getMovementDirection().z = getMovementDirection().z - / millisecondFriction; - } + private void translateAvatarLocation(int millisecondsPassedSinceLastFrame) { + location.x -= (float) sin(getAngleXZ()) + * getMovementVector().z * SPEED_MULTIPLIER + * millisecondsPassedSinceLastFrame; + location.z += (float) cos(getAngleXZ()) + * getMovementVector().z * SPEED_MULTIPLIER + * millisecondsPassedSinceLastFrame; + + location.x += (float) cos(getAngleXZ()) + * getMovementVector().x * SPEED_MULTIPLIER + * millisecondsPassedSinceLastFrame; + location.z += (float) sin(getAngleXZ()) + * getMovementVector().x * SPEED_MULTIPLIER + * millisecondsPassedSinceLastFrame; + + location.y += getMovementVector().y * SPEED_MULTIPLIER + * millisecondsPassedSinceLastFrame; } } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/View.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/View.java index bd60473..6f1b474 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/View.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/View.java @@ -235,12 +235,12 @@ public class View extends JPanel implements ComponentListener { lastUpdateMillis = currentTime; // notify update listeners - boolean rerenderView = false; + boolean reRenderFrame = false; for (final ViewUpdateListener listener : viewUpdateListeners) if (listener.beforeViewUpdate(context, millisecondsPassedSinceLastUpdate)) - rerenderView = true; + reRenderFrame = true; // abort rendering if window size is invalid if ((getWidth() <= 0) || (getHeight() <= 0)) @@ -248,10 +248,10 @@ public class View extends JPanel implements ComponentListener { if (repaintDuringNextViewUpdate) { repaintDuringNextViewUpdate = false; - rerenderView = true; + reRenderFrame = true; } - if (rerenderView) { + if (reRenderFrame) { renderFrame(); handleDetectedComponentMouseEvents(); } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewUpdateListener.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewUpdateListener.java index 00f1faf..41a51f9 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewUpdateListener.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/ViewUpdateListener.java @@ -12,10 +12,11 @@ package eu.svjatoslav.sixth.e3d.gui; public interface ViewUpdateListener { /** - * @return true if underlying view shall be re-rendered. If at - * least one of the view update listeners returns true, - * view is re-rendered. + * Notifies that it is about time to render next frame. Update listener can determine if frame repaint is actually + * needed from its perspective. Frame will be rendered if at least one listener says yes. + * + * @return true if underlying view shall be re-rendered. If at least one of the view update listeners + * returns true, view is re-rendered. */ - boolean beforeViewUpdate(ViewContext viewContext, - final int millisecondsSinceLastFrame); + boolean beforeViewUpdate(ViewContext viewContext, final int millisecondsSinceLastFrame); } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java index 8e02ddf..dedfd78 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/UserInputTracker.java @@ -229,7 +229,7 @@ public class UserInputTracker // track mouse wheel movements final double actualAcceleration = 50 * avatar.avatarAcceleration * (1 + (avatar.getMovementSpeed() / 10)); - avatar.getMovementDirection().y += (wheelMovedDirection * actualAcceleration); + avatar.getMovementVector().y += (wheelMovedDirection * actualAcceleration); avatar.enforceSpeedLimit(); // check if view shall be repainted diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java index 62f5586..59066a8 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/gui/humaninput/WorldNavigationTracker.java @@ -56,16 +56,16 @@ public class WorldNavigationTracker implements UserInputHandler { * (1 + (avatar.getMovementSpeed() / 10)); if (inputTracker.isKeyPressed(KeyboardHelper.UP)) - avatar.getMovementDirection().z += actualAcceleration; + avatar.getMovementVector().z += actualAcceleration; if (inputTracker.isKeyPressed(KeyboardHelper.DOWN)) - avatar.getMovementDirection().z -= actualAcceleration; + avatar.getMovementVector().z -= actualAcceleration; if (inputTracker.isKeyPressed(KeyboardHelper.RIGHT)) - avatar.getMovementDirection().x += actualAcceleration; + avatar.getMovementVector().x += actualAcceleration; if (inputTracker.isKeyPressed(KeyboardHelper.LEFT)) - avatar.getMovementDirection().x -= actualAcceleration; + avatar.getMovementVector().x -= actualAcceleration; avatar.enforceSpeedLimit(); } diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/RenderAggregator.java b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/RenderAggregator.java index 049938c..3384351 100644 --- a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/RenderAggregator.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/RenderAggregator.java @@ -14,21 +14,16 @@ import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.AbstractCoordinateShape; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; public class RenderAggregator { - ArrayList shapes = new ArrayList<>(); - ShapesComparator comparator = new ShapesComparator(); + private ArrayList shapes = new ArrayList<>(); + private ShapesZIndexComparator comparator = new ShapesZIndexComparator(); public void paint(final RenderingContext renderBuffer) { - - Collections.sort(shapes, comparator); - - for (final AbstractCoordinateShape shape : shapes) - shape.paint(renderBuffer); - + shapes.sort(comparator); + shapes.forEach(shape -> shape.paint(renderBuffer)); } public void queueShapeForRendering(final AbstractCoordinateShape shape) { @@ -39,7 +34,7 @@ public class RenderAggregator { shapes.clear(); } - static class ShapesComparator implements Comparator, Serializable { + static class ShapesZIndexComparator implements Comparator, Serializable { @Override public int compare(final AbstractCoordinateShape o1, final AbstractCoordinateShape o2) { diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/ShapeCollection.java b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/ShapeCollection.java index cbab6f4..b453f74 100755 --- a/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/ShapeCollection.java +++ b/src/main/java/eu/svjatoslav/sixth/e3d/renderer/raster/ShapeCollection.java @@ -47,7 +47,7 @@ public class ShapeCollection { aggregator.reset(); transformPipe.clear(); - // translate scene according to avatar current location + // translate scene according to camera current location final Avatar avatar = viewContext.getAvatar(); // rotate scene according to avatar looking direction -- 2.20.1