Entire project
12
.gitignore
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Archive files
|
||||
*.jar
|
||||
*.zip
|
||||
|
||||
# Project files
|
||||
*.classpath
|
||||
*.project
|
||||
|
||||
# Other stuff
|
||||
bin/
|
||||
.settings/
|
||||
*.bat
|
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
Mit License
|
||||
|
||||
Copyright (c) 2018 Gnarly Narwhal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
22
README.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Ludum Dare 39
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
Must have [Java](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) installed
|
||||
* NOTE: I run Java 8 so I cannot guarantee that it will work on earlier version, but I don't believe I've used anything preventing it from running on some older versions. Click [here](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) to download Java 8.
|
||||
|
||||
Graphics driver must have support for OpenGL 3.3 Core or later
|
||||
|
||||
### What's this all about?
|
||||
This project is my game for Ludum Dare 39. If you don't know what [Ludum Dare](https://ldjam.com/about) is and you're into making games then definitely check it out [here](https://ldjam.com/about).
|
||||
|
||||
### So what's the game?
|
||||
Well the game is a game in which you, the player, must control a system of mirrors to direct a laser to the target. You do this by writing programs that control the mirrors and the laser cannons. The game is very short and has some maybe game breaking bugs, but overall its fairly complete.
|
||||
|
||||
### Can I play it?
|
||||
Of course! Here's how:
|
||||
|
||||
Click [here](https://drive.google.com/open?id=0B30vfj3rcantWWxEcHRZZnRWREE) to download the game. Once you've downloaded it just run the jar file.
|
||||
|
||||
Of course you can always download the source and compile it yourself. You are going to need [LWJGL 3](https://www.lwjgl.org/download). Make sure to include JOML under **Addons**
|
BIN
res/img/bars/blcorner.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
res/img/bars/brcorner.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
res/img/bars/corner.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
res/img/bars/leftbar.png
Normal file
After Width: | Height: | Size: 271 B |
BIN
res/img/bars/numbers/0.png
Normal file
After Width: | Height: | Size: 174 B |
BIN
res/img/bars/numbers/1.png
Normal file
After Width: | Height: | Size: 171 B |
BIN
res/img/bars/numbers/10.png
Normal file
After Width: | Height: | Size: 181 B |
BIN
res/img/bars/numbers/11.png
Normal file
After Width: | Height: | Size: 158 B |
BIN
res/img/bars/numbers/12.png
Normal file
After Width: | Height: | Size: 190 B |
BIN
res/img/bars/numbers/2.png
Normal file
After Width: | Height: | Size: 185 B |
BIN
res/img/bars/numbers/3.png
Normal file
After Width: | Height: | Size: 185 B |
BIN
res/img/bars/numbers/4.png
Normal file
After Width: | Height: | Size: 174 B |
BIN
res/img/bars/numbers/5.png
Normal file
After Width: | Height: | Size: 183 B |
BIN
res/img/bars/numbers/6.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
res/img/bars/numbers/7.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
res/img/bars/numbers/8.png
Normal file
After Width: | Height: | Size: 180 B |
BIN
res/img/bars/numbers/9.png
Normal file
After Width: | Height: | Size: 181 B |
BIN
res/img/bars/tlcorner.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
res/img/bars/topbar.png
Normal file
After Width: | Height: | Size: 285 B |
BIN
res/img/bars/trcorner.png
Normal file
After Width: | Height: | Size: 196 B |
BIN
res/img/fonts/default.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/img/header.png
Normal file
After Width: | Height: | Size: 850 B |
BIN
res/img/map/buttons/menu/hovered.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
res/img/map/buttons/menu/pressed.png
Normal file
After Width: | Height: | Size: 349 B |
BIN
res/img/map/buttons/menu/unpressed.png
Normal file
After Width: | Height: | Size: 366 B |
BIN
res/img/map/buttons/run/hovered.png
Normal file
After Width: | Height: | Size: 303 B |
BIN
res/img/map/buttons/run/pressed.png
Normal file
After Width: | Height: | Size: 337 B |
BIN
res/img/map/buttons/run/unpressed.png
Normal file
After Width: | Height: | Size: 307 B |
BIN
res/img/map/buttons/smenu/hovered.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
res/img/map/buttons/smenu/pressed.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
res/img/map/buttons/smenu/unpressed.png
Normal file
After Width: | Height: | Size: 253 B |
BIN
res/img/map/buttons/stop/hovered.png
Normal file
After Width: | Height: | Size: 249 B |
BIN
res/img/map/buttons/stop/pressed.png
Normal file
After Width: | Height: | Size: 250 B |
BIN
res/img/map/buttons/stop/unpressed.png
Normal file
After Width: | Height: | Size: 291 B |
BIN
res/img/map/cannon.png
Normal file
After Width: | Height: | Size: 994 B |
BIN
res/img/map/empty.png
Normal file
After Width: | Height: | Size: 350 B |
BIN
res/img/map/laser/laserBend.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/img/map/laser/laserBendBack.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/img/map/laser/laserStraight.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
res/img/map/laser/laserStraightBack.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
res/img/map/mirror135.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
res/img/map/mirror45.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
res/img/map/track.png
Normal file
After Width: | Height: | Size: 460 B |
BIN
res/img/map/trigger.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
res/img/menu/background.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
res/img/menu/close/hovered.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
res/img/menu/close/pressed.png
Normal file
After Width: | Height: | Size: 228 B |
BIN
res/img/menu/close/unpressed.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
res/img/menu/help/helpMenu.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
res/img/menu/help/hovered.png
Normal file
After Width: | Height: | Size: 683 B |
BIN
res/img/menu/help/pressed.png
Normal file
After Width: | Height: | Size: 681 B |
BIN
res/img/menu/help/unpressed.png
Normal file
After Width: | Height: | Size: 641 B |
BIN
res/img/menu/next/hovered.png
Normal file
After Width: | Height: | Size: 232 B |
BIN
res/img/menu/next/pressed.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
res/img/menu/next/unpressed.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
res/img/menu/play/hovered.png
Normal file
After Width: | Height: | Size: 734 B |
BIN
res/img/menu/play/pressed.png
Normal file
After Width: | Height: | Size: 733 B |
BIN
res/img/menu/play/unpressed.png
Normal file
After Width: | Height: | Size: 686 B |
BIN
res/img/menu/prev/hovered.png
Normal file
After Width: | Height: | Size: 229 B |
BIN
res/img/menu/prev/pressed.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
res/img/menu/prev/unpressed.png
Normal file
After Width: | Height: | Size: 245 B |
13
res/maps/level1.llm
Normal file
|
@ -0,0 +1,13 @@
|
|||
0 0 0 0 0 4 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 3 0 0 0 0 0 0
|
||||
|
||||
1
|
||||
0 8
|
13
res/maps/level2.llm
Normal file
|
@ -0,0 +1,13 @@
|
|||
0 0 0 0 0 0 4 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 1 2 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 3 0 0 0 0 0 0
|
||||
|
||||
1
|
||||
0 10
|
13
res/maps/level3.llm
Normal file
|
@ -0,0 +1,13 @@
|
|||
0 0 0 0 0 0 4 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 1 2 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 3 0 0 0 0 0 0
|
||||
|
||||
1
|
||||
0 9
|
BIN
res/samby.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
res/sambyanim.png
Normal file
After Width: | Height: | Size: 917 B |
13
res/shaders/s2a/frag.fs
Normal file
|
@ -0,0 +1,13 @@
|
|||
#version 330 core
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
in vec2 texCoords;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = texture(sampler, texCoords);
|
||||
if(color.a == 0)
|
||||
discard;
|
||||
}
|
17
res/shaders/s2a/vert.vs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#version 330 core
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 model;
|
||||
|
||||
uniform vec2 animProps; // Loc 0 - Frame Width, Loc 1 - Offset
|
||||
|
||||
layout (location = 0) in vec3 vertices;
|
||||
layout (location = 1) in vec2 iTexCoords;
|
||||
|
||||
out vec2 texCoords;
|
||||
|
||||
void main() {
|
||||
texCoords = vec2(((iTexCoords.x * animProps.x) + animProps.y), iTexCoords.y);
|
||||
gl_Position = projection * view * model * vec4(vertices, 1.0);
|
||||
}
|
9
res/shaders/s2c/frag.fs
Normal file
|
@ -0,0 +1,9 @@
|
|||
#version 330 core
|
||||
|
||||
uniform vec4 iColor;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = iColor;
|
||||
}
|
11
res/shaders/s2c/vert.vs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 330 core
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 model;
|
||||
|
||||
layout (location = 0) in vec3 vertices;
|
||||
|
||||
void main() {
|
||||
gl_Position = projection * view * model * vec4(vertices, 1.0);
|
||||
}
|
13
res/shaders/s2t/frag.fs
Normal file
|
@ -0,0 +1,13 @@
|
|||
#version 330 core
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
in vec2 texCoords;
|
||||
|
||||
layout (location = 0) out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = texture(sampler, texCoords);
|
||||
if(color.a == 0)
|
||||
discard;
|
||||
}
|
15
res/shaders/s2t/vert.vs
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 330 core
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 model;
|
||||
|
||||
layout (location = 0) in vec3 vertices;
|
||||
layout (location = 1) in vec2 iTexCoords;
|
||||
|
||||
out vec2 texCoords;
|
||||
|
||||
void main() {
|
||||
texCoords = iTexCoords;
|
||||
gl_Position = projection * view * model * vec4(vertices, 1.0);
|
||||
}
|
15
res/shaders/s2x/frag.fs
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 330 core
|
||||
|
||||
uniform vec4 iColor;
|
||||
|
||||
uniform sampler2D sampler;
|
||||
|
||||
in vec2 texCoords;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main() {
|
||||
color = iColor * texture(sampler, texCoords);
|
||||
if(color.a == 0)
|
||||
discard;
|
||||
}
|
17
res/shaders/s2x/vert.vs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#version 330 core
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform mat4 view;
|
||||
uniform mat4 model;
|
||||
|
||||
uniform vec2 character;
|
||||
|
||||
layout (location = 0) in vec3 vertices;
|
||||
layout (location = 1) in vec2 iTexCoords;
|
||||
|
||||
out vec2 texCoords;
|
||||
|
||||
void main() {
|
||||
texCoords = iTexCoords + character;
|
||||
gl_Position = projection * view * model * vec4(vertices, 1.0);
|
||||
}
|
65
src/com/gnarly/engine/display/Camera.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package com.gnarly.engine.display;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class Camera {
|
||||
|
||||
private float width, height;
|
||||
private Matrix4f projection;
|
||||
private Vector3f position;
|
||||
private float rotation;
|
||||
|
||||
public Camera(int width, int height) {
|
||||
position = new Vector3f();
|
||||
rotation = 0;
|
||||
projection = new Matrix4f();
|
||||
setDims(width, height);
|
||||
}
|
||||
|
||||
public void setDims(float width, float height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
projection.setOrtho(0, width, height, 0, 1, -1);
|
||||
}
|
||||
|
||||
public void translate(int x, int y) {
|
||||
position.sub(x, y, 0);
|
||||
}
|
||||
|
||||
public void translate(Vector3f vector) {
|
||||
position.sub(vector);
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y) {
|
||||
position.set(x, y, 0);
|
||||
}
|
||||
|
||||
public void setPosition(Vector3f vector) {
|
||||
position.set(vector);
|
||||
}
|
||||
|
||||
public void rotate(float angle) {
|
||||
this.rotation -= angle;
|
||||
}
|
||||
|
||||
public void setRotation(float angle) {
|
||||
this.rotation = angle;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Matrix4f getProjection() {
|
||||
return projection;
|
||||
}
|
||||
|
||||
public Matrix4f getView() {
|
||||
return new Matrix4f().rotateZ(rotation).translate(position);
|
||||
}
|
||||
}
|
65
src/com/gnarly/engine/display/Framebuffer.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package com.gnarly.engine.display;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.opengl.GL30.*;
|
||||
import static org.lwjgl.opengl.GL32.*;
|
||||
|
||||
public class Framebuffer {
|
||||
|
||||
private int fbo;
|
||||
private int texture;
|
||||
private int depth;
|
||||
|
||||
private int width, height;
|
||||
|
||||
public Framebuffer(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
fbo = createFrameBuffer();
|
||||
texture = createTextureAttachment();
|
||||
depth = createDepthBufferAttachment();
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
glDeleteFramebuffers(fbo);
|
||||
glDeleteTextures(texture);
|
||||
glDeleteRenderbuffers(depth);
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
public int getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
private int createFrameBuffer() {
|
||||
int frameBuffer = glGenFramebuffers();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
return frameBuffer;
|
||||
}
|
||||
|
||||
private int createTextureAttachment() {
|
||||
int texture = glGenTextures();
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, (ByteBuffer) null);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private int createDepthBufferAttachment() {
|
||||
int depthBuffer = glGenRenderbuffers();
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
|
||||
return depthBuffer;
|
||||
}
|
||||
}
|
279
src/com/gnarly/engine/display/Window.java
Normal file
|
@ -0,0 +1,279 @@
|
|||
package com.gnarly.engine.display;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_FALSE;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_PRESS;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_RESIZABLE;
|
||||
import static org.lwjgl.glfw.GLFW.GLFW_TRUE;
|
||||
import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetKey;
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetMouseButton;
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetPrimaryMonitor;
|
||||
import static org.lwjgl.glfw.GLFW.glfwGetVideoMode;
|
||||
import static org.lwjgl.glfw.GLFW.glfwInit;
|
||||
import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
|
||||
import static org.lwjgl.glfw.GLFW.glfwPollEvents;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetScrollCallback;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetWindowPos;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSetWindowSizeCallback;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
|
||||
import static org.lwjgl.glfw.GLFW.glfwSwapInterval;
|
||||
import static org.lwjgl.glfw.GLFW.glfwWindowHint;
|
||||
import static org.lwjgl.glfw.GLFW.glfwWindowShouldClose;
|
||||
import static org.lwjgl.opengl.GL.createCapabilities;
|
||||
import static org.lwjgl.opengl.GL11.GL_BLEND;
|
||||
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
|
||||
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
|
||||
import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
|
||||
import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
|
||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
|
||||
import static org.lwjgl.opengl.GL11.glBlendFunc;
|
||||
import static org.lwjgl.opengl.GL11.glClear;
|
||||
import static org.lwjgl.opengl.GL11.glClearColor;
|
||||
import static org.lwjgl.opengl.GL11.glEnable;
|
||||
import static org.lwjgl.opengl.GL11.glViewport;
|
||||
import static org.lwjgl.opengl.GL30.*;
|
||||
import static org.lwjgl.system.MemoryUtil.NULL;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.glfw.GLFWCharCallback;
|
||||
import org.lwjgl.glfw.GLFWCharModsCallback;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWKeyCallback;
|
||||
import org.lwjgl.glfw.GLFWScrollCallback;
|
||||
import org.lwjgl.glfw.GLFWVidMode;
|
||||
import org.lwjgl.glfw.GLFWWindowSizeCallback;
|
||||
|
||||
public class Window {
|
||||
|
||||
public static final byte
|
||||
UNPRESSED = 0,
|
||||
RELEASED = 1,
|
||||
PRESSED = 2,
|
||||
HELD = 3;
|
||||
|
||||
private long window;
|
||||
|
||||
private GLFWVidMode vidMode;
|
||||
|
||||
private int xOff, yOff, vWidth, vHeight;
|
||||
|
||||
private double scrollX, scrollY;
|
||||
|
||||
private StringBuilder input;
|
||||
|
||||
private boolean resized;
|
||||
|
||||
byte[] keys = new byte[GLFW_KEY_LAST];
|
||||
|
||||
public Window(int width, int height, boolean vSync, boolean resizable, String title) {
|
||||
init(width, height, vSync, resizable, title);
|
||||
}
|
||||
|
||||
public Window(boolean vSync) {
|
||||
init(0, 0, vSync, false, null);
|
||||
}
|
||||
|
||||
private void init(int width, int height, boolean vSync, boolean resizable, String title) {
|
||||
glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err));
|
||||
|
||||
if(!glfwInit()) {
|
||||
System.err.println("GLFW failed to initialize!");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE);
|
||||
|
||||
vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
if(width == 0 || height == 0 || width >= vidMode.width() || height >= vidMode.height()) {
|
||||
width = vidMode.width();
|
||||
height = vidMode.height();
|
||||
window = glfwCreateWindow(width, height, "", glfwGetPrimaryMonitor(), NULL);
|
||||
}
|
||||
else {
|
||||
window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
glfwSetWindowPos(window, (vidMode.width() - width) / 2, (vidMode.height() - height) / 2);
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
createCapabilities();
|
||||
|
||||
glfwSwapInterval(vSync ? 1 : 0);
|
||||
|
||||
glfwSetWindowSizeCallback(window, new GLFWWindowSizeCallback() {
|
||||
public void invoke(long window, int width, int height) {
|
||||
resized = true;
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
});
|
||||
|
||||
glfwSetScrollCallback(window, new GLFWScrollCallback() {
|
||||
public void invoke(long window, double x, double y) {
|
||||
scrollX = x;
|
||||
scrollY = y;
|
||||
}
|
||||
});
|
||||
|
||||
input = new StringBuilder();
|
||||
glfwSetCharModsCallback(window, new GLFWCharModsCallback() {
|
||||
public void invoke(long window, int key, int mods) {
|
||||
input.append((char) key);
|
||||
}
|
||||
});
|
||||
glfwSetKeyCallback(window, new GLFWKeyCallback() {
|
||||
public void invoke(long window, int key, int scancode, int action, int mods) {
|
||||
if(action != GLFW_RELEASE) {
|
||||
if(glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) != GLFW_PRESS && glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) != GLFW_PRESS && glfwGetKey(window, GLFW_KEY_LEFT_ALT) != GLFW_PRESS && glfwGetKey(window, GLFW_KEY_RIGHT_ALT) != GLFW_PRESS) {
|
||||
switch (key) {
|
||||
case GLFW_KEY_ENTER:
|
||||
input.append((char) 10);
|
||||
break;
|
||||
case GLFW_KEY_BACKSPACE:
|
||||
input.append((char) 8);
|
||||
break;
|
||||
case GLFW_KEY_DELETE:
|
||||
input.append((char) 127);
|
||||
break;
|
||||
case GLFW_KEY_LEFT:
|
||||
input.append((char) 1);
|
||||
break;
|
||||
case GLFW_KEY_RIGHT:
|
||||
input.append((char) 2);
|
||||
break;
|
||||
case GLFW_KEY_UP:
|
||||
input.append((char) 3);
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
input.append((char) 4);
|
||||
break;
|
||||
case GLFW_KEY_TAB:
|
||||
input.append((char) 9);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(keys[key] < PRESSED)
|
||||
keys[key] = PRESSED;
|
||||
else
|
||||
keys[key] = HELD;
|
||||
}
|
||||
else {
|
||||
if(keys[key] > RELEASED)
|
||||
keys[key] = RELEASED;
|
||||
else
|
||||
keys[key] = UNPRESSED;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
float vWidth = 0, vHeight = 0;
|
||||
while(vWidth < vidMode.width() && vHeight < vidMode.height()) {
|
||||
vWidth += 1;
|
||||
vHeight += 9 /16f;
|
||||
}
|
||||
|
||||
xOff = (int) ((vidMode.width() - vWidth) / 2);
|
||||
yOff = (int) ((vidMode.height() - vHeight) / 2);
|
||||
this.vWidth = (int) vWidth;
|
||||
this.vHeight = (int) vHeight;
|
||||
bind();
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if(keys[i] == PRESSED)
|
||||
++keys[i];
|
||||
else if(keys[i] == RELEASED)
|
||||
--keys[i];
|
||||
}
|
||||
scrollX = 0;
|
||||
scrollY = 0;
|
||||
resized = false;
|
||||
input.delete(0, input.length());
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public void swap() {
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
public void setVSync(boolean vSync) {
|
||||
glfwSwapInterval(vSync ? 1 : 0);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
|
||||
public boolean shouldClose() {
|
||||
return glfwWindowShouldClose(window);
|
||||
}
|
||||
|
||||
public String getInput() {
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
public byte getKey(int keyCode) {
|
||||
return keys[keyCode];
|
||||
}
|
||||
|
||||
public Vector3f getMouseCoords(Camera camera) {
|
||||
double[] x = new double[1], y = new double[1];
|
||||
glfwGetCursorPos(window, x, y);
|
||||
Vector3f ret = new Vector3f((float) x[0] - xOff, (float) y[0] - yOff, 0);
|
||||
ret.mul(camera.getWidth() / vWidth, camera.getHeight() / vHeight, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean mousePressed(int button) {
|
||||
return glfwGetMouseButton(window, button) == GLFW_PRESS;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return vWidth;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return vHeight;
|
||||
}
|
||||
|
||||
public boolean wasResized() {
|
||||
return resized;
|
||||
}
|
||||
|
||||
public float getScrollX() {
|
||||
return (float) scrollX;
|
||||
}
|
||||
|
||||
public float getScrollY() {
|
||||
return (float) scrollY;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(xOff, yOff, vWidth, vHeight);
|
||||
}
|
||||
}
|
68
src/com/gnarly/engine/model/Vao.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
package com.gnarly.engine.model;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_FLOAT;
|
||||
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
|
||||
import static org.lwjgl.opengl.GL11.glDrawElements;
|
||||
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
|
||||
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
|
||||
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
|
||||
import static org.lwjgl.opengl.GL15.glBindBuffer;
|
||||
import static org.lwjgl.opengl.GL15.glBufferData;
|
||||
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
|
||||
import static org.lwjgl.opengl.GL15.glGenBuffers;
|
||||
import static org.lwjgl.opengl.GL20.glDisableVertexAttribArray;
|
||||
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
|
||||
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
|
||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||
import static org.lwjgl.opengl.GL30.glDeleteVertexArrays;
|
||||
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Vao {
|
||||
|
||||
private int numAttribs = 0;
|
||||
|
||||
private int vao, ibo, count;
|
||||
|
||||
private ArrayList<Integer> vbos = new ArrayList<>();
|
||||
|
||||
public Vao(float[] vertices, int[] indices) {
|
||||
vao = glGenVertexArrays();
|
||||
glBindVertexArray(vao);
|
||||
addAttribute(vertices, 3);
|
||||
ibo = glGenBuffers();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
|
||||
count = indices.length;
|
||||
}
|
||||
|
||||
public void addAttribute(float[] data, int size) {
|
||||
int vbo = glGenBuffers();
|
||||
vbos.add(vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(numAttribs, size, GL_FLOAT, false, 0, 0);
|
||||
++numAttribs;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
glBindVertexArray(vao);
|
||||
|
||||
for (int i = 0; i < numAttribs; ++i)
|
||||
glEnableVertexAttribArray(i);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0);
|
||||
|
||||
for (int i = 0; i < numAttribs; ++i)
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
for(int vbo : vbos)
|
||||
glDeleteBuffers(vbo);
|
||||
glDeleteBuffers(ibo);
|
||||
glDeleteVertexArrays(vao);
|
||||
}
|
||||
}
|
42
src/com/gnarly/engine/rects/ColRect.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
package com.gnarly.engine.rects;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.shaders.Shader;
|
||||
import com.gnarly.engine.shaders.Shader2c;
|
||||
|
||||
public class ColRect extends Rect {
|
||||
|
||||
private Shader2c shader;
|
||||
|
||||
private float r, g, b, a;
|
||||
|
||||
public ColRect(Camera camera, float x, float y, float depth, float width, float height, float r, float g, float b, float a) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
shader = Shader.SHADER2C;
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
shader.enable();
|
||||
shader.setProjection(camera.getProjection());
|
||||
shader.setView(camera.getView());
|
||||
shader.setModel(new Matrix4f().translate(position).translate(dims.mul(0.5f * sx, 0.5f * sy, 1, new Vector3f())).rotateZ(rotation).scale(sx * flipX, sy * flipY, 1).translate(dims.mul(0.5f, new Vector3f()).negate()));
|
||||
shader.setColor(r, g, b, a);
|
||||
vao.render();
|
||||
shader.disable();
|
||||
}
|
||||
}
|
84
src/com/gnarly/engine/rects/Rect.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
package com.gnarly.engine.rects;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.model.Vao;
|
||||
|
||||
public abstract class Rect {
|
||||
|
||||
protected static final Vector3f dims = new Vector3f(10, 10, 0);
|
||||
protected static Vao vao = null;
|
||||
|
||||
protected Camera camera;
|
||||
|
||||
protected Vector3f position;
|
||||
protected float rotation;
|
||||
protected float sx, sy;
|
||||
protected byte flipX, flipY;
|
||||
|
||||
protected void initVao() {
|
||||
float[] vertices = new float[] {
|
||||
0, 0, 0.0f,
|
||||
0, dims.y, 0.0f,
|
||||
dims.x, dims.y, 0.0f,
|
||||
dims.x, 0, 0.0f
|
||||
};
|
||||
int[] indices = new int[] {
|
||||
0, 1, 3,
|
||||
3, 1, 2
|
||||
};
|
||||
float[] texCoords = new float[] {
|
||||
0, 0,
|
||||
0, 1,
|
||||
1, 1,
|
||||
1, 0
|
||||
};
|
||||
vao = new Vao(vertices, indices);
|
||||
vao.addAttribute(texCoords, 2);
|
||||
}
|
||||
|
||||
public abstract void render();
|
||||
|
||||
public float getX() {
|
||||
return position.x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return position.y;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return sx * dims.x;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return sy * dims.y;
|
||||
}
|
||||
|
||||
public void setRotation(float angle) {
|
||||
this.rotation = (angle * 3.1415926535f) / 180f;
|
||||
}
|
||||
|
||||
public void setPos(float x, float y) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
}
|
||||
|
||||
public void setSize(float width, float height) {
|
||||
this.sx = width / dims.x;
|
||||
this.sy = height / dims.y;
|
||||
}
|
||||
|
||||
public void setFlip(int x, int y) {
|
||||
this.flipX = (byte) x;
|
||||
this.flipY = (byte) y;
|
||||
}
|
||||
|
||||
public void reset(float x, float y, float width, float height) {
|
||||
this.position.x = x;
|
||||
this.position.y = y;
|
||||
this.sx = width / dims.x;
|
||||
this.sy = height / dims.y;
|
||||
}
|
||||
}
|
94
src/com/gnarly/engine/rects/TexRect.java
Normal file
|
@ -0,0 +1,94 @@
|
|||
package com.gnarly.engine.rects;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.shaders.Shader;
|
||||
import com.gnarly.engine.shaders.Shader2a;
|
||||
import com.gnarly.engine.texture.Anim;
|
||||
import com.gnarly.engine.texture.Texture;
|
||||
|
||||
public class TexRect extends Rect {
|
||||
|
||||
private Camera camera;
|
||||
private Texture texture;
|
||||
private Shader shader;
|
||||
|
||||
public TexRect(Camera camera, String texPath, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
texture = new Texture(texPath);
|
||||
shader = Shader.SHADER2T;
|
||||
}
|
||||
|
||||
public TexRect(Camera camera, String texPath, int frames, int fps, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
texture = new Anim(texPath, frames, fps);
|
||||
shader = Shader.SHADER2A;
|
||||
}
|
||||
|
||||
public TexRect(Camera camera, Texture texture, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
this.texture = texture;
|
||||
shader = Shader.SHADER2T;
|
||||
}
|
||||
|
||||
public TexRect(Camera camera, Anim anim, float x, float y, float depth, float width, float height) {
|
||||
this.camera = camera;
|
||||
if(vao == null)
|
||||
initVao();
|
||||
position = new Vector3f(x, y, depth);
|
||||
rotation = 0;
|
||||
sx = width / dims.x;
|
||||
sy = height / dims.y;
|
||||
flipX = 1;
|
||||
flipY = 1;
|
||||
texture = anim;
|
||||
shader = Shader.SHADER2A;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
texture.bind();
|
||||
shader.enable();
|
||||
shader.setProjection(camera.getProjection());
|
||||
shader.setView(camera.getView());
|
||||
shader.setModel(new Matrix4f().translate(position).translate(dims.mul(0.5f * sx, 0.5f * sy, 1, new Vector3f())).rotateZ(rotation).scale(sx * flipX, sy * flipY, 1).translate(dims.mul(0.5f, new Vector3f()).negate()));
|
||||
if(shader instanceof Shader2a)
|
||||
((Shader2a) shader).setAnim((Anim) texture);
|
||||
vao.render();
|
||||
shader.disable();
|
||||
texture.unbind();
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
((Anim) texture).pause();
|
||||
}
|
||||
|
||||
public void setFrame(int frame) {
|
||||
((Anim) texture).setFrame(frame);
|
||||
}
|
||||
}
|
131
src/com/gnarly/engine/shaders/Shader.java
Normal file
|
@ -0,0 +1,131 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.GL_COMPILE_STATUS;
|
||||
import static org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER;
|
||||
import static org.lwjgl.opengl.GL20.GL_VERTEX_SHADER;
|
||||
import static org.lwjgl.opengl.GL20.glAttachShader;
|
||||
import static org.lwjgl.opengl.GL20.glCompileShader;
|
||||
import static org.lwjgl.opengl.GL20.glCreateProgram;
|
||||
import static org.lwjgl.opengl.GL20.glCreateShader;
|
||||
import static org.lwjgl.opengl.GL20.glDeleteShader;
|
||||
import static org.lwjgl.opengl.GL20.glDetachShader;
|
||||
import static org.lwjgl.opengl.GL20.glGetShaderInfoLog;
|
||||
import static org.lwjgl.opengl.GL20.glGetShaderi;
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||
import static org.lwjgl.opengl.GL20.glShaderSource;
|
||||
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
|
||||
import static org.lwjgl.opengl.GL20.glUseProgram;
|
||||
import static org.lwjgl.opengl.GL20.glValidateProgram;
|
||||
import static org.lwjgl.opengl.GL32.GL_GEOMETRY_SHADER;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
public abstract class Shader {
|
||||
|
||||
public static final Shader2a SHADER2A = new Shader2a();
|
||||
public static final Shader2c SHADER2C = new Shader2c();
|
||||
public static final Shader2t SHADER2T = new Shader2t();
|
||||
public static final Shader2x SHADER2X = new Shader2x();
|
||||
|
||||
protected int program;
|
||||
|
||||
protected int projLoc, viewLoc, modelLoc;
|
||||
|
||||
protected Shader(String vertPath, String fragPath) {
|
||||
program = glCreateProgram();
|
||||
|
||||
int vert = load(vertPath, GL_VERTEX_SHADER);
|
||||
int frag = load(fragPath, GL_FRAGMENT_SHADER);
|
||||
|
||||
glAttachShader(program, vert);
|
||||
glAttachShader(program, frag);
|
||||
|
||||
glLinkProgram(program);
|
||||
glValidateProgram(program);
|
||||
|
||||
glDetachShader(program, vert);
|
||||
glDetachShader(program, frag);
|
||||
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
|
||||
getUniformLocs();
|
||||
}
|
||||
|
||||
protected Shader(String vertPath, String fragPath, String geomPath) {
|
||||
program = glCreateProgram();
|
||||
|
||||
int vert = load(vertPath, GL_VERTEX_SHADER);
|
||||
int frag = load(fragPath, GL_FRAGMENT_SHADER);
|
||||
int geom = load(geomPath, GL_GEOMETRY_SHADER);
|
||||
|
||||
glAttachShader(program, vert);
|
||||
glAttachShader(program, frag);
|
||||
glAttachShader(program, geom);
|
||||
|
||||
glLinkProgram(program);
|
||||
glValidateProgram(program);
|
||||
|
||||
glDetachShader(program, vert);
|
||||
glDetachShader(program, frag);
|
||||
glDetachShader(program, geom);
|
||||
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
glDeleteShader(geom);
|
||||
|
||||
getUniformLocs();
|
||||
}
|
||||
|
||||
private int load(String path, int type) {
|
||||
StringBuilder file = new StringBuilder();
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(new File(path)));
|
||||
String line;
|
||||
while((line = reader.readLine()) != null)
|
||||
file.append(line + '\n');
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
String source = file.toString();
|
||||
int shader = glCreateShader(type);
|
||||
glShaderSource(shader, source);
|
||||
glCompileShader(shader);
|
||||
if(glGetShaderi(shader, GL_COMPILE_STATUS) != 1)
|
||||
throw new RuntimeException("Failed to compile shader: " + path + "! " + glGetShaderInfoLog(shader));
|
||||
return shader;
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
projLoc = glGetUniformLocation(program, "projection");
|
||||
viewLoc = glGetUniformLocation(program, "view");
|
||||
modelLoc = glGetUniformLocation(program, "model");
|
||||
}
|
||||
|
||||
public void setProjection(Matrix4f projection) {
|
||||
glUniformMatrix4fv(projLoc, false, projection.get(new float[16]));
|
||||
}
|
||||
|
||||
public void setView(Matrix4f view) {
|
||||
glUniformMatrix4fv(viewLoc, false, view.get(new float[16]));
|
||||
}
|
||||
|
||||
public void setModel(Matrix4f model) {
|
||||
glUniformMatrix4fv(modelLoc, false, model.get(new float[16]));
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
glUseProgram(program);
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
glUseProgram(0);
|
||||
}
|
||||
}
|
24
src/com/gnarly/engine/shaders/Shader2a.java
Normal file
|
@ -0,0 +1,24 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform2f;
|
||||
|
||||
import com.gnarly.engine.texture.Anim;
|
||||
|
||||
public class Shader2a extends Shader {
|
||||
|
||||
private int animLoc;
|
||||
|
||||
protected Shader2a() {
|
||||
super("res/shaders/s2a/vert.vs", "res/shaders/s2a/frag.fs");
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
super.getUniformLocs();
|
||||
animLoc = glGetUniformLocation(program, "animProps");
|
||||
}
|
||||
|
||||
public void setAnim(Anim anim) {
|
||||
glUniform2f(animLoc, anim.getFrameWidth(), anim.getOffset());
|
||||
}
|
||||
}
|
22
src/com/gnarly/engine/shaders/Shader2c.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform4f;
|
||||
|
||||
public class Shader2c extends Shader {
|
||||
|
||||
int colorLoc;
|
||||
|
||||
protected Shader2c() {
|
||||
super("res/shaders/s2c/vert.vs", "res/shaders/s2c/frag.fs");
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
super.getUniformLocs();
|
||||
colorLoc = glGetUniformLocation(program, "iColor");
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float a) {
|
||||
glUniform4f(colorLoc, r, g, b, a);
|
||||
}
|
||||
}
|
8
src/com/gnarly/engine/shaders/Shader2t.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
public class Shader2t extends Shader {
|
||||
|
||||
protected Shader2t() {
|
||||
super("res/shaders/s2t/vert.vs", "res/shaders/s2t/frag.fs");
|
||||
}
|
||||
}
|
30
src/com/gnarly/engine/shaders/Shader2x.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package com.gnarly.engine.shaders;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform2f;
|
||||
import static org.lwjgl.opengl.GL20.glUniform4f;
|
||||
|
||||
public class Shader2x extends Shader {
|
||||
|
||||
private int charLoc;
|
||||
private int colorLoc;
|
||||
|
||||
protected Shader2x() {
|
||||
super("res/shaders/s2x/vert.vs", "res/shaders/s2x/frag.fs");
|
||||
}
|
||||
|
||||
protected void getUniformLocs() {
|
||||
super.getUniformLocs();
|
||||
colorLoc = glGetUniformLocation(program, "iColor");
|
||||
charLoc = glGetUniformLocation(program, "character");
|
||||
}
|
||||
|
||||
public void setColor(float r, float g, float b, float a) {
|
||||
glUniform4f(colorLoc, r, g, b, a);
|
||||
}
|
||||
|
||||
public void setChar(int character) {
|
||||
int column = character % 16, row = character / 16;
|
||||
glUniform2f(charLoc, (float) column / 16f, (float) row / 16f);
|
||||
}
|
||||
}
|
82
src/com/gnarly/engine/text/Font.java
Normal file
|
@ -0,0 +1,82 @@
|
|||
package com.gnarly.engine.text;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.model.Vao;
|
||||
import com.gnarly.engine.shaders.Shader;
|
||||
import com.gnarly.engine.shaders.Shader2x;
|
||||
import com.gnarly.engine.texture.Texture;
|
||||
|
||||
public class Font {
|
||||
|
||||
private final int
|
||||
WIDTH = 5,
|
||||
HEIGHT = 8;
|
||||
|
||||
private Camera camera;
|
||||
private Texture texture;
|
||||
private Shader2x shader;
|
||||
private Vao vao;
|
||||
|
||||
public Font(Camera camera, String fontPath) {
|
||||
this.camera = camera;
|
||||
texture = new Texture(fontPath);
|
||||
shader = Shader.SHADER2X;
|
||||
float[] vertices = new float[] {
|
||||
0, 0, 0,
|
||||
0, HEIGHT, 0,
|
||||
WIDTH, HEIGHT, 0,
|
||||
WIDTH, 0, 0
|
||||
};
|
||||
int[] indices = new int[] {
|
||||
0, 1, 3,
|
||||
3, 1, 2
|
||||
};
|
||||
float[] texCoords = new float[] {
|
||||
0, 0,
|
||||
0, 0.0625f,
|
||||
0.0625f, 0.0625f,
|
||||
0.0625f, 0
|
||||
};
|
||||
vao = new Vao(vertices, indices);
|
||||
vao.addAttribute(texCoords, 2);
|
||||
}
|
||||
|
||||
public void drawString(String string, float x, float y, float depth, float height, float r, float g, float b, float a) {
|
||||
float scale = height / (float) HEIGHT;
|
||||
texture.bind();
|
||||
shader.enable();
|
||||
shader.setProjection(camera.getProjection());
|
||||
shader.setView(camera.getView());
|
||||
shader.setColor(r, g, b, a);
|
||||
char[] chars = string.toCharArray();
|
||||
float lx = x;
|
||||
for (char c : chars) {
|
||||
if(c == '\n') {
|
||||
y += (float) (HEIGHT + 1) * scale;
|
||||
lx = x;
|
||||
}
|
||||
else {
|
||||
if(c != ' ') {
|
||||
shader.setModel(new Matrix4f().translate(lx, y, depth).scale(scale, scale, 0));
|
||||
shader.setChar(c);
|
||||
vao.render();
|
||||
}
|
||||
lx += (float) (WIDTH + 1) * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float getWidth(float height) {
|
||||
return (height / (float) HEIGHT) * (WIDTH + 1);
|
||||
}
|
||||
|
||||
public float getCharWidth(float height) {
|
||||
return (height / (float) HEIGHT) * WIDTH;
|
||||
}
|
||||
|
||||
public float getHeight(float height) {
|
||||
return (height / (float) HEIGHT) * (HEIGHT + 1);
|
||||
}
|
||||
}
|
57
src/com/gnarly/engine/texture/Anim.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package com.gnarly.engine.texture;
|
||||
|
||||
public class Anim extends Texture {
|
||||
|
||||
private final float FRAME_WIDTH;
|
||||
private final long NANO_PER_FRAME;
|
||||
private final int NUM_FRAMES;
|
||||
|
||||
private int curFrame;
|
||||
private long startTime;
|
||||
private boolean playing;
|
||||
|
||||
public Anim(String path, int numFrames, int fps) {
|
||||
super(path);
|
||||
FRAME_WIDTH = 1f / (float) numFrames;
|
||||
NANO_PER_FRAME = 1000000000l / fps;
|
||||
this.curFrame = 0;
|
||||
this.NUM_FRAMES = numFrames;
|
||||
startTime = System.nanoTime();
|
||||
playing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind() {
|
||||
super.bind();
|
||||
if(playing) {
|
||||
int frame = (int) ((System.nanoTime() - startTime) / NANO_PER_FRAME);
|
||||
curFrame = frame % NUM_FRAMES;
|
||||
}
|
||||
}
|
||||
|
||||
public void play() {
|
||||
startTime = System.nanoTime();
|
||||
playing = true;
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
playing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return width / NUM_FRAMES;
|
||||
}
|
||||
|
||||
public float getFrameWidth() {
|
||||
return FRAME_WIDTH;
|
||||
}
|
||||
|
||||
public float getOffset() {
|
||||
return FRAME_WIDTH * curFrame;
|
||||
}
|
||||
|
||||
public void setFrame(int frame) {
|
||||
curFrame = frame;
|
||||
}
|
||||
}
|
83
src/com/gnarly/engine/texture/Texture.java
Normal file
|
@ -0,0 +1,83 @@
|
|||
package com.gnarly.engine.texture;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_NEAREST;
|
||||
import static org.lwjgl.opengl.GL11.GL_RGBA;
|
||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
|
||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
|
||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
|
||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
||||
import static org.lwjgl.opengl.GL11.glBindTexture;
|
||||
import static org.lwjgl.opengl.GL11.glGenTextures;
|
||||
import static org.lwjgl.opengl.GL11.glTexImage2D;
|
||||
import static org.lwjgl.opengl.GL11.glTexParameterf;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
public class Texture {
|
||||
|
||||
protected int id, width, height;
|
||||
|
||||
public Texture(String fileName) {
|
||||
try {
|
||||
BufferedImage bi = ImageIO.read(new File(fileName));
|
||||
width = bi.getWidth();
|
||||
height = bi.getHeight();
|
||||
|
||||
int[] pixelsRaw = new int[width * height];
|
||||
pixelsRaw = bi.getRGB(0, 0, width, height, null, 0, width);
|
||||
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4);
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int pixel = pixelsRaw[i * width + j];
|
||||
pixels.put((byte)((pixel >> 16) & 0xFF)); //RED
|
||||
pixels.put((byte)((pixel >> 8) & 0xFF)); //GREEN
|
||||
pixels.put((byte)((pixel ) & 0xFF)); //BLUE
|
||||
pixels.put((byte)((pixel >> 24) & 0xFF)); //ALPHA
|
||||
}
|
||||
}
|
||||
pixels.flip();
|
||||
|
||||
id = glGenTextures();
|
||||
|
||||
bind();
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
unbind();
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public Texture(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
116
src/com/gnarly/game/GamePanel.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package com.gnarly.game;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
import com.gnarly.engine.rects.ColRect;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
import com.gnarly.game.board.Map;
|
||||
import com.gnarly.game.objs.Button;
|
||||
import com.gnarly.game.text.Console;
|
||||
import com.gnarly.game.text.EditorManager;
|
||||
import com.gnarly.game.text.TextBox;
|
||||
|
||||
public class GamePanel {
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
|
||||
private Map map;
|
||||
private EditorManager editor;
|
||||
private Button run, stop, menu;
|
||||
private TexRect header;
|
||||
|
||||
private TextBox background;
|
||||
private ColRect darkener;
|
||||
private Button next, smenu;
|
||||
private Font font;
|
||||
|
||||
private boolean success;
|
||||
private int level = 1;
|
||||
private int max;
|
||||
|
||||
private int state = 1;
|
||||
|
||||
public GamePanel(Window window, Camera camera) {
|
||||
max = new File("res/maps").list().length;
|
||||
this.window = window;
|
||||
this.camera = camera;
|
||||
|
||||
map = new Map(camera, "res/maps/level1.llm");
|
||||
editor = new EditorManager(window, camera);
|
||||
run = new Button(window, camera, "res/img/map/buttons/run/unpressed.png", "res/img/map/buttons/run/hovered.png", "res/img/map/buttons/run/pressed.png", 0, 324, 0, 75, 24);
|
||||
stop = new Button(window, camera, "res/img/map/buttons/stop/unpressed.png", "res/img/map/buttons/stop/hovered.png", "res/img/map/buttons/stop/pressed.png", 76, 324, 0, 76, 24);
|
||||
menu = new Button(window, camera, "res/img/map/buttons/menu/unpressed.png", "res/img/map/buttons/menu/hovered.png", "res/img/map/buttons/menu/pressed.png", 153, 324, 0, 75, 24);
|
||||
header = new TexRect(camera, "res/img/header.png", 0, 0, 0, 228, 32);
|
||||
|
||||
background = new TextBox(camera, "", 220, 100, -0.5f, 200, 100, 24);
|
||||
darkener = new ColRect(camera, 0, 0, -0.25f, 640, 360, 0, 0, 0, 0.5f);
|
||||
next = new Button(window, camera, "res/img/menu/next/unpressed.png", "res/img/menu/next/hovered.png", "res/img/menu/next/pressed.png", 362, 182, -0.75f, 16, 16);
|
||||
smenu = new Button(window, camera, "res/img/map/buttons/smenu/unpressed.png", "res/img/map/buttons/smenu/hovered.png", "res/img/map/buttons/smenu/pressed.png", 262, 182, -0.75f, 16, 16);
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(!success) {
|
||||
editor.update();
|
||||
map.update();
|
||||
run.update();
|
||||
stop.update();
|
||||
menu.update();
|
||||
if(run.getState() == Button.RELEASED) {
|
||||
Console.error.clear();
|
||||
map.execute(editor.getCommands());
|
||||
}
|
||||
else if(stop.getState() == Button.RELEASED)
|
||||
map.fullStop();
|
||||
else if(menu.getState() == Button.RELEASED)
|
||||
state = 0;
|
||||
success = map.success();
|
||||
if(success) {
|
||||
++level;
|
||||
if(level > max)
|
||||
level = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
next.update();
|
||||
smenu.update();
|
||||
if(next.getState() == Button.RELEASED) {
|
||||
map = new Map(camera, "res/maps/level" + level + ".llm");
|
||||
editor = new EditorManager(window, camera);
|
||||
success = false;
|
||||
}
|
||||
else if(smenu.getState() == Button.RELEASED) {
|
||||
map = new Map(camera, "res/maps/level" + level + ".llm");
|
||||
editor = new EditorManager(window, camera);
|
||||
success = false;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
header.render();
|
||||
run.render();
|
||||
stop.render();
|
||||
menu.render();
|
||||
map.render();
|
||||
editor.render();
|
||||
if(success) {
|
||||
font.drawString("SUCCESS!", (640 - font.getWidth(24) * 7 - font.getCharWidth(24)) / 2, 106, -0.75f, 24, 1, 1, 1, 1);
|
||||
darkener.render();
|
||||
background.render();
|
||||
next.render();
|
||||
smenu.render();
|
||||
}
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
int temp = state;
|
||||
state = 1;
|
||||
return temp;
|
||||
}
|
||||
}
|
90
src/com/gnarly/game/Main.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
package com.gnarly.game;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
|
||||
public class Main implements Runnable {
|
||||
|
||||
public static final int BIG_TICK = 8;
|
||||
|
||||
private final int TICK_RATE = 64;
|
||||
private final int FPS = 59;
|
||||
|
||||
public static int tick = 0;
|
||||
public static int fps = 0;
|
||||
|
||||
private int state;
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
private MenuPanel menu;
|
||||
private GamePanel panel;
|
||||
|
||||
public void start() {
|
||||
Thread gameLoop = new Thread(this, "OpenGL");
|
||||
gameLoop.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
long pastTime, curTime, npf = 1000000000 / FPS, pastSec, pastUTime, npt = 1000000000 / TICK_RATE;
|
||||
int frames = 0;
|
||||
init();
|
||||
pastTime = System.nanoTime();
|
||||
pastUTime = pastTime;
|
||||
pastSec = pastTime;
|
||||
while(!window.shouldClose()) {
|
||||
curTime = System.nanoTime();
|
||||
while(curTime - pastUTime >= npt) {
|
||||
update();
|
||||
pastUTime += npt;
|
||||
++tick;
|
||||
}
|
||||
curTime = System.nanoTime();
|
||||
if(curTime - pastTime > npf) {
|
||||
render();
|
||||
pastTime += npf;
|
||||
++frames;
|
||||
}
|
||||
if(curTime - pastSec >= 1000000000) {
|
||||
fps = frames;
|
||||
frames = 0;
|
||||
pastSec += 1000000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
state = 0;
|
||||
window = new Window(false);
|
||||
camera = new Camera(640, 360);
|
||||
menu = new MenuPanel(window, camera);
|
||||
panel = new GamePanel(window, camera);
|
||||
window.bind();
|
||||
}
|
||||
|
||||
private void update() {
|
||||
window.update();
|
||||
if(state == 0) {
|
||||
menu.update();
|
||||
state = menu.getState();
|
||||
}
|
||||
else {
|
||||
panel.update();
|
||||
state = panel.getState();
|
||||
}
|
||||
}
|
||||
|
||||
private void render() {
|
||||
window.clear();
|
||||
if(state == 0)
|
||||
menu.render();
|
||||
else
|
||||
panel.render();
|
||||
window.bind();
|
||||
window.swap();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Main().start();
|
||||
}
|
||||
}
|
104
src/com/gnarly/game/MenuPanel.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
package com.gnarly.game;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.display.Window;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.engine.text.Font;
|
||||
import com.gnarly.game.objs.Button;
|
||||
|
||||
public class MenuPanel {
|
||||
|
||||
private Window window;
|
||||
private Camera camera;
|
||||
|
||||
private Font font;
|
||||
|
||||
private Button play, help, close, next, prev;
|
||||
|
||||
private TexRect background;
|
||||
private TexRect helpMenu;
|
||||
|
||||
private int state = 0, page = 0;
|
||||
private boolean showHelp = false;
|
||||
private String[] headers, content;
|
||||
|
||||
|
||||
public MenuPanel(Window window, Camera camera) {
|
||||
this.window = window;
|
||||
this.camera = camera;
|
||||
font = new Font(camera, "res/img/fonts/default.png");
|
||||
background = new TexRect(camera, "res/img/menu/background.png", 0, 0, 0, 640, 360);
|
||||
play = new Button(window, camera, "res/img/menu/play/unpressed.png", "res/img/menu/play/hovered.png", "res/img/menu/play/pressed.png", 260, 160, 0, 120, 32);
|
||||
help = new Button(window, camera, "res/img/menu/help/unpressed.png", "res/img/menu/help/hovered.png", "res/img/menu/help/pressed.png", 260, 200, 0, 120, 32);
|
||||
close = new Button(window, camera, "res/img/menu/close/unpressed.png", "res/img/menu/close/hovered.png", "res/img/menu/close/pressed.png", 384, 110, 0, 16, 16);
|
||||
next = new Button(window, camera, "res/img/menu/next/unpressed.png", "res/img/menu/next/hovered.png", "res/img/menu/next/pressed.png", 384, 264, 0, 16, 16);
|
||||
prev = new Button(window, camera, "res/img/menu/prev/unpressed.png", "res/img/menu/prev/hovered.png", "res/img/menu/prev/pressed.png", 240, 264, 0, 16, 16);
|
||||
helpMenu = new TexRect(camera, "res/img/menu/help/helpMenu.png", 240, 110, 0, 160, 170);
|
||||
headers = new String[8];
|
||||
headers[0] = "OVERVIEW";
|
||||
headers[1] = "GOAL";
|
||||
headers[2] = "PROGRAMMING";
|
||||
headers[3] = "FIRE";
|
||||
headers[4] = "ROTATE";
|
||||
headers[5] = "WAIT";
|
||||
headers[6] = "THREADS";
|
||||
headers[7] = "TIMING";
|
||||
content = new String[8];
|
||||
content[0] = "SO WHAT THE HECK IS THIS GAME?\n\nWELL BASICALLY ITS A PROGRAMMING\nGAME IN WHICH THE PLAYER CONTROLS\nMIRRORS IN ORDER TO DIRECT A LASER TO\nA TRIGGER.";
|
||||
content[1] = "THE GOAL OF THE GAME IS TO BEAT\nALL THE LEVELS. THE EXACT GOAL\nOF EACH LEVEL VARIES BUT THE GOAL\nIS ALWAYS ABOUT TRIGGERING A TRIGGER\nWITH A LASER. WHICH TRIGGER AND AT\nWHAT TIMES ARE LEVEL SPECIFIC.\nTHE BOX AT THE TOP WILL TELL\nYOU THE GOAL FOR THAT LEVEL";
|
||||
content[2] = "TO CONTROL THE GAME BOARD YOU USE THE\nPROGRAMMING INTRFACE ON THE LEFT.\n\nTHERE ARE THREE COMMANDS YOU CAN USE.\n\n- FIRE\n- ROTATE\n- WAIT";
|
||||
content[3] = "THE FIRE COMMAND DOES EXACTLY WHAT\nIT SAYS. IT FIRES A LASER.\n\nUSAGE:\n\nFIRE X\n\n - X IS THE X COMPONENT OF\n THE LOCATION OF THE\n CANNON YOU WANT TO FIRE.";
|
||||
content[4] = "THE ROTATE COMMAND ROTATES A MIRROR\n90 DEGREES.\n\nUSAGE:\n\nROTATE X Y\n\n - X IS THE X COMPONENT OF\n THE LOCATION OF THE\n THE MIRROR YOU WANT ROTATED\n\n - Y IS THE Y COMPONENT OF\n THE LOCATION OF THE\n THE MIRROR YOU WANT ROTATED";
|
||||
content[5] = "THE WAIT COMMAND PAUSES THE CURRENT\nTHREAD FOR A CERTAIN NUMBER FO TICKS.\n\nUSAGE:\n\nWAIT X\n\n - X IS THE NUMBER OF TICKS\n YOU WANT THE THREAD TO PAUSE";
|
||||
content[6] = "YOU HAVE FOUR THREADS AT YOUR DISPOAL.\nEACH THREAD CAN ONLY HOUSE A\nCERTAIN NUMBER OF COMMANDS.\nTHE MAIN ADVANTAGE OF MUTIPLE THREADS\nIS IT ALLOWS YOU TO RUN MUTIPLE\nCOMMANDS SIMULTANEOUSLY.";
|
||||
content[7] = "THE WHOLE GAME RUNS ON A SYSTEM\nOF TICKS. EACH TICK IS 1/16TH\nOF A SECOND. DURING ONE TICK\nONE COMMAND FROM EACH THREAD\nIS EXECUTED.";
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(!showHelp) {
|
||||
play.update();
|
||||
help.update();
|
||||
if(play.getState() == Button.RELEASED)
|
||||
state = 1;
|
||||
else if(help.getState() == Button.RELEASED)
|
||||
showHelp = true;
|
||||
}
|
||||
else {
|
||||
close.update();
|
||||
next.update();
|
||||
prev.update();
|
||||
if(close.getState() == Button.RELEASED) {
|
||||
page = 0;
|
||||
showHelp = false;
|
||||
}
|
||||
else if(next.getState() == Button.RELEASED && page < headers.length - 1)
|
||||
++page;
|
||||
else if(prev.getState() == Button.RELEASED && page > 0)
|
||||
--page;
|
||||
}
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if(!showHelp) {
|
||||
play.render();
|
||||
help.render();
|
||||
}
|
||||
else {
|
||||
close.render();
|
||||
next.render();
|
||||
prev.render();
|
||||
String pageString = "[" + (page + 1) + "/" + headers.length + "]";
|
||||
font.drawString(pageString, (640 - (pageString.length() * 5 + pageString.length() - 1)) / 2, 269, 0, 8, 1, 1, 1, 1);
|
||||
font.drawString(headers[page], 243, 113, 0, 16, 1, 1, 1, 1);
|
||||
font.drawString(content[page], 243, 136, 0, 5.3333333333f, 1, 1, 1, 1);
|
||||
helpMenu.render();
|
||||
}
|
||||
background.render();
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
int temp = state;
|
||||
state = 0;
|
||||
return temp;
|
||||
}
|
||||
}
|
308
src/com/gnarly/game/board/Map.java
Normal file
|
@ -0,0 +1,308 @@
|
|||
package com.gnarly.game.board;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.game.Main;
|
||||
import com.gnarly.game.board.laser.Cannon;
|
||||
import com.gnarly.game.board.laser.Laser;
|
||||
import com.gnarly.game.board.laser.Trigger;
|
||||
import com.gnarly.game.commands.Command;
|
||||
import com.gnarly.game.commands.Fire;
|
||||
import com.gnarly.game.commands.Rotate;
|
||||
import com.gnarly.game.commands.Wait;
|
||||
import com.gnarly.game.text.Console;
|
||||
import com.gnarly.game.text.TextBox;
|
||||
|
||||
public class Map {
|
||||
|
||||
public static final int
|
||||
EMPTY = 0,
|
||||
M45 = 1,
|
||||
M135 = 2,
|
||||
CANNON = 3,
|
||||
TRIGGER = 4;
|
||||
|
||||
private static final int
|
||||
OFFSET = 14,
|
||||
WIDTH = 32,
|
||||
HEIGHT = 32,
|
||||
COLUMNS = 12,
|
||||
ROWS = 10;
|
||||
|
||||
private String mapPath;
|
||||
|
||||
private Console console;
|
||||
|
||||
private Camera camera;
|
||||
private TexRect[] states;
|
||||
private int map[][];
|
||||
|
||||
private TexRect topbar, leftbar;
|
||||
private TexRect[] corners, nums;
|
||||
|
||||
private float x, y;
|
||||
|
||||
private TextBox ghead, goals;
|
||||
|
||||
private ArrayList<Laser> lasers;
|
||||
private ArrayList<Cannon> cannons;
|
||||
private ArrayList<Trigger> triggers;
|
||||
|
||||
private boolean execute, lastRan;
|
||||
private ArrayList<Command>[] commands;
|
||||
|
||||
private boolean success = false;
|
||||
|
||||
public Map(Camera camera, String mapPath) {
|
||||
this.mapPath = mapPath;
|
||||
this.camera = camera;
|
||||
this.x = camera.getWidth() - getWidth();
|
||||
this.y = 0;
|
||||
ghead = new TextBox(camera, "GOALS\nTRIG |TICK", 182, 33, 0, 46, 15, 5.3333333f);
|
||||
goals = new TextBox(camera, "", 182, 49, 0, 46, 185, 5.3333333f);
|
||||
map = new int[COLUMNS][ROWS];
|
||||
states = new TexRect[5];
|
||||
states[EMPTY] = new TexRect(camera, "res/img/map/empty.png", 0, 0, 0, 32, 32);
|
||||
states[M45] = new TexRect(camera, "res/img/map/mirror45.png", 0, 0, 0, 32, 32);
|
||||
states[M135] = new TexRect(camera, "res/img/map/mirror135.png", 0, 0, 0, 32, 32);
|
||||
states[CANNON] = new TexRect(camera, "res/img/map/cannon.png", 10, 8, 0, 0, 0, 32, 32);
|
||||
states[TRIGGER] = new TexRect(camera, "res/img/map/trigger.png", 32, 32, 0, 0, 0, 32, 32);
|
||||
states[TRIGGER].pause();
|
||||
corners = new TexRect[4];
|
||||
corners[0] = new TexRect(camera, "res/img/bars/tlcorner.png", x, y, 0, OFFSET, OFFSET);
|
||||
corners[1] = new TexRect(camera, "res/img/bars/blcorner.png", x, y + getHeight() - OFFSET, 0, OFFSET, OFFSET);
|
||||
corners[2] = new TexRect(camera, "res/img/bars/brcorner.png", x + getWidth()- OFFSET, y + getHeight() - OFFSET, 0, OFFSET, OFFSET);
|
||||
corners[3] = new TexRect(camera, "res/img/bars/trcorner.png", x + getWidth()- OFFSET, y, 0, OFFSET, OFFSET);
|
||||
topbar = new TexRect(camera, "res/img/bars/topbar.png", 0, 0, 0, WIDTH, OFFSET);
|
||||
leftbar = new TexRect(camera, "res/img/bars/leftbar.png", 0, 0, 0, OFFSET, HEIGHT);
|
||||
lasers = new ArrayList<>();
|
||||
cannons = new ArrayList<>();
|
||||
triggers = new ArrayList<>();
|
||||
nums = new TexRect[12];
|
||||
for (int i = 0; i < nums.length; i++)
|
||||
nums[i] = new TexRect(camera, "res/img/bars/numbers/" + i + ".png", 0, 0, 0, 8, 8);
|
||||
loadMap();
|
||||
console = new Console(camera);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(Main.tick % Main.BIG_TICK == 0) {
|
||||
boolean ran = false;
|
||||
if(execute || lasers.size() > 0) {
|
||||
ran = true;
|
||||
if(commands != null) {
|
||||
String[] commandStrings = new String[4];
|
||||
for (int i = 0; i < commandStrings.length; i++)
|
||||
commandStrings[i] = new String();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if(commands[i].size() > 0) {
|
||||
commandStrings[i] = commands[i].get(0).getCommand();
|
||||
Command command = commands[i].get(0);
|
||||
if(command instanceof Wait) {
|
||||
Wait wait = (Wait) command;
|
||||
wait.decrement();
|
||||
if(wait.getTicks() == 0)
|
||||
commands[i].remove(0);
|
||||
}
|
||||
else if(command instanceof Rotate) {
|
||||
Rotate rotate = (Rotate) command;
|
||||
int x = rotate.getX();
|
||||
int y = rotate.getY() + 1;
|
||||
if(map[x][y] == M45)
|
||||
map[x][y] = M135;
|
||||
else if(map[x][y] == M135)
|
||||
map[x][y] = M45;
|
||||
else {
|
||||
Console.error.add("LOCATION " + x + " " + y + " IS NOT A MIRROR");
|
||||
execute = false;
|
||||
}
|
||||
commands[i].remove(0);
|
||||
}
|
||||
else if(command instanceof Fire) {
|
||||
Fire fire = (Fire) command;
|
||||
fire(fire.getCannon());
|
||||
commands[i].remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
int num = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
if(commands[i].size() > 0)
|
||||
++num;
|
||||
if(num == 0) {
|
||||
commands = null;
|
||||
execute = false;
|
||||
}
|
||||
console.printCommands(commandStrings);
|
||||
}
|
||||
}
|
||||
if(!ran && lastRan) {
|
||||
for (int i = 0; i < triggers.size(); i++) {
|
||||
triggers.get(i).update();
|
||||
if(!triggers.get(i).success())
|
||||
Console.error.add("FAILED TO MEET ALL TRIGGER CONDITIONS!");
|
||||
}
|
||||
if(Console.error.size() == 0)
|
||||
success = true;
|
||||
for (int i = 0; i < triggers.size(); i++)
|
||||
triggers.get(i).reset();
|
||||
fullStop();
|
||||
}
|
||||
lastRan = ran;
|
||||
}
|
||||
for (int i = 0; i < lasers.size(); i++)
|
||||
lasers.get(i).update();
|
||||
for (int i = 0; i < lasers.size(); i++)
|
||||
if(lasers.get(i).done())
|
||||
lasers.remove(i);
|
||||
if(execute || lasers.size() > 0)
|
||||
for (int i = 0; i < triggers.size(); i++)
|
||||
triggers.get(i).update();
|
||||
}
|
||||
|
||||
public void render() {
|
||||
ghead.render();
|
||||
goals.render();
|
||||
console.render();
|
||||
for (int i = 0; i < lasers.size(); i++)
|
||||
lasers.get(i).render();
|
||||
for (int i = 0; i < corners.length; i++)
|
||||
corners[i].render();
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
nums[i].setPos(x + i * WIDTH + OFFSET + 12, y + 3);
|
||||
nums[i].render();
|
||||
topbar.setPos(x + i * WIDTH + OFFSET, y);
|
||||
topbar.render();
|
||||
nums[i].setPos(x + i * WIDTH + OFFSET + 12, y + getHeight() - OFFSET + 3);
|
||||
nums[i].render();
|
||||
topbar.setPos(x + i * WIDTH + OFFSET, y + getHeight() - OFFSET);
|
||||
topbar.render();
|
||||
}
|
||||
for (int i = 0; i < map[0].length; i++) {
|
||||
if (i > 0 && i < map[0].length - 1) {
|
||||
nums[i - 1].setPos(x + 3, y + i * HEIGHT + OFFSET + 12);
|
||||
nums[i - 1].render();
|
||||
nums[i - 1].setPos(x + getWidth() - OFFSET + 3, y + i * HEIGHT + OFFSET + 12);
|
||||
nums[i - 1].render();
|
||||
}
|
||||
leftbar.setPos(x, y + i * HEIGHT + OFFSET);
|
||||
leftbar.render();
|
||||
leftbar.setPos(x + getWidth() - OFFSET, y + i * HEIGHT + OFFSET);
|
||||
leftbar.render();
|
||||
}
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
for (int j = 0; j < map[0].length; j++) {
|
||||
int state = map[i][j];
|
||||
if(state != TRIGGER) {
|
||||
states[state].setPos(x + i * WIDTH + OFFSET, y + j * HEIGHT + OFFSET);
|
||||
states[state].render();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < triggers.size(); i++) {
|
||||
Trigger trigger = triggers.get(i);
|
||||
states[TRIGGER].setFrame(trigger.getFrame());
|
||||
states[TRIGGER].setPos(x + trigger.getX() * WIDTH + OFFSET, y + trigger.getY() * HEIGHT + OFFSET);
|
||||
states[TRIGGER].render();
|
||||
}
|
||||
}
|
||||
|
||||
public static float getWidth() {
|
||||
return WIDTH * COLUMNS + OFFSET * 2;
|
||||
}
|
||||
|
||||
public static float getHeight() {
|
||||
return HEIGHT * ROWS + OFFSET * 2;
|
||||
}
|
||||
|
||||
private void fire(int cannonNum) {
|
||||
Cannon cannon = null;
|
||||
for (int i = 0; i < cannons.size() && cannon == null; i++) {
|
||||
if(cannons.get(i).getX() == cannonNum)
|
||||
cannon = cannons.get(i);
|
||||
}
|
||||
if(cannon == null)
|
||||
Console.error.add("NO CANNON AT POSITION " + cannonNum + "!");
|
||||
else {
|
||||
int x = cannon.getX();
|
||||
int y = cannon.getY();
|
||||
Vector3f dir = cannon.getDir();
|
||||
x += dir.x;
|
||||
y += dir.y;
|
||||
lasers.add(new Laser(camera, dir, this.x + OFFSET, this.y + OFFSET, x, y, map, triggers));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMap() {
|
||||
Scanner scanner = null;
|
||||
try {
|
||||
triggers.clear();
|
||||
cannons.clear();
|
||||
scanner = new Scanner(new File(mapPath));
|
||||
for (int j = 0; j < this.map[0].length; j++) {
|
||||
for (int i = 0; i < this.map.length; i++) {
|
||||
this.map[i][j] = scanner.nextInt();
|
||||
if(this.map[i][j] == CANNON)
|
||||
cannons.add(new Cannon(i, j, Laser.UP));
|
||||
if(this.map[i][j] == TRIGGER)
|
||||
triggers.add(new Trigger(i, j));
|
||||
}
|
||||
}
|
||||
int numGoals = scanner.nextInt();
|
||||
String goals = new String();
|
||||
for (int i = 0; i < numGoals; i++) {
|
||||
String curGoal = new String();
|
||||
int trigger = scanner.nextInt();
|
||||
int tickNum = scanner.nextInt();
|
||||
curGoal += triggers.get(trigger).getX();
|
||||
while(curGoal.length() < 4)
|
||||
curGoal += ' ';
|
||||
curGoal += " |";
|
||||
curGoal += tickNum + "\n";
|
||||
goals += curGoal;
|
||||
triggers.get(trigger).addCondition(tickNum);
|
||||
}
|
||||
this.goals.setText(goals);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void execute(ArrayList<Command>[] commands) {
|
||||
if(Console.error.size() == 0) {
|
||||
lasers.clear();
|
||||
console.clear();
|
||||
execute = true;
|
||||
this.commands = commands;
|
||||
}
|
||||
}
|
||||
|
||||
public void fullStop() {
|
||||
loadMap();
|
||||
lasers.clear();
|
||||
execute = false;
|
||||
commands = null;
|
||||
}
|
||||
|
||||
public void setMap(String mapPath) {
|
||||
this.mapPath = mapPath;
|
||||
loadMap();
|
||||
}
|
||||
|
||||
public int[][] getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return success;
|
||||
}
|
||||
}
|
27
src/com/gnarly/game/board/laser/Cannon.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package com.gnarly.game.board.laser;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class Cannon {
|
||||
|
||||
int x, y;
|
||||
Vector3f dir;
|
||||
|
||||
public Cannon(int x, int y, Vector3f dir) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3f getDir() {
|
||||
return dir;
|
||||
}
|
||||
}
|
182
src/com/gnarly/game/board/laser/Laser.java
Normal file
|
@ -0,0 +1,182 @@
|
|||
package com.gnarly.game.board.laser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gnarly.engine.display.Camera;
|
||||
import com.gnarly.engine.rects.TexRect;
|
||||
import com.gnarly.engine.texture.Anim;
|
||||
import com.gnarly.game.Main;
|
||||
import com.gnarly.game.board.Map;
|
||||
|
||||
public class Laser {
|
||||
|
||||
public static final Vector3f
|
||||
UP = new Vector3f(0, -1, 0),
|
||||
DOWN = new Vector3f(0, 1, 0),
|
||||
LEFT = new Vector3f(-1, 0, 0),
|
||||
RIGHT = new Vector3f(1, 0, 0);
|
||||
|
||||
private final int
|
||||
STRAIGHT = 0,
|
||||
BEND = 1,
|
||||
TRIGGER = 2,
|
||||
SOLID = 3;
|
||||
|
||||
private Anim[] fanims;
|
||||
private TexRect[] frects;
|
||||
private Anim[] banims;
|
||||
private TexRect[] brects;
|
||||
|
||||
private float startX, startY;
|
||||
|
||||
private int fx, fy, ftype, frame;
|
||||
private int[] props;
|
||||
private Vector3f fdir;
|
||||
|
||||
private int bx, by, btype;
|
||||
|
||||
private boolean renderFront, renderBack;
|
||||
|
||||
private ArrayList<Trigger> triggers;
|
||||
private int[][] map;
|
||||
|
||||
public Laser(Camera camera, Vector3f dir, float startX, float startY, int x, int y, int[][] map, ArrayList<Trigger> triggers) {
|
||||
this.startX = startX;
|
||||
this.startY = startY;
|
||||
bx = 0;
|
||||
by = 0;
|
||||
fx = x;
|
||||
fy = y;
|
||||
fdir = dir;
|
||||
this.map = map;
|
||||
this.triggers = triggers;
|
||||
renderFront = true;
|
||||
renderBack = false;
|
||||
initAnims(camera);
|
||||
}
|
||||
|
||||
private void initAnims(Camera camera) {
|
||||
banims = new Anim[2];
|
||||
banims[0] = new Anim("res/img/map/laser/laserStraightBack.png", 32, 64);
|
||||
banims[1] = new Anim("res/img/map/laser/laserBendBack.png", 32, 64);
|
||||
brects = new TexRect[2];
|
||||
brects[STRAIGHT] = new TexRect(camera, banims[0], 0, 0, 0, 32, 32);
|
||||
brects[BEND] = new TexRect(camera, banims[1], 0, 0, 0, 32, 32);
|
||||
for (int i = 0; i < banims.length; i++)
|
||||
banims[i].pause();
|
||||
fanims = new Anim[2];
|
||||
fanims[0] = new Anim("res/img/map/laser/laserStraight.png", 32, 64);
|
||||
fanims[1] = new Anim("res/img/map/laser/laserBend.png", 32, 64);
|
||||
frects = new TexRect[2];
|
||||
frects[STRAIGHT] = new TexRect(camera, fanims[0], 0, 0, 0, 32, 32);
|
||||
frects[BEND] = new TexRect(camera, fanims[1], 0, 0, 0, 32, 32);
|
||||
for (int i = 0; i < fanims.length; i++)
|
||||
fanims[i].pause();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
frame = Main.tick % Main.BIG_TICK * (32 / Main.BIG_TICK);
|
||||
if(frame == 0) {
|
||||
if(bx < 0 || by < 0 || bx >= map.length || by >= map[0].length || getType(bx, by) >= TRIGGER)
|
||||
renderBack = false;
|
||||
else if(props != null) {
|
||||
btype = ftype;
|
||||
brects[btype].setPos(startX + bx * 32, startY + by * 32);
|
||||
brects[btype].setRotation(props[0]);
|
||||
brects[btype].setFlip(1, props[1]);
|
||||
renderBack = true;
|
||||
}
|
||||
if(fx < 0 || fy < 0 || fx >= map.length || fy >= map[0].length || getType(fx, fy) == SOLID)
|
||||
renderFront = false;
|
||||
else if(getType(fx, fy) == TRIGGER) {
|
||||
for (int i = 0; i < triggers.size(); i++) {
|
||||
if(triggers.get(i).getX() == fx && triggers.get(i).getY() == fy)
|
||||
triggers.get(i).trigger();
|
||||
}
|
||||
renderFront = false;
|
||||
}
|
||||
else {
|
||||
ftype = getType(fx, fy);
|
||||
props = getProps(fx, fy, fdir);
|
||||
frects[ftype].setPos(startX + fx * 32, startY + fy * 32);
|
||||
frects[ftype].setRotation(props[0]);
|
||||
frects[ftype].setFlip(1, props[1]);
|
||||
fdir = getDir(fx, fy, fdir);
|
||||
}
|
||||
bx = fx;
|
||||
by = fy;
|
||||
fx += fdir.x;
|
||||
fy += fdir.y;
|
||||
}
|
||||
}
|
||||
|
||||
private int getType(int x, int y) {
|
||||
if(map[x][y] == 0)
|
||||
return STRAIGHT;
|
||||
else if(map[x][y] >= 1 && map[x][y] <= 2)
|
||||
return BEND;
|
||||
else if(map[x][y] == 4)
|
||||
return TRIGGER;
|
||||
else
|
||||
return SOLID;
|
||||
}
|
||||
|
||||
private int[] getProps(int x, int y, Vector3f dir) {
|
||||
if((dir.x == 1 && dir.y == 0 && map[x][y] == Map.M45))
|
||||
return new int[] {0, 1};
|
||||
else if((dir.x == 1 && dir.y == 0 && map[x][y] == Map.M135))
|
||||
return new int[] {0, -1};
|
||||
else if((dir.x == 1 && dir.y == 0 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {90, 1};
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M45))
|
||||
return new int[] {180, 1};
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M135))
|
||||
return new int[] {180, -1};
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {90, -1};
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M45))
|
||||
return new int[] {90, -1};
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M135))
|
||||
return new int[] {90, 1};
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {0, -1};
|
||||
else if((dir.x == 0 && dir.y == -1 && map[x][y] == Map.M45))
|
||||
return new int[] {270, -1};
|
||||
else if((dir.x == 0 && dir.y == -1 && map[x][y] == Map.M135))
|
||||
return new int[] {270, 1};
|
||||
else if((dir.x == 0 && dir.y == -1 && map[x][y] == Map.EMPTY))
|
||||
return new int[] {0, 1};
|
||||
return null;
|
||||
}
|
||||
|
||||
private Vector3f getDir(int x, int y, Vector3f dir) {
|
||||
if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M45) || (dir.x == 0 && dir.y == -1 && map[x][y] == Map.M135))
|
||||
return LEFT;
|
||||
else if((dir.x == 0 && dir.y == 1 && map[x][y] == Map.M135) || (dir.x == 0 && dir.y == -1 && map[x][y] == Map.M45))
|
||||
return RIGHT;
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M135) || (dir.x == 1 && dir.y == 0 && map[x][y] == Map.M45))
|
||||
return UP;
|
||||
else if((dir.x == -1 && dir.y == 0 && map[x][y] == Map.M45) || (dir.x == 1 && dir.y == 0 && map[x][y] == Map.M135))
|
||||
return DOWN;
|
||||
else if(map[x][y] == Map.EMPTY)
|
||||
return dir;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if(renderBack) {
|
||||
banims[btype].setFrame(frame);
|
||||
brects[btype].render();
|
||||
}
|
||||
if(renderFront) {
|
||||
fanims[ftype].setFrame(frame);
|
||||
frects[ftype].render();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean done() {
|
||||
return !renderBack && !renderFront;
|
||||
}
|
||||
}
|
79
src/com/gnarly/game/board/laser/Trigger.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package com.gnarly.game.board.laser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.gnarly.game.Main;
|
||||
import com.gnarly.game.text.Console;
|
||||
|
||||
public class Trigger {
|
||||
|
||||
private int tick = 0;
|
||||
private int frame = 0;
|
||||
private int triggered = 0;
|
||||
|
||||
private int x, y, met;
|
||||
|
||||
private ArrayList<Integer> conditions;
|
||||
|
||||
public Trigger(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
conditions = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(triggered == 2) {
|
||||
frame = Main.tick % Main.BIG_TICK * (32 / Main.BIG_TICK);
|
||||
if(Main.tick % Main.BIG_TICK == Main.BIG_TICK - 1)
|
||||
--triggered;
|
||||
}
|
||||
else
|
||||
frame = 0;
|
||||
if(Main.tick % Main.BIG_TICK == 0) {
|
||||
boolean check = false;
|
||||
for (int i = 0; i < conditions.size(); i++) {
|
||||
if(conditions.get(i).intValue() == tick) {
|
||||
check = true;
|
||||
if(triggered == 0)
|
||||
Console.error.add("TRIGGER FAILED TO BE TRIGGERED AT PROPER TIME!");
|
||||
else
|
||||
++met; }
|
||||
}
|
||||
if(!check && triggered == 2) {
|
||||
--met;
|
||||
Console.error.add("TRIGGER WAS TRIGGERED AT AN UNEXPECTED TIME!");
|
||||
}
|
||||
++tick;
|
||||
}
|
||||
}
|
||||
|
||||
public void trigger() {
|
||||
triggered = 2;
|
||||
}
|
||||
|
||||
public int getFrame() {
|
||||
return frame;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void addCondition(int condition) {
|
||||
conditions.add(condition);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
conditions.clear();
|
||||
tick = 0;
|
||||
met = 0;
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return met == conditions.size();
|
||||
}
|
||||
}
|
5
src/com/gnarly/game/commands/Command.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package com.gnarly.game.commands;
|
||||
|
||||
public interface Command {
|
||||
public String getCommand();
|
||||
}
|