2 * Sixth 3D engine. Author: Svjatoslav Agejenko.
3 * This project is released under Creative Commons Zero (CC0) license.
8 package eu.svjatoslav.sixth.e3d.gui;
10 import eu.svjatoslav.sixth.e3d.geometry.Point3D;
12 import static java.lang.Math.cos;
13 import static java.lang.Math.sin;
15 public class Avatar implements ViewRenderListener {
17 public static final double SPEED_LIMIT = 30;
19 * Just in case we want to adjust global speed for some reason.
21 private static final double SPEED_MULTIPLIER = .02d;
23 * Determines amount of friction user experiences every millisecond while moving around in space.
25 private static final double MILLISECOND_FRICTION = 1.005;
27 * Avatar movement speed, relative to avatar itself. When avatar coordinates
28 * are updated within the world, avatar orientation relative to the world is
31 private final Point3D movementVector = new Point3D();
32 public double avatarAcceleration = 0.1;
34 * Avatar location within the 3D world.
36 private Point3D location = new Point3D();
38 * Avatar orientation on the X-Z plane. It changes when turning left or
41 private double orientationXZ;
43 * Avatar orientation on the Y-Z plane. It changes when looking up or down.
45 private double orientationYZ;
50 public Avatar(final Avatar sourceView) {
51 setLocation(new Point3D(sourceView.location));
52 setAngleXZ(sourceView.getAngleXZ());
53 setAngleYZ(sourceView.getAngleYZ());
56 public Avatar(final Point3D location) {
57 setLocation(location);
60 public Avatar(final Point3D location, final float angleXZ,
61 final float angleYZ) {
62 setLocation(location);
68 public boolean beforeRender(final ViewPanel viewPanel, final int millisecondsSinceLastFrame) {
70 final Point3D locationBeforeUpdate = new Point3D(location);
71 translateAvatarLocationBasedOnMovementVector(millisecondsSinceLastFrame);
72 applyFrictionToUserMovement(millisecondsSinceLastFrame);
73 return isFrameRepaintNeeded(locationBeforeUpdate);
76 private boolean isFrameRepaintNeeded(Point3D locationBeforeUpdate) {
77 final double distanceMoved = location.getDistanceTo(locationBeforeUpdate);
78 return distanceMoved > 0.03;
81 public void enforceSpeedLimit() {
82 final double currentSpeed = movementVector.getVectorLength();
84 if (currentSpeed <= SPEED_LIMIT)
87 movementVector.scaleDown(currentSpeed / SPEED_LIMIT);
90 public double getAngleXZ() {
94 public void setAngleXZ(final double angleXZ) {
95 orientationXZ = angleXZ;
98 public double getAngleYZ() {
102 public void setAngleYZ(final double angleYZ) {
103 orientationYZ = angleYZ;
106 public Point3D getLocation() {
110 public void setLocation(final Point3D location) {
111 this.location = location;
114 public Point3D getMovementVector() {
115 return movementVector;
118 public double getMovementSpeed() {
119 return movementVector.getVectorLength();
122 private void applyFrictionToUserMovement(int millisecondsPassedSinceLastFrame) {
123 for (int i = 0; i < millisecondsPassedSinceLastFrame; i++)
124 applyMillisecondFrictionToUserMovementVector();
127 private void applyMillisecondFrictionToUserMovementVector() {
128 getMovementVector().x /= MILLISECOND_FRICTION;
129 getMovementVector().y /= MILLISECOND_FRICTION;
130 getMovementVector().z /= MILLISECOND_FRICTION;
134 * Translate coordinates based on avatar movement vector and avatar orientation in the world.
136 * @param millisecondsPassedSinceLastFrame We want avatar movement to be independent of framerate.
137 * Therefore we take frame rendering time into account when translating
138 * avatar between consecutive frames.
140 private void translateAvatarLocationBasedOnMovementVector(int millisecondsPassedSinceLastFrame) {
141 location.x -= (float) sin(getAngleXZ())
142 * getMovementVector().z * SPEED_MULTIPLIER
143 * millisecondsPassedSinceLastFrame;
144 location.z += (float) cos(getAngleXZ())
145 * getMovementVector().z * SPEED_MULTIPLIER
146 * millisecondsPassedSinceLastFrame;
148 location.x += (float) cos(getAngleXZ())
149 * getMovementVector().x * SPEED_MULTIPLIER
150 * millisecondsPassedSinceLastFrame;
151 location.z += (float) sin(getAngleXZ())
152 * getMovementVector().x * SPEED_MULTIPLIER
153 * millisecondsPassedSinceLastFrame;
155 location.y += getMovementVector().y * SPEED_MULTIPLIER
156 * millisecondsPassedSinceLastFrame;