summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitri Morozov <snoopdesigns@gmail.com>2024-02-02 18:58:12 +0100
committerue86388 <dmitrii.morozov@sbb.ch>2024-02-02 18:58:12 +0100
commite3935fe4b6ecfbe161001fc95d295f53e8520c52 (patch)
tree0cb9525d8a616674be57aa5cc90444c081fadc03
parente55b03a924ab9dc02e2baca77ce49deae27dda6d (diff)
Initial commit
-rw-r--r--assets/badlogic.jpgbin0 -> 68465 bytes
-rw-r--r--assets/bg.pngbin0 -> 16109 bytes
-rw-r--r--assets/calibri.fnt194
-rw-r--r--assets/calibri.pngbin0 -> 26528 bytes
-rw-r--r--assets/crosshair.pngbin0 -> 777 bytes
-rw-r--r--assets/particle.pngbin0 -> 1821 bytes
-rw-r--r--assets/particles.p160
-rw-r--r--assets/ship.pngbin0 -> 1410 bytes
-rw-r--r--build.gradle55
-rw-r--r--core/build.gradle6
-rw-r--r--core/src/org/snoopdesigns/endless/EndlessGame.java66
-rw-r--r--core/src/org/snoopdesigns/endless/config/Config.java17
-rw-r--r--core/src/org/snoopdesigns/endless/context/Context.java37
-rw-r--r--core/src/org/snoopdesigns/endless/context/OnInit.java5
-rw-r--r--core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java51
-rw-r--r--core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java28
-rw-r--r--core/src/org/snoopdesigns/endless/physics/Box2DLocation.java46
-rw-r--r--core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java22
-rw-r--r--core/src/org/snoopdesigns/endless/physics/PhysicalBody.java32
-rw-r--r--core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java115
-rw-r--r--core/src/org/snoopdesigns/endless/physics/WorldContext.java17
-rw-r--r--core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java48
-rw-r--r--core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java55
-rw-r--r--core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java29
-rw-r--r--core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java54
-rw-r--r--core/src/org/snoopdesigns/endless/renderer/Renderer.java11
-rw-r--r--core/src/org/snoopdesigns/endless/utils/ExitControllable.java17
-rw-r--r--core/src/org/snoopdesigns/endless/world/Controllable.java7
-rw-r--r--core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java41
-rw-r--r--core/src/org/snoopdesigns/endless/world/Renderable.java9
-rw-r--r--core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java35
-rw-r--r--core/src/org/snoopdesigns/endless/world/player/PlayerShip.java150
-rw-r--r--core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java163
-rw-r--r--desktop/build.gradle49
-rw-r--r--desktop/src/org/snoopdesigns/endless/DesktopLauncher.java23
-rw-r--r--gradle.properties4
-rw-r--r--gradle/wrapper/gradle-wrapper.properties7
-rw-r--r--gradlew249
-rw-r--r--gradlew.bat92
-rw-r--r--settings.gradle1
40 files changed, 1895 insertions, 0 deletions
diff --git a/assets/badlogic.jpg b/assets/badlogic.jpg
new file mode 100644
index 0000000..4390da6
--- /dev/null
+++ b/assets/badlogic.jpg
Binary files differ
diff --git a/assets/bg.png b/assets/bg.png
new file mode 100644
index 0000000..04a2f3d
--- /dev/null
+++ b/assets/bg.png
Binary files differ
diff --git a/assets/calibri.fnt b/assets/calibri.fnt
new file mode 100644
index 0000000..2302da5
--- /dev/null
+++ b/assets/calibri.fnt
@@ -0,0 +1,194 @@
+info face="Calibri" size=32 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0
+common lineHeight=40 base=28 scaleW=512 scaleH=512 pages=1 packed=0
+page id=0 file="calibri.png"
+chars count=189
+char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=28 xadvance=7 page=0 chnl=0
+char id=36 x=0 y=0 width=15 height=30 xoffset=1 yoffset=3 xadvance=16 page=0 chnl=0
+char id=124 x=15 y=0 width=4 height=30 xoffset=6 yoffset=5 xadvance=15 page=0 chnl=0
+char id=41 x=19 y=0 width=8 height=30 xoffset=2 yoffset=5 xadvance=10 page=0 chnl=0
+char id=40 x=27 y=0 width=7 height=30 xoffset=2 yoffset=5 xadvance=10 page=0 chnl=0
+char id=92 x=34 y=0 width=14 height=29 xoffset=0 yoffset=4 xadvance=12 page=0 chnl=0
+char id=47 x=48 y=0 width=14 height=29 xoffset=0 yoffset=4 xadvance=12 page=0 chnl=0
+char id=125 x=62 y=0 width=10 height=29 xoffset=1 yoffset=5 xadvance=10 page=0 chnl=0
+char id=123 x=72 y=0 width=10 height=29 xoffset=1 yoffset=5 xadvance=10 page=0 chnl=0
+char id=93 x=82 y=0 width=7 height=29 xoffset=1 yoffset=5 xadvance=10 page=0 chnl=0
+char id=91 x=89 y=0 width=8 height=29 xoffset=2 yoffset=5 xadvance=10 page=0 chnl=0
+char id=106 x=97 y=0 width=8 height=29 xoffset=0 yoffset=6 xadvance=8 page=0 chnl=0
+char id=64 x=105 y=0 width=24 height=27 xoffset=3 yoffset=6 xadvance=29 page=0 chnl=0
+char id=81 x=129 y=0 width=22 height=25 xoffset=2 yoffset=7 xadvance=22 page=0 chnl=0
+char id=38 x=151 y=0 width=21 height=24 xoffset=1 yoffset=5 xadvance=22 page=0 chnl=0
+char id=37 x=172 y=0 width=23 height=24 xoffset=1 yoffset=6 xadvance=23 page=0 chnl=0
+char id=33 x=195 y=0 width=5 height=24 xoffset=4 yoffset=5 xadvance=10 page=0 chnl=0
+char id=108 x=200 y=0 width=5 height=24 xoffset=2 yoffset=5 xadvance=7 page=0 chnl=0
+char id=107 x=205 y=0 width=14 height=24 xoffset=2 yoffset=5 xadvance=15 page=0 chnl=0
+char id=104 x=219 y=0 width=15 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=102 x=234 y=0 width=11 height=24 xoffset=1 yoffset=5 xadvance=10 page=0 chnl=0
+char id=100 x=245 y=0 width=15 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=98 x=260 y=0 width=15 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=63 x=275 y=0 width=13 height=23 xoffset=2 yoffset=6 xadvance=15 page=0 chnl=0
+char id=121 x=288 y=0 width=15 height=23 xoffset=0 yoffset=12 xadvance=14 page=0 chnl=0
+char id=113 x=303 y=0 width=15 height=23 xoffset=2 yoffset=12 xadvance=17 page=0 chnl=0
+char id=112 x=318 y=0 width=15 height=23 xoffset=2 yoffset=12 xadvance=17 page=0 chnl=0
+char id=105 x=333 y=0 width=5 height=23 xoffset=2 yoffset=6 xadvance=7 page=0 chnl=0
+char id=103 x=338 y=0 width=14 height=23 xoffset=1 yoffset=12 xadvance=15 page=0 chnl=0
+char id=127 x=352 y=0 width=17 height=22 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=0
+char id=35 x=369 y=0 width=17 height=22 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=0
+char id=48 x=386 y=0 width=16 height=22 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=0
+char id=57 x=402 y=0 width=15 height=22 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=0
+char id=56 x=417 y=0 width=16 height=22 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=0
+char id=55 x=433 y=0 width=14 height=22 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=0
+char id=54 x=447 y=0 width=15 height=22 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=0
+char id=53 x=462 y=0 width=15 height=22 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=0
+char id=52 x=477 y=0 width=16 height=22 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=0
+char id=51 x=493 y=0 width=14 height=22 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=0
+char id=50 x=0 y=30 width=14 height=22 xoffset=2 yoffset=7 xadvance=16 page=0 chnl=0
+char id=49 x=14 y=30 width=13 height=22 xoffset=3 yoffset=7 xadvance=16 page=0 chnl=0
+char id=90 x=27 y=30 width=16 height=22 xoffset=0 yoffset=7 xadvance=15 page=0 chnl=0
+char id=89 x=43 y=30 width=16 height=22 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=0
+char id=88 x=59 y=30 width=17 height=22 xoffset=0 yoffset=7 xadvance=17 page=0 chnl=0
+char id=87 x=76 y=30 width=29 height=22 xoffset=0 yoffset=7 xadvance=28 page=0 chnl=0
+char id=86 x=105 y=30 width=19 height=22 xoffset=0 yoffset=7 xadvance=18 page=0 chnl=0
+char id=85 x=124 y=30 width=17 height=22 xoffset=3 yoffset=7 xadvance=21 page=0 chnl=0
+char id=84 x=141 y=30 width=16 height=22 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=0
+char id=83 x=157 y=30 width=13 height=22 xoffset=1 yoffset=7 xadvance=15 page=0 chnl=0
+char id=82 x=170 y=30 width=15 height=22 xoffset=3 yoffset=7 xadvance=17 page=0 chnl=0
+char id=80 x=185 y=30 width=13 height=22 xoffset=3 yoffset=7 xadvance=17 page=0 chnl=0
+char id=79 x=198 y=30 width=20 height=22 xoffset=2 yoffset=7 xadvance=21 page=0 chnl=0
+char id=78 x=218 y=30 width=17 height=22 xoffset=3 yoffset=7 xadvance=21 page=0 chnl=0
+char id=77 x=235 y=30 width=24 height=22 xoffset=3 yoffset=7 xadvance=27 page=0 chnl=0
+char id=76 x=259 y=30 width=11 height=22 xoffset=3 yoffset=7 xadvance=13 page=0 chnl=0
+char id=75 x=270 y=30 width=15 height=22 xoffset=3 yoffset=7 xadvance=17 page=0 chnl=0
+char id=74 x=285 y=30 width=10 height=22 xoffset=0 yoffset=7 xadvance=10 page=0 chnl=0
+char id=73 x=295 y=30 width=5 height=22 xoffset=3 yoffset=7 xadvance=8 page=0 chnl=0
+char id=72 x=300 y=30 width=17 height=22 xoffset=3 yoffset=7 xadvance=20 page=0 chnl=0
+char id=71 x=317 y=30 width=18 height=22 xoffset=1 yoffset=7 xadvance=20 page=0 chnl=0
+char id=70 x=335 y=30 width=12 height=22 xoffset=3 yoffset=7 xadvance=15 page=0 chnl=0
+char id=69 x=347 y=30 width=12 height=22 xoffset=3 yoffset=7 xadvance=16 page=0 chnl=0
+char id=68 x=359 y=30 width=18 height=22 xoffset=3 yoffset=7 xadvance=20 page=0 chnl=0
+char id=67 x=377 y=30 width=15 height=22 xoffset=2 yoffset=7 xadvance=17 page=0 chnl=0
+char id=66 x=392 y=30 width=15 height=22 xoffset=3 yoffset=7 xadvance=17 page=0 chnl=0
+char id=65 x=407 y=30 width=19 height=22 xoffset=0 yoffset=7 xadvance=19 page=0 chnl=0
+char id=116 x=426 y=30 width=11 height=21 xoffset=1 yoffset=8 xadvance=11 page=0 chnl=0
+char id=59 x=437 y=30 width=8 height=20 xoffset=0 yoffset=13 xadvance=9 page=0 chnl=0
+char id=62 x=445 y=30 width=15 height=18 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=0
+char id=60 x=460 y=30 width=15 height=18 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=0
+char id=58 x=475 y=30 width=4 height=17 xoffset=3 yoffset=12 xadvance=9 page=0 chnl=0
+char id=122 x=479 y=30 width=11 height=17 xoffset=1 yoffset=12 xadvance=13 page=0 chnl=0
+char id=120 x=490 y=30 width=15 height=17 xoffset=0 yoffset=12 xadvance=14 page=0 chnl=0
+char id=119 x=0 y=52 width=23 height=17 xoffset=0 yoffset=12 xadvance=23 page=0 chnl=0
+char id=118 x=23 y=52 width=15 height=17 xoffset=0 yoffset=12 xadvance=14 page=0 chnl=0
+char id=117 x=38 y=52 width=14 height=17 xoffset=2 yoffset=12 xadvance=17 page=0 chnl=0
+char id=115 x=52 y=52 width=11 height=17 xoffset=1 yoffset=12 xadvance=13 page=0 chnl=0
+char id=114 x=63 y=52 width=10 height=17 xoffset=2 yoffset=12 xadvance=11 page=0 chnl=0
+char id=111 x=73 y=52 width=15 height=17 xoffset=1 yoffset=12 xadvance=17 page=0 chnl=0
+char id=110 x=88 y=52 width=15 height=17 xoffset=2 yoffset=12 xadvance=17 page=0 chnl=0
+char id=109 x=103 y=52 width=23 height=17 xoffset=2 yoffset=12 xadvance=26 page=0 chnl=0
+char id=101 x=126 y=52 width=15 height=17 xoffset=1 yoffset=12 xadvance=16 page=0 chnl=0
+char id=99 x=141 y=52 width=13 height=17 xoffset=1 yoffset=12 xadvance=14 page=0 chnl=0
+char id=97 x=154 y=52 width=14 height=17 xoffset=1 yoffset=12 xadvance=15 page=0 chnl=0
+char id=43 x=168 y=52 width=15 height=16 xoffset=1 yoffset=11 xadvance=16 page=0 chnl=0
+char id=42 x=183 y=52 width=13 height=14 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=0
+char id=94 x=196 y=52 width=15 height=14 xoffset=1 yoffset=7 xadvance=16 page=0 chnl=0
+char id=61 x=211 y=52 width=14 height=10 xoffset=1 yoffset=14 xadvance=16 page=0 chnl=0
+char id=44 x=225 y=52 width=7 height=10 xoffset=0 yoffset=23 xadvance=8 page=0 chnl=0
+char id=39 x=232 y=52 width=4 height=10 xoffset=2 yoffset=5 xadvance=7 page=0 chnl=0
+char id=34 x=236 y=52 width=10 height=10 xoffset=2 yoffset=5 xadvance=13 page=0 chnl=0
+char id=126 x=246 y=52 width=16 height=8 xoffset=1 yoffset=9 xadvance=16 page=0 chnl=0
+char id=96 x=262 y=52 width=8 height=7 xoffset=1 yoffset=5 xadvance=9 page=0 chnl=0
+char id=46 x=270 y=52 width=5 height=5 xoffset=2 yoffset=24 xadvance=8 page=0 chnl=0
+char id=95 x=275 y=52 width=17 height=4 xoffset=0 yoffset=31 xadvance=16 page=0 chnl=0
+char id=45 x=292 y=52 width=9 height=4 xoffset=1 yoffset=18 xadvance=10 page=0 chnl=0
+char id=175 x=301 y=52 width=10 height=4 xoffset=2 yoffset=7 xadvance=13 page=0 chnl=0
+char id=168 x=311 y=52 width=11 height=5 xoffset=2 yoffset=6 xadvance=13 page=0 chnl=0
+char id=183 x=322 y=52 width=5 height=6 xoffset=2 yoffset=16 xadvance=8 page=0 chnl=0
+char id=172 x=327 y=52 width=15 height=7 xoffset=1 yoffset=17 xadvance=16 page=0 chnl=0
+char id=180 x=342 y=52 width=8 height=7 xoffset=1 yoffset=5 xadvance=9 page=0 chnl=0
+char id=184 x=350 y=52 width=7 height=8 xoffset=2 yoffset=27 xadvance=10 page=0 chnl=0
+char id=176 x=357 y=52 width=10 height=10 xoffset=2 yoffset=5 xadvance=11 page=0 chnl=0
+char id=174 x=367 y=52 width=14 height=14 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=0
+char id=178 x=381 y=52 width=9 height=14 xoffset=1 yoffset=4 xadvance=11 page=0 chnl=0
+char id=179 x=390 y=52 width=10 height=14 xoffset=1 yoffset=4 xadvance=11 page=0 chnl=0
+char id=185 x=400 y=52 width=7 height=14 xoffset=1 yoffset=4 xadvance=8 page=0 chnl=0
+char id=215 x=407 y=52 width=14 height=14 xoffset=2 yoffset=12 xadvance=16 page=0 chnl=0
+char id=171 x=421 y=52 width=14 height=15 xoffset=1 yoffset=12 xadvance=16 page=0 chnl=0
+char id=187 x=435 y=52 width=14 height=15 xoffset=2 yoffset=12 xadvance=16 page=0 chnl=0
+char id=170 x=449 y=52 width=11 height=16 xoffset=1 yoffset=8 xadvance=13 page=0 chnl=0
+char id=186 x=460 y=52 width=12 height=17 xoffset=1 yoffset=7 xadvance=14 page=0 chnl=0
+char id=230 x=472 y=52 width=24 height=17 xoffset=1 yoffset=12 xadvance=25 page=0 chnl=0
+char id=247 x=496 y=52 width=15 height=18 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=0
+char id=164 x=0 y=70 width=15 height=19 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=0
+char id=177 x=15 y=70 width=15 height=19 xoffset=1 yoffset=10 xadvance=16 page=0 chnl=0
+char id=162 x=30 y=70 width=13 height=21 xoffset=3 yoffset=8 xadvance=16 page=0 chnl=0
+char id=163 x=43 y=70 width=16 height=21 xoffset=1 yoffset=8 xadvance=16 page=0 chnl=0
+char id=248 x=59 y=70 width=16 height=21 xoffset=1 yoffset=10 xadvance=17 page=0 chnl=0
+char id=165 x=75 y=70 width=18 height=22 xoffset=0 yoffset=7 xadvance=16 page=0 chnl=0
+char id=198 x=93 y=70 width=25 height=22 xoffset=-1 yoffset=7 xadvance=24 page=0 chnl=0
+char id=208 x=118 y=70 width=20 height=22 xoffset=0 yoffset=7 xadvance=20 page=0 chnl=0
+char id=222 x=138 y=70 width=13 height=22 xoffset=3 yoffset=7 xadvance=17 page=0 chnl=0
+char id=181 x=151 y=70 width=17 height=23 xoffset=2 yoffset=12 xadvance=18 page=0 chnl=0
+char id=227 x=168 y=70 width=14 height=23 xoffset=1 yoffset=6 xadvance=15 page=0 chnl=0
+char id=228 x=182 y=70 width=14 height=23 xoffset=1 yoffset=6 xadvance=15 page=0 chnl=0
+char id=231 x=196 y=70 width=13 height=23 xoffset=1 yoffset=12 xadvance=14 page=0 chnl=0
+char id=235 x=209 y=70 width=15 height=23 xoffset=1 yoffset=6 xadvance=16 page=0 chnl=0
+char id=239 x=224 y=70 width=10 height=23 xoffset=0 yoffset=6 xadvance=7 page=0 chnl=0
+char id=241 x=234 y=70 width=15 height=23 xoffset=2 yoffset=6 xadvance=17 page=0 chnl=0
+char id=245 x=249 y=70 width=15 height=23 xoffset=1 yoffset=6 xadvance=17 page=0 chnl=0
+char id=246 x=264 y=70 width=15 height=23 xoffset=1 yoffset=6 xadvance=17 page=0 chnl=0
+char id=252 x=279 y=70 width=14 height=23 xoffset=2 yoffset=6 xadvance=17 page=0 chnl=0
+char id=161 x=293 y=70 width=5 height=24 xoffset=2 yoffset=9 xadvance=10 page=0 chnl=0
+char id=169 x=298 y=70 width=23 height=24 xoffset=2 yoffset=5 xadvance=27 page=0 chnl=0
+char id=188 x=321 y=70 width=19 height=24 xoffset=1 yoffset=6 xadvance=20 page=0 chnl=0
+char id=189 x=340 y=70 width=20 height=24 xoffset=1 yoffset=6 xadvance=21 page=0 chnl=0
+char id=190 x=360 y=70 width=20 height=24 xoffset=1 yoffset=6 xadvance=22 page=0 chnl=0
+char id=191 x=380 y=70 width=13 height=24 xoffset=1 yoffset=9 xadvance=15 page=0 chnl=0
+char id=223 x=393 y=70 width=15 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=224 x=408 y=70 width=14 height=24 xoffset=1 yoffset=5 xadvance=15 page=0 chnl=0
+char id=225 x=422 y=70 width=14 height=24 xoffset=1 yoffset=5 xadvance=15 page=0 chnl=0
+char id=226 x=436 y=70 width=14 height=24 xoffset=1 yoffset=5 xadvance=15 page=0 chnl=0
+char id=229 x=450 y=70 width=14 height=24 xoffset=1 yoffset=5 xadvance=15 page=0 chnl=0
+char id=232 x=464 y=70 width=15 height=24 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
+char id=233 x=479 y=70 width=15 height=24 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
+char id=234 x=494 y=70 width=15 height=24 xoffset=1 yoffset=5 xadvance=16 page=0 chnl=0
+char id=236 x=0 y=94 width=8 height=24 xoffset=-1 yoffset=5 xadvance=7 page=0 chnl=0
+char id=237 x=8 y=94 width=8 height=24 xoffset=1 yoffset=5 xadvance=7 page=0 chnl=0
+char id=238 x=16 y=94 width=10 height=24 xoffset=-1 yoffset=5 xadvance=7 page=0 chnl=0
+char id=240 x=26 y=94 width=15 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=242 x=41 y=94 width=15 height=24 xoffset=1 yoffset=5 xadvance=17 page=0 chnl=0
+char id=243 x=56 y=94 width=15 height=24 xoffset=1 yoffset=5 xadvance=17 page=0 chnl=0
+char id=244 x=71 y=94 width=15 height=24 xoffset=1 yoffset=5 xadvance=17 page=0 chnl=0
+char id=249 x=86 y=94 width=14 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=250 x=100 y=94 width=14 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=251 x=114 y=94 width=14 height=24 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=182 x=128 y=94 width=16 height=26 xoffset=2 yoffset=7 xadvance=19 page=0 chnl=0
+char id=167 x=144 y=94 width=14 height=27 xoffset=2 yoffset=5 xadvance=16 page=0 chnl=0
+char id=196 x=158 y=94 width=19 height=27 xoffset=0 yoffset=2 xadvance=19 page=0 chnl=0
+char id=203 x=177 y=94 width=12 height=27 xoffset=3 yoffset=2 xadvance=16 page=0 chnl=0
+char id=207 x=189 y=94 width=11 height=27 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0
+char id=214 x=200 y=94 width=20 height=27 xoffset=2 yoffset=2 xadvance=21 page=0 chnl=0
+char id=220 x=220 y=94 width=17 height=27 xoffset=3 yoffset=2 xadvance=21 page=0 chnl=0
+char id=195 x=237 y=94 width=19 height=28 xoffset=0 yoffset=1 xadvance=19 page=0 chnl=0
+char id=197 x=256 y=94 width=19 height=28 xoffset=0 yoffset=1 xadvance=19 page=0 chnl=0
+char id=199 x=275 y=94 width=16 height=28 xoffset=2 yoffset=7 xadvance=17 page=0 chnl=0
+char id=209 x=291 y=94 width=17 height=28 xoffset=3 yoffset=1 xadvance=21 page=0 chnl=0
+char id=213 x=308 y=94 width=20 height=28 xoffset=2 yoffset=1 xadvance=21 page=0 chnl=0
+char id=216 x=328 y=94 width=20 height=28 xoffset=1 yoffset=4 xadvance=21 page=0 chnl=0
+char id=192 x=348 y=94 width=19 height=29 xoffset=0 yoffset=0 xadvance=19 page=0 chnl=0
+char id=193 x=367 y=94 width=19 height=29 xoffset=0 yoffset=0 xadvance=19 page=0 chnl=0
+char id=194 x=386 y=94 width=19 height=29 xoffset=0 yoffset=0 xadvance=19 page=0 chnl=0
+char id=200 x=405 y=94 width=13 height=29 xoffset=2 yoffset=0 xadvance=16 page=0 chnl=0
+char id=201 x=418 y=94 width=12 height=29 xoffset=3 yoffset=0 xadvance=16 page=0 chnl=0
+char id=202 x=430 y=94 width=12 height=29 xoffset=3 yoffset=0 xadvance=16 page=0 chnl=0
+char id=204 x=442 y=94 width=10 height=29 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0
+char id=205 x=452 y=94 width=10 height=29 xoffset=2 yoffset=0 xadvance=8 page=0 chnl=0
+char id=206 x=462 y=94 width=13 height=29 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0
+char id=210 x=475 y=94 width=20 height=29 xoffset=2 yoffset=0 xadvance=21 page=0 chnl=0
+char id=211 x=0 y=123 width=20 height=29 xoffset=2 yoffset=0 xadvance=21 page=0 chnl=0
+char id=212 x=20 y=123 width=20 height=29 xoffset=2 yoffset=0 xadvance=21 page=0 chnl=0
+char id=217 x=40 y=123 width=17 height=29 xoffset=3 yoffset=0 xadvance=21 page=0 chnl=0
+char id=218 x=57 y=123 width=17 height=29 xoffset=3 yoffset=0 xadvance=21 page=0 chnl=0
+char id=219 x=74 y=123 width=17 height=29 xoffset=3 yoffset=0 xadvance=21 page=0 chnl=0
+char id=221 x=91 y=123 width=16 height=29 xoffset=0 yoffset=0 xadvance=16 page=0 chnl=0
+char id=255 x=107 y=123 width=15 height=29 xoffset=0 yoffset=6 xadvance=14 page=0 chnl=0
+char id=253 x=122 y=123 width=15 height=30 xoffset=0 yoffset=5 xadvance=14 page=0 chnl=0
+char id=254 x=137 y=123 width=15 height=30 xoffset=2 yoffset=5 xadvance=17 page=0 chnl=0
+char id=166 x=152 y=123 width=5 height=31 xoffset=6 yoffset=4 xadvance=16 page=0 chnl=0
diff --git a/assets/calibri.png b/assets/calibri.png
new file mode 100644
index 0000000..63deb95
--- /dev/null
+++ b/assets/calibri.png
Binary files differ
diff --git a/assets/crosshair.png b/assets/crosshair.png
new file mode 100644
index 0000000..cbb5af8
--- /dev/null
+++ b/assets/crosshair.png
Binary files differ
diff --git a/assets/particle.png b/assets/particle.png
new file mode 100644
index 0000000..632fcc1
--- /dev/null
+++ b/assets/particle.png
Binary files differ
diff --git a/assets/particles.p b/assets/particles.p
new file mode 100644
index 0000000..ad82dfc
--- /dev/null
+++ b/assets/particles.p
@@ -0,0 +1,160 @@
+Untitled
+- Delay -
+active: false
+- Duration -
+lowMin: 100.0
+lowMax: 100.0
+- Count -
+min: 0
+max: 200
+- Emission -
+lowMin: 200.0
+lowMax: 200.0
+highMin: 200.0
+highMax: 200.0
+relative: false
+scalingCount: 1
+scaling0: 1.0
+timelineCount: 1
+timeline0: 0.0
+- Life -
+lowMin: 0.0
+lowMax: 0.0
+highMin: 1000.0
+highMax: 1000.0
+relative: false
+scalingCount: 3
+scaling0: 1.0
+scaling1: 1.0
+scaling2: 1.0
+timelineCount: 3
+timeline0: 0.0
+timeline1: 0.66
+timeline2: 1.0
+independent: false
+- Life Offset -
+active: false
+independent: false
+- X Offset -
+active: false
+- Y Offset -
+active: false
+- Spawn Shape -
+shape: point
+- Spawn Width -
+lowMin: 0.0
+lowMax: 0.0
+highMin: 0.0
+highMax: 0.0
+relative: false
+scalingCount: 1
+scaling0: 1.0
+timelineCount: 1
+timeline0: 0.0
+- Spawn Height -
+lowMin: 0.0
+lowMax: 0.0
+highMin: 0.0
+highMax: 0.0
+relative: false
+scalingCount: 1
+scaling0: 1.0
+timelineCount: 1
+timeline0: 0.0
+- X Scale -
+lowMin: 1.0
+lowMax: 1.0
+highMin: 2.0
+highMax: 4.0
+relative: false
+scalingCount: 1
+scaling0: 1.0
+timelineCount: 1
+timeline0: 0.0
+- Y Scale -
+active: false
+- Velocity -
+active: true
+lowMin: 0.0
+lowMax: 0.0
+highMin: 10.0
+highMax: 20.0
+relative: false
+scalingCount: 1
+scaling0: 1.0
+timelineCount: 1
+timeline0: 0.0
+- Angle -
+active: true
+lowMin: -90.0
+lowMax: -90.0
+highMin: -90.0
+highMax: -90.0
+relative: false
+scalingCount: 3
+scaling0: 1.0
+scaling1: 1.0
+scaling2: 1.0
+timelineCount: 3
+timeline0: 0.0
+timeline1: 0.6369863
+timeline2: 1.0
+- Rotation -
+active: false
+- Wind -
+active: false
+- Gravity -
+active: true
+lowMin: 0.0
+lowMax: 0.0
+highMin: 0.0
+highMax: 0.0
+relative: false
+scalingCount: 1
+scaling0: 1.0
+timelineCount: 1
+timeline0: 0.0
+- Tint -
+colorsCount: 9
+colors0: 1.0
+colors1: 1.0
+colors2: 1.0
+colors3: 1.0
+colors4: 1.0
+colors5: 1.0
+colors6: 0.0
+colors7: 1.0
+colors8: 0.9764706
+timelineCount: 3
+timeline0: 0.0
+timeline1: 0.097770154
+timeline2: 1.0
+- Transparency -
+lowMin: 0.0
+lowMax: 0.0
+highMin: 1.0
+highMax: 1.0
+relative: false
+scalingCount: 5
+scaling0: 0.0
+scaling1: 1.0
+scaling2: 0.8245614
+scaling3: 0.47368422
+scaling4: 0.0
+timelineCount: 5
+timeline0: 0.0
+timeline1: 0.001
+timeline2: 0.46575344
+timeline3: 0.7876712
+timeline4: 1.0
+- Options -
+attached: false
+continuous: true
+aligned: false
+additive: true
+behind: false
+premultipliedAlpha: false
+spriteMode: single
+- Image Paths -
+particle.png
+
diff --git a/assets/ship.png b/assets/ship.png
new file mode 100644
index 0000000..1833839
--- /dev/null
+++ b/assets/ship.png
Binary files differ
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..82f04a8
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,55 @@
+buildscript {
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ gradlePluginPortal()
+ maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
+ google()
+ }
+ dependencies {
+ }
+}
+
+allprojects {
+ apply plugin: "eclipse"
+ version = '1.0'
+ ext {
+ appName = "Endless"
+ gdxVersion = '1.12.1'
+ gdxAiVersion = '1.8.2'
+ roboVMVersion = '2.3.20'
+ box2DLightsVersion = '1.5'
+ ashleyVersion = '1.7.4'
+ aiVersion = '1.8.2'
+ gdxControllersVersion = '2.2.1'
+ }
+
+ repositories {
+ mavenLocal()
+ mavenCentral()
+ google()
+ gradlePluginPortal()
+ maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
+ maven { url "https://oss.sonatype.org/content/repositories/releases/" }
+ maven { url "https://jitpack.io" }
+ }
+}
+
+project(":desktop") {
+ apply plugin: "java-library"
+ dependencies {
+ implementation project(":core")
+ api "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
+ api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
+ }
+}
+
+project(":core") {
+ apply plugin: "java-library"
+ dependencies {
+ api "com.badlogicgames.gdx:gdx:$gdxVersion"
+ api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
+ api "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"
+ api "com.badlogicgames.gdx:gdx-ai:$gdxAiVersion"
+ }
+}
diff --git a/core/build.gradle b/core/build.gradle
new file mode 100644
index 0000000..01ed732
--- /dev/null
+++ b/core/build.gradle
@@ -0,0 +1,6 @@
+sourceCompatibility = 17
+[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
+
+sourceSets.main.java.srcDirs = [ "src/" ]
+
+eclipse.project.name = appName + "-core"
diff --git a/core/src/org/snoopdesigns/endless/EndlessGame.java b/core/src/org/snoopdesigns/endless/EndlessGame.java
new file mode 100644
index 0000000..fc72c66
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/EndlessGame.java
@@ -0,0 +1,66 @@
+package org.snoopdesigns.endless;
+
+import java.util.List;
+
+import com.badlogic.gdx.ApplicationAdapter;
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.InputMultiplexer;
+import com.badlogic.gdx.utils.ScreenUtils;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.context.OnInit;
+import org.snoopdesigns.endless.physics.Box2DDebugRenderer;
+import org.snoopdesigns.endless.physics.Box2DRenderer;
+import org.snoopdesigns.endless.physics.camera.CameraRenderer;
+import org.snoopdesigns.endless.renderer.CursorRenderer;
+import org.snoopdesigns.endless.renderer.DebugRenderer;
+import org.snoopdesigns.endless.renderer.Renderer;
+import org.snoopdesigns.endless.utils.ExitControllable;
+import org.snoopdesigns.endless.world.ObjectsRenderer;
+import org.snoopdesigns.endless.world.bg.BackgroundRenderer;
+
+public class EndlessGame extends ApplicationAdapter {
+
+ private final List<Renderer> renderers = List.of(
+ new BackgroundRenderer(),
+ new Box2DRenderer(),
+ new CameraRenderer(),
+ new Box2DDebugRenderer(),
+ new ObjectsRenderer(),
+ new CursorRenderer(),
+ new DebugRenderer()
+ );
+
+ private final List<OnInit> intializers = List.of(
+ new Context()
+ );
+
+ @Override
+ public void create () {
+ intializers.forEach(OnInit::create);
+
+ final InputMultiplexer inputMultiplexer = new InputMultiplexer();
+ renderers.forEach(inputMultiplexer::addProcessor);
+ inputMultiplexer.addProcessor(Context.getInstance().getPlayerShip());
+ inputMultiplexer.addProcessor(new ExitControllable());
+ Gdx.input.setInputProcessor(inputMultiplexer);
+
+ renderers.forEach(Renderer::create);
+ }
+
+ @Override
+ public void render () {
+ ScreenUtils.clear(0, 0, 0, 1);
+ renderers.forEach(Renderer::render);
+ }
+
+ @Override
+ public void resize(int width, int height) {
+ renderers.forEach(renderer ->
+ renderer.resize(width, height));
+ }
+
+ @Override
+ public void dispose() {
+ renderers.forEach(Renderer::dispose);
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/config/Config.java b/core/src/org/snoopdesigns/endless/config/Config.java
new file mode 100644
index 0000000..34ce45d
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/config/Config.java
@@ -0,0 +1,17 @@
+package org.snoopdesigns.endless.config;
+
+public final class Config {
+ private static int screenWidth = 1280;
+ private static int screenHeight = 720;
+
+ private Config() {
+ }
+
+ public static int getScreenWidth() {
+ return screenWidth;
+ }
+
+ public static int getScreenHeight() {
+ return screenHeight;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/context/Context.java b/core/src/org/snoopdesigns/endless/context/Context.java
new file mode 100644
index 0000000..4081c87
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/context/Context.java
@@ -0,0 +1,37 @@
+package org.snoopdesigns.endless.context;
+
+import org.snoopdesigns.endless.physics.WorldContext;
+import org.snoopdesigns.endless.physics.camera.CameraContext;
+import org.snoopdesigns.endless.world.player.PlayerShip;
+
+public final class Context implements OnInit {
+ private static Context INSTANCE;
+
+ private CameraContext cameraContext;
+ private WorldContext worldContext;
+ private PlayerShip playerShip;
+
+ @Override
+ public void create() {
+ INSTANCE = new Context();
+ INSTANCE.cameraContext = new CameraContext();
+ INSTANCE.worldContext = new WorldContext();
+ INSTANCE.playerShip = new PlayerShip();
+ }
+
+ public static Context getInstance() {
+ return INSTANCE;
+ }
+
+ public CameraContext getCameraContext() {
+ return cameraContext;
+ }
+
+ public WorldContext getWorldContext() {
+ return worldContext;
+ }
+
+ public PlayerShip getPlayerShip() {
+ return playerShip;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/context/OnInit.java b/core/src/org/snoopdesigns/endless/context/OnInit.java
new file mode 100644
index 0000000..7b5678a
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/context/OnInit.java
@@ -0,0 +1,5 @@
+package org.snoopdesigns.endless.context;
+
+public interface OnInit {
+ void create();
+}
diff --git a/core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java b/core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java
new file mode 100644
index 0000000..ca3f301
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/input/DefaultInputProcessor.java
@@ -0,0 +1,51 @@
+package org.snoopdesigns.endless.input;
+
+import com.badlogic.gdx.InputProcessor;
+
+public interface DefaultInputProcessor extends InputProcessor {
+
+ @Override
+ default boolean keyDown(int keycode) {
+ return false;
+ }
+
+ @Override
+ default boolean keyUp(int keycode) {
+ return false;
+ }
+
+ @Override
+ default boolean keyTyped(char character) {
+ return false;
+ }
+
+ @Override
+ default boolean touchDown(int screenX, int screenY, int pointer, int button) {
+ return false;
+ }
+
+ @Override
+ default boolean touchUp(int screenX, int screenY, int pointer, int button) {
+ return false;
+ }
+
+ @Override
+ default boolean touchCancelled(int screenX, int screenY, int pointer, int button) {
+ return false;
+ }
+
+ @Override
+ default boolean touchDragged(int screenX, int screenY, int pointer) {
+ return false;
+ }
+
+ @Override
+ default boolean mouseMoved(int screenX, int screenY) {
+ return false;
+ }
+
+ @Override
+ default boolean scrolled(float amountX, float amountY) {
+ return false;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java b/core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java
new file mode 100644
index 0000000..15f930f
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/Box2DDebugRenderer.java
@@ -0,0 +1,28 @@
+package org.snoopdesigns.endless.physics;
+
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class Box2DDebugRenderer implements Renderer {
+
+ private com.badlogic.gdx.physics.box2d.Box2DDebugRenderer debugRenderer;
+
+ @Override
+ public void create() {
+ debugRenderer = new com.badlogic.gdx.physics.box2d.Box2DDebugRenderer();
+ debugRenderer.setDrawBodies(true);
+ debugRenderer.setDrawVelocities(true);
+ debugRenderer.setDrawAABBs(true);
+ }
+
+ @Override
+ public void render() {
+ debugRenderer.render(
+ Context.getInstance().getWorldContext().getWorld(),
+ Context.getInstance().getCameraContext().getCameraProjection());
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/Box2DLocation.java b/core/src/org/snoopdesigns/endless/physics/Box2DLocation.java
new file mode 100644
index 0000000..338b595
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/Box2DLocation.java
@@ -0,0 +1,46 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.ai.utils.Location;
+import com.badlogic.gdx.math.Vector2;
+
+public class Box2DLocation implements Location<Vector2> {
+ Vector2 position;
+ float orientation;
+
+ public Box2DLocation () {
+ this.position = new Vector2();
+ this.orientation = 0;
+ }
+
+ @Override
+ public Vector2 getPosition () {
+ return position;
+ }
+
+ @Override
+ public float getOrientation () {
+ return orientation;
+ }
+
+ @Override
+ public void setOrientation (float orientation) {
+ this.orientation = orientation;
+ }
+
+ @Override
+ public Location<Vector2> newLocation () {
+ return new Box2DLocation();
+ }
+
+ @Override
+ public float vectorToAngle (Vector2 vector) {
+ return (float)Math.atan2(-vector.x, vector.y);
+ }
+
+ @Override
+ public Vector2 angleToVector (Vector2 outVector, float angle) {
+ outVector.x = -(float)Math.sin(angle);
+ outVector.y = (float)Math.cos(angle);
+ return outVector;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java b/core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java
new file mode 100644
index 0000000..641e397
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/Box2DRenderer.java
@@ -0,0 +1,22 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.physics.box2d.Box2D;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class Box2DRenderer implements Renderer {
+
+ @Override
+ public void create() {
+ Box2D.init();
+ }
+
+ @Override
+ public void render() {
+ Context.getInstance().getWorldContext().getWorld().step(1/60f, 6, 2);
+ }
+
+ @Override
+ public void dispose() {
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java b/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
new file mode 100644
index 0000000..23ede8d
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/PhysicalBody.java
@@ -0,0 +1,32 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.Body;
+import com.badlogic.gdx.physics.box2d.BodyDef;
+import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
+import com.badlogic.gdx.physics.box2d.FixtureDef;
+import org.snoopdesigns.endless.context.Context;
+
+public abstract class PhysicalBody {
+
+ Body body;
+
+ public abstract BodyType getBodyType();
+ public abstract FixtureDef getFixture();
+
+ public Vector2 getInitialPosition() {
+ return new Vector2(0, 0);
+ }
+
+ public void initBody() {
+ final BodyDef bodyDef = new BodyDef();
+ bodyDef.type = getBodyType();
+ bodyDef.position.set(getInitialPosition());
+ body = Context.getInstance().getWorldContext().getWorld().createBody(bodyDef);
+ body.createFixture(getFixture());
+ }
+
+ public Body getBody() {
+ return body;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java b/core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java
new file mode 100644
index 0000000..9e9a85c
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/SteerablePhysicalBody.java
@@ -0,0 +1,115 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.ai.steer.Steerable;
+import com.badlogic.gdx.ai.utils.Location;
+import com.badlogic.gdx.math.Vector2;
+
+public abstract class SteerablePhysicalBody extends PhysicalBody implements Steerable<Vector2> {
+
+ public abstract float getMaxSpeed();
+ public abstract float getMaxAcceleration();
+ public abstract float getMaxRotationSpeed();
+ public abstract float getMaxRotationAcceleration();
+
+ @Override
+ public Vector2 getLinearVelocity() {
+ return getBody().getLinearVelocity();
+ }
+
+ @Override
+ public float getAngularVelocity() {
+ return getBody().getAngularVelocity();
+ }
+
+ @Override
+ public float getBoundingRadius() {
+ return 0.001f;
+ }
+
+ @Override
+ public boolean isTagged() {
+ return false;
+ }
+
+ @Override
+ public void setTagged(boolean tagged) {
+ }
+
+ @Override
+ public float getZeroLinearSpeedThreshold() {
+ return 0.1f;
+ }
+
+ @Override
+ public void setZeroLinearSpeedThreshold(float value) {
+ }
+
+ @Override
+ public float getMaxLinearSpeed() {
+ return getMaxSpeed();
+ }
+
+ @Override
+ public void setMaxLinearSpeed(float maxLinearSpeed) {
+ }
+
+ @Override
+ public float getMaxLinearAcceleration() {
+ return getMaxAcceleration();
+ }
+
+ @Override
+ public void setMaxLinearAcceleration(float maxLinearAcceleration) {
+ }
+
+ @Override
+ public float getMaxAngularSpeed() {
+ return getMaxRotationSpeed();
+ }
+
+ @Override
+ public void setMaxAngularSpeed(float maxAngularSpeed) {
+ }
+
+ @Override
+ public float getMaxAngularAcceleration() {
+ return getMaxRotationAcceleration();
+ }
+
+ @Override
+ public void setMaxAngularAcceleration(float maxAngularAcceleration) {
+ }
+
+ @Override
+ public Vector2 getPosition() {
+ return getBody().getPosition();
+ }
+
+ @Override
+ public float getOrientation() {
+ return getBody().getAngle();
+ }
+
+ @Override
+ public void setOrientation(float orientation) {
+ getBody().setTransform(getPosition(), orientation);
+ }
+
+ @Override
+ public float vectorToAngle(Vector2 vector) {
+ return vector.angleRad();
+ }
+
+ @Override
+ public Vector2 angleToVector(Vector2 outVector, float angle) {
+ final var tmpVector = new Vector2(1, 0).rotateRad(angle);
+ outVector.x = tmpVector.x;
+ outVector.y = tmpVector.y;
+ return outVector;
+ }
+
+ @Override
+ public Location<Vector2> newLocation() {
+ return new Box2DLocation();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/WorldContext.java b/core/src/org/snoopdesigns/endless/physics/WorldContext.java
new file mode 100644
index 0000000..5f10ba8
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/WorldContext.java
@@ -0,0 +1,17 @@
+package org.snoopdesigns.endless.physics;
+
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.World;
+
+public class WorldContext {
+
+ private final World world;
+
+ public WorldContext() {
+ this.world = new World(new Vector2(0, 0), true);
+ }
+
+ public World getWorld() {
+ return world;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java b/core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java
new file mode 100644
index 0000000..635813c
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/camera/CameraContext.java
@@ -0,0 +1,48 @@
+package org.snoopdesigns.endless.physics.camera;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.math.Matrix4;
+import com.badlogic.gdx.math.Vector2;
+
+public final class CameraContext {
+
+ private static final float DEFAULT_WORLD_WIDTH = 300.0f;
+
+ private final Vector2 position;
+ private final Vector2 viewport;
+ private float zoom;
+ private Matrix4 cameraProjection;
+
+ public CameraContext() {
+ final float w = Gdx.graphics.getWidth();
+ final float h = Gdx.graphics.getHeight();
+
+ this.position = new Vector2(0, 0);
+ this.zoom = 1.0f;
+ this.viewport = new Vector2(DEFAULT_WORLD_WIDTH, DEFAULT_WORLD_WIDTH * (h / w));
+ }
+
+ public Matrix4 getCameraProjection() {
+ return cameraProjection;
+ }
+
+ public void setCameraProjection(Matrix4 cameraProjection) {
+ this.cameraProjection = cameraProjection;
+ }
+
+ public Vector2 getPosition() {
+ return position;
+ }
+
+ public float getZoom() {
+ return zoom;
+ }
+
+ public void setZoom(float zoom) {
+ this.zoom = zoom;
+ }
+
+ public Vector2 getViewport() {
+ return viewport;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java b/core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java
new file mode 100644
index 0000000..165240a
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/physics/camera/CameraRenderer.java
@@ -0,0 +1,55 @@
+package org.snoopdesigns.endless.physics.camera;
+
+import com.badlogic.gdx.graphics.OrthographicCamera;
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.utils.viewport.ExtendViewport;
+import com.badlogic.gdx.utils.viewport.Viewport;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class CameraRenderer implements Renderer {
+
+ private static final float DEFAULT_WORLD_WIDTH = 300.0f;
+ private static final float DEFAULT_WORLD_HEIGHT = 300.0f;
+
+ private OrthographicCamera camera;
+ private Viewport viewport;
+
+ @Override
+ public void create() {
+ camera = new OrthographicCamera();
+ camera.zoom = Context.getInstance().getCameraContext().getZoom();
+ viewport = new ExtendViewport(
+ Context.getInstance().getCameraContext().getViewport().x,
+ Context.getInstance().getCameraContext().getViewport().y,
+ camera);
+ camera.update();
+ Context.getInstance().getCameraContext().setCameraProjection(camera.combined);
+ }
+
+ @Override
+ public void render() {
+ final Vector2 cameraPosition = Context.getInstance().getCameraContext().getPosition();
+ camera.position.set(cameraPosition.x, cameraPosition.y, 0);
+ camera.update();
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void resize(int width, int height) {
+ viewport.update(width, height);
+ Context.getInstance().getCameraContext().getViewport().set(
+ camera.viewportWidth,
+ camera.viewportHeight);
+ }
+
+ @Override
+ public boolean scrolled(float amountX, float amountY) {
+ camera.zoom += amountY / 10f;
+ Context.getInstance().getCameraContext().setZoom(camera.zoom);
+ return true;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java b/core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java
new file mode 100644
index 0000000..05b12f9
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/renderer/CursorRenderer.java
@@ -0,0 +1,29 @@
+package org.snoopdesigns.endless.renderer;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Cursor;
+import com.badlogic.gdx.graphics.Pixmap;
+
+public class CursorRenderer implements Renderer {
+
+ private Pixmap crosshair;
+
+ @Override
+ public void create() {
+ crosshair = new Pixmap(Gdx.files.internal("crosshair.png"));
+ final Cursor cursor = Gdx.graphics.newCursor(crosshair,
+ crosshair.getWidth() / 2,
+ crosshair.getHeight() / 2);
+ Gdx.graphics.setCursor(cursor);
+ }
+
+ @Override
+ public void render() {
+
+ }
+
+ @Override
+ public void dispose() {
+ crosshair.dispose();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java b/core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java
new file mode 100644
index 0000000..f31336b
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/renderer/DebugRenderer.java
@@ -0,0 +1,54 @@
+package org.snoopdesigns.endless.renderer;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Color;
+import com.badlogic.gdx.graphics.g2d.BitmapFont;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import org.snoopdesigns.endless.context.Context;
+
+public class DebugRenderer implements Renderer {
+
+ private BitmapFont font;
+ private SpriteBatch batch;
+
+ @Override
+ public void create() {
+ font = new BitmapFont(Gdx.files.internal("calibri.fnt"), false);
+ font.setColor(Color.GREEN);
+ font.getData().setScale(0.7f);
+ batch = new SpriteBatch();
+ }
+
+ @Override
+ public void render() {
+ batch.begin();
+ final String debugText = String.format("""
+ window size %d x %d
+ viewport %f %f
+ zoom %f
+ position %f %f
+ angle %f
+ speed %f
+ velocity %f %f
+ """,
+ Gdx.graphics.getWidth(),
+ Gdx.graphics.getHeight(),
+ Context.getInstance().getCameraContext().getViewport().x,
+ Context.getInstance().getCameraContext().getViewport().y,
+ Context.getInstance().getCameraContext().getZoom(),
+ Context.getInstance().getCameraContext().getPosition().x,
+ Context.getInstance().getCameraContext().getPosition().y,
+ Context.getInstance().getPlayerShip().getBody().getAngle(),
+ Context.getInstance().getPlayerShip().getBody().getLinearVelocity().len(),
+ Context.getInstance().getPlayerShip().getBody().getLinearVelocity().x,
+ Context.getInstance().getPlayerShip().getBody().getLinearVelocity().y);
+ font.draw(batch, debugText, 10f, 190f);
+ batch.end();
+ }
+
+ @Override
+ public void dispose() {
+ font.dispose();
+ batch.dispose();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/renderer/Renderer.java b/core/src/org/snoopdesigns/endless/renderer/Renderer.java
new file mode 100644
index 0000000..a98e36a
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/renderer/Renderer.java
@@ -0,0 +1,11 @@
+package org.snoopdesigns.endless.renderer;
+
+import org.snoopdesigns.endless.input.DefaultInputProcessor;
+
+public interface Renderer extends DefaultInputProcessor {
+ void create();
+ void render();
+ void dispose();
+ default void resize(int width, int height) {
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/utils/ExitControllable.java b/core/src/org/snoopdesigns/endless/utils/ExitControllable.java
new file mode 100644
index 0000000..12469a6
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/utils/ExitControllable.java
@@ -0,0 +1,17 @@
+package org.snoopdesigns.endless.utils;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input.Keys;
+import org.snoopdesigns.endless.world.Controllable;
+
+public class ExitControllable implements Controllable {
+
+ @Override
+ public boolean keyDown(int keycode) {
+ if (keycode == Keys.ESCAPE) {
+ Gdx.app.exit();
+ System.exit(1);
+ }
+ return true;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/Controllable.java b/core/src/org/snoopdesigns/endless/world/Controllable.java
new file mode 100644
index 0000000..77f1181
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/Controllable.java
@@ -0,0 +1,7 @@
+package org.snoopdesigns.endless.world;
+
+import org.snoopdesigns.endless.input.DefaultInputProcessor;
+
+public interface Controllable extends DefaultInputProcessor {
+
+}
diff --git a/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java b/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
new file mode 100644
index 0000000..f97f05c
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/ObjectsRenderer.java
@@ -0,0 +1,41 @@
+package org.snoopdesigns.endless.world;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+import org.snoopdesigns.endless.world.ship.SteerableEnemyShip;
+
+public class ObjectsRenderer implements Renderer {
+
+ private final List<Renderable> renderables = new ArrayList<>();
+
+ private SpriteBatch batch;
+
+ @Override
+ public void create() {
+ batch = new SpriteBatch();
+ renderables.add(Context.getInstance().getPlayerShip());
+ renderables.add(new SteerableEnemyShip());
+ renderables.add(new SteerableEnemyShip());
+ renderables.add(new SteerableEnemyShip());
+
+ renderables.forEach(Renderable::create);
+ }
+
+ @Override
+ public void render() {
+ batch.setProjectionMatrix(Context.getInstance().getCameraContext().getCameraProjection());
+ batch.begin();
+ renderables.forEach(renderable -> renderable.render(batch));
+ batch.end();
+ }
+
+ @Override
+ public void dispose() {
+ batch.dispose();
+ renderables.forEach(Renderable::dispose);
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/Renderable.java b/core/src/org/snoopdesigns/endless/world/Renderable.java
new file mode 100644
index 0000000..e5ba159
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/Renderable.java
@@ -0,0 +1,9 @@
+package org.snoopdesigns.endless.world;
+
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+
+public interface Renderable {
+ void create();
+ void render(final SpriteBatch batch);
+ void dispose();
+}
diff --git a/core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java b/core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java
new file mode 100644
index 0000000..094a827
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/bg/BackgroundRenderer.java
@@ -0,0 +1,35 @@
+package org.snoopdesigns.endless.world.bg;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.renderer.Renderer;
+
+public class BackgroundRenderer implements Renderer {
+
+ private SpriteBatch batch;
+ private Sprite bgSprite;
+
+ @Override
+ public void create() {
+ batch = new SpriteBatch();
+ bgSprite = new Sprite(new Texture(Gdx.files.internal("bg.png")));
+ bgSprite.setCenter(0, 0);
+ bgSprite.setSize(1000, 1000);
+ }
+
+ @Override
+ public void render() {
+ batch.setProjectionMatrix(Context.getInstance().getCameraContext().getCameraProjection());
+ batch.begin();
+ bgSprite.draw(batch);
+ batch.end();
+ }
+
+ @Override
+ public void dispose() {
+ batch.dispose();
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/player/PlayerShip.java b/core/src/org/snoopdesigns/endless/world/player/PlayerShip.java
new file mode 100644
index 0000000..3670d6f
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/player/PlayerShip.java
@@ -0,0 +1,150 @@
+package org.snoopdesigns.endless.world.player;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.Input.Keys;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.ParticleEffect;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.math.MathUtils;
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
+import com.badlogic.gdx.physics.box2d.CircleShape;
+import com.badlogic.gdx.physics.box2d.FixtureDef;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.physics.PhysicalBody;
+import org.snoopdesigns.endless.world.Controllable;
+import org.snoopdesigns.endless.world.Renderable;
+
+public final class PlayerShip extends PhysicalBody implements Controllable, Renderable {
+
+ private final Queue<ParticleEffect> effects = new LinkedList<>();
+ private Sprite sprite;
+
+ @Override
+ public BodyType getBodyType() {
+ return BodyType.DynamicBody;
+ }
+
+ @Override
+ public FixtureDef getFixture() {
+ final CircleShape circle = new CircleShape();
+ circle.setRadius(7f);
+ final FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = circle;
+ fixtureDef.density = 1f; // weight of body
+ return fixtureDef;
+ }
+
+ @Override
+ public void create() {
+ initBody();
+
+ final Texture texture = new Texture(Gdx.files.internal("ship.png"));
+ sprite = new Sprite(texture);
+ sprite.setScale(0.1f);
+ }
+
+ @Override
+ public void render(SpriteBatch batch) {
+ handleInput();
+ handleMousePosition();
+ final float x = getBody().getPosition().x;
+ final float y = getBody().getPosition().y;
+ Context.getInstance().getCameraContext().getPosition().set(x, y);
+
+ sprite.setCenter(x, y);
+ sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
+
+ effects.removeIf(ParticleEffect::isComplete);
+ effects.forEach(effect -> {
+ final Vector2 effectOffset = new Vector2(-5f, 0f).rotateRad(getBody().getAngle());
+ effect.setPosition(x + effectOffset.x, y + effectOffset.y);
+ effect.getEmitters().forEach(emitter -> {
+ final float effectRotation = MathUtils.radDeg * getBody().getAngle();
+ emitter.getAngle().setLow(effectRotation);
+ emitter.getAngle().setHigh(effectRotation);
+ });
+ });
+
+ sprite.draw(batch);
+ effects.forEach(effect ->
+ effect.draw(batch, Gdx.graphics.getDeltaTime()));
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean keyDown(int keycode) {
+ if (keycode == Keys.SPACE) {
+ final ParticleEffect effect = new ParticleEffect();
+ effect.load(Gdx.files.internal("particles.p"), Gdx.files.internal(""));
+ effect.setPosition(
+ getBody().getPosition().x,
+ getBody().getPosition().y);
+ effect.start();
+ effects.add(effect);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean keyUp(int keycode) {
+ if (keycode == Keys.SPACE) {
+ effects.forEach(ParticleEffect::allowCompletion);
+ return true;
+ }
+ return false;
+ }
+
+ private void speedUp() {
+ final float force = 100000.0f;
+ final Vector2 impulse = new Vector2(force, 0).rotateRad(getBody().getAngle());
+ getBody().applyForceToCenter(impulse, true);
+ }
+
+ private void slowDown() {
+ getBody().setLinearVelocity(
+ getBody().getLinearVelocity().x * 0.98f,
+ getBody().getLinearVelocity().y * 0.98f);
+ }
+
+ private void handleInput() {
+ if (Gdx.input.isKeyPressed(Keys.SPACE)) {
+ speedUp();
+ } else {
+ slowDown();
+ }
+ }
+
+ private void handleMousePosition() {
+ final float screenX = Gdx.input.getX();
+ final float screenY = Gdx.input.getY();
+ final float screenCenterX = (float) Gdx.graphics.getWidth() / 2;
+ final float screenCenterY = (float) Gdx.graphics.getHeight() / 2;
+ final float effectiveViewportWidth = Context.getInstance().getCameraContext().getViewport().x *
+ Context.getInstance().getCameraContext().getZoom();
+ final float effectiveViewportHeight = Context.getInstance().getCameraContext().getViewport().y *
+ Context.getInstance().getCameraContext().getZoom();
+
+ final float directionX = (screenX - screenCenterX) * (effectiveViewportWidth / Gdx.graphics.getWidth());
+ final float directionY = ((Gdx.graphics.getHeight() - screenY) - screenCenterY) * (effectiveViewportHeight / Gdx.graphics.getHeight());
+
+ final Vector2 direction = new Vector2(directionX, directionY);
+ float rotationRad = direction.angleRad();
+
+ float c = 10; //speed of rotation
+ getBody().setAngularVelocity(c * (angleDifference(rotationRad, getBody().getAngle())));
+ }
+
+ public static float angleDifference(float angle1, float angle2) {
+ float diff = (angle1 - angle2) % (MathUtils.PI * 2);
+ return diff < -1 * MathUtils.PI ? diff + 2 * MathUtils.PI : diff;
+ }
+}
diff --git a/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java b/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
new file mode 100644
index 0000000..4c24408
--- /dev/null
+++ b/core/src/org/snoopdesigns/endless/world/ship/SteerableEnemyShip.java
@@ -0,0 +1,163 @@
+package org.snoopdesigns.endless.world.ship;
+
+import java.util.List;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.ai.steer.SteeringAcceleration;
+import com.badlogic.gdx.ai.steer.SteeringBehavior;
+import com.badlogic.gdx.ai.steer.behaviors.BlendedSteering;
+import com.badlogic.gdx.ai.steer.behaviors.Face;
+import com.badlogic.gdx.ai.steer.behaviors.Wander;
+import com.badlogic.gdx.ai.utils.Location;
+import com.badlogic.gdx.graphics.Texture;
+import com.badlogic.gdx.graphics.g2d.Sprite;
+import com.badlogic.gdx.graphics.g2d.SpriteBatch;
+import com.badlogic.gdx.math.MathUtils;
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
+import com.badlogic.gdx.physics.box2d.CircleShape;
+import com.badlogic.gdx.physics.box2d.FixtureDef;
+import org.snoopdesigns.endless.context.Context;
+import org.snoopdesigns.endless.physics.Box2DLocation;
+import org.snoopdesigns.endless.physics.SteerablePhysicalBody;
+import org.snoopdesigns.endless.world.Renderable;
+
+public class SteerableEnemyShip extends SteerablePhysicalBody implements Renderable {
+
+ private Sprite sprite;
+ private final SteeringAcceleration<Vector2> steeringOutput = new SteeringAcceleration<>(new Vector2());
+ private BlendedSteering<Vector2> steeringCombination;
+
+ private Location<Vector2> target;
+
+ @Override
+ public BodyType getBodyType() {
+ return BodyType.DynamicBody;
+ }
+
+ @Override
+ public FixtureDef getFixture() {
+ final CircleShape circle = new CircleShape();
+ circle.setRadius(7f);
+ final FixtureDef fixtureDef = new FixtureDef();
+ fixtureDef.shape = circle;
+ fixtureDef.density = 1f;
+ return fixtureDef;
+ }
+
+ @Override
+ public Vector2 getInitialPosition() {
+ return new Vector2(MathUtils.random(50), MathUtils.random(50));
+ }
+
+ @Override
+ public void create() {
+ initBody();
+ final Texture texture = new Texture(Gdx.files.internal("ship.png"));
+ sprite = new Sprite(texture);
+ sprite.setScale(0.1f);
+ sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
+
+ target = new Box2DLocation();
+ target.getPosition().set(
+ Context.getInstance().getPlayerShip().getBody().getPosition().x,
+ Context.getInstance().getPlayerShip().getBody().getPosition().y);
+ target.setOrientation(Context.getInstance().getPlayerShip().getBody().getAngle());
+
+ steeringCombination = new BlendedSteering<>(this);
+ getSteeringBehaviours().forEach(steeringBehaviour ->
+ steeringCombination.add(steeringBehaviour, 0.5f));
+ }
+ @Override
+ public void render(SpriteBatch batch) {
+ target.getPosition().set(
+ Context.getInstance().getPlayerShip().getBody().getPosition().x,
+ Context.getInstance().getPlayerShip().getBody().getPosition().y);
+ target.setOrientation(Context.getInstance().getPlayerShip().getBody().getAngle());
+
+ steeringCombination.calculateSteering(steeringOutput);
+ applySteering();
+
+ sprite.setCenter(getBody().getPosition().x, getBody().getPosition().y);
+ sprite.setRotation(MathUtils.radDeg * getBody().getAngle());
+ sprite.draw(batch);
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ private List<SteeringBehavior<Vector2>> getSteeringBehaviours() {
+ return List.of(
+ new Face<>(this, target),
+ /*new Arrive<>(this, target)
+ .setTimeToTarget(0.1f)
+ .setArrivalTolerance(1f)
+ .setDecelerationRadius(100f)*/
+ new Wander<>(this)
+ .setTarget(target)
+ .setFaceEnabled(true) // We want to use Face internally (independent facing is on)
+ .setAlignTolerance(0.001f) // Used by Face
+ .setDecelerationRadius(100f) // Used by Face
+ .setTimeToTarget(0.1f) // Used by Face
+ .setWanderOffset(200) //
+ .setWanderOrientation(10) //
+ .setWanderRadius(200f) //
+ .setWanderRate(MathUtils.PI2 * 4)
+ );
+ }
+
+ private void applySteering() {
+ // Update position and linear velocity.
+ if (steeringOutput.angular != 0) {
+ // this method internally scales the torque by deltaTime
+ getBody().setAngularVelocity(steeringOutput.angular);
+ } else {
+ // Update orientation and angular velocity
+ final Vector2 linearVelocity = getLinearVelocity();
+ if (!linearVelocity.isZero(getZeroLinearSpeedThreshold())) {
+ float newOrientation = linearVelocity.angleRad();
+ getBody().setAngularVelocity(
+ getMaxRotationAcceleration() *
+ angleDifference(newOrientation, getBody().getAngle()));
+ }
+ }
+
+ if (!steeringOutput.linear.isZero()) {
+ speedUp(steeringOutput.linear);
+ }
+ }
+
+ private void speedUp(final Vector2 force) {
+ getBody().applyForceToCenter(
+ force.x * 100,
+ force.y * 100,
+ true);
+ }
+
+ // TODO common
+ private float angleDifference(float angle1, float angle2) {
+ float diff = (angle1 - angle2) % (MathUtils.PI * 2);
+ return diff < -1 * MathUtils.PI ? diff + 2 * MathUtils.PI : diff;
+ }
+
+ @Override
+ public float getMaxSpeed() {
+ return 70f;
+ }
+
+ @Override
+ public float getMaxAcceleration() {
+ return 50000f;
+ }
+
+ @Override
+ public float getMaxRotationSpeed() {
+ return 5f;
+ }
+
+ @Override
+ public float getMaxRotationAcceleration() {
+ return 5f;
+ }
+}
diff --git a/desktop/build.gradle b/desktop/build.gradle
new file mode 100644
index 0000000..cd2a88a
--- /dev/null
+++ b/desktop/build.gradle
@@ -0,0 +1,49 @@
+sourceCompatibility = 17
+sourceSets.main.java.srcDirs = [ "src/" ]
+sourceSets.main.resources.srcDirs = ["../assets"]
+
+project.ext.mainClassName = "org.snoopdesigns.endless.DesktopLauncher"
+project.ext.assetsDir = new File("../assets")
+
+import org.gradle.internal.os.OperatingSystem
+
+tasks.register('run', JavaExec) {
+ dependsOn classes
+ mainClass = project.mainClassName
+ classpath = sourceSets.main.runtimeClasspath
+ standardInput = System.in
+ workingDir = project.assetsDir
+ ignoreExitValue = true
+
+ if (OperatingSystem.current() == OperatingSystem.MAC_OS) {
+ // Required to run on macOS
+ jvmArgs += "-XstartOnFirstThread"
+ }
+}
+
+tasks.register('debug', JavaExec) {
+ dependsOn classes
+ mainClass = project.mainClassName
+ classpath = sourceSets.main.runtimeClasspath
+ standardInput = System.in
+ workingDir = project.assetsDir
+ ignoreExitValue = true
+ debug = true
+}
+
+tasks.register('dist', Jar) {
+ duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
+ manifest {
+ attributes 'Main-Class': project.mainClassName
+ }
+ dependsOn configurations.runtimeClasspath
+ from {
+ configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
+ }
+ with jar
+}
+
+
+dist.dependsOn classes
+
+eclipse.project.name = appName + "-desktop"
diff --git a/desktop/src/org/snoopdesigns/endless/DesktopLauncher.java b/desktop/src/org/snoopdesigns/endless/DesktopLauncher.java
new file mode 100644
index 0000000..3ece708
--- /dev/null
+++ b/desktop/src/org/snoopdesigns/endless/DesktopLauncher.java
@@ -0,0 +1,23 @@
+package org.snoopdesigns.endless;
+
+import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
+import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
+import org.snoopdesigns.endless.config.Config;
+
+public final class DesktopLauncher {
+
+ private final static String TITLE = "Endless";
+
+ private DesktopLauncher() {
+ }
+
+ public static void main(String[] arg) {
+ Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
+ config.setForegroundFPS(60);
+ config.setTitle(TITLE);
+ config.useVsync(true);
+ config.setWindowedMode(Config.getScreenWidth(), Config.getScreenHeight());
+ //config.setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode());
+ new Lwjgl3Application(new EndlessGame(), config);
+ }
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..c5aae14
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,4 @@
+org.gradle.daemon=true
+org.gradle.jvmargs=-Xms128m -Xmx1500m
+org.gradle.configureondemand=false
+android.enableR8.fullMode=false
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1af9e09
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..1aa94a4
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..74fc652
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include 'desktop', 'core' \ No newline at end of file