epix camera & routing

pull/1/head
Valerie 2022-05-20 00:02:00 -04:00
parent 8e1f91d947
commit 557d0eb569
11 changed files with 188 additions and 91 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -19,7 +19,7 @@ public class App {
// The window handle
private long window;
private int width = 800, height = 450;
private int width = 1024, height = 576;
private Matrix4f matrix = Matrix4f.orthographic(0, width, height, 0, 1, -1);
public static int mouseX, mouseY;
public static boolean mouseLeft, mouseMiddle, mouseRight;

View File

@ -6,37 +6,37 @@ import xyz.valnet.engine.shaders.SimpleShader;
public class Drawing {
private static Texture bound = null;
private static Texture bound = null;
public static void drawSprite(Sprite sprite, int x, int y) {
drawSprite(sprite, x, y, sprite.width, sprite.height);
public static void drawSprite(Sprite sprite, int x, int y) {
drawSprite(sprite, x, y, sprite.width, sprite.height);
}
private static float layer = 0f;
public static void setLayer(float layer) {
Drawing.layer = layer;
}
public static void drawSprite(Sprite sprite, int x, int y, int width, int height) {
// lazy texture binding
if(bound != sprite.atlas) {
if(bound != null) bound.unbind();
sprite.atlas.bind();
}
private static float layer = 0f;
glBegin(GL_QUADS);
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x, sprite.sourceBoxUV.y);
glVertex3f(x, y, layer);
public static void setLayer(float layer) {
Drawing.layer = layer;
}
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x + sprite.sourceBoxUV.z, sprite.sourceBoxUV.y);
glVertex3f(x + width, y, layer);
public static void drawSprite(Sprite sprite, int x, int y, int width, int height) {
// lazy texture binding
if(bound != sprite.atlas) {
if(bound != null) bound.unbind();
sprite.atlas.bind();
}
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x + sprite.sourceBoxUV.z, sprite.sourceBoxUV.y + sprite.sourceBoxUV.w);
glVertex3f(x + width, y + height, layer);
glBegin(GL_QUADS);
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x, sprite.sourceBoxUV.y);
glVertex3f(x, y, layer);
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x + sprite.sourceBoxUV.z, sprite.sourceBoxUV.y);
glVertex3f(x + width, y, layer);
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x + sprite.sourceBoxUV.z, sprite.sourceBoxUV.y + sprite.sourceBoxUV.w);
glVertex3f(x + width, y + height, layer);
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x, sprite.sourceBoxUV.y + sprite.sourceBoxUV.w);
glVertex3f(x, y + height, layer);
glEnd();
}
glVertexAttrib2f(SimpleShader.TEX_COORD, sprite.sourceBoxUV.x, sprite.sourceBoxUV.y + sprite.sourceBoxUV.w);
glVertex3f(x, y + height, layer);
glEnd();
}
}

View File

@ -0,0 +1,17 @@
package xyz.valnet.engine.math;
public class Vector2f {
public float x, y;
public Vector2f() {
x = 0.0f;
y = 0.0f;
}
public Vector2f(float x, float y) {
this.x = x;
this.y = y;
}
}

View File

@ -18,4 +18,6 @@ public class GameObject implements IRenderable, ITickable {
@Override
public void tick(float dTime) {}
public void start() {}
}

View File

