Added gravity and refactored player controls
- Added gravity (still testing) - Two modes: realistic (9.8 m/s^2) and Minecraft (32 m/s^2) - Switch with G - Changing (0; 0; 0) rebound to H - Added walking controls - Minecraft-style - WIP - LayerTestGUI now displays dev options - Added Units
This commit is contained in:
parent
9c894215f8
commit
154cc0a3b8
@ -3,10 +3,10 @@ package ru.windcorp.progressia.client;
|
|||||||
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
||||||
import ru.windcorp.progressia.client.graphics.GUI;
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
import ru.windcorp.progressia.client.graphics.flat.LayerTestUI;
|
import ru.windcorp.progressia.client.graphics.flat.LayerTestUI;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.LayerTestGUI;
|
|
||||||
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
||||||
import ru.windcorp.progressia.common.world.WorldData;
|
import ru.windcorp.progressia.common.world.WorldData;
|
||||||
import ru.windcorp.progressia.server.ServerState;
|
import ru.windcorp.progressia.server.ServerState;
|
||||||
|
import ru.windcorp.progressia.test.LayerTestGUI;
|
||||||
|
|
||||||
public class ClientState {
|
public class ClientState {
|
||||||
|
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Progressia
|
|
||||||
* Copyright (C) 2020 Wind Corporation
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*******************************************************************************/
|
|
||||||
package ru.windcorp.progressia.client.graphics.gui;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import glm.vec._2.i.Vec2i;
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
import ru.windcorp.progressia.client.graphics.Colors;
|
|
||||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
|
||||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
|
||||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
|
||||||
import ru.windcorp.progressia.client.localization.Localizer;
|
|
||||||
import ru.windcorp.progressia.client.localization.MutableString;
|
|
||||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
|
||||||
|
|
||||||
public class LayerTestGUI extends GUILayer {
|
|
||||||
|
|
||||||
private static class DebugComponent extends Component {
|
|
||||||
private final int color;
|
|
||||||
|
|
||||||
public DebugComponent(String name, Vec2i size, int color) {
|
|
||||||
super(name);
|
|
||||||
this.color = color;
|
|
||||||
|
|
||||||
setPreferredSize(size);
|
|
||||||
|
|
||||||
addListener(new Object() {
|
|
||||||
@Subscribe
|
|
||||||
public void onHoverChanged(HoverEvent e) {
|
|
||||||
requestReassembly();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
addListener(KeyEvent.class, this::onClicked);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean onClicked(KeyEvent event) {
|
|
||||||
if (!event.isMouse()) {
|
|
||||||
return false;
|
|
||||||
} else if (event.isPress() && event.isLeftMouseButton()) {
|
|
||||||
System.out.println("You pressed a Component!");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void assembleSelf(RenderTarget target) {
|
|
||||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.BLACK);
|
|
||||||
|
|
||||||
target.fill(
|
|
||||||
getX() + 2, getY() + 2,
|
|
||||||
getWidth() - 4, getHeight() - 4,
|
|
||||||
isHovered() ? Colors.DEBUG_YELLOW : color
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LayerTestGUI() {
|
|
||||||
super("LayerTestGui", new LayoutAlign(1, 0.75, 5));
|
|
||||||
|
|
||||||
Panel panel = new Panel("Alex", new LayoutVertical(5));
|
|
||||||
|
|
||||||
panel.addChild(new DebugComponent("Bravo", new Vec2i(200, 100), 0x44FF44));
|
|
||||||
|
|
||||||
Component charlie = new DebugComponent("Charlie", null, 0x222222);
|
|
||||||
charlie.setLayout(new LayoutVertical(5));
|
|
||||||
|
|
||||||
//Debug
|
|
||||||
Localizer.getInstance().setLanguage("ru-RU");
|
|
||||||
MutableString epsilon = new MutableStringLocalized("Epsilon")
|
|
||||||
.addListener(() -> ((Label)charlie.getChild(0)).update()).format(34, "thirty-four");
|
|
||||||
// These two are swapped in code due to a bug in layouts, fixing ATM
|
|
||||||
charlie.addChild(
|
|
||||||
new Label(
|
|
||||||
"Delta",
|
|
||||||
new Font().withColor(0xCCBB44).deriveShadow().deriveBold(),
|
|
||||||
"Пре-альфа!"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
charlie.addChild(
|
|
||||||
new Label(
|
|
||||||
"Epsilon",
|
|
||||||
new Font().withColor(0x4444BB).deriveItalic(),
|
|
||||||
() -> epsilon.get().concat("\u269b")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
panel.addChild(charlie);
|
|
||||||
|
|
||||||
|
|
||||||
charlie.addListener(KeyEvent.class, e -> {
|
|
||||||
if(e.isPress() && e.getKey() == GLFW.GLFW_KEY_L) {
|
|
||||||
Localizer localizer = Localizer.getInstance();
|
|
||||||
if (localizer.getLanguage().equals("ru-RU")) {
|
|
||||||
localizer.setLanguage("en-US");
|
|
||||||
} else {
|
|
||||||
localizer.setLanguage("ru-RU");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} return false;
|
|
||||||
});
|
|
||||||
charlie.setFocusable(true);
|
|
||||||
charlie.takeFocus();
|
|
||||||
|
|
||||||
getRoot().addChild(panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -272,6 +272,10 @@ public class Camera {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCurrentModeIndex() {
|
||||||
|
return currentModeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public float getLastAnchorYaw() {
|
public float getLastAnchorYaw() {
|
||||||
return lastAnchorYaw;
|
return lastAnchorYaw;
|
||||||
}
|
}
|
||||||
|
@ -20,41 +20,27 @@ package ru.windcorp.progressia.client.graphics.world;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
import glm.Glm;
|
|
||||||
import glm.mat._3.Mat3;
|
|
||||||
import glm.vec._2.Vec2;
|
|
||||||
import glm.vec._3.Vec3;
|
|
||||||
import ru.windcorp.progressia.client.Client;
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.ClientState;
|
||||||
import ru.windcorp.progressia.client.comms.controls.InputBasedControls;
|
import ru.windcorp.progressia.client.comms.controls.InputBasedControls;
|
||||||
import ru.windcorp.progressia.client.graphics.Layer;
|
import ru.windcorp.progressia.client.graphics.Layer;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
|
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
||||||
|
import ru.windcorp.progressia.common.Units;
|
||||||
import ru.windcorp.progressia.common.collision.Collideable;
|
import ru.windcorp.progressia.common.collision.Collideable;
|
||||||
import ru.windcorp.progressia.common.collision.colliders.Collider;
|
import ru.windcorp.progressia.common.collision.colliders.Collider;
|
||||||
import ru.windcorp.progressia.common.util.FloatMathUtils;
|
|
||||||
import ru.windcorp.progressia.common.util.Vectors;
|
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
import ru.windcorp.progressia.test.CollisionModelRenderer;
|
import ru.windcorp.progressia.test.CollisionModelRenderer;
|
||||||
|
import ru.windcorp.progressia.test.TestPlayerControls;
|
||||||
|
|
||||||
public class LayerWorld extends Layer {
|
public class LayerWorld extends Layer {
|
||||||
|
|
||||||
private final Mat3 angMat = new Mat3();
|
|
||||||
|
|
||||||
private int movementForward = 0;
|
|
||||||
private int movementRight = 0;
|
|
||||||
private int movementUp = 0;
|
|
||||||
|
|
||||||
private final WorldRenderHelper helper = new WorldRenderHelper();
|
private final WorldRenderHelper helper = new WorldRenderHelper();
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final InputBasedControls inputBasedControls;
|
private final InputBasedControls inputBasedControls;
|
||||||
|
private final TestPlayerControls tmp_testControls = TestPlayerControls.getInstance();
|
||||||
|
|
||||||
public LayerWorld(Client client) {
|
public LayerWorld(Client client) {
|
||||||
super("World");
|
super("World");
|
||||||
@ -75,40 +61,12 @@ public class LayerWorld extends Layer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doRender() {
|
protected void doRender() {
|
||||||
if (client.getLocalPlayer() != null) {
|
|
||||||
tmp_handleControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
Camera camera = client.getCamera();
|
Camera camera = client.getCamera();
|
||||||
if (camera.hasAnchor()) {
|
if (camera.hasAnchor()) {
|
||||||
renderWorld();
|
renderWorld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tmp_handleControls() {
|
|
||||||
EntityData player = client.getLocalPlayer();
|
|
||||||
|
|
||||||
angMat.identity().rotateZ(player.getYaw());
|
|
||||||
|
|
||||||
Vec3 movement = Vectors.grab3();
|
|
||||||
|
|
||||||
// Horizontal and vertical max control speed
|
|
||||||
final float movementSpeed = 0.1f * 60.0f;
|
|
||||||
// (0; 1], 1 is instant change, 0 is no control authority
|
|
||||||
final float controlAuthority = 0.1f;
|
|
||||||
|
|
||||||
movement.set(movementForward, -movementRight, 0);
|
|
||||||
if (movementForward != 0 && movementRight != 0) movement.normalize();
|
|
||||||
angMat.mul_(movement); // bug in jglm, .mul() and mul_() are swapped
|
|
||||||
movement.z = movementUp;
|
|
||||||
movement.mul(movementSpeed);
|
|
||||||
movement.sub(player.getVelocity());
|
|
||||||
movement.mul(controlAuthority);
|
|
||||||
player.getVelocity().add(movement);
|
|
||||||
|
|
||||||
Vectors.release(movement);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderWorld() {
|
private void renderWorld() {
|
||||||
client.getCamera().apply(helper);
|
client.getCamera().apply(helper);
|
||||||
FaceCulling.push(true);
|
FaceCulling.push(true);
|
||||||
@ -127,11 +85,16 @@ public class LayerWorld extends Layer {
|
|||||||
private static final boolean RENDER_COLLISION_MODELS = false;
|
private static final boolean RENDER_COLLISION_MODELS = false;
|
||||||
|
|
||||||
private void tmp_doEveryFrame() {
|
private void tmp_doEveryFrame() {
|
||||||
|
float tickLength = (float) GraphicsInterface.getFrameLength();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
tmp_performCollisions();
|
tmp_performCollisions(tickLength);
|
||||||
|
|
||||||
|
tmp_testControls.applyPlayerControls();
|
||||||
|
|
||||||
for (EntityData data : this.client.getWorld().getData().getEntities()) {
|
for (EntityData data : this.client.getWorld().getData().getEntities()) {
|
||||||
tmp_applyFriction(data);
|
tmp_applyFriction(data);
|
||||||
|
tmp_applyGravity(data, tickLength);
|
||||||
tmp_renderCollisionModel(data);
|
tmp_renderCollisionModel(data);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -147,121 +110,47 @@ public class LayerWorld extends Layer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tmp_performCollisions() {
|
private void tmp_performCollisions(float tickLength) {
|
||||||
tmp_collideableList.clear();
|
tmp_collideableList.clear();
|
||||||
tmp_collideableList.addAll(this.client.getWorld().getData().getEntities());
|
tmp_collideableList.addAll(this.client.getWorld().getData().getEntities());
|
||||||
|
|
||||||
Collider.performCollisions(
|
Collider.performCollisions(
|
||||||
tmp_collideableList,
|
tmp_collideableList,
|
||||||
this.client.getWorld().getData(),
|
this.client.getWorld().getData(),
|
||||||
(float) GraphicsInterface.getFrameLength(),
|
tickLength,
|
||||||
tmp_colliderWorkspace
|
tmp_colliderWorkspace
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tmp_applyFriction(EntityData entity) {
|
private void tmp_applyFriction(EntityData entity) {
|
||||||
final float frictionCoeff = 1 - 1e-2f;
|
final float frictionCoeff = 1 - 1e-5f;
|
||||||
entity.getVelocity().mul(frictionCoeff);
|
entity.getVelocity().mul(frictionCoeff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tmp_applyGravity(EntityData entity, float tickLength) {
|
||||||
|
if (ClientState.getInstance().getLocalPlayer() == entity && tmp_testControls.isFlying()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final float gravitationalAcceleration;
|
||||||
|
|
||||||
|
if (tmp_testControls.useMinecraftGravity()) {
|
||||||
|
gravitationalAcceleration = 32f * Units.METERS_PER_SECOND_SQUARED; // plz dont sue me M$
|
||||||
|
} else {
|
||||||
|
gravitationalAcceleration = 9.81f * Units.METERS_PER_SECOND_SQUARED;
|
||||||
|
}
|
||||||
|
entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleInput(Input input) {
|
protected void handleInput(Input input) {
|
||||||
if (input.isConsumed()) return;
|
if (input.isConsumed()) return;
|
||||||
|
|
||||||
InputEvent event = input.getEvent();
|
tmp_testControls.handleInput(input);
|
||||||
|
|
||||||
if (event instanceof KeyEvent) {
|
|
||||||
if (onKeyEvent((KeyEvent) event)) {
|
|
||||||
input.consume();
|
|
||||||
}
|
|
||||||
} else if (event instanceof CursorMoveEvent) {
|
|
||||||
onMouseMoved((CursorMoveEvent) event);
|
|
||||||
input.consume();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!input.isConsumed()) {
|
if (!input.isConsumed()) {
|
||||||
inputBasedControls.handleInput(input);
|
inputBasedControls.handleInput(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean flag = true;
|
|
||||||
|
|
||||||
private boolean onKeyEvent(KeyEvent event) {
|
|
||||||
if (event.isRepeat()) return false;
|
|
||||||
|
|
||||||
int multiplier = event.isPress() ? 1 : -1;
|
|
||||||
|
|
||||||
switch (event.getKey()) {
|
|
||||||
case GLFW.GLFW_KEY_W:
|
|
||||||
movementForward += +1 * multiplier;
|
|
||||||
break;
|
|
||||||
case GLFW.GLFW_KEY_S:
|
|
||||||
movementForward += -1 * multiplier;
|
|
||||||
break;
|
|
||||||
case GLFW.GLFW_KEY_A:
|
|
||||||
movementRight += -1 * multiplier;
|
|
||||||
break;
|
|
||||||
case GLFW.GLFW_KEY_D:
|
|
||||||
movementRight += +1 * multiplier;
|
|
||||||
break;
|
|
||||||
case GLFW.GLFW_KEY_SPACE:
|
|
||||||
movementUp += +1 * multiplier;
|
|
||||||
break;
|
|
||||||
case GLFW.GLFW_KEY_LEFT_SHIFT:
|
|
||||||
movementUp += -1 * multiplier;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GLFW.GLFW_KEY_ESCAPE:
|
|
||||||
if (!event.isPress()) return false;
|
|
||||||
|
|
||||||
if (flag) {
|
|
||||||
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
|
||||||
} else {
|
|
||||||
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
flag = !flag;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GLFW.GLFW_KEY_F5:
|
|
||||||
if (!event.isPress()) return false;
|
|
||||||
|
|
||||||
if (client.getCamera().hasAnchor()) {
|
|
||||||
client.getCamera().selectNextMode();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onMouseMoved(CursorMoveEvent event) {
|
|
||||||
if (!flag) return;
|
|
||||||
|
|
||||||
final float yawScale = -0.002f;
|
|
||||||
final float pitchScale = yawScale;
|
|
||||||
|
|
||||||
EntityData player = client.getLocalPlayer();
|
|
||||||
|
|
||||||
if (player != null) {
|
|
||||||
normalizeAngles(player.getDirection().add(
|
|
||||||
(float) (event.getChangeX() * yawScale),
|
|
||||||
(float) (event.getChangeY() * pitchScale)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void normalizeAngles(Vec2 dir) {
|
|
||||||
// Normalize yaw
|
|
||||||
dir.x = FloatMathUtils.normalizeAngle(dir.x);
|
|
||||||
|
|
||||||
// Clamp pitch
|
|
||||||
dir.y = Glm.clamp(
|
|
||||||
dir.y, -FloatMathUtils.PI_F/2, +FloatMathUtils.PI_F/2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
56
src/main/java/ru/windcorp/progressia/common/Units.java
Normal file
56
src/main/java/ru/windcorp/progressia/common/Units.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package ru.windcorp.progressia.common;
|
||||||
|
|
||||||
|
public class Units {
|
||||||
|
|
||||||
|
// Base units
|
||||||
|
// We're SI.
|
||||||
|
public static final float METERS = 1;
|
||||||
|
public static final float KILOGRAMS = 1;
|
||||||
|
public static final float SECONDS = 1;
|
||||||
|
|
||||||
|
// Length
|
||||||
|
public static final float CENTIMETERS = METERS / 100;
|
||||||
|
public static final float MILLIMETERS = METERS / 1000;
|
||||||
|
public static final float KILOMETERS = METERS * 1000;
|
||||||
|
|
||||||
|
// Surface
|
||||||
|
public static final float SQUARE_CENTIMETERS = CENTIMETERS * CENTIMETERS;
|
||||||
|
public static final float SQUARE_METERS = METERS * METERS;
|
||||||
|
public static final float SQUARE_MILLIMETERS = MILLIMETERS * MILLIMETERS;
|
||||||
|
public static final float SQUARE_KILOMETERS = KILOMETERS * KILOMETERS;
|
||||||
|
|
||||||
|
// Volume
|
||||||
|
public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS;
|
||||||
|
public static final float CUBIC_METERS = METERS * METERS * METERS;
|
||||||
|
public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
|
||||||
|
public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
|
||||||
|
|
||||||
|
// Mass
|
||||||
|
public static final float GRAMS = KILOGRAMS / 1000;
|
||||||
|
public static final float TONNES = KILOGRAMS * 1000;
|
||||||
|
|
||||||
|
// Density
|
||||||
|
public static final float KILOGRAMS_PER_CUBIC_METER = KILOGRAMS / CUBIC_METERS;
|
||||||
|
public static final float GRAMS_PER_CUBIC_CENTIMETER = GRAMS / CUBIC_CENTIMETERS;
|
||||||
|
|
||||||
|
// Time
|
||||||
|
public static final float MILLISECONDS = SECONDS / 1000;
|
||||||
|
public static final float MINUTES = SECONDS * 60;
|
||||||
|
public static final float HOURS = MINUTES * 60;
|
||||||
|
public static final float DAYS = HOURS * 24;
|
||||||
|
|
||||||
|
// Frequency
|
||||||
|
public static final float HERTZ = 1 / SECONDS;
|
||||||
|
public static final float KILOHERTZ = HERTZ * 1000;
|
||||||
|
|
||||||
|
// Velocity
|
||||||
|
public static final float METERS_PER_SECOND = METERS / SECONDS;
|
||||||
|
public static final float KILOMETERS_PER_HOUR = KILOMETERS / HOURS;
|
||||||
|
|
||||||
|
// Acceleration
|
||||||
|
public static final float METERS_PER_SECOND_SQUARED = METERS_PER_SECOND / SECONDS;
|
||||||
|
|
||||||
|
// Force
|
||||||
|
public static final float NEWTONS = METERS_PER_SECOND_SQUARED * KILOGRAMS;
|
||||||
|
|
||||||
|
}
|
155
src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java
Executable file
155
src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java
Executable file
@ -0,0 +1,155 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020 Wind Corporation
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*******************************************************************************/
|
||||||
|
package ru.windcorp.progressia.test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.ClientState;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||||
|
|
||||||
|
public class LayerTestGUI extends GUILayer {
|
||||||
|
|
||||||
|
public LayerTestGUI() {
|
||||||
|
super("LayerTestGui", new LayoutAlign(0, 1, 5));
|
||||||
|
|
||||||
|
Panel panel = new Panel("ControlDisplays", new LayoutVertical(5));
|
||||||
|
|
||||||
|
Collection<Label> labels = new ArrayList<>();
|
||||||
|
|
||||||
|
panel.addChild(new Label(
|
||||||
|
"IsFlyingDisplay", new Font().withColor(0x37A3E6).deriveShadow(),
|
||||||
|
() -> String.format("Flying: %5s (Space bar x2)", TestPlayerControls.getInstance().isFlying())
|
||||||
|
));
|
||||||
|
|
||||||
|
panel.addChild(new Label(
|
||||||
|
"IsMouseCapturedDisplay", new Font().withColor(0x37A3E6).deriveShadow(),
|
||||||
|
() -> String.format("Mouse captured: %5s (esc)", TestPlayerControls.getInstance().isMouseCaptured())
|
||||||
|
));
|
||||||
|
|
||||||
|
panel.addChild(new Label(
|
||||||
|
"CameraModeDisplay", new Font().withColor(0x37A3E6).deriveShadow(),
|
||||||
|
() -> String.format("Camera mode: %5d (F5)", ClientState.getInstance().getCamera().getCurrentModeIndex())
|
||||||
|
));
|
||||||
|
|
||||||
|
panel.addChild(new Label(
|
||||||
|
"GravityModeDisplay", new Font().withColor(0x37A3E6).deriveShadow(),
|
||||||
|
() -> String.format("Gravity: %9s (G)", TestPlayerControls.getInstance().useMinecraftGravity() ? "Minecraft" : "Realistic")
|
||||||
|
));
|
||||||
|
|
||||||
|
panel.getChildren().forEach(c -> labels.add((Label) c));
|
||||||
|
TestPlayerControls.getInstance().setUpdateCallback(() -> labels.forEach(Label::update));
|
||||||
|
|
||||||
|
getRoot().addChild(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private static class DebugComponent extends Component {
|
||||||
|
// private final int color;
|
||||||
|
//
|
||||||
|
// public DebugComponent(String name, Vec2i size, int color) {
|
||||||
|
// super(name);
|
||||||
|
// this.color = color;
|
||||||
|
//
|
||||||
|
// setPreferredSize(size);
|
||||||
|
//
|
||||||
|
// addListener(new Object() {
|
||||||
|
// @Subscribe
|
||||||
|
// public void onHoverChanged(HoverEvent e) {
|
||||||
|
// requestReassembly();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// addListener(KeyEvent.class, this::onClicked);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private boolean onClicked(KeyEvent event) {
|
||||||
|
// if (!event.isMouse()) {
|
||||||
|
// return false;
|
||||||
|
// } else if (event.isPress() && event.isLeftMouseButton()) {
|
||||||
|
// System.out.println("You pressed a Component!");
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// protected void assembleSelf(RenderTarget target) {
|
||||||
|
// target.fill(getX(), getY(), getWidth(), getHeight(), Colors.BLACK);
|
||||||
|
//
|
||||||
|
// target.fill(
|
||||||
|
// getX() + 2, getY() + 2,
|
||||||
|
// getWidth() - 4, getHeight() - 4,
|
||||||
|
// isHovered() ? Colors.DEBUG_YELLOW : color
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public LayerTestGUI() {
|
||||||
|
// super("LayerTestGui", new LayoutAlign(1, 0.75, 5));
|
||||||
|
//
|
||||||
|
// Panel panel = new Panel("Alex", new LayoutVertical(5));
|
||||||
|
//
|
||||||
|
// panel.addChild(new DebugComponent("Bravo", new Vec2i(200, 100), 0x44FF44));
|
||||||
|
//
|
||||||
|
// Component charlie = new DebugComponent("Charlie", null, 0x222222);
|
||||||
|
// charlie.setLayout(new LayoutVertical(5));
|
||||||
|
//
|
||||||
|
// //Debug
|
||||||
|
// Localizer.getInstance().setLanguage("ru-RU");
|
||||||
|
// MutableString epsilon = new MutableStringLocalized("Epsilon")
|
||||||
|
// .addListener(() -> ((Label)charlie.getChild(0)).update()).format(34, "thirty-four");
|
||||||
|
// // These two are swapped in code due to a bug in layouts, fixing ATM
|
||||||
|
// charlie.addChild(
|
||||||
|
// new Label(
|
||||||
|
// "Delta",
|
||||||
|
// new Font().withColor(0xCCBB44).deriveShadow().deriveBold(),
|
||||||
|
// "Пре-альфа!"
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// charlie.addChild(
|
||||||
|
// new Label(
|
||||||
|
// "Epsilon",
|
||||||
|
// new Font().withColor(0x4444BB).deriveItalic(),
|
||||||
|
// () -> epsilon.get().concat("\u269b")
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
// panel.addChild(charlie);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// charlie.addListener(KeyEvent.class, e -> {
|
||||||
|
// if(e.isPress() && e.getKey() == GLFW.GLFW_KEY_L) {
|
||||||
|
// Localizer localizer = Localizer.getInstance();
|
||||||
|
// if (localizer.getLanguage().equals("ru-RU")) {
|
||||||
|
// localizer.setLanguage("en-US");
|
||||||
|
// } else {
|
||||||
|
// localizer.setLanguage("ru-RU");
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// } return false;
|
||||||
|
// });
|
||||||
|
// charlie.setFocusable(true);
|
||||||
|
// charlie.takeFocus();
|
||||||
|
//
|
||||||
|
// getRoot().addChild(panel);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
@ -98,7 +98,7 @@ public class TestContent {
|
|||||||
|
|
||||||
private static void regsiterControls() {
|
private static void regsiterControls() {
|
||||||
ControlDataRegistry.getInstance().register(new ControlData("Test", "Switch000"));
|
ControlDataRegistry.getInstance().register(new ControlData("Test", "Switch000"));
|
||||||
ControlTriggerRegistry.getInstance().register(new ControlTriggerOnKeyPress("Test", "Switch000", new KeyMatcher(GLFW.GLFW_KEY_G, new int[0], 0)::matches));
|
ControlTriggerRegistry.getInstance().register(new ControlTriggerOnKeyPress("Test", "Switch000", new KeyMatcher(GLFW.GLFW_KEY_H, new int[0], 0)::matches));
|
||||||
ControlLogicRegistry.getInstance().register(new ControlLogic("Test", "Switch000") {
|
ControlLogicRegistry.getInstance().register(new ControlLogic("Test", "Switch000") {
|
||||||
@Override
|
@Override
|
||||||
public void apply(Server server, PacketControl packet, Client client) {
|
public void apply(Server server, PacketControl packet, Client client) {
|
||||||
|
@ -0,0 +1,270 @@
|
|||||||
|
package ru.windcorp.progressia.test;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import glm.Glm;
|
||||||
|
import glm.mat._3.Mat3;
|
||||||
|
import glm.vec._2.Vec2;
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import ru.windcorp.progressia.client.ClientState;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
||||||
|
import ru.windcorp.progressia.common.Units;
|
||||||
|
import ru.windcorp.progressia.common.util.FloatMathUtils;
|
||||||
|
import ru.windcorp.progressia.common.util.Matrices;
|
||||||
|
import ru.windcorp.progressia.common.util.Vectors;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
|
|
||||||
|
public class TestPlayerControls {
|
||||||
|
|
||||||
|
private static final TestPlayerControls INSTANCE = new TestPlayerControls();
|
||||||
|
|
||||||
|
public static TestPlayerControls getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestPlayerControls() {}
|
||||||
|
|
||||||
|
private static final double MODE_SWITCH_MAX_DELAY = 100 * Units.MILLISECONDS;
|
||||||
|
private static final double MIN_JUMP_DELAY = 200 * Units.MILLISECONDS;
|
||||||
|
|
||||||
|
// Horizontal and vertical max control speed when flying
|
||||||
|
private static final float FLYING_SPEED = 6.0f * Units.METERS_PER_SECOND;
|
||||||
|
|
||||||
|
// (0; 1], 1 is instant change, 0 is no control authority
|
||||||
|
private static final float FLYING_CONTROL_AUTHORITY = 0.05f;
|
||||||
|
|
||||||
|
// Horizontal and vertical max control speed when walking
|
||||||
|
private static final float WALKING_SPEED = 5.0f * Units.METERS_PER_SECOND;
|
||||||
|
|
||||||
|
// (0; 1], 1 is instant change, 0 is no control authority
|
||||||
|
private static final float WALKING_CONTROL_AUTHORITY = 0.1f;
|
||||||
|
|
||||||
|
// Vertical velocity instantly add to player when they jump
|
||||||
|
private static final float JUMP_VELOCITY = 5f * Units.METERS_PER_SECOND;
|
||||||
|
|
||||||
|
private boolean isFlying = true;
|
||||||
|
|
||||||
|
private int movementForward = 0;
|
||||||
|
private int movementRight = 0;
|
||||||
|
private int movementUp = 0;
|
||||||
|
|
||||||
|
private double lastSpacePress = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
private boolean captureMouse = true;
|
||||||
|
private boolean useMinecraftGravity = false;
|
||||||
|
|
||||||
|
private Runnable updateCallback = null;
|
||||||
|
|
||||||
|
public void applyPlayerControls() {
|
||||||
|
if (ClientState.getInstance() == null || ClientState.getInstance().getLocalPlayer() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityData player = getPlayer();
|
||||||
|
Mat3 angMat = Matrices.grab3();
|
||||||
|
|
||||||
|
angMat.identity().rotateZ(player.getYaw());
|
||||||
|
|
||||||
|
Vec3 movement = Vectors.grab3();
|
||||||
|
|
||||||
|
movement.set(movementForward, -movementRight, 0);
|
||||||
|
|
||||||
|
if (movementForward != 0 && movementRight != 0) {
|
||||||
|
movement.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
angMat.mul_(movement); // bug in jglm, .mul() and mul_() are swapped
|
||||||
|
|
||||||
|
if (isFlying) {
|
||||||
|
movement.z = movementUp;
|
||||||
|
movement.mul(FLYING_SPEED);
|
||||||
|
movement.sub(player.getVelocity());
|
||||||
|
movement.mul(FLYING_CONTROL_AUTHORITY);
|
||||||
|
} else {
|
||||||
|
movement.mul(WALKING_SPEED);
|
||||||
|
movement.sub(player.getVelocity());
|
||||||
|
movement.mul(WALKING_CONTROL_AUTHORITY);
|
||||||
|
movement.z = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.getVelocity().add(movement);
|
||||||
|
|
||||||
|
Matrices.release(angMat);
|
||||||
|
Vectors.release(movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleInput(Input input) {
|
||||||
|
if (ClientState.getInstance() == null || ClientState.getInstance().getLocalPlayer() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputEvent event = input.getEvent();
|
||||||
|
|
||||||
|
if (event instanceof KeyEvent) {
|
||||||
|
if (onKeyEvent((KeyEvent) event)) {
|
||||||
|
input.consume();
|
||||||
|
}
|
||||||
|
} else if (event instanceof CursorMoveEvent) {
|
||||||
|
onMouseMoved((CursorMoveEvent) event);
|
||||||
|
input.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onKeyEvent(KeyEvent event) {
|
||||||
|
if (event.isRepeat()) return false;
|
||||||
|
|
||||||
|
int multiplier = event.isPress() ? 1 : -1;
|
||||||
|
|
||||||
|
switch (event.getKey()) {
|
||||||
|
case GLFW.GLFW_KEY_W:
|
||||||
|
movementForward += +1 * multiplier;
|
||||||
|
break;
|
||||||
|
case GLFW.GLFW_KEY_S:
|
||||||
|
movementForward += -1 * multiplier;
|
||||||
|
break;
|
||||||
|
case GLFW.GLFW_KEY_A:
|
||||||
|
movementRight += -1 * multiplier;
|
||||||
|
break;
|
||||||
|
case GLFW.GLFW_KEY_D:
|
||||||
|
movementRight += +1 * multiplier;
|
||||||
|
break;
|
||||||
|
case GLFW.GLFW_KEY_SPACE:
|
||||||
|
handleSpace(multiplier);
|
||||||
|
break;
|
||||||
|
case GLFW.GLFW_KEY_LEFT_SHIFT:
|
||||||
|
handleShift(multiplier);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW.GLFW_KEY_ESCAPE:
|
||||||
|
if (!event.isPress()) return false;
|
||||||
|
handleEscape();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW.GLFW_KEY_F5:
|
||||||
|
if (!event.isPress()) return false;
|
||||||
|
handleCameraMode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLFW.GLFW_KEY_G:
|
||||||
|
if (!event.isPress()) return false;
|
||||||
|
handleGravitySwitch();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSpace(int multiplier) {
|
||||||
|
boolean isPressed = multiplier > 0;
|
||||||
|
|
||||||
|
double timeSinceLastSpacePress = GraphicsInterface.getTime() - lastSpacePress;
|
||||||
|
|
||||||
|
if (isPressed && timeSinceLastSpacePress < MODE_SWITCH_MAX_DELAY) {
|
||||||
|
isFlying = !isFlying;
|
||||||
|
updateGUI();
|
||||||
|
movementUp = +1;
|
||||||
|
} else {
|
||||||
|
if (isFlying) {
|
||||||
|
movementUp += +1 * multiplier;
|
||||||
|
} else {
|
||||||
|
if (isPressed && timeSinceLastSpacePress > MIN_JUMP_DELAY) {
|
||||||
|
jump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSpacePress = GraphicsInterface.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void jump() {
|
||||||
|
getPlayer().getVelocity().add(0, 0, JUMP_VELOCITY * (useMinecraftGravity ? 2 : 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleShift(int multiplier) {
|
||||||
|
if (isFlying) {
|
||||||
|
movementUp += -1 * multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleEscape() {
|
||||||
|
if (captureMouse) {
|
||||||
|
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_NORMAL);
|
||||||
|
} else {
|
||||||
|
GLFW.glfwSetInputMode(GraphicsBackend.getWindowHandle(), GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
captureMouse = !captureMouse;
|
||||||
|
updateGUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCameraMode() {
|
||||||
|
if (ClientState.getInstance().getCamera().hasAnchor()) {
|
||||||
|
ClientState.getInstance().getCamera().selectNextMode();
|
||||||
|
updateGUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleGravitySwitch() {
|
||||||
|
useMinecraftGravity = !useMinecraftGravity;
|
||||||
|
updateGUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMouseMoved(CursorMoveEvent event) {
|
||||||
|
if (!captureMouse) return;
|
||||||
|
|
||||||
|
final float yawScale = -0.002f;
|
||||||
|
final float pitchScale = yawScale;
|
||||||
|
|
||||||
|
EntityData player = getPlayer();
|
||||||
|
|
||||||
|
normalizeAngles(player.getDirection().add(
|
||||||
|
(float) (event.getChangeX() * yawScale),
|
||||||
|
(float) (event.getChangeY() * pitchScale)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalizeAngles(Vec2 dir) {
|
||||||
|
// Normalize yaw
|
||||||
|
dir.x = FloatMathUtils.normalizeAngle(dir.x);
|
||||||
|
|
||||||
|
// Clamp pitch
|
||||||
|
dir.y = Glm.clamp(
|
||||||
|
dir.y, -FloatMathUtils.PI_F/2, +FloatMathUtils.PI_F/2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityData getPlayer() {
|
||||||
|
return ClientState.getInstance().getLocalPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateCallback(Runnable updateCallback) {
|
||||||
|
this.updateCallback = updateCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateGUI() {
|
||||||
|
if (this.updateCallback != null) {
|
||||||
|
this.updateCallback.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFlying() {
|
||||||
|
return isFlying;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMouseCaptured() {
|
||||||
|
return captureMouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean useMinecraftGravity() {
|
||||||
|
return useMinecraftGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user