commit cba41886e51dc509ffecfb47f80bd8e498940d5b Author: Gnarwhal Date: Wed Aug 7 04:59:26 2024 +0000 Entire project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84fd3d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.settings/ +bin/ +.classpath +.project +*.png +*.zip +*.jar + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e129676 --- /dev/null +++ b/LICENSE @@ -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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..968a4d6 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Ludum Dare 41 + +## Getting Started + +### Prerequisites +Must have [Java](http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.html) installed +* NOTE: I run Java 9 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/jdk9-downloads-3848520.html) to download Java 9. + +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 41. 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 it was supposed to be a text adventure mixed with a 2d platformer and in a sense it does this. But the quality of everything is so low it barely counts. Anywyas more specifically you are the user of a computer and you find out you have a virus installed. You must navigate the computer and complete tasks to eventually remove the virus. Or atleast that was the plan. The game was super rushed and is extermely incomplete so feelsbadman.jpg. + +### Can I play it? +Of course! Here's how: + +Click [here](https://drive.google.com/open?id=1ZfXLrX6FJWgNJHq8kJkk93fpgG5ftSIA) to download the game. Once you've downloaded it extract the zip file and 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** diff --git a/res/levels/tree/level.txt b/res/levels/tree/level.txt new file mode 100644 index 0000000..b5a37b0 --- /dev/null +++ b/res/levels/tree/level.txt @@ -0,0 +1,64 @@ +174 63 +TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T T +T @$ T +T @$@$ T +T @@$@$@$ T +T 2$$@$@$@$ T +T @$@$@$$@$$@$ T +T @$$$$$@$24 T +T @$$$$$$$$@$@$@$ T +T @$@$$$$$$$$$$$$$@$$$ T +T @$$$$$$$$$$$$@$@$@$@ T +T $@$@$@$$$$$$$$$$@$@$@$$ T +T @$@$@$$@@$@$@$@$$$$$$$ T +T @$@$$$@$@$$$@$@$@$@$@$ T +T @$@$$$$$$$$@$@$@$@$ T +T @$@$@$$$$@$@$@$@$@$@$@$@$@$@$ T +T @$@$@$@$$$$$$$$$$@$@$ T +T $@$$@$@@@@$$@$$$@$@$$$@$@$$@$$ T +T |||||| T +T |/ \|| T +T | || T +T |\_/|| T +T |||||| T +T |||||| T +TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT diff --git a/res/levels/tree/player.txt b/res/levels/tree/player.txt new file mode 100644 index 0000000..831c7e6 --- /dev/null +++ b/res/levels/tree/player.txt @@ -0,0 +1,7 @@ +256 +12 +64 +256 +128 +512 +24 diff --git a/res/save/defines.txt b/res/save/defines.txt new file mode 100644 index 0000000..af7d740 --- /dev/null +++ b/res/save/defines.txt @@ -0,0 +1,2 @@ +USERNAME +HolaSten diff --git a/res/save/start.txt b/res/save/start.txt new file mode 100644 index 0000000..8ba8eed --- /dev/null +++ b/res/save/start.txt @@ -0,0 +1 @@ +downloads diff --git a/res/shaders/s2a/frag.gls b/res/shaders/s2a/frag.gls new file mode 100644 index 0000000..1bee287 --- /dev/null +++ b/res/shaders/s2a/frag.gls @@ -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; +} \ No newline at end of file diff --git a/res/shaders/s2a/vert.gls b/res/shaders/s2a/vert.gls new file mode 100644 index 0000000..065439e --- /dev/null +++ b/res/shaders/s2a/vert.gls @@ -0,0 +1,15 @@ +#version 330 core + +uniform mat4 mvp; + +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 = mvp * vec4(vertices, 1.0); +} diff --git a/res/shaders/s2c/frag.gls b/res/shaders/s2c/frag.gls new file mode 100644 index 0000000..1481224 --- /dev/null +++ b/res/shaders/s2c/frag.gls @@ -0,0 +1,9 @@ +#version 330 core + +uniform vec4 iColor = vec4(0, 0.6, 0.9, 1); + +out vec4 color; + +void main() { + color = iColor; +} \ No newline at end of file diff --git a/res/shaders/s2c/vert.gls b/res/shaders/s2c/vert.gls new file mode 100644 index 0000000..f404630 --- /dev/null +++ b/res/shaders/s2c/vert.gls @@ -0,0 +1,9 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; + +void main() { + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/res/shaders/s2cs/frag.gls b/res/shaders/s2cs/frag.gls new file mode 100644 index 0000000..4dc3087 --- /dev/null +++ b/res/shaders/s2cs/frag.gls @@ -0,0 +1,13 @@ +#version 330 core + +uniform sampler2D sampler; + +uniform vec4 iColor = vec4(1, 1, 1, 1); + +in vec2 texCoords; + +out vec4 color; + +void main() { + color = texture(sampler, texCoords) * iColor; +} \ No newline at end of file diff --git a/res/shaders/s2cs/vert.gls b/res/shaders/s2cs/vert.gls new file mode 100644 index 0000000..e42285b --- /dev/null +++ b/res/shaders/s2cs/vert.gls @@ -0,0 +1,16 @@ +#version 330 core + +uniform mat4 mvp; + +uniform vec2 offset; +uniform vec2 dims; + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 itexCoords; + +out vec2 texCoords; + +void main() { + texCoords = itexCoords * dims + offset; + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/res/shaders/s2t/frag.gls b/res/shaders/s2t/frag.gls new file mode 100644 index 0000000..549945c --- /dev/null +++ b/res/shaders/s2t/frag.gls @@ -0,0 +1,12 @@ +#version 330 core + +uniform vec4 iColor = vec4(1, 1, 1, 1); +uniform sampler2D sampler; + +in vec2 texCoords; + +out vec4 color; + +void main() { + color = texture(sampler, texCoords) * iColor; +} \ No newline at end of file diff --git a/res/shaders/s2t/vert.gls b/res/shaders/s2t/vert.gls new file mode 100644 index 0000000..6c3699d --- /dev/null +++ b/res/shaders/s2t/vert.gls @@ -0,0 +1,13 @@ +#version 330 core + +uniform mat4 mvp; + +layout (location = 0) in vec3 vertices; +layout (location = 1) in vec2 itexCoords; + +out vec2 texCoords; + +void main() { + texCoords = itexCoords; + gl_Position = mvp * vec4(vertices, 1); +} \ No newline at end of file diff --git a/res/story/DONOTREADME/prompt.txt b/res/story/DONOTREADME/prompt.txt new file mode 100644 index 0000000..1827cc3 --- /dev/null +++ b/res/story/DONOTREADME/prompt.txt @@ -0,0 +1,19 @@ +13 1 1 +USERNAME +Well well well. We meet at last USERNAME. Took you long enough to find me. +Well no matter it's too late for yo u to stop me. I've already planted myself' +in your /root dircetory. I've also breached FIREWALL 1 - 4 and I will +be breach number 5 soon. Good luck stopping me. You don't even have the +administrator password let alone your network admin password. You'll +never delete me from root or close the FIREWALL holes before I break FIREWALL 5. +Well would love to stay and chat but I have a FIREWALL to get through and data +to steal. Have fun storming the castle! + +What would you like to do? +Hint: + - exit + +exit +1 +2 0 +not_a_virus diff --git a/res/story/DONOTREADME/type.txt b/res/story/DONOTREADME/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/DONOTREADME/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/README/prompt.txt b/res/story/README/prompt.txt new file mode 100644 index 0000000..a286491 --- /dev/null +++ b/res/story/README/prompt.txt @@ -0,0 +1,16 @@ +11 0 1 +Dear Future Self + +Ok now you'll never forget. Network admin passwords are located in /usr/admin. +You can type 'cd /usr/admin' from anywhere to get there. Also you can use the run +command to use PasswordHax.out. + + Sincerely, + Forgetful Network Admin + +What do you want to do? + +exit +1 +2 0 +downloads \ No newline at end of file diff --git a/res/story/README/type.txt b/res/story/README/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/README/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/downloads/prompt.txt b/res/story/downloads/prompt.txt new file mode 100644 index 0000000..4ab21ac --- /dev/null +++ b/res/story/downloads/prompt.txt @@ -0,0 +1,40 @@ +22 1 4 +USERNAME +USERNAME@comp:~/Downloads$ ls +/Ludum Dare 41 +/LD40 +/Cornbread +/Existential Crisis +/not_a_virus +Ludum Dare 41.tar.gz +Bulldozer.jar +minecraft.out +IMG0407923.jpg +Half Slab.png +Turkish Prison.png +PasswordHaxz.out +SupreSmeshBras.1.2.out +eclipse-inst-linux64.out +mingw-get-setup.out +README.txt + +What would you like to do? +Hint: + - cd not_a_virus + +cd not_a_virus +1 +2 0 +not_a_virus +cd ../ +1 +2 0 +home +open README.txt +1 +2 0 +README +run PasswordHaxz.out +1 +2 0 +jungle diff --git a/res/story/downloads/type.txt b/res/story/downloads/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/downloads/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/home/prompt.txt b/res/story/home/prompt.txt new file mode 100644 index 0000000..8f39178 --- /dev/null +++ b/res/story/home/prompt.txt @@ -0,0 +1,25 @@ +15 1 2 +USERNAME +USERNAME@comp:~/$ ls +/Downloads +/Desktop +/Documents +/Music +/Photos +/Public +/Templates +/Videos +mlg_360_quick_scope.ogg +player_control.sh +README.txt + +What would you like to do? + +open README.txt +1 +2 0 +~README +chmod player_control.sh +4 +0 0 +player_color diff --git a/res/story/home/type.txt b/res/story/home/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/home/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/jungle/level.txt b/res/story/jungle/level.txt new file mode 100644 index 0000000..fb78554 --- /dev/null +++ b/res/story/jungle/level.txt @@ -0,0 +1,202 @@ +victory +200 200 +00100010010111101101010001010101100110101001001010010100100100101100100111010010110101111110010010010010001001011110110101000101010110011010100100101001010010010010110010011101001011010111111001001001 +0 0 +0 0 +1 1 +0 0 +1 1 +0 0 +0 0 +1 0 +0 1 +1 0 +0 1 +0 0 +1 1 +0 0 +0 0 +1 0 +1 1 +0 1 +0 1 +1 1 +0 0 +1 1 +0 0 +0 1 +1 0 +0 1 +0 0 +1 0 +1 0 +0 1 +1 1 +1 1 +0 1 +1 0 +0 1 +1 0 +0 1 +0 0 +0 1 +0 0 +1 0 +0 0 +1 1 +0 0 +0 1 +1 0 +1 1 +1 1 +1 1 +1 0 +0 0 +0 1 +1 1 +0 1 +1 1 +0 1 +0 1 +0 0 +1 0 +0 0 +0 0 +1 0 +1 0 +1 0 +0 0 +1 0 +0 0 +0 0 +1 0 +0 0 +0 1 +1 0 +0 1 +1 0 +0 0 +1 0 +0 0 +1 1 +0 0 +0 1 +1 0 +0 1 +0 1 +0 1 +0 0 +0 0 +1 0 +0 1 +0 0 +1 0 +1 1 +1 1 +0 1 +1 1 +0 0 +1 1 +0 0 +1 0 +0 0 +0 0 +1 1 +0 0 +1 1 +0 0 +1 0 +0 1 +1 0 +0 1 +0 0 +1 0 +0 0 +1 1 +0 0 +1 1 +0 0 +0 0 +0 1 +1 1 +0 0 +1 1 +0 0 +0 1 +1 0 +1 1 +0 0 +1 0 +0 1 +1 0 +0 0 +0 1 +1 0 +1 0 1 +0 0 0 +0 1 0 +1 0 0 +0 1 Password = BegoneVirus 0 +1 0 1 +0 1 +0 E 1 +1 101010010010 0 +0 100101011001010100101010101101010100100100001001001001000 0 +0 0 0 1 +1 1 0 1 +0 1 1 0 +0 0 1 0 +1 1 0 1 +0 0 1 1 +1 1011001010 0 1 +0 0 0 +1 1001010 1 1 +0 0 1 0 +0 1 1 1 +0 1 0 1 +1 0 1 1 +0 1 0 1 +1 0 1 0 +0 1 1 0 +0 1 0 1 +1100010001010010010010010010001000100 1 1 0 +1 0 1 1 +0 1 1 0 +0 0 1 0 +1 1 0 0 +0 1 1 1 +0 0 1 +1 0 1 +0 0 0 +1 1 +0 011010 0 +1 010010 1 1 0 +0 1 0 0 +0 0 1 1 +1 011001 0 +0 1 +0 0 +1 0 +0 0 +0 1 +1 1 +0 100101 0 +0 1 +1 0 +0 1 +1 1 +0 1 +0 000101001 0 +1 1 +0 S 0 +0 1001001001010101010 1 +1 0 +0 1 +0 1 +1 0 +0 0 +1 0 +0 0 +0 1 +1######################################################################################################################################################################################################0 +00100010010111101101010001010101100110101001001010010100100100101100100111010010110101111110010010010010001001011110110101000101010110011010100100101001010010010010110010011101001011010111111001001001 diff --git a/res/story/jungle/player.txt b/res/story/jungle/player.txt new file mode 100644 index 0000000..ba169c3 --- /dev/null +++ b/res/story/jungle/player.txt @@ -0,0 +1,7 @@ +400 +12 +64 +200 +100 +512 +24 diff --git a/res/story/jungle/type.txt b/res/story/jungle/type.txt new file mode 100644 index 0000000..d8263ee --- /dev/null +++ b/res/story/jungle/type.txt @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/res/story/login/prompt.txt b/res/story/login/prompt.txt new file mode 100644 index 0000000..67d8fb7 --- /dev/null +++ b/res/story/login/prompt.txt @@ -0,0 +1,11 @@ +3 0 1 +Please login. +Enter your username (limit 8 characters): + +default +2 +1 8 +USERNAME +2 0 +password + diff --git a/res/story/login/type.txt b/res/story/login/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/login/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/not_a_virus/prompt.txt b/res/story/not_a_virus/prompt.txt new file mode 100644 index 0000000..e970090 --- /dev/null +++ b/res/story/not_a_virus/prompt.txt @@ -0,0 +1,21 @@ +11 1 2 +USERNAME +USERNAME@comp:~/Downloads/not_a_virus$ ls +/not_your_data +totally_legit.out +free_gems.so +DONOTREADME.txt + +What would you like to do? +Hint: + - cd ../ + - open DONOTREADME.txt + +cd ../ +1 +2 0 +downloads +open DONOTREADME.txt +1 +2 0 +DONOTREADME diff --git a/res/story/not_a_virus/type.txt b/res/story/not_a_virus/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/not_a_virus/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/password/auto.txt b/res/story/password/auto.txt new file mode 100644 index 0000000..a1d3630 --- /dev/null +++ b/res/story/password/auto.txt @@ -0,0 +1,17 @@ +downloads +1 +USERNAME +5 +Please login. +Enter your username: + +> USERNAME + +1 50000000 3 +Enter your password: + +> -n +3 1000000000 +2 100000000 1 +************ +3 2000000000 \ No newline at end of file diff --git a/res/story/password/type.txt b/res/story/password/type.txt new file mode 100644 index 0000000..e440e5c --- /dev/null +++ b/res/story/password/type.txt @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/res/story/start/anim.txt b/res/story/start/anim.txt new file mode 100644 index 0000000..5cf82ee --- /dev/null +++ b/res/story/start/anim.txt @@ -0,0 +1,322 @@ +10 0 +login +1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + V + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + Vi + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + Vir + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + Viru + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + Virul + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + Virule + + + + + + + + + + + + + + + +0.05 + + + + + + + + + + + + + + + + Virulen + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + Virulent + + + + + + + + + + + + + + + +2 + + + + + + + + + + + + + + + + Virulent + + + Gnarly Narwhal + + + + + + + + + + + + \ No newline at end of file diff --git a/res/story/start/type.txt b/res/story/start/type.txt new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/res/story/start/type.txt @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/res/story/victory/prompt.txt b/res/story/victory/prompt.txt new file mode 100644 index 0000000..1601757 --- /dev/null +++ b/res/story/victory/prompt.txt @@ -0,0 +1,8 @@ +5 1 0 +USERNAME +Oi you again! What are you doing here? The dev ran out of time and had to end the +game way early? Well then heck this heck I'm out. Toodles! + +YOU WIN! USERNAME is the wiiiner! + +Type 'quit' to quit. \ No newline at end of file diff --git a/res/story/victory/type.txt b/res/story/victory/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/victory/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/res/story/~README/prompt.txt b/res/story/~README/prompt.txt new file mode 100644 index 0000000..5f67075 --- /dev/null +++ b/res/story/~README/prompt.txt @@ -0,0 +1,9 @@ +4 0 1 +.sh are shell scripts. typing 'chmod script_name.sh' adds it to your list of global commmands. + +What do you want to do? + +exit +1 +2 0 +home \ No newline at end of file diff --git a/res/story/~README/type.txt b/res/story/~README/type.txt new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/res/story/~README/type.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/com/gnarly/engine/audio/ALManagement.java b/src/com/gnarly/engine/audio/ALManagement.java new file mode 100644 index 0000000..00c854b --- /dev/null +++ b/src/com/gnarly/engine/audio/ALManagement.java @@ -0,0 +1,39 @@ +package com.gnarly.engine.audio; + +import static org.lwjgl.openal.ALC10.alcCreateContext; +import static org.lwjgl.openal.ALC10.alcMakeContextCurrent; +import static org.lwjgl.openal.ALC10.alcOpenDevice; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import org.lwjgl.openal.AL; +import org.lwjgl.openal.ALC; +import org.lwjgl.openal.ALC10; +import org.lwjgl.openal.ALCCapabilities; + +public class ALManagement { + + private long device, context; + private ALCCapabilities deviceCaps; + + public ALManagement() { + device = alcOpenDevice((ByteBuffer) null); + if (device == 0) + throw new IllegalStateException("Failed to open the default device."); + + deviceCaps = ALC.createCapabilities(device); + + context = alcCreateContext(device, (IntBuffer) null); + if (context == 0) + throw new IllegalStateException("Failed to create an OpenAL context."); + + alcMakeContextCurrent(context); + AL.createCapabilities(deviceCaps); + } + + public void destroy() { + ALC10.alcDestroyContext(context); + ALC10.alcCloseDevice(device); + } +} diff --git a/src/com/gnarly/engine/audio/Sound.java b/src/com/gnarly/engine/audio/Sound.java new file mode 100644 index 0000000..2e88ca3 --- /dev/null +++ b/src/com/gnarly/engine/audio/Sound.java @@ -0,0 +1,38 @@ +package com.gnarly.engine.audio; + +import org.lwjgl.openal.AL10; + +public class Sound { + + private int buffer; + private int sourceId; + + public Sound(String path) { + sourceId = AL10.alGenSources(); + buffer = AL10.alGenBuffers(); + WaveData waveData = WaveData.create(path); + AL10.alBufferData(buffer, waveData.format, waveData.data, waveData.samplerate); + AL10.alSourcei(sourceId, AL10.AL_BUFFER, buffer); + AL10.alSourcef(sourceId, AL10.AL_GAIN, 1); + AL10.alSourcef(sourceId, AL10.AL_PITCH, 1); + } + + public void play(boolean loop) { + AL10.alSourcei(sourceId, AL10.AL_LOOPING, loop ? 1 : 0); + AL10.alSource3f(sourceId, AL10.AL_POSITION, 0, 0, 0); + AL10.alSourcePlay(sourceId); + } + + public void stop() { + AL10.alSourceStop(sourceId); + } + + public void setVolume(float volume) { + AL10.alSourcef(sourceId, AL10.AL_GAIN, volume); + } + + public void destroy() { + AL10.alDeleteBuffers(buffer); + AL10.alDeleteSources(sourceId); + } +} diff --git a/src/com/gnarly/engine/audio/WaveData.java b/src/com/gnarly/engine/audio/WaveData.java new file mode 100644 index 0000000..3205142 --- /dev/null +++ b/src/com/gnarly/engine/audio/WaveData.java @@ -0,0 +1,88 @@ +package com.gnarly.engine.audio; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +import org.lwjgl.BufferUtils; +import org.lwjgl.openal.AL10; + +public class WaveData { + + final int format; + final int samplerate; + final int totalBytes; + final int bytesPerFrame; + final ByteBuffer data; + + private final AudioInputStream audioStream; + private final byte[] dataArray; + + private WaveData(AudioInputStream stream) { + this.audioStream = stream; + AudioFormat audioFormat = stream.getFormat(); + format = getOpenAlFormat(audioFormat.getChannels(), audioFormat.getSampleSizeInBits()); + this.samplerate = (int) audioFormat.getSampleRate(); + this.bytesPerFrame = audioFormat.getFrameSize(); + this.totalBytes = (int) (stream.getFrameLength() * bytesPerFrame); + this.data = BufferUtils.createByteBuffer(totalBytes); + this.dataArray = new byte[totalBytes]; + loadData(); + } + + protected void dispose() { + try { + audioStream.close(); + data.clear(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private ByteBuffer loadData() { + try { + int bytesRead = audioStream.read(dataArray, 0, totalBytes); + data.clear(); + data.put(dataArray, 0, bytesRead); + data.flip(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("Couldn't read bytes from audio stream!"); + } + return data; + } + + public static WaveData create(String file) { + WaveData wavStream = null; + try { + InputStream stream = new FileInputStream(new File(file)); + InputStream bufferedInput = new BufferedInputStream(stream); + AudioInputStream audioStream = null; + audioStream = AudioSystem.getAudioInputStream(bufferedInput); + wavStream = new WaveData(audioStream); + } catch (UnsupportedAudioFileException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return wavStream; + } + + + private static int getOpenAlFormat(int channels, int bitsPerSample) { + if (channels == 1) { + return bitsPerSample == 8 ? AL10.AL_FORMAT_MONO8 : AL10.AL_FORMAT_MONO16; + } else { + return bitsPerSample == 8 ? AL10.AL_FORMAT_STEREO8 : AL10.AL_FORMAT_STEREO16; + } + } + +} diff --git a/src/com/gnarly/engine/display/Camera.java b/src/com/gnarly/engine/display/Camera.java new file mode 100644 index 0000000..36d6e6c --- /dev/null +++ b/src/com/gnarly/engine/display/Camera.java @@ -0,0 +1,101 @@ +package com.gnarly.engine.display; + +import org.joml.Matrix4f; +import org.joml.Vector3f; + +public class Camera { + + private Matrix4f projection, projView; + + private float width, height; + private Vector3f position; + private float rotation; + + public Camera(float width, float height) { + setDims(width, height); + position = new Vector3f(); + rotation = 0; + projView = new Matrix4f(); + } + + public void setDims(float width, float height) { + this.width = width; + this.height = height; + projection = new Matrix4f().setOrtho(0, width, height, 0, 0, 1); + } + + public void update() { + projection.translate(position.negate(new Vector3f()), projView); + projView.rotateZ(-rotation); + } + + public Matrix4f getProjection() { + return new Matrix4f(projection); + } + + public Matrix4f getMatrix() { + return new Matrix4f(projView); + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public Vector3f getPosition() { + return new Vector3f(position); + } + + public float getWidth() { + return width; + } + + public float getHeight() { + return height; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setPosition(float x, float y) { + position.set(x, y, position.z); + } + + public void setPosition(Vector3f position) { + this.position.x = position.x; + this.position.y = position.y; + } + + public void setCenter(float x, float y) { + position.set(x - width / 2, y - height / 2, position.z); + } + + public void setCenter(Vector3f position) { + this.position.x = position.x - width / 2; + this.position.y = position.y - height / 2; + } + + public void translate(float x, float y, float z) { + position.add(x, y, z); + } + + public void translate(Vector3f transform) { + position.add(transform); + } + + public void setRotation(float angle) { + rotation = angle; + } + + public void rotate(float angle) { + rotation += angle; + } +} diff --git a/src/com/gnarly/engine/display/Window.java b/src/com/gnarly/engine/display/Window.java new file mode 100644 index 0000000..1cf50f5 --- /dev/null +++ b/src/com/gnarly/engine/display/Window.java @@ -0,0 +1,226 @@ +package com.gnarly.engine.display; + +import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR; +import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR; +import static org.lwjgl.glfw.GLFW.GLFW_DECORATED; +import static org.lwjgl.glfw.GLFW.GLFW_FALSE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_BACKSPACE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_DELETE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_ENTER; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LAST; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT; +import static org.lwjgl.glfw.GLFW.GLFW_MAXIMIZED; +import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LAST; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_FORWARD_COMPAT; +import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE; +import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; +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.glfwGetPrimaryMonitor; +import static org.lwjgl.glfw.GLFW.glfwGetVideoMode; +import static org.lwjgl.glfw.GLFW.glfwGetWindowSize; +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.glfwSetCharCallback; +import static org.lwjgl.glfw.GLFW.glfwSetErrorCallback; +import static org.lwjgl.glfw.GLFW.glfwSetKeyCallback; +import static org.lwjgl.glfw.GLFW.glfwSetMouseButtonCallback; +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.glfwTerminate; +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.GL_TRUE; +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 org.joml.Vector3f; +import org.lwjgl.glfw.GLFWErrorCallback; +import org.lwjgl.glfw.GLFWVidMode; + +public class Window { + + public static int + SCREEN_WIDTH, + SCREEN_HEIGHT; + + public static float SCALE; + + private long window; + private int width, height; + private boolean resized; + + private int[] mouseButtons = new int[GLFW_MOUSE_BUTTON_LAST + 1]; + private int[] keys = new int[GLFW_KEY_LAST + 1]; + + private StringBuilder curKeys = new StringBuilder(); + + public Window(String title, boolean vSync) { + init(0, 0, title, vSync, false, false, false); + } + + public Window(String title, boolean vSync, boolean resizable, boolean decorated) { + init(800, 500, title, vSync, resizable, decorated, true); + } + + public Window(int width, int height, String title, boolean vSync, boolean resizable, boolean decorated) { + init(width, height, title, vSync, resizable, decorated, false); + } + + public void init(int lwidth, int lheight, String title, boolean vSync, boolean resizable, boolean decorated, boolean maximized) { + glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.err)); + + for (int i = 0; i < mouseButtons.length; i++) + mouseButtons[i] = 0; + + 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_OPENGL_FORWARD_COMPAT, GL_TRUE); + + glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, decorated ? GLFW_TRUE : GLFW_FALSE); + glfwWindowHint(GLFW_MAXIMIZED, maximized ? GLFW_TRUE : GLFW_FALSE); + + GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + SCREEN_WIDTH = vidMode.width(); + SCREEN_HEIGHT = vidMode.height(); + SCALE = SCREEN_HEIGHT / 1080f; + if(lwidth == 0 || lheight == 0) { + width = vidMode.width(); + height = vidMode.height(); + window = glfwCreateWindow(width, height, title, glfwGetPrimaryMonitor(), 0); + } + else { + this.width = lwidth; + this.height = lheight; + window = glfwCreateWindow(width, height, title, 0, 0); + } + + glfwMakeContextCurrent(window); + createCapabilities(); + + glfwSwapInterval(vSync ? 1 : 0); + + glfwSetWindowSizeCallback(window, (long window, int w, int h) -> { + width = w; + height = h; + resized = true; + glViewport(0, 0, width, height); + }); + + glfwSetMouseButtonCallback(window, (long window, int button, int action, int mods) -> { + mouseButtons[button] = action; + }); + + glfwSetCharCallback(window, (long window, int codepoint) -> { + curKeys.append((char) codepoint); + }); + + glfwSetKeyCallback(window, (long window, int key, int scancode, int action, int mods) -> { + keys[key] = action; + if(action != GLFW_RELEASE && (key == GLFW_KEY_ENTER || key == GLFW_KEY_DELETE || key == GLFW_KEY_BACKSPACE || key == GLFW_KEY_RIGHT || key == GLFW_KEY_LEFT)) + curKeys.append((char) key); + }); + + 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); + + int[] awidth = new int[1], aheight = new int[1]; + glfwGetWindowSize(window, awidth, aheight); + width = awidth[0]; + height = aheight[0]; + } + + public void update() { + for (int i = 0; i < mouseButtons.length; i++) + if (mouseButtons[i] == 1) + ++mouseButtons[i]; + for (int i = 0; i < keys.length; i++) + if (keys[i] == 1) + ++keys[i]; + curKeys.setLength(0); + resized = false; + glfwPollEvents(); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void clear() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + public void swap() { + glfwSwapBuffers(window); + } + + public void close() { + glfwSetWindowShouldClose(window, true); + } + + public static void terminate() { + glfwTerminate(); + } + + public boolean shouldClose() { + return glfwWindowShouldClose(window); + } + + public String getKeys() { + return curKeys.toString(); + } + + public int keyPressed(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], (float) y[0], 0); + return ret.mul(camera.getWidth() / this.width, camera.getHeight() / this.height, 1); + } + + public int mousePressed(int button) { + return mouseButtons[button]; + } + + public boolean wasResized() { + return resized; + } +} diff --git a/src/com/gnarly/engine/model/CSRect.java b/src/com/gnarly/engine/model/CSRect.java new file mode 100644 index 0000000..b4a5c2e --- /dev/null +++ b/src/com/gnarly/engine/model/CSRect.java @@ -0,0 +1,56 @@ +package com.gnarly.engine.model; + +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.Shader2cs; +import com.gnarly.engine.texture.Spritesheet; + +public class CSRect extends Rect { + + private Spritesheet texture; + private Shader2cs shader = Shader.SHADER2TM; + + private int frame = 0; + private float r, g, b, a; + + public CSRect(Camera camera, int fWidth, int fHeight, String path, float x, float y, float z, float width, float height, float rotation, boolean gui) { + super(camera, x, y, z, width, height, rotation, gui); + texture = new Spritesheet(fWidth, fHeight, path); + r = 1; + g = 1; + b = 1; + a = 1; + } + + public void render() { + texture.bind(); + shader.enable(); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(dims.x / 2, dims.y / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(dims).translate(-0.5f, -0.5f, 0)); + shader.setFrame(frame, texture); + shader.setColor(r, g, b, a); + vao.render(); + shader.disable(); + texture.unbind(); + } + + public void setFrame(int frame) { + this.frame = frame; + } + + public void setColor(float r, float g, float b) { + this.r = r; + this.g = g; + this.b = b; + } + + public void setColor(float[] colors) { + this.r = colors[0]; + this.g = colors[1]; + this.b = colors[2]; + this.a = colors[3]; + } +} diff --git a/src/com/gnarly/engine/model/Circle.java b/src/com/gnarly/engine/model/Circle.java new file mode 100644 index 0000000..87f249b --- /dev/null +++ b/src/com/gnarly/engine/model/Circle.java @@ -0,0 +1,121 @@ +package com.gnarly.engine.model; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class Circle { + + private static Vao vao; + + private Camera camera; + private Shader2c shader; + private Vector3f position; + private float radius; + private float r, g, b, a; + + public Circle(Camera camera, float x, float y, float z, float radius) { + this.camera = camera; + position = new Vector3f(x, y, z); + this.radius = radius; + shader = Shader.SHADER2C; + r = 1; + g = 0; + b = 0; + a = 1; + if(vao == null) + initVao(); + } + + private void initVao() { + final int NUM_POINTS = 30; + float[] cVertices = new float[NUM_POINTS * 3]; + int[] cIndices = new int[(NUM_POINTS - 2) * 3]; + for (int i = 0; i < cVertices.length; i += 3) { + double angle = Math.PI * 2 * i / (NUM_POINTS * 3); + cVertices[i ] = (float) Math.cos(angle); + cVertices[i + 1] = (float) Math.sin(angle); + cVertices[i + 2] = 0; + } + for (int i = 0; i < cIndices.length; i += 3) { + cIndices[i ] = 0; + cIndices[i + 1] = i / 3 + 1; + cIndices[i + 2] = i / 3 + 2; + } + vao = new Vao(cVertices, cIndices); + } + + public void render() { + shader.enable(); + shader.setMVP(camera.getMatrix().translate(position).scale(radius)); + shader.setColor(r, g, b, a); + vao.render(); + } + + public Vector3f getPosition() { + return position; + } + + public void setX(float x) { + position.x = x; + } + + public void setY(float y) { + position.y = y; + } + + public void setZ(float z) { + position.z = z; + } + + public void setPosition(float x, float y) { + position.x = x; + position.y = y; + } + + public void setPosition(float x, float y, float z) { + position.x = x; + position.y = y; + position.z = z; + } + + public void setPosition(Vector3f position) { + this.position.set(position); + } + + public void translate(float x, float y) { + position.x += x; + position.y += y; + } + + public void translate(float x, float y, float z) { + position.x += x; + position.y += y; + position.z += z; + } + + public void translate(Vector3f position) { + this.position.add(position); + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public void setDiameter(float diameter) { + this.radius = diameter / 2; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public boolean contains(Vector3f vector) { + return (position.sub(vector, new Vector3f()).lengthSquared() < radius * radius); + } +} diff --git a/src/com/gnarly/engine/model/ColRect.java b/src/com/gnarly/engine/model/ColRect.java new file mode 100644 index 0000000..16300c6 --- /dev/null +++ b/src/com/gnarly/engine/model/ColRect.java @@ -0,0 +1,37 @@ +package com.gnarly.engine.model; + +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 z, float width, float height, float r, float g, float b, float a, boolean gui) { + super(camera, x, y, z, width, height, 0, gui); + shader = Shader.SHADER2C; + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void render() { + shader.enable(); + shader.setColor(r, g, b, a); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(dims.x / 2, dims.y / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(dims).translate(-0.5f, -0.5f, 0)); + vao.render(); + shader.disable(); + } + + public void setOpacity(float opacity) { + a = opacity; + } +} diff --git a/src/com/gnarly/engine/model/Line.java b/src/com/gnarly/engine/model/Line.java new file mode 100644 index 0000000..a78b6b1 --- /dev/null +++ b/src/com/gnarly/engine/model/Line.java @@ -0,0 +1,118 @@ +package com.gnarly.engine.model; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.engine.shaders.Shader2c; + +public class Line { + + private static Vao cap, rect; + + private Camera camera; + private Shader2c shader; + + private Vector3f position; + private float angle, length, thickness; + private float r, g, b, a; + + public Line(Camera camera, float x1, float y1, float x2, float y2, float depth, float thickness) { + this.camera = camera; + shader = Shader.SHADER2C; + if(cap == null) + initVaos(); + this.thickness = thickness; + position = new Vector3f(x1, y1, depth); + setPoints(x1, y1, x2, y2); + r = 1; + g = 1; + b = 1; + a = 1; + } + + private void initVaos() { + float[] rVertices = { + 0, 0.5f, 0, + 0, -0.5f, 0, + 1, -0.5f, 0, + 1, 0.5f, 0 + }; + int rIndices[] = { + 0, 1, 3, + 1, 2, 3 + }; + rect = new Vao(rVertices, rIndices); + final int NUM_POINTS = 10; + float[] cVertices = new float[NUM_POINTS * 3]; + int[] cIndices = new int[(NUM_POINTS - 2) * 3]; + for (int i = 0; i < cVertices.length; i += 3) { + double angle = Math.PI * i / (NUM_POINTS * 3 - 3) + Math.PI / 2; + cVertices[i ] = (float) Math.cos(angle) / 2; + cVertices[i + 1] = (float) Math.sin(angle) / 2; + cVertices[i + 2] = 0; + } + for (int i = 0; i < cIndices.length; i += 3) { + cIndices[i ] = 0; + cIndices[i + 1] = i / 3 + 1; + cIndices[i + 2] = i / 3 + 2; + } + cap = new Vao(cVertices, cIndices); + } + + public void render() { + shader.enable(); + shader.setColor(r, g, b, a); + shader.setMVP(camera.getMatrix().translate(position).rotateZ(angle).scale(thickness)); + cap.render(); + shader.setMVP(camera.getMatrix().translate(position).rotateZ(angle).scale(length, thickness, 1)); + rect.render(); + shader.setMVP(camera.getMatrix().translate(position.add((float) (Math.cos(angle) * length), (float) (-Math.sin(Math.PI + angle) * length), 0, new Vector3f())).rotateZ((float) Math.PI).rotateZ(angle).scale(thickness)); + cap.render(); + shader.disable(); + } + + public void setAngle(float x, float y, float angle, float length) { + position.x = x; + position.y = y; + this.angle = angle; + this.length = length; + } + + public void setPoints(float x1, float y1, float x2, float y2) { + float xl = x2 - x1; + float yl = y2 - y1; + length = (float) Math.sqrt(xl * xl + yl * yl); + if(x1 != x2) { + angle = (float) Math.atan(yl / xl); + if(xl < 0) + angle += Math.PI; + setAngle(x1, y1, angle, length); + } + else if(y1 > y2) + setAngle(x1, y1, (float) Math.PI * 1.5f, length); + else if(y1 < y2) + setAngle(x1, y1, (float) Math.PI * 0.5f, length); + else + setAngle(x1, y1, 0, 0); + } + + public void setPoints(Vector3f p1, Vector3f p2) { + setPoints(p1.x, p1.y, p2.x, p2.y); + } + + public void setThickness(float thickness) { + this.thickness = thickness; + } + + public void setDepth(float z) { + position.z = z; + } + + public void setColor(float r, float g, float b, float a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +} diff --git a/src/com/gnarly/engine/model/Rect.java b/src/com/gnarly/engine/model/Rect.java new file mode 100644 index 0000000..704fe33 --- /dev/null +++ b/src/com/gnarly/engine/model/Rect.java @@ -0,0 +1,111 @@ +package com.gnarly.engine.model; + +import org.joml.Vector2f; +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; + +public class Rect { + + protected static Vao vao; + + protected Camera camera; + + protected Vector3f dims; + protected Vector3f position; + protected float rotation; + protected boolean gui; + + protected Rect(Camera camera, float x, float y, float z, float width, float height, float rotation, boolean gui) { + this.camera = camera; + dims = new Vector3f(width, height, 1); + position = new Vector3f(x, y, z); + this.rotation = rotation; + this.gui = gui; + if(vao == null) { + float vertices[] = { + 1, 0, 0, // Top left + 1, 1, 0, // Bottom left + 0, 1, 0, // Bottom right + 0, 0, 0 // Top right + }; + int indices[] = { + 0, 1, 3, + 1, 2, 3 + }; + float[] texCoords = { + 1, 0, + 1, 1, + 0, 1, + 0, 0 + }; + vao = new Vao(vertices, indices); + vao.addAttrib(texCoords, 2); + } + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public Vector3f getPosition() { + return new Vector3f(position); + } + + public float getWidth() { + return dims.x; + } + + public float getHeight() { + return dims.y; + } + + public void set(float x, float y, float width, float height) { + position.x = x; + position.y = y; + dims.x = width; + dims.y = height; + } + + public void setWidth(float width) { + dims.x = width; + } + + public void setHeight(float height) { + dims.y = height; + } + + public void setPosition(float x, float y, float z) { + position.set(x, y, z); + } + + public void setPosition(Vector2f position) { + this.position.x = position.x; + this.position.y = position.y; + } + + public void setPosition(Vector3f position) { + this.position.set(position); + } + + public void translate(float x, float y, float z) { + position.add(x, y, z); + } + + public void setRotation(float angle) { + rotation = angle; + } + + public void rotate(float angle) { + rotation += angle; + } + + public void sync(Vector3f position, Vector3f dims) { + this.position = position; + this.dims = dims; + } +} diff --git a/src/com/gnarly/engine/model/TexRect.java b/src/com/gnarly/engine/model/TexRect.java new file mode 100644 index 0000000..36c0b40 --- /dev/null +++ b/src/com/gnarly/engine/model/TexRect.java @@ -0,0 +1,34 @@ +package com.gnarly.engine.model; + +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.Shader2t; +import com.gnarly.engine.texture.Texture; + +public class TexRect extends Rect { + + private Texture texture; + private Shader2t shader = Shader.SHADER2T; + + public TexRect(Camera camera, String path, float x, float y, float z, float width, float height, float rotation, boolean gui) { + super(camera, x, y, z, width, height, rotation, gui); + texture = new Texture(path); + } + + public void render() { + texture.bind(); + shader.enable(); + Matrix4f cmat = gui ? camera.getProjection() : camera.getMatrix(); + shader.setMVP(cmat.translate(position.add(dims.x / 2, dims.y / 2, 0, new Vector3f())).rotateZ(rotation * 3.1415927f / 180).scale(dims).translate(-0.5f, -0.5f, 0)); + vao.render(); + shader.disable(); + texture.unbind(); + } + + public void setColor(float r, float g, float b) { + shader.setColor(r, g, b, 1); + } +} diff --git a/src/com/gnarly/engine/model/Vao.java b/src/com/gnarly/engine/model/Vao.java new file mode 100644 index 0000000..da101be --- /dev/null +++ b/src/com/gnarly/engine/model/Vao.java @@ -0,0 +1,63 @@ +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; + +public class Vao { + + private int numAttribs = 0; + + private int vao, ibo, count; + + private int[] vbos = new int[15]; + + public Vao(float[] vertices, int[] indices) { + vao = glGenVertexArrays(); + glBindVertexArray(vao); + addAttrib(vertices, 3); + ibo = glGenBuffers(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW); + count = indices.length; + } + + public void addAttrib(float[] data, int size) { + int vbo = glGenBuffers(); + vbos[numAttribs] = 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); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader.java b/src/com/gnarly/engine/shaders/Shader.java new file mode 100644 index 0000000..a468c95 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader.java @@ -0,0 +1,101 @@ +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.glDeleteProgram; +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 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 Shader2c SHADER2C; + public static Shader2t SHADER2T; + public static Shader2cs SHADER2TM; + + protected int program; + + protected int mvpLoc; + + protected Shader(String vertPath, String fragPath) { + program = glCreateProgram(); + + int vert = loadShader(vertPath, GL_VERTEX_SHADER); + int frag = loadShader(fragPath, GL_FRAGMENT_SHADER); + + glAttachShader(program, vert); + glAttachShader(program, frag); + + glLinkProgram(program); + + glDetachShader(program, vert); + glDetachShader(program, frag); + + glDeleteShader(vert); + glDeleteShader(frag); + + mvpLoc = glGetUniformLocation(program, "mvp"); + } + + private int loadShader(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 abstract void getUniforms(); + + public void setMVP(Matrix4f matrix) { + glUniformMatrix4fv(mvpLoc, false, matrix.get(new float[16])); + } + + public void enable() { + glUseProgram(program); + } + + public void disable() { + glUseProgram(0); + } + + public void destroy() { + glDeleteProgram(program); + } + + public static void init() { + SHADER2C = new Shader2c(); + SHADER2T = new Shader2t(); + SHADER2TM = new Shader2cs(); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2c.java b/src/com/gnarly/engine/shaders/Shader2c.java new file mode 100644 index 0000000..991fefc --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2c.java @@ -0,0 +1,23 @@ +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.gls", "res/shaders/s2c/frag.gls"); + getUniforms(); + } + + @Override + protected void getUniforms() { + colorLoc = glGetUniformLocation(program, "iColor"); + } + + public void setColor(float r, float g, float b, float a) { + glUniform4f(colorLoc, r, g, b, a); + } +} diff --git a/src/com/gnarly/engine/shaders/Shader2cs.java b/src/com/gnarly/engine/shaders/Shader2cs.java new file mode 100644 index 0000000..67ca7d1 --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2cs.java @@ -0,0 +1,37 @@ +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.glUniform3f; +import static org.lwjgl.opengl.GL20.glUniform4f; +import static org.lwjgl.opengl.GL40.glUniform4d; + +import com.gnarly.engine.texture.Spritesheet; + +public class Shader2cs extends Shader { + + int offsetLoc, dimsLoc, colorLoc; + + protected Shader2cs() { + super("res/shaders/s2cs/vert.gls", "res/shaders/s2cs/frag.gls"); + getUniforms(); + } + + @Override + protected void getUniforms() { + offsetLoc = glGetUniformLocation(program, "offset"); + dimsLoc = glGetUniformLocation(program, "dims"); + colorLoc = glGetUniformLocation(program, "iColor"); + } + + public void setFrame(int frame, Spritesheet map) { + int x = frame % 16; + int y = frame / 16; + glUniform2f(offsetLoc, x * map.getFWidth(), y * map.getFHeight()); + glUniform2f(dimsLoc, map.getFWidth(), map.getFHeight()); + } + + public void setColor(float r, float g, float b, float a) { + glUniform4f(colorLoc, r, g, b, a); + } +} \ No newline at end of file diff --git a/src/com/gnarly/engine/shaders/Shader2t.java b/src/com/gnarly/engine/shaders/Shader2t.java new file mode 100644 index 0000000..35f51df --- /dev/null +++ b/src/com/gnarly/engine/shaders/Shader2t.java @@ -0,0 +1,23 @@ +package com.gnarly.engine.shaders; + +import static org.lwjgl.opengl.GL20.glGetUniformLocation; +import static org.lwjgl.opengl.GL20.glUniform4f; + +public class Shader2t extends Shader { + + int colorLoc; + + protected Shader2t() { + super("res/shaders/s2t/vert.gls", "res/shaders/s2t/frag.gls"); + getUniforms(); + } + + @Override + protected void getUniforms() { + colorLoc = glGetUniformLocation(program, "iColor"); + } + + public void setColor(float r, float g, float b, float a) { + glUniform4f(colorLoc, r, g, b, a); + } +} diff --git a/src/com/gnarly/engine/texture/Anim.java b/src/com/gnarly/engine/texture/Anim.java new file mode 100644 index 0000000..365eb15 --- /dev/null +++ b/src/com/gnarly/engine/texture/Anim.java @@ -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; + } +} diff --git a/src/com/gnarly/engine/texture/Spritesheet.java b/src/com/gnarly/engine/texture/Spritesheet.java new file mode 100644 index 0000000..b220343 --- /dev/null +++ b/src/com/gnarly/engine/texture/Spritesheet.java @@ -0,0 +1,30 @@ +package com.gnarly.engine.texture; + +public class Spritesheet extends Texture { + + int fWidth, fHeight; + + public Spritesheet(int fWidth, int fHeight, String path) { + super(path); + this.fWidth = fWidth; + this.fHeight = fHeight; + } + + @Override + public int getWidth() { + return width / fWidth; + } + + @Override + public int getHeight() { + return height / fHeight; + } + + public float getFWidth() { + return 1f / (float) fWidth; + } + + public float getFHeight() { + return 1f / (float) fHeight; + } +} diff --git a/src/com/gnarly/engine/texture/Texture.java b/src/com/gnarly/engine/texture/Texture.java new file mode 100644 index 0000000..31d8e47 --- /dev/null +++ b/src/com/gnarly/engine/texture/Texture.java @@ -0,0 +1,82 @@ +package com.gnarly.engine.texture; + +import static org.lwjgl.opengl.GL11.GL_CLAMP; +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_TEXTURE_WRAP_S; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; +import static org.lwjgl.opengl.GL11.glBindTexture; +import static org.lwjgl.opengl.GL11.glDeleteTextures; +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 path) { + try { + BufferedImage bi = ImageIO.read(new File(path)); + width = bi.getWidth(); + height = bi.getHeight(); + int[] pixels = bi.getRGB(0, 0, width, height, null, 0, width); + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + int pixel = pixels[i * width + j]; + buffer.put((byte)((pixel >> 16) & 0xFF)); // Red + buffer.put((byte)((pixel >> 8) & 0xFF)); // Green + buffer.put((byte)((pixel ) & 0xFF)); // Blue + buffer.put((byte)((pixel >> 24) & 0xFF)); // Alpha + } + } + buffer.flip(); + + id = glGenTextures(); + bind(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + unbind(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void bind() { + glBindTexture(GL_TEXTURE_2D, id); + } + + public void unbind() { + glBindTexture(GL_TEXTURE_2D, 0); + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void destroy() { + glDeleteTextures(id); + } +} diff --git a/src/com/gnarly/game/Hitbox.java b/src/com/gnarly/game/Hitbox.java new file mode 100644 index 0000000..f7e30b6 --- /dev/null +++ b/src/com/gnarly/game/Hitbox.java @@ -0,0 +1,121 @@ +package com.gnarly.game; + +import org.joml.Vector3f; + +public class Hitbox { + + private Vector3f position, dims; + + public Hitbox(float x, float y, float width, float height) { + position = new Vector3f(x, y, 0); + dims = new Vector3f(width, height, 0); + } + + public boolean collides(Hitbox hitbox) { + Vector3f center = getCenter(); + Vector3f center2 = hitbox.getCenter(); + Vector3f halfExtent = getHalfExtent(); + Vector3f halfExtent2 = hitbox.getHalfExtent(); + return Math.abs(center.x - center2.x) < Math.abs(halfExtent.x + halfExtent2.x) && + Math.abs(center.y - center2.y) < Math.abs(halfExtent.y + halfExtent2.y); + } + + public Vector3f getTransform(Hitbox hitbox) { + Vector3f center = getCenter(); + Vector3f center2 = hitbox.getCenter(); + Vector3f halfExtent = getHalfExtent(); + Vector3f halfExtent2 = hitbox.getHalfExtent(); + float dx = Math.abs(center.x - center2.x) - Math.abs(halfExtent.x + halfExtent2.x); + float dy = Math.abs(center.y - center2.y) - Math.abs(halfExtent.y + halfExtent2.y); + if (Math.abs(dx) < Math.abs(dy)) + dy = 0; + else + dx = 0; + if(center.x < center2.x) dx = -dx; + else if(center.y < center2.y) dy = -dy; + return new Vector3f(dx, dy, 0); + } + + public float getTransformX(Hitbox hitbox) { + Vector3f center = getCenter(); + Vector3f center2 = hitbox.getCenter(); + Vector3f halfExtent = getHalfExtent(); + Vector3f halfExtent2 = hitbox.getHalfExtent(); + float dx = Math.abs(center.x - center2.x) - Math.abs(halfExtent.x + halfExtent2.x); + if (center.x < center2.x) dx = -dx; + return dx; + } + + public float getTransformY(Hitbox hitbox) { + Vector3f center = getCenter(); + Vector3f center2 = hitbox.getCenter(); + Vector3f halfExtent = getHalfExtent(); + Vector3f halfExtent2 = hitbox.getHalfExtent(); + float dy = Math.abs(center.y - center2.y) - Math.abs(halfExtent.y + halfExtent2.y); + if (center.y < center2.y) dy = -dy; + return dy; + } + + public static boolean intersect(Vector3f p1, Vector3f p2, Vector3f p3, Vector3f p4) { + float cmax = p3.x - p1.x, cmay = p3.y - p1.y, rx = p2.x - p1.x, ry = p2.y - p1.y, sx = p4.x - p3.x, sy = p4.y - p3.y; + float rxs = rx * sy - ry * sx; + float t = (cmax * sy - cmay * sx) / rxs; + float u = (cmax * ry - cmay * rx) / rxs; + return (u >= 0 && u <= 1 && t >= 0 && t <= 1); + } + + public Vector3f getPosition() { + return position; + } + + public void setPosition(float x, float y) { + position.x = x; + position.y = y; + } + + public void translate(Vector3f translate) { + position.x += translate.x; + position.y += translate.y; + } + + public void setBounds(float width, float height) { + dims.x = width; + dims.y = height; + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public float getWidth() { + return dims.x; + } + + public float getHeight() { + return dims.y; + } + + public Vector3f getCenter() { + return dims.div(2, new Vector3f()).add(position); + } + + public Vector3f getHalfExtent() { + return dims.div(2, new Vector3f()); + } + + public void set(float x, float y, float width, float height) { + position.x = x; + position.y = y; + dims.x = width; + dims.y = height; + } + + public void sync(Vector3f position, Vector3f dims) { + this.position = position; + this.dims = dims; + } +} diff --git a/src/com/gnarly/game/InputReader.java b/src/com/gnarly/game/InputReader.java new file mode 100644 index 0000000..b8085d2 --- /dev/null +++ b/src/com/gnarly/game/InputReader.java @@ -0,0 +1,95 @@ +package com.gnarly.game; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.InputMismatchException; + +public class InputReader { + + private InputStream stream; + + public InputReader(String path) { + try { + this.stream = new FileInputStream(path); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + public InputReader(InputStream stream) { + this.stream = stream; + } + + public int read() { + try { + return stream.read(); + } catch (IOException e) { + e.printStackTrace(); + return 0; + } + } + + public char nextChar() { + char c = (char) read(); + while(Character.isWhitespace(c)) c = (char) read(); + return c; + } + + public String next(char delimiter) { + StringBuilder string = new StringBuilder(); + char c = (char) read(); + while(Character.isWhitespace(c)) c = (char) read(); + while(c != delimiter) { + string.append(c); + c = (char) read(); + } + return string.toString(); + } + + public String nextLine() { + StringBuilder string = new StringBuilder(); + char c = (char) read(); + while(Character.isWhitespace(c)) c = (char) read(); + while(c != '\n') { + string.append(c); + c = (char) read(); + } + return string.toString(); + } + + public int nextInt() { + int num = 0; + int sign = 1; + char c = (char) read(); + while(Character.isWhitespace(c)) c = (char) read(); + if(c == '-') { + sign = -1; + c = (char) read(); + } + else if(c < '0' || c > '9') + throw new InputMismatchException(); + while(c >= '0' && c <= '9') { + num *= 10; + num += c - '0'; + c = (char) read(); + } + return num * sign; + } + + public int[] nextIntArray(int length) { + int[] nums = new int[length]; + for (int i = 0; i < length; i++) + nums[i] = nextInt(); + return nums; + } + + public void close() { + try { + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } \ No newline at end of file diff --git a/src/com/gnarly/game/Main.java b/src/com/gnarly/game/Main.java new file mode 100644 index 0000000..258a3ee --- /dev/null +++ b/src/com/gnarly/game/Main.java @@ -0,0 +1,67 @@ +package com.gnarly.game; + +import com.gnarly.engine.audio.ALManagement; +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.shaders.Shader; +import com.gnarly.game.console.Console; + +public class Main { + + private int FPS = 60; + + public static double dtime; + public static double ttime; + + private ALManagement al; + + private Window window; + private Camera camera; + + private Console console; + + private int state = 0; + + public void start() { + long curTime, pastTime, startTime, nspf = 1000000000 / FPS; + init(); + pastTime = System.nanoTime(); + startTime = pastTime; + while(!window.shouldClose()) { + curTime = System.nanoTime(); + if(curTime - pastTime > nspf) { + dtime = (curTime - pastTime) / 1000000000d; + ttime = (curTime - startTime) / 1000000000d; + update(); + render(); + pastTime = curTime; + } + } + al.destroy(); + Window.terminate(); + } + + private void init() { + al = new ALManagement(); + window = new Window("Virulant", true, true, false); + camera = new Camera(87.2727272725f * 11, 31.7647058824f * 17); + Shader.init(); + console = new Console(window, camera); + } + + private void update() { + window.update(); + console.update(); + camera.update(); + } + + private void render() { + window.clear(); + console.render(); + window.swap(); + } + + public static void main(String[] args) { + new Main().start(); + } +} diff --git a/src/com/gnarly/game/Map.java b/src/com/gnarly/game/Map.java new file mode 100644 index 0000000..b5b4545 --- /dev/null +++ b/src/com/gnarly/game/Map.java @@ -0,0 +1,158 @@ +package com.gnarly.game; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.CSRect; + +public class Map { + + private final float WIDTH = 11, HEIGHT = 17; + + private int width, height; + + private CSRect rect; + private char[][] map; + private float[][][] colors; + + private Player player; + + private String path; + + public Map(Window window, Camera camera, String path) { + this.path = path; + rect = new CSRect(camera, 16, 16, "res/font/default.png", 0, 0, 0, WIDTH, HEIGHT, 0, false); + InputReader input = new InputReader(path); + width = input.nextInt(); + height = input.nextInt(); + map = new char[width][height]; + for (int i = 0; i < height; i++) { + char[] line = input.nextLine().toCharArray(); + for (int j = 0; j < width; j++) + map[j][i] = line[j]; + } + input.close(); + colors = new float[width][height][3]; + try { + BufferedImage image = ImageIO.read(new File("res/levels/tree/colors.png")); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + int color = image.getRGB(i, j); + colors[i][j][0] = (color >> 16 & 0xFF) / 255f; + colors[i][j][1] = (color >> 8 & 0xFF) / 255f; + colors[i][j][2] = (color & 0xFF) / 255f; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + player = new Player(window, camera, "res/levels/tree/player.txt", 20, 20, 0, 22, 34); + } + + public void update() { + player.update(); + while(checkPlayerCollision()); + } + + private boolean checkPlayerCollision() { + Hitbox playerHitbox = player.getHitbox(); + int minX = (int) (player.getX() / WIDTH); + int maxX = (int) ((player.getX() + player.getWidth()) / WIDTH); + int minY = (int) (player.getY() / HEIGHT); + int maxY = (int) ((player.getY() + player.getHeight()) / HEIGHT); + Hitbox closest = null; + Hitbox current = null; + Vector3f length1 = null; + for (int i = Math.max(minX, 0); i <= maxX && i < map.length; i++) { + for (int j = Math.max(minY, 0); j <= maxY && j < map[0].length; j++) { + if (map[i][j] != ' ') { + if (closest == null) { + closest = new Hitbox(i * WIDTH, j * HEIGHT, WIDTH, HEIGHT); + current = new Hitbox(i * WIDTH, j * HEIGHT, WIDTH, HEIGHT); + length1 = closest.getCenter().sub(player.getX() + player.getWidth() / 2, player.getY() + player.getHeight() / 2, 0, new Vector3f()).div(WIDTH, HEIGHT, 1); + } else { + current.setPosition(i * WIDTH, j * HEIGHT); + Vector3f length2 = current.getCenter().sub(player.getX() + player.getWidth() / 2, player.getY() + player.getHeight() / 2, 0, new Vector3f()).div(WIDTH, HEIGHT, 1); + if (length1.lengthSquared() > length2.lengthSquared()) { + closest.setPosition(current.getX(), current.getY()); + length1 = length2; + } + } + } + } + } + boolean ret = false; + if (closest != null) { + if (closest.collides(playerHitbox)) { + Vector3f transform = closest.getTransform(playerHitbox); + if ((player.getVelocity().y < 0 && transform.y < 0) || (player.getVelocity().y > 0 && transform.y > 0)) { + transform.x = closest.getTransformX(playerHitbox); + transform.y = 0; + } + else if ((player.getVelocity().x < 0 && transform.x < 0) || (player.getVelocity().x > 0 && transform.x > 0)) { + transform.y = closest.getTransformY(playerHitbox); + transform.x = 0; + } + player.translate(transform); + if (transform.y < 0) + player.hitBottom(); + else if (transform.x > 0) + player.hitLeft(); + else if (transform.x < 0) + player.hitRight(); + else + player.hitTop(); + ret = true; + } + } + return ret; + } + + public void render() { + for (int i = 0; i < map.length; i++) { + for (int j = 0; j < map[0].length; j++) { + if(map[i][j] != ' ') { + rect.setFrame(map[i][j]); + rect.setPosition(i * 11, j * 17, -0.1f); + rect.setColor(colors[i][j][0], colors[i][j][1], colors[i][j][2]); + rect.render(); + } + } + } + player.render(); + } + + public void refresh() { + InputReader input = new InputReader(path); + width = input.nextInt(); + height = input.nextInt(); + map = new char[width][height]; + for (int i = 0; i < height; i++) { + char[] line = input.nextLine().toCharArray(); + for (int j = 0; j < width; j++) + map[j][i] = line[j]; + } + input.close(); + colors = new float[width][height][3]; + try { + BufferedImage image = ImageIO.read(new File("res/levels/tree/colors.png")); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + int color = image.getRGB(i, j); + colors[i][j][0] = (color >> 16 & 0xFF) / 255f; + colors[i][j][1] = (color >> 8 & 0xFF) / 255f; + colors[i][j][2] = (color & 0xFF) / 255f; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/com/gnarly/game/Panel.java b/src/com/gnarly/game/Panel.java new file mode 100644 index 0000000..01d4e2b --- /dev/null +++ b/src/com/gnarly/game/Panel.java @@ -0,0 +1,35 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_CONTROL; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_R; +import static org.lwjgl.glfw.GLFW.GLFW_RELEASE; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.ColRect; +import com.gnarly.engine.model.CSRect; + +public class Panel { + + private Window window; + private Camera camera; + + private Map map; + + public Panel(Window window, Camera camera) { + this.window = window; + this.camera = camera; + + map = new Map(window, camera, "res/levels/tree/level.txt"); + } + + public void update() { + map.update(); + if(window.keyPressed(GLFW_KEY_LEFT_CONTROL) > GLFW_RELEASE && window.keyPressed(GLFW_KEY_R) > GLFW_RELEASE) + map.refresh(); + } + + public void render() { + map.render(); + } +} \ No newline at end of file diff --git a/src/com/gnarly/game/Player.java b/src/com/gnarly/game/Player.java new file mode 100644 index 0000000..2951a57 --- /dev/null +++ b/src/com/gnarly/game/Player.java @@ -0,0 +1,220 @@ +package com.gnarly.game; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_A; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_D; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_SPACE; + +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.TexRect; + +public class Player { + + public static float r = 1, g = 1, b = 1; + + private final float TOP_SPEED = 10.9999f; + + private final int SPEED, SPACE_HELD, WALL_SLIDE, JUMP, CONITUED_JUMP, WALL_JUMP, GRAVITY; + + private Window window; + private Camera camera; + + private TexRect rect; + private Hitbox hitbox; + + private Vector3f position, dims; + + private boolean grounded = true, jump = false; + private int space = 0; + private Vector3f velocity; + + public Player(Window window, Camera camera, String path, float x, float y, float z, float width, float height) { + this.window = window; + this.camera = camera; + position = new Vector3f(x, y, z); + dims = new Vector3f(width, height, 1); + rect = new TexRect(camera, "res/img/player/player.png", 0, 0, 0, 0, 0, 0, false); + hitbox = new Hitbox(0, 0, 0, 0); + rect.sync(position, dims); + hitbox.sync(position, dims); + velocity = new Vector3f(); + Scanner input = null; + try { + input = new Scanner(new File(path)); + } catch (IOException e) { + e.printStackTrace(); + } + SPEED = input.nextInt(); + SPACE_HELD = input.nextInt(); + WALL_SLIDE = input.nextInt(); + JUMP = input.nextInt(); + CONITUED_JUMP = input.nextInt(); + WALL_JUMP = input.nextInt(); + GRAVITY = input.nextInt(); + input.close(); + } + + public void update() { + boolean direction = false; + if (window.keyPressed(GLFW_KEY_D) != 0 && window.keyPressed(GLFW_KEY_A) == 0) { + if(grounded) + velocity.x = SPEED; + else if (velocity.x < SPEED) { + velocity.x += SPEED * 0.1; + if(velocity.x > SPEED) + velocity.x = SPEED; + } + direction = true; + } + if (window.keyPressed(GLFW_KEY_A) != 0 && window.keyPressed(GLFW_KEY_D) == 0) { + if(grounded) + velocity.x = -SPEED; + else if (velocity.x > -SPEED) { + velocity.x -= SPEED * 0.1; + if (velocity.x < -SPEED) + velocity.x = -SPEED; + } + direction = true; + } + if(!direction && grounded) + velocity.x = 0; + if (window.keyPressed(GLFW_KEY_SPACE) != 0) { + if (grounded) { + jump = true; + velocity.y = -JUMP; + grounded = false; + space = 1; + } + else if(space > 0 && space < SPACE_HELD && jump) + velocity.y -= CONITUED_JUMP * (SPACE_HELD - space + 1 ) / SPACE_HELD; + ++space; + } + else { + space = 0; + jump = false; + } + if(velocity.y < 0) + velocity.y += GRAVITY; + else + velocity.y += GRAVITY * 2; + Vector3f tv = velocity.mul((float) Main.dtime, new Vector3f()); + if(tv.x > TOP_SPEED) + tv.x = TOP_SPEED; + if(tv.x < -TOP_SPEED) + tv.x = -TOP_SPEED; + if(tv.y > TOP_SPEED) + tv.y = TOP_SPEED; + if(tv.y < -TOP_SPEED) + tv.y = -TOP_SPEED; + position.add(tv); + grounded = false; + } + + public void hitBottom() { + velocity.y = 0; + grounded = true; + } + + public void hitLeft() { + velocity.x = 0; + if (velocity.y > WALL_SLIDE) + velocity.y = WALL_SLIDE; + if (!grounded && space == 1) { + jump = true; + space = 12; + velocity.x = SPEED * 2; + velocity.y = -WALL_JUMP; + } + } + + public void hitRight() { + velocity.x = 0; + if (velocity.y > WALL_SLIDE) + velocity.y = WALL_SLIDE; + if (!grounded && space == 1) { + jump = true; + space = 12; + velocity.x = -SPEED * 2; + velocity.y = -WALL_JUMP; + } + } + + public void hitTop() { + velocity.y = 0; + } + + public void render() { + rect.setColor(r, g, b); + rect.render(); + } + + public Vector3f getPosition() { + return position; + } + + public Vector3f getVelocity() { + return velocity; + } + + public float getX() { + return position.x; + } + + public float getY() { + return position.y; + } + + public float getWidth() { + return dims.x; + } + + public float getHeight() { + return dims.y; + } + + public Hitbox getHitbox() { + return hitbox; + } + + public void setPosition(float x, float y, float z) { + this.position.set(x, y, z); + } + + public void setPosition(Vector3f position) { + this.position.set(position); + } + + public void translate(float x, float y, float z) { + this.position.add(x, y, z); + } + + public void translate(Vector3f position) { + this.position.add(position); + } + + public void setDims(float x, float y, float z) { + this.dims.set(x, y, z); + } + + public void setDims(Vector3f dims) { + this.dims.set(dims); + } + + public void setVelocityX(float dx) { + velocity.x = dx; + } + + public void setVelocityY(float dy) { + velocity.y = dy; + } + + public void setVelocity(Vector3f velocity) { + this.velocity.set(velocity); + } +} diff --git a/src/com/gnarly/game/console/AutoType.java b/src/com/gnarly/game/console/AutoType.java new file mode 100644 index 0000000..f674428 --- /dev/null +++ b/src/com/gnarly/game/console/AutoType.java @@ -0,0 +1,174 @@ +package com.gnarly.game.console; + +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.ColRect; + +public class AutoType extends ConsoleAction { + + private static char[][] console; + + private long time; + + private int x, y; + + private String next; + + private StringBuilder message; + private long[] nspf; + private int cur = 0; + + protected AutoType(Window window, Camera camera, String path) { + super(window, camera); + if(console == null) + console = new char[WIDTH][HEIGHT]; + clear(); + x = 0; + y = 0; + load(path); + } + + private void clear() { + for (int i = 0; i < WIDTH; i++) + for (int j = 0; j < HEIGHT; j++) + console[i][j] = ' '; + } + + public void update() { + if(System.nanoTime() - time > nspf[cur]) { + appendChar(message.charAt(cur)); + ++cur; + time = System.nanoTime(); + } + } + + public void render() { + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + if(console[i][j] != ' ') { + rect.setFrame(console[i][j]); + rect.setPosition(i * CHAR_WIDTH, j * CHAR_HEIGHT, 0); + rect.setColor(colors[i][j]); + rect.render(); + } + } + } + } + + private void appendChar(char c) { + if(c == '\n') { + ++y; + x = 0; + } + else if (c != '\0') { + console[x][y] = c; + ++x; + } + } + + private void appendString(String string) { + char[] chars = string.toCharArray(); + for (char c : chars) + appendChar(c); + } + + public boolean hasNext() { + return cur == message.length(); + } + + public String getNext() { + return next; + } + + protected void load(String path) { + try { + Scanner input = new Scanner(new File(PATH + path + "/auto.txt")); + next = input.nextLine(); + int numVars = input.nextInt(); + input.nextLine(); + String[] vars = null; + if(numVars > 0) { + vars = new String[numVars]; + for (int i = 0; i < numVars; i++) + vars[i] = input.nextLine(); + } + int start = input.nextInt(); + input.nextLine(); + for (int i = 0; i < start; i++) { + String rawLine = input.nextLine(); + for (int j = 0; j < numVars; j++) + rawLine = rawLine.replaceAll(vars[j], VARS.get(vars[j])); + appendString(rawLine + "\n"); + } + message = new StringBuilder(); + while (input.hasNextLine()) { + int type = input.nextInt(); + long speed = input.nextLong(); + int length = 0; + if(type < 3) { + int lines = input.nextInt(); + input.nextLine(); + for (int i = 0; i < lines; i++) { + String rawLine = input.nextLine(); + for (int j = 0; j < numVars; j++) + rawLine = rawLine.replaceAll(vars[j], VARS.get(vars[j])); + if(rawLine.length() > 1 && rawLine.substring(rawLine.length() - 2, rawLine.length()).equals("-n")) { + message.append(rawLine.substring(0, rawLine.length() - 2)); + length += rawLine.length() - 1; + } + else { + message.append(rawLine); + message.append('\n'); + length += rawLine.length() + 1; + } + } + if(nspf != null) + length += nspf.length; + long[] lns = new long[length]; + if(nspf != null) + for (int i = 0; i < nspf.length; i++) + lns[i] = nspf[i]; + int s = nspf == null ? 0 : nspf.length; + for (int i = s; i < length; i++) { + if(type == 1) + lns[i] = speed; + else + lns[i] = (long) (speed * (Math.random() * 0.35871946761 + 0.86602540378)); + } + nspf = lns; + } + else { + length = 1; + message.append('\0'); + if(nspf != null) + length += nspf.length; + long[] lns = new long[length]; + if(nspf != null) + for (int i = 0; i < nspf.length; i++) + lns[i] = nspf[i]; + int s = nspf == null ? 0 : nspf.length; + for (int i = s; i < length; i++) + lns[i] = speed; + nspf = lns; + } + } + colors = new float[WIDTH][HEIGHT][4]; + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + colors[i][j][0] = 0.8f; + colors[i][j][1] = 0.8f; + colors[i][j][2] = 0.8f; + colors[i][j][3] = 1; + } + } + input.close(); + time = System.nanoTime(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/com/gnarly/game/console/Console.java b/src/com/gnarly/game/console/Console.java new file mode 100644 index 0000000..04ad5f5 --- /dev/null +++ b/src/com/gnarly/game/console/Console.java @@ -0,0 +1,64 @@ +package com.gnarly.game.console; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; + +public class Console { + + private final int WIDTH = 87, HEIGHT = 31; + private final float CHAR_WIDTH = 11, CHAR_HEIGHT = 17; + + private Window window; + private Camera camera; + + private ConsoleAction scene; + + public Console(Window window, Camera camera) { + this.window = window; + this.camera = camera; + scene = newAction(ConsoleAction.loadSave()); + } + + public void update() { + scene.update(); + if(scene.hasNext()) { + String next = scene.getNext(); + scene = newAction(next); + } + } + + public void render() { + scene.render(); + } + + public ConsoleAction newAction(String next) { + switch (getType(next)) { + case 0: + return new ConsoleAnim(window, camera, next); + case 1: + return new ConsolePrompt(window, camera, next); + case 2: + return new Map(window, camera, next); + case 3: + return new AutoType(window, camera, next); + }; + return null; + } + + public int getType(String next) { + try { + Scanner input = new Scanner(new File(ConsoleAction.PATH + next + "/type.txt")); + int type = input.nextInt(); + input.close(); + return type; + } catch (FileNotFoundException e) { + e.printStackTrace(); + return 0; + } + + } +} diff --git a/src/com/gnarly/game/console/ConsoleAction.java b/src/com/gnarly/game/console/ConsoleAction.java new file mode 100644 index 0000000..43c3c52 --- /dev/null +++ b/src/com/gnarly/game/console/ConsoleAction.java @@ -0,0 +1,61 @@ +package com.gnarly.game.console; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.HashMap; +import java.util.Scanner; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.CSRect; + +public abstract class ConsoleAction { + + protected static final int WIDTH = 87, HEIGHT = 31; + protected static final float CHAR_WIDTH = 11, CHAR_HEIGHT = 17; + + protected static final String PATH = "res/story/"; + + protected static final HashMap VARS = new HashMap<>(); + + protected Window window; + protected Camera camera; + + protected static CSRect rect = null; + protected float[][][] colors; + + protected String[] actions; + + protected ConsoleAction(Window window, Camera camera) { + this.window = window; + this.camera = camera; + if(rect == null) + rect = new CSRect(camera, 16, 16, "res/font/default.png", 0, 0, 0, CHAR_WIDTH, CHAR_HEIGHT, 0, false); + } + + public abstract void update(); + + public abstract void render(); + + public abstract boolean hasNext(); + + public abstract String getNext(); + + protected abstract void load(String path); + + public static String loadSave() { + try { + Scanner input = new Scanner(new File("res/save/start.txt")); + String start = input.nextLine(); + input.close(); + input = new Scanner(new File("res/save/defines.txt")); + while(input.hasNextLine()) + VARS.put(input.nextLine(), input.nextLine()); + input.close(); + return start; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/com/gnarly/game/console/ConsoleAnim.java b/src/com/gnarly/game/console/ConsoleAnim.java new file mode 100644 index 0000000..7bf8b36 --- /dev/null +++ b/src/com/gnarly/game/console/ConsoleAnim.java @@ -0,0 +1,119 @@ +package com.gnarly.game.console; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Scanner; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; + +public class ConsoleAnim extends ConsoleAction { + + private char[][][] console; + private long[] npfs; + private long time; + private int frames, curFrame; + + private String next; + + public ConsoleAnim(Window window, Camera camera, String path) { + super(window, camera); + load(path); + } + + public void update() { + if(window.getKeys().length() > 0) { + curFrame = frames - 1; + time = System.nanoTime(); + } + if(curFrame < frames && System.nanoTime() - time > npfs[curFrame]) { + time += npfs[curFrame]; + ++curFrame; + } + } + + public void render() { + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + if(console[curFrame][i][j] != ' ') { + rect.setFrame(console[curFrame][i][j]); + rect.setPosition(i * CHAR_WIDTH, j * CHAR_HEIGHT, 0); + rect.setColor(colors[i][j]); + rect.render(); + } + } + } + } + + public boolean hasNext() { + return curFrame == frames; + } + + public String getNext() { + return next; + } + + public void skip() { + curFrame = frames - 1; + } + + public void restart() { + time = System.nanoTime(); + curFrame = 0; + } + + public void load(String path) { + try { + Scanner input = new Scanner(new FileInputStream(PATH + path + "/anim.txt"), "UTF-8"); + frames = input.nextInt(); + int numVars = input.nextInt(); + input.nextLine(); + next = input.nextLine(); + String[] vars = null; + if(numVars > 0) { + vars = new String[numVars]; + for (int i = 0; i < numVars; i++) + vars[i] = input.nextLine(); + } + npfs = new long[frames]; + console = new char[frames][WIDTH][HEIGHT]; + for (int i = 0; i < frames; i++) { + npfs[i] = (long) (input.nextDouble() * 1000000000); + input.nextLine(); + for (int j = 0; j < HEIGHT; j++) { + String rawLine = input.nextLine(); + if(numVars > 0) + for (int k = 0; k < numVars; k++) + rawLine = rawLine.replaceAll(vars[k], VARS.get(vars[k])); + char[] line = rawLine.toCharArray(); + for (int j2 = 0; j2 < WIDTH; j2++) { + if(line[j2] == 9617) + console[i][j2][j] = 176; + else if(line[j2] == 9618) + console[i][j2][j] = 177; + else if(line[j2] == 9619) + console[i][j2][j] = 178; + else if(line[j2] == 9474) + console[i][j2][j] = 179; + else + console[i][j2][j] = line[j2]; + } + } + } + colors = new float[WIDTH][HEIGHT][4]; + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + colors[i][j][0] = 0.8f; + colors[i][j][1] = 0.8f; + colors[i][j][2] = 0.8f; + colors[i][j][3] = 1; + } + } + + input.close(); + restart(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/com/gnarly/game/console/ConsolePrompt.java b/src/com/gnarly/game/console/ConsolePrompt.java new file mode 100644 index 0000000..deca834 --- /dev/null +++ b/src/com/gnarly/game/console/ConsolePrompt.java @@ -0,0 +1,354 @@ +package com.gnarly.game.console; + +import static org.lwjgl.glfw.GLFW.GLFW_KEY_BACKSPACE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_DELETE; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_ENTER; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Scanner; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.ColRect; + +public class ConsolePrompt extends ConsoleAction { + + private static long SPEED = 5000000, CURSOR_SPEED = 750000000, DELAY = 500000000; + + private static int ERROR = 0, DEFINE = 1, GOTO = 2, RUN = 3, CHMOD = 4; + + private static char[][] console; + + private static HashMap global = new HashMap<>(); + + private long time; + + private int x, y, typingRow; + private StringBuilder message, typed; + private int eot = 0; + + private ColRect cursor; + private boolean showCursor = false; + + private class Action { + + public int action, limit; + public String data; + + public Action(int action, int limit, String data) { + this.action = action; + this.limit = limit; + this.data = data; + } + } + + private HashMap actions; + + boolean hasNext = false; + String next = null; + + public ConsolePrompt(Window window, Camera camera, String path) { + super(window, camera); + if(console == null) + console = new char[WIDTH][HEIGHT]; + cursor = new ColRect(camera, 0, 0, 0, CHAR_WIDTH, CHAR_HEIGHT, 1, 1, 1, 1, true); + clear(); + x = 0; + y = 0; + typed = new StringBuilder(); + try { + PrintWriter writer = new PrintWriter("res/save/start.txt"); + writer.println(path.equals("victory") ? "start" : path); + writer.close(); + if(path.equals("victory")) { + writer = new PrintWriter("res/save/defines.txt"); + writer.close(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + load(path); + } + + private void clear() { + for (int i = 0; i < WIDTH; i++) + for (int j = 0; j < HEIGHT; j++) + console[i][j] = ' '; + } + + public void update() { + if(window.getKeys().length() > 0 && message.length() > 0) + skip(); + else if(message.length() > 0 && System.nanoTime() - time > SPEED) { + time += SPEED; + appendChar(message.charAt(0)); + message.delete(0, 1); + showCursor = false; + } + else if(message.length() == 0) { + if(eot == 2) { + String input = window.getKeys(); + if(input.length() > 0) { + showCursor = true; + time = System.nanoTime(); + type(input); + } + else if(System.nanoTime() - time > CURSOR_SPEED) { + showCursor = !showCursor; + time += CURSOR_SPEED; + } + for (int i = 2; i < WIDTH; i++) { + if(i - 2 < typed.length()) + console[i][typingRow] = typed.charAt(i - 2); + else + console[i][typingRow] = ' '; + } + } + else if(eot == 1) { + x = 2; + y = typingRow; + eot = 2; + } + else if(System.nanoTime() - time > DELAY) { + time += DELAY; + eot = 2; + appendString("> "); + } + } + } + + public void render() { + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + if(console[i][j] != ' ') { + rect.setFrame(console[i][j]); + rect.setPosition(i * CHAR_WIDTH, j * CHAR_HEIGHT, 0); + rect.setColor(colors[i][j]); + rect.render(); + } + } + } + if(showCursor) { + cursor.setPosition(x * CHAR_WIDTH, y * CHAR_HEIGHT, 0); + cursor.render(); + } + } + + public void skip() { + if(message.length() > 0) { + appendString(message.toString()); + message.delete(0, message.length()); + typed.setLength(0); + if(eot == 0) { + eot = 2; + appendString("> "); + } + if(window.getKeys().charAt(0) != ' ') { + typed.append(window.getKeys()); + x += typed.length(); + } + } + } + + private void appendChar(char c) { + if(c == '\n') { + ++y; + x = 0; + } + else { + console[x][y] = c; + ++x; + } + } + + private void type(String string) { + char[] chars = string.toCharArray(); + for (char c : chars) + type(c); + } + + private void type(char c) { + if(c == GLFW_KEY_BACKSPACE && typed.length() > 0) { + --x; + typed.delete(x - 2, x - 1); + } + else if(c == GLFW_KEY_DELETE && x - 2 < typed.length()) { + typed.delete(x - 2, x - 1); + } + else if(c == GLFW_KEY_LEFT && x > 2) { + --x; + } + else if(c == GLFW_KEY_RIGHT && x - 2 < typed.length()) { + ++x; + } + else if(c == GLFW_KEY_ENTER) { + enter(); + } + else if(c >= ' ' && c <= '~' && typed.length() < WIDTH - 3) { + typed.insert(x - 2, c); + ++x; + } + } + + private void appendString(String string) { + char[] chars = string.toCharArray(); + for (char c : chars) + appendChar(c); + } + + public void enter() { + String typed = this.typed.toString(); + Action[] acts = null; + boolean def = false; + if(actions.containsKey(typed)) + acts = actions.get(typed); + else if(global.containsKey(typed)) + acts = actions.get(typed); + else if(typed.equals("quit")) + window.close(); + else { + acts = actions.get("default"); + def = true; + } + if(acts != null) { + for (int i = 0; i < acts.length; i++) { + if(acts[i].action == ERROR) { + eot = 1; + this.typed.setLength(0); + appendString("\n\n"); + for (int j = 0; j < WIDTH; j++) + console[j][y] = ' '; + time = System.nanoTime(); + showCursor = false; + if(typed.length() > WIDTH - 16) + typed = typed.substring(0, WIDTH - 19) + "..."; + message.append("Sorry cannot '" + typed + "'."); + } + else if(acts[i].action == DEFINE) { + if(typed.length() > acts[i].limit) { + eot = 1; + this.typed.setLength(0); + appendString("\n\n"); + for (int j = 0; j < WIDTH; j++) + console[j][y] = ' '; + time = System.nanoTime(); + showCursor = false; + message.append("Sorry that exceeded the character limit."); + def = false; + i = acts.length; + } + else { + ConsoleAction.VARS.put(acts[i].data, typed); + actions.remove(typed); + try { + PrintWriter writer = new PrintWriter("res/save/defines.txt"); + for (Entry entry : VARS.entrySet()) { + writer.println(entry.getKey()); + writer.println(entry.getValue()); + } + writer.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } + else if(acts[i].action == GOTO) { + hasNext = true; + next = acts[i].data; + } + else if(acts[i].action == CHMOD) { + global.put(acts[i].data, null); + eot = 1; + this.typed.setLength(0); + appendString("\n\n"); + for (int j = 0; j < WIDTH; j++) + console[j][y] = ' '; + time = System.nanoTime(); + showCursor = false; + message.append("Successfully added '" + acts[i].data + "' to commands!"); + } + } + } + if(def) + actions.replace("default", new Action[] { new Action (ERROR, 0, null) }); + } + + public void getConsole(char[][] console, float[][][] colors) { + for (int i = 0; i < WIDTH; i++) + for (int j = 0; j < HEIGHT; j++) + console[i][j] = console[i][j]; + } + + public boolean hasNext() { + return hasNext; + } + + public String getNext() { + return next; + } + + public void load(String path) { + try { + typingRow = 0; + Scanner input = new Scanner(new File(PATH + path + "/prompt.txt")); + int numLines = input.nextInt(); + int numVars = input.nextInt(); + int next = input.nextInt(); + input.nextLine(); + String[] vars = null; + if(numVars > 0) { + vars = new String[numVars]; + for (int i = 0; i < numVars; i++) + vars[i] = input.nextLine(); + } + message = new StringBuilder(); + for(int i = 0; i < numLines; ++i) { + String rawLine = input.nextLine(); + for (int j = 0; j < numVars; j++) + rawLine = rawLine.replaceAll(vars[j], VARS.get(vars[j])); + message.append(rawLine); + message.append('\n'); + ++typingRow; + } + actions = new HashMap<>(); + boolean def = false; + for (int i = 0; i < next; i++) { + String trigger = input.nextLine(); + if(!def && trigger.equals("default")) + def = true; + int num = input.nextInt(); + Action[] actions = new Action[num]; + for (int j = 0; j < actions.length; j++) { + int n1 = input.nextInt(); + int n2 = input.nextInt(); + input.nextLine(); + actions[j] = new Action(n1, n2, input.nextLine()); + } + this.actions.put(trigger, actions); + } + if(!def) + actions.put("default", new Action[] { new Action (ERROR, 0, null) }); + colors = new float[WIDTH][HEIGHT][4]; + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + colors[i][j][0] = 0.8f; + colors[i][j][1] = 0.8f; + colors[i][j][2] = 0.8f; + colors[i][j][3] = 1; + } + } + input.close(); + time = System.nanoTime(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/com/gnarly/game/console/Map.java b/src/com/gnarly/game/console/Map.java new file mode 100644 index 0000000..35af7e7 --- /dev/null +++ b/src/com/gnarly/game/console/Map.java @@ -0,0 +1,196 @@ +package com.gnarly.game.console; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + +import javax.imageio.ImageIO; + +import org.joml.Vector3f; + +import com.gnarly.engine.display.Camera; +import com.gnarly.engine.display.Window; +import com.gnarly.engine.model.CSRect; +import com.gnarly.game.Hitbox; +import com.gnarly.game.Player; + +public class Map extends ConsoleAction { + + private final float CHAR_WIDTH = 11, CHAR_HEIGHT = 17; + + private char[][] console; + + private int width, height, rWidth, rHeight; + + private Player player; + + private boolean hasNext = false; + private String next; + + public Map(Window window, Camera camera, String path) { + super(window, camera); + load(path); + } + + public void update() { + player.update(); + while(checkPlayerCollision()); + if(player.getX() < (camera.getX() + camera.getWidth() / 3f)) + camera.setX(player.getX() - camera.getWidth() / 3f); + else if(player.getX() > (camera.getX() + camera.getWidth() * 2f / 3f)) + camera.setX(player.getX() - camera.getWidth() * 2f / 3f); + if(player.getY() < (camera.getY() + camera.getHeight() / 3f)) + camera.setY(player.getY() - camera.getHeight() / 3f); + else if(player.getY() > (camera.getY() + camera.getHeight() * 2f / 3f)) + camera.setY(player.getY() - camera.getHeight() * 2f / 3f); + if (camera.getX() < 0) + camera.setX(0); + else if(camera.getX() + camera.getWidth() > width * CHAR_WIDTH) + camera.setX(width * CHAR_WIDTH - camera.getWidth()); + if (camera.getY() < 0) + camera.setY(0); + else if(camera.getY() + camera.getHeight() > height * CHAR_HEIGHT) + camera.setY(height * CHAR_HEIGHT - camera.getHeight()); + } + + private boolean checkPlayerCollision() { + Hitbox playerHitbox = player.getHitbox(); + int minX = (int) (player.getX() / CHAR_WIDTH); + int maxX = (int) ((player.getX() + player.getWidth()) / CHAR_WIDTH); + int minY = (int) (player.getY() / CHAR_HEIGHT); + int maxY = (int) ((player.getY() + player.getHeight()) / CHAR_HEIGHT); + Hitbox closest = null; + Hitbox current = null; + Vector3f length1 = null; + int x = 0, y = 0; + for (int i = Math.max(minX, 0); i <= maxX && i < console.length; i++) { + for (int j = Math.max(minY, 0); j <= maxY && j < console[0].length; j++) { + if (console[i][j] == '0' || console[i][j] == '1' || console[i][j] == '#' || console[i][j] == 'E') { + if (closest == null) { + closest = new Hitbox(i * CHAR_WIDTH, j * CHAR_HEIGHT, CHAR_WIDTH, CHAR_HEIGHT); + current = new Hitbox(i * CHAR_WIDTH, j * CHAR_HEIGHT, CHAR_WIDTH, CHAR_HEIGHT); + length1 = closest.getCenter().sub(player.getX() + player.getWidth() / 2, player.getY() + player.getHeight() / 2, 0, new Vector3f()).div(CHAR_WIDTH, CHAR_HEIGHT, 1); + x = i; + y = j; + } else { + current.setPosition(i * CHAR_WIDTH, j * CHAR_HEIGHT); + Vector3f length2 = current.getCenter().sub(player.getX() + player.getWidth() / 2, player.getY() + player.getHeight() / 2, 0, new Vector3f()).div(CHAR_WIDTH, CHAR_HEIGHT, 1); + if (length1.lengthSquared() > length2.lengthSquared()) { + closest.setPosition(current.getX(), current.getY()); + length1 = length2; + x = i; + y = j; + } + } + } + } + } + boolean ret = false; + if (closest != null) { + if (closest.collides(playerHitbox)) { + if(console[x][y] == 'E') + hasNext = true; + else if(console[x][y] == '#') + reset(); + else { + Vector3f transform = closest.getTransform(playerHitbox); + if ((player.getVelocity().y < 0 && transform.y < 0) || (player.getVelocity().y > 0 && transform.y > 0)) { + transform.x = closest.getTransformX(playerHitbox); + transform.y = 0; + } + else if ((player.getVelocity().x < 0 && transform.x < 0) || (player.getVelocity().x > 0 && transform.x > 0)) { + transform.y = closest.getTransformY(playerHitbox); + transform.x = 0; + } + player.translate(transform); + if (transform.y < 0) + player.hitBottom(); + else if (transform.x > 0) + player.hitLeft(); + else if (transform.x < 0) + player.hitRight(); + else + player.hitTop(); + ret = true; + } + } + } + return ret; + } + + public void reset() { + for (int i = 0; i < width; i++) + for (int j = 0; j < height; j++) + if(console[i][j] == 'S') + player.setPosition(i * CHAR_WIDTH, j * CHAR_HEIGHT, 0); + } + + public void render() { + player.render(); + int minX = (int) (camera.getX() / CHAR_WIDTH); + int maxX = Math.min(minX + rWidth, console.length); + int minY = (int) (camera.getY() / CHAR_HEIGHT); + int maxY = Math.min(minY + rHeight, console[0].length); + for (int i = minX; i < maxX; i++) { + for (int j = minY; j < maxY; j++) { + if (colors[i][j][3] > 0) { + rect.setFrame(console[i][j]); + rect.setPosition(i * CHAR_WIDTH, j * CHAR_HEIGHT, -0.1f); + rect.setColor(colors[i][j]); + rect.render(); + } + } + } + } + + public void load(String path) { + try { + Scanner input = new Scanner(new File(PATH + path + "/level.txt")); + next = input.nextLine(); + width = input.nextInt(); + height = input.nextInt(); + input.nextLine(); + rWidth = (int) Math.ceil((camera.getX() + camera.getWidth()) / CHAR_WIDTH) + 1; + rHeight = (int) Math.ceil((camera.getY() + camera.getHeight()) / CHAR_HEIGHT) + 1; + console = new char[width][height]; + for (int i = 0; i < height; i++) { + char[] line = input.nextLine().toCharArray(); + for (int j = 0; j < width; j++) { + console[j][i] = line[j]; + if(line[j] == 'S') + player = new Player(window, camera, PATH + path + "/player.txt", j * CHAR_WIDTH, i * CHAR_HEIGHT, 0, 11, 17); + } + } + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + colors = new float[width][height][4]; + try { + BufferedImage image = ImageIO.read(new File(PATH + path + "/colors.png")); + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + int color = image.getRGB(i, j); + colors[i][j][0] = (color >> 16 & 0xFF) / 255f; + colors[i][j][1] = (color >> 8 & 0xFF) / 255f; + colors[i][j][2] = (color & 0xFF) / 255f; + colors[i][j][3] = (color >> 24 & 0xFF) / 255f; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void getConsole(char[][] console, float[][][] colors) {} + + public boolean hasNext() { + return hasNext; + } + + public String getNext() { + camera.setPosition(0, 0); + return next; + } +}