@ -39,7 +39,7 @@ public class HadeanGame extends Game {
Assets.font.drawString("FPS: " + Math.round(averageFPS) + "/" + measuredFPS + " | AVG/MEASURED", 1, 1);
Assets.font.drawString("Mouse: <" + App.mouseX + ", " + App.mouseY + ">", 1, 17);
Assets.font.drawString("MEMORY: " + (int)((allocated / (double)max) * 100) + "% (" + (allocated / (1024 * 1024)) + "/" + (max / (1024 * 1024)) + "MB)", 1, 33);
Assets.font.drawString("", 1, 49);
Assets.font.drawString("IPATHABLE", 1, 49);
Assets.font.drawString("", 1, 65);
Assets.font.drawString("", 1, 81);
@ -47,7 +47,7 @@ public class HadeanGame extends Game {
Assets.font.drawString("FPS: " + Math.round(averageFPS) + "/" + measuredFPS + " | AVG/MEASURED", 0, 0);
Assets.font.drawString("Mouse: <" + App.mouseX + ", " + App.mouseY + ">", 0, 16);
Assets.font.drawString("MEMORY: " + (int)((allocated / (double)max) * 100) + "% (" + (allocated / (1024 * 1024)) + "/" + (max / (1024 * 1024)) + "MB)", 0, 32);
Assets.font.drawString("", 0, 48);
Assets.font.drawString("IPATHABLE", 0, 48);
Assets.font.drawString("", 0, 64);
Assets.font.drawString("", 0, 80);

View File

@ -3,28 +3,35 @@ package xyz.valnet.hadean;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.util.Assets;
// TODO make these tiles REAL gameobjects...
public class Tile {
private final int x, y;
private final Vector4f color = new Vector4f((float) Math.random() * 0.1f, 0.4f + (float) Math.random() * 0.15f, (float) Math.random() * 0.05f, 1f);
private final Sprite sprite = Assets.defaultTerrain[(int)Math.floor(Math.random() * Assets.defaultTerrain.length)];
private final boolean obstacle;
private boolean obstacle;
public Tile(int x, int y) {
float distanceFromOrigin = 0.9f - (float)Math.sqrt(x * x + y * y) / 42;
this.x = x;
this.y = y;
this.obstacle = Math.random() > 0.8f;
this.obstacle = false;
// this.obstacle = Math.random() > 0.8f;
}
public void render() {
public void render(Camera camera) {
Assets.flat.pushColor(isWalkable() ? color : new Vector4f(0.1f, 0.1f, 0.1f, 1f));
Drawing.drawSprite(sprite, Terrain.left + x * Terrain.TILE_SIZE, Terrain.top + y * Terrain.TILE_SIZE);
camera.draw(sprite, x, y);
// Drawing.drawSprite(sprite, Terrain.left + x * Terrain.TILE_SIZE, Terrain.top + y * Terrain.TILE_SIZE);
Assets.flat.popColor();
}
public void wall() {
obstacle = true;
}
public boolean isWalkable() {
return !obstacle;
}

View File

@ -0,0 +1,35 @@
package xyz.valnet.hadean.gameobjects;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.scenes.GameScene;
public class Camera extends GameObject {
private int tileWidth = 24;
// TODO link these in some way to the real resolution.
private int screenWidth = 1024, screenHeight = 576;
private Vector2f focus = new Vector2f(0, 0);
public Camera(GameScene scene) {
super(scene);
}
public void focus(float x, float y) {
this.focus.x = x;
this.focus.y = y;
}
public Vector2f world2screen(float x, float y) {
return new Vector2f(x * tileWidth + screenWidth / 2 - focus.x * tileWidth, y * tileWidth + screenHeight / 2 - focus.y * tileWidth);
}
public void draw(Sprite sprite, float x, float y) {
Vector2f screenPos = world2screen(x, y);
Drawing.drawSprite(sprite, (int)(screenPos.x), (int)(screenPos.y), tileWidth, tileWidth);
}
}

View File

@ -1,69 +1,71 @@
package xyz.valnet.hadean.gameobjects;
import static org.lwjgl.opengl.GL11.GL_LINES;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glVertex2f;
import static xyz.valnet.engine.util.Math.lerp;
import java.util.Stack;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.Tile;
import xyz.valnet.hadean.pathfinding.Node;
import xyz.valnet.hadean.scenes.GameScene;
import xyz.valnet.hadean.util.Assets;
import static org.lwjgl.opengl.GL20.*;
// import org.lwjgl.opengl.GL20;
public class Pawn extends GameObject {
private float x, y;
private float x = 0.5f, y = 0.5f;
private float dx, dy;
private float counter = 0;
private Stack<Node> path;
private final float speed = 20f;
private final float speed = 50f;
private Camera camera;
private Terrain terrain;
public Pawn(GameScene scene) {
super(scene);
}
@Override
public void start() {
camera = get(Camera.class);
terrain = get(Terrain.class);
}
@Override
public void render() {
Drawing.setLayer(0.15f);
Drawing.setLayer(0.5f);
if(path != null && path.size() > 0) {
float cx = (int)(Terrain.left + (x - 0.5f) * Terrain.TILE_SIZE);
float cy = (int)(Terrain.top + (y - 0.5f) * Terrain.TILE_SIZE);
Node n = path.peek();
float nx = Terrain.left + n.x * Terrain.TILE_SIZE;
float ny = Terrain.top + n.y * Terrain.TILE_SIZE;
System.out.println("" + n.x + " " + n.y);
Drawing.drawSprite(Assets.pawn, (int)lerp(cx, nx, counter / speed), (int)lerp(cy, ny, counter / speed));
Node next = path.peek();
float t = counter / speed;
camera.draw(Assets.pawn, lerp(x - 0.5f, next.x, t), lerp(y - 0.5f, next.y, t));
if(path != null) {
for(Node node : path) {
glBegin(GL_LINES);
if(node.from == null) {
glVertex2f(Terrain.left + x * Terrain.TILE_SIZE, Terrain.top + y * Terrain.TILE_SIZE);
} else {
glVertex2f(Terrain.left + (node.from.x + 0.5f) * Terrain.TILE_SIZE, Terrain.top + (node.from.y + 0.5f) * Terrain.TILE_SIZE);
}
glVertex2f(Terrain.left + (node.x + 0.5f) * Terrain.TILE_SIZE, Terrain.top + (node.y + 0.5f) * Terrain.TILE_SIZE);
Vector2f u, v;
if(node.from == null) u = camera.world2screen(x, y);
else u = camera.world2screen(node.from.x + 0.5f, node.from.y + 0.5f);
v = camera.world2screen(node.x + 0.5f, node.y + 0.5f);
glVertex2f(u.x, u.y);
glVertex2f(v.x, v.y);
glEnd();
}
}
} else {
int nx = (int)(Terrain.left + (x - 0.5f) * Terrain.TILE_SIZE);
int ny = (int)(Terrain.top + (y - 0.5f) * Terrain.TILE_SIZE);
Drawing.drawSprite(Assets.pawn, nx, ny);
camera.draw(Assets.pawn, x - 0.5f, y - 0.5f);
}
// Drawing.setLayer(0.1f);
@ -78,34 +80,53 @@ public class Pawn extends GameObject {
@Override
public void tick(float dTime) {
counter ++;
if(counter >= speed) action();
if(path != null && !path.empty()) move();
else newPath();
}
private void newPath() {
// set new destination
dx = 0.5f + (float)Math.floor(Math.random() * Terrain.WORLD_SIZE);
dy = 0.5f + (float)Math.floor(Math.random() * Terrain.WORLD_SIZE);
// and route there.
route();
}
private void action() {
if(path == null || path.empty()) {
dx = 0.5f + (float)Math.floor(Math.random() * Terrain.WORLD_SIZE);
dy = 0.5f + (float)Math.floor(Math.random() * Terrain.WORLD_SIZE);
private void route() {
// intify all the coordinates
int ix = (int)Math.floor(x);
int iy = (int)Math.floor(y);
int ix = (int)Math.floor(x);
int iy = (int)Math.floor(y);
int idx = (int)Math.floor(dx);
int idy = (int)Math.floor(dy);
int idx = (int)Math.floor(dx);
int idy = (int)Math.floor(dy);
// try to make a new path.
path = get(Terrain.class).getPath(ix, iy, idx, idy);
}
path = get(Terrain.class).getPath(ix, iy, idx, idy);
if(path != null) {
counter = 0;
private void move() {
// check if we CAN move.
Node nextNode = path.peek();
Tile nextTile = terrain.getTile(nextNode.x, nextNode.y);
if(!nextTile.isWalkable()) {
if(counter > 0) counter --;
if(counter < 0) counter = 0;
if(counter == 0) {
route();
}
} else {
Node n = path.pop();
x = n.x + 0.5f;
y = n.y + 0.5f;
counter = 0;
return;
}
counter ++;
if(counter < speed) return;
path.pop();
x = nextNode.x + 0.5f;
y = nextNode.y + 0.5f;
counter = 0;
nextTile.wall();
}
}

View File

@ -2,34 +2,40 @@ package xyz.valnet.hadean.gameobjects;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IScene;
import xyz.valnet.hadean.Tile;
import xyz.valnet.hadean.pathfinding.Node;
import xyz.valnet.hadean.scenes.GameScene;
// implements IPathable, the thing that has callbacks for interfacing with a pathfinder.
// TODO SPLIT PATHABLES. | implements IPathable, the thing that has callbacks for interfacing with a pathfinder.
public class Terrain extends GameObject {
public static final int WORLD_SIZE = 40;
public static final int WORLD_SIZE = 24;
public static final int TILE_SIZE = 8;
public static int left, top;
// public static int left, top;
private Tile[][] tiles = new Tile[WORLD_SIZE][WORLD_SIZE];
private Camera camera;
public Terrain(GameScene scene) {
super(scene);
}
public void start() {
for (int i = 0; i < WORLD_SIZE; i++) {
for (int j = 0; j < WORLD_SIZE; j++) {
tiles[i][j] = new Tile(i, j);
}
}
camera = get(Camera.class);
camera.focus(WORLD_SIZE / 2, WORLD_SIZE / 2);
}
public Tile getTile(int x, int y) {
@ -44,8 +50,8 @@ public class Terrain extends GameObject {
}
private Node getPathfindingNode(int x, int y, List<Node> open, List<Node> closed, Node parent, int dstX, int dstY) {
// TODO this isnt necessarily the BOUNDS so... think about that.
if(x < 0 || y < 0 || x >= WORLD_SIZE || y >= WORLD_SIZE) {
// * out of bounds
return null;
}
@ -126,6 +132,8 @@ public class Terrain extends GameObject {
n = n.from;
}
path.pop();
return path;
}
@ -164,13 +172,13 @@ public class Terrain extends GameObject {
@Override
public void render() {
left = 400 - (WORLD_SIZE * TILE_SIZE / 2);
top = 225 - (WORLD_SIZE * TILE_SIZE / 2);
// left = 400 - (WORLD_SIZE * TILE_SIZE / 2);
// top = 225 - (WORLD_SIZE * TILE_SIZE / 2);
Drawing.setLayer(0f);
for (int i = 0; i < WORLD_SIZE; i++) {
for (int j = 0; j < WORLD_SIZE; j++) {
tiles[i][j].render();
tiles[i][j].render(camera);
}
}
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IScene;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Pawn;
import xyz.valnet.hadean.gameobjects.Terrain;
@ -45,6 +46,12 @@ public class GameScene implements IScene {
for(int i = 0; i < 3; i ++) {
objects.add(new Pawn(this));
}
Camera camera = new Camera(this);
objects.add(camera);
for(GameObject obj : objects) {
obj.start();
}
}
@Override