diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/bin/sjgs/__example_games/__InventoryExample$ExampleInventory.class b/bin/sjgs/__example_games/__InventoryExample$ExampleInventory.class new file mode 100755 index 0000000..311e277 Binary files /dev/null and b/bin/sjgs/__example_games/__InventoryExample$ExampleInventory.class differ diff --git a/bin/sjgs/__example_games/__InventoryExample$ExampleInventorySlot.class b/bin/sjgs/__example_games/__InventoryExample$ExampleInventorySlot.class new file mode 100755 index 0000000..9035668 Binary files /dev/null and b/bin/sjgs/__example_games/__InventoryExample$ExampleInventorySlot.class differ diff --git a/bin/sjgs/__example_games/__InventoryExample$MouseInput.class b/bin/sjgs/__example_games/__InventoryExample$MouseInput.class new file mode 100755 index 0000000..986af7f Binary files /dev/null and b/bin/sjgs/__example_games/__InventoryExample$MouseInput.class differ diff --git a/bin/sjgs/__example_games/__InventoryExample$items.class b/bin/sjgs/__example_games/__InventoryExample$items.class new file mode 100755 index 0000000..17300d5 Binary files /dev/null and b/bin/sjgs/__example_games/__InventoryExample$items.class differ diff --git a/bin/sjgs/__example_games/__InventoryExample.class b/bin/sjgs/__example_games/__InventoryExample.class new file mode 100755 index 0000000..c36b46a Binary files /dev/null and b/bin/sjgs/__example_games/__InventoryExample.class differ diff --git a/bin/sjgs/__example_games/__LightingDemonstration$Block.class b/bin/sjgs/__example_games/__LightingDemonstration$Block.class new file mode 100755 index 0000000..a019cfc Binary files /dev/null and b/bin/sjgs/__example_games/__LightingDemonstration$Block.class differ diff --git a/bin/sjgs/__example_games/__LightingDemonstration$KeyInput.class b/bin/sjgs/__example_games/__LightingDemonstration$KeyInput.class new file mode 100755 index 0000000..28cb096 Binary files /dev/null and b/bin/sjgs/__example_games/__LightingDemonstration$KeyInput.class differ diff --git a/bin/sjgs/__example_games/__LightingDemonstration$Player.class b/bin/sjgs/__example_games/__LightingDemonstration$Player.class new file mode 100755 index 0000000..3ff13e4 Binary files /dev/null and b/bin/sjgs/__example_games/__LightingDemonstration$Player.class differ diff --git a/bin/sjgs/__example_games/__LightingDemonstration$StaticLight.class b/bin/sjgs/__example_games/__LightingDemonstration$StaticLight.class new file mode 100755 index 0000000..b5522e2 Binary files /dev/null and b/bin/sjgs/__example_games/__LightingDemonstration$StaticLight.class differ diff --git a/bin/sjgs/__example_games/__LightingDemonstration.class b/bin/sjgs/__example_games/__LightingDemonstration.class new file mode 100755 index 0000000..5dc9f1b Binary files /dev/null and b/bin/sjgs/__example_games/__LightingDemonstration.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleBullet.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleBullet.class new file mode 100755 index 0000000..53d99df Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleBullet.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleDevConsole$ExampleSaveFile.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleDevConsole$ExampleSaveFile.class new file mode 100755 index 0000000..2f8c47e Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleDevConsole$ExampleSaveFile.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleDevConsole.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleDevConsole.class new file mode 100755 index 0000000..efa61ec Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleDevConsole.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleKeyInput.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleKeyInput.class new file mode 100755 index 0000000..dff438f Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleKeyInput.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleMouseInput.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleMouseInput.class new file mode 100755 index 0000000..a8b2d5e Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleMouseInput.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleObject.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleObject.class new file mode 100755 index 0000000..ea268e3 Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleObject.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExamplePlayer.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExamplePlayer.class new file mode 100755 index 0000000..aafd202 Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExamplePlayer.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleTile.class b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleTile.class new file mode 100755 index 0000000..1cfa011 Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration$ExampleTile.class differ diff --git a/bin/sjgs/__example_games/__PhysicsDemonstration.class b/bin/sjgs/__example_games/__PhysicsDemonstration.class new file mode 100755 index 0000000..284bb99 Binary files /dev/null and b/bin/sjgs/__example_games/__PhysicsDemonstration.class differ diff --git a/bin/sjgs/base_objects/BaseTile.class b/bin/sjgs/base_objects/BaseTile.class new file mode 100755 index 0000000..8ae9c09 Binary files /dev/null and b/bin/sjgs/base_objects/BaseTile.class differ diff --git a/bin/sjgs/base_objects/Bullet.class b/bin/sjgs/base_objects/Bullet.class new file mode 100755 index 0000000..5ad4d6a Binary files /dev/null and b/bin/sjgs/base_objects/Bullet.class differ diff --git a/bin/sjgs/base_objects/GameObject.class b/bin/sjgs/base_objects/GameObject.class new file mode 100755 index 0000000..c24d786 Binary files /dev/null and b/bin/sjgs/base_objects/GameObject.class differ diff --git a/bin/sjgs/base_objects/HardObject.class b/bin/sjgs/base_objects/HardObject.class new file mode 100755 index 0000000..0696c57 Binary files /dev/null and b/bin/sjgs/base_objects/HardObject.class differ diff --git a/bin/sjgs/base_objects/Mob.class b/bin/sjgs/base_objects/Mob.class new file mode 100755 index 0000000..c3cb2b9 Binary files /dev/null and b/bin/sjgs/base_objects/Mob.class differ diff --git a/bin/sjgs/base_objects/PlayerBase.class b/bin/sjgs/base_objects/PlayerBase.class new file mode 100755 index 0000000..7311ee1 Binary files /dev/null and b/bin/sjgs/base_objects/PlayerBase.class differ diff --git a/bin/sjgs/base_objects/SoftObject.class b/bin/sjgs/base_objects/SoftObject.class new file mode 100755 index 0000000..99d2d1b Binary files /dev/null and b/bin/sjgs/base_objects/SoftObject.class differ diff --git a/bin/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py b/bin/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py new file mode 100755 index 0000000..103f2d3 --- /dev/null +++ b/bin/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py @@ -0,0 +1,43 @@ +# mob will travel around a given rectangle -- think like in early stages of metroid +# territory === given rectangle +def mob_travel_around_rectangle_ai(mob, territory, speed, clockWise): + fullBounds = mob.getFullBounds() + rightBounds = mob.getRightBounds() + leftBounds = mob.getLeftBounds() + topBounds = mob.getTopBounds() + bottomBounds = mob.getBottomBounds() + + top = territory.getTop() + right = territory.getRight() + left = territory.getLeft() + bottom = territory.getBottom() + + if clockWise: + if fullBounds.intersects(right) and not fullBounds.intersects(bottom): + mob.setVelocity(0, speed) + mob.setX(territory.pos.x + territory.getWidth()) + mob.setY(restrict(mob.getY(), territory.getY() - 2)) + elif fullBounds.intersects(top): + mob.setVelocity(speed, 0) + mob.setY(territory.pos.y - mob.getHeight()) + mob.setX(restrict(mob.getX(), territory.getX() - 1)) + elif fullBounds.intersects(left) and not fullBounds.intersects(top) and not topBounds.intersects(bottom): + mob.setVelocity(0, -speed) + mob.setX(territory.pos.x - mob.getHeight()) + elif fullBounds.intersects(bottom): + mob.setVelocity(-speed, 0) + mob.setY(territory.pos.y + 2 + mob.getHeight()) + else: + if fullBounds.intersects(right) and not fullBounds.intersects(top): + mob.setVelocity(0, -speed) + mob.setX(territory.pos.x + territory.getWidth()) + mob.setY(restrict(mob.getY(), territory.getY() - 2)) + elif fullBounds.intersects(top) and not fullBounds.intersects(left): + mob.setVelocity(-speed, 0) + mob.setY(territory.pos.y - mob.getHeight()) + elif fullBounds.intersects(bottom) and not fullBounds.intersects(right): + mob.setVelocity(speed, 0) + mob.setY(territory.pos.y + mob.getHeight() + 2) + elif fullBounds.intersects(left): + mob.setVelocity(0, speed) + mob.setX(territory.pos.x - mob.getHeight()) \ No newline at end of file diff --git a/bin/sjgs/core/Camera.class b/bin/sjgs/core/Camera.class new file mode 100755 index 0000000..ded9940 Binary files /dev/null and b/bin/sjgs/core/Camera.class differ diff --git a/bin/sjgs/core/DeveloperConsole.class b/bin/sjgs/core/DeveloperConsole.class new file mode 100755 index 0000000..dd66048 Binary files /dev/null and b/bin/sjgs/core/DeveloperConsole.class differ diff --git a/bin/sjgs/core/Engine.class b/bin/sjgs/core/Engine.class new file mode 100755 index 0000000..08255dd Binary files /dev/null and b/bin/sjgs/core/Engine.class differ diff --git a/bin/sjgs/core/Handler.class b/bin/sjgs/core/Handler.class new file mode 100755 index 0000000..33a02a9 Binary files /dev/null and b/bin/sjgs/core/Handler.class differ diff --git a/bin/sjgs/core/input/Keyboard.class b/bin/sjgs/core/input/Keyboard.class new file mode 100755 index 0000000..b3f7f4f Binary files /dev/null and b/bin/sjgs/core/input/Keyboard.class differ diff --git a/bin/sjgs/core/input/Mouse.class b/bin/sjgs/core/input/Mouse.class new file mode 100755 index 0000000..708fe12 Binary files /dev/null and b/bin/sjgs/core/input/Mouse.class differ diff --git a/bin/sjgs/core/input/__Keyboard$1.class b/bin/sjgs/core/input/__Keyboard$1.class new file mode 100755 index 0000000..548e8bc Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$1.class differ diff --git a/bin/sjgs/core/input/__Keyboard$10.class b/bin/sjgs/core/input/__Keyboard$10.class new file mode 100755 index 0000000..bd0fbc4 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$10.class differ diff --git a/bin/sjgs/core/input/__Keyboard$11.class b/bin/sjgs/core/input/__Keyboard$11.class new file mode 100755 index 0000000..9d74b0d Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$11.class differ diff --git a/bin/sjgs/core/input/__Keyboard$12.class b/bin/sjgs/core/input/__Keyboard$12.class new file mode 100755 index 0000000..f2a9300 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$12.class differ diff --git a/bin/sjgs/core/input/__Keyboard$13.class b/bin/sjgs/core/input/__Keyboard$13.class new file mode 100755 index 0000000..fd46648 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$13.class differ diff --git a/bin/sjgs/core/input/__Keyboard$14.class b/bin/sjgs/core/input/__Keyboard$14.class new file mode 100755 index 0000000..3959ce4 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$14.class differ diff --git a/bin/sjgs/core/input/__Keyboard$15.class b/bin/sjgs/core/input/__Keyboard$15.class new file mode 100755 index 0000000..2487efa Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$15.class differ diff --git a/bin/sjgs/core/input/__Keyboard$16.class b/bin/sjgs/core/input/__Keyboard$16.class new file mode 100755 index 0000000..205d626 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$16.class differ diff --git a/bin/sjgs/core/input/__Keyboard$17.class b/bin/sjgs/core/input/__Keyboard$17.class new file mode 100755 index 0000000..604e4de Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$17.class differ diff --git a/bin/sjgs/core/input/__Keyboard$18.class b/bin/sjgs/core/input/__Keyboard$18.class new file mode 100755 index 0000000..9f0218b Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$18.class differ diff --git a/bin/sjgs/core/input/__Keyboard$19.class b/bin/sjgs/core/input/__Keyboard$19.class new file mode 100755 index 0000000..c55738d Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$19.class differ diff --git a/bin/sjgs/core/input/__Keyboard$2.class b/bin/sjgs/core/input/__Keyboard$2.class new file mode 100755 index 0000000..a10d4c9 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$2.class differ diff --git a/bin/sjgs/core/input/__Keyboard$20.class b/bin/sjgs/core/input/__Keyboard$20.class new file mode 100755 index 0000000..96c1f06 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$20.class differ diff --git a/bin/sjgs/core/input/__Keyboard$21.class b/bin/sjgs/core/input/__Keyboard$21.class new file mode 100755 index 0000000..3113e88 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$21.class differ diff --git a/bin/sjgs/core/input/__Keyboard$22.class b/bin/sjgs/core/input/__Keyboard$22.class new file mode 100755 index 0000000..c1a8f71 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$22.class differ diff --git a/bin/sjgs/core/input/__Keyboard$23.class b/bin/sjgs/core/input/__Keyboard$23.class new file mode 100755 index 0000000..856b25d Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$23.class differ diff --git a/bin/sjgs/core/input/__Keyboard$24.class b/bin/sjgs/core/input/__Keyboard$24.class new file mode 100755 index 0000000..6901ac6 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$24.class differ diff --git a/bin/sjgs/core/input/__Keyboard$25.class b/bin/sjgs/core/input/__Keyboard$25.class new file mode 100755 index 0000000..a6d2911 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$25.class differ diff --git a/bin/sjgs/core/input/__Keyboard$26.class b/bin/sjgs/core/input/__Keyboard$26.class new file mode 100755 index 0000000..ca697e1 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$26.class differ diff --git a/bin/sjgs/core/input/__Keyboard$27.class b/bin/sjgs/core/input/__Keyboard$27.class new file mode 100755 index 0000000..51c641f Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$27.class differ diff --git a/bin/sjgs/core/input/__Keyboard$28.class b/bin/sjgs/core/input/__Keyboard$28.class new file mode 100755 index 0000000..fe62138 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$28.class differ diff --git a/bin/sjgs/core/input/__Keyboard$29.class b/bin/sjgs/core/input/__Keyboard$29.class new file mode 100755 index 0000000..4e6f96e Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$29.class differ diff --git a/bin/sjgs/core/input/__Keyboard$3.class b/bin/sjgs/core/input/__Keyboard$3.class new file mode 100755 index 0000000..1eea8e4 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$3.class differ diff --git a/bin/sjgs/core/input/__Keyboard$30.class b/bin/sjgs/core/input/__Keyboard$30.class new file mode 100755 index 0000000..28f9cf8 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$30.class differ diff --git a/bin/sjgs/core/input/__Keyboard$31.class b/bin/sjgs/core/input/__Keyboard$31.class new file mode 100755 index 0000000..225c312 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$31.class differ diff --git a/bin/sjgs/core/input/__Keyboard$32.class b/bin/sjgs/core/input/__Keyboard$32.class new file mode 100755 index 0000000..abba144 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$32.class differ diff --git a/bin/sjgs/core/input/__Keyboard$33.class b/bin/sjgs/core/input/__Keyboard$33.class new file mode 100755 index 0000000..c5abcdd Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$33.class differ diff --git a/bin/sjgs/core/input/__Keyboard$34.class b/bin/sjgs/core/input/__Keyboard$34.class new file mode 100755 index 0000000..4911c2d Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$34.class differ diff --git a/bin/sjgs/core/input/__Keyboard$35.class b/bin/sjgs/core/input/__Keyboard$35.class new file mode 100755 index 0000000..f60931f Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$35.class differ diff --git a/bin/sjgs/core/input/__Keyboard$36.class b/bin/sjgs/core/input/__Keyboard$36.class new file mode 100755 index 0000000..6afd09b Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$36.class differ diff --git a/bin/sjgs/core/input/__Keyboard$37.class b/bin/sjgs/core/input/__Keyboard$37.class new file mode 100755 index 0000000..c6093c2 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$37.class differ diff --git a/bin/sjgs/core/input/__Keyboard$38.class b/bin/sjgs/core/input/__Keyboard$38.class new file mode 100755 index 0000000..a2e7853 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$38.class differ diff --git a/bin/sjgs/core/input/__Keyboard$39.class b/bin/sjgs/core/input/__Keyboard$39.class new file mode 100755 index 0000000..44bf763 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$39.class differ diff --git a/bin/sjgs/core/input/__Keyboard$4.class b/bin/sjgs/core/input/__Keyboard$4.class new file mode 100755 index 0000000..d6bb19f Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$4.class differ diff --git a/bin/sjgs/core/input/__Keyboard$40.class b/bin/sjgs/core/input/__Keyboard$40.class new file mode 100755 index 0000000..ddaa9ac Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$40.class differ diff --git a/bin/sjgs/core/input/__Keyboard$41.class b/bin/sjgs/core/input/__Keyboard$41.class new file mode 100755 index 0000000..b61011a Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$41.class differ diff --git a/bin/sjgs/core/input/__Keyboard$42.class b/bin/sjgs/core/input/__Keyboard$42.class new file mode 100755 index 0000000..d14d04d Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$42.class differ diff --git a/bin/sjgs/core/input/__Keyboard$43.class b/bin/sjgs/core/input/__Keyboard$43.class new file mode 100755 index 0000000..a906276 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$43.class differ diff --git a/bin/sjgs/core/input/__Keyboard$44.class b/bin/sjgs/core/input/__Keyboard$44.class new file mode 100755 index 0000000..e2b95f5 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$44.class differ diff --git a/bin/sjgs/core/input/__Keyboard$45.class b/bin/sjgs/core/input/__Keyboard$45.class new file mode 100755 index 0000000..2d4ad34 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$45.class differ diff --git a/bin/sjgs/core/input/__Keyboard$46.class b/bin/sjgs/core/input/__Keyboard$46.class new file mode 100755 index 0000000..39d68ae Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$46.class differ diff --git a/bin/sjgs/core/input/__Keyboard$47.class b/bin/sjgs/core/input/__Keyboard$47.class new file mode 100755 index 0000000..4a51cb3 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$47.class differ diff --git a/bin/sjgs/core/input/__Keyboard$48.class b/bin/sjgs/core/input/__Keyboard$48.class new file mode 100755 index 0000000..9920afe Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$48.class differ diff --git a/bin/sjgs/core/input/__Keyboard$49.class b/bin/sjgs/core/input/__Keyboard$49.class new file mode 100755 index 0000000..848f4e4 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$49.class differ diff --git a/bin/sjgs/core/input/__Keyboard$5.class b/bin/sjgs/core/input/__Keyboard$5.class new file mode 100755 index 0000000..0329f2d Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$5.class differ diff --git a/bin/sjgs/core/input/__Keyboard$50.class b/bin/sjgs/core/input/__Keyboard$50.class new file mode 100755 index 0000000..92cd501 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$50.class differ diff --git a/bin/sjgs/core/input/__Keyboard$51.class b/bin/sjgs/core/input/__Keyboard$51.class new file mode 100755 index 0000000..7ea015a Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$51.class differ diff --git a/bin/sjgs/core/input/__Keyboard$52.class b/bin/sjgs/core/input/__Keyboard$52.class new file mode 100755 index 0000000..9921db9 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$52.class differ diff --git a/bin/sjgs/core/input/__Keyboard$53.class b/bin/sjgs/core/input/__Keyboard$53.class new file mode 100755 index 0000000..6716875 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$53.class differ diff --git a/bin/sjgs/core/input/__Keyboard$54.class b/bin/sjgs/core/input/__Keyboard$54.class new file mode 100755 index 0000000..343703b Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$54.class differ diff --git a/bin/sjgs/core/input/__Keyboard$55.class b/bin/sjgs/core/input/__Keyboard$55.class new file mode 100755 index 0000000..317b8df Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$55.class differ diff --git a/bin/sjgs/core/input/__Keyboard$56.class b/bin/sjgs/core/input/__Keyboard$56.class new file mode 100755 index 0000000..fecbd5c Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$56.class differ diff --git a/bin/sjgs/core/input/__Keyboard$57.class b/bin/sjgs/core/input/__Keyboard$57.class new file mode 100755 index 0000000..061d3fa Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$57.class differ diff --git a/bin/sjgs/core/input/__Keyboard$58.class b/bin/sjgs/core/input/__Keyboard$58.class new file mode 100755 index 0000000..c440330 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$58.class differ diff --git a/bin/sjgs/core/input/__Keyboard$59.class b/bin/sjgs/core/input/__Keyboard$59.class new file mode 100755 index 0000000..d8fbfca Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$59.class differ diff --git a/bin/sjgs/core/input/__Keyboard$6.class b/bin/sjgs/core/input/__Keyboard$6.class new file mode 100755 index 0000000..99b5438 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$6.class differ diff --git a/bin/sjgs/core/input/__Keyboard$60.class b/bin/sjgs/core/input/__Keyboard$60.class new file mode 100755 index 0000000..9e8f88b Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$60.class differ diff --git a/bin/sjgs/core/input/__Keyboard$61.class b/bin/sjgs/core/input/__Keyboard$61.class new file mode 100755 index 0000000..b5013a6 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$61.class differ diff --git a/bin/sjgs/core/input/__Keyboard$62.class b/bin/sjgs/core/input/__Keyboard$62.class new file mode 100755 index 0000000..58c0121 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$62.class differ diff --git a/bin/sjgs/core/input/__Keyboard$63.class b/bin/sjgs/core/input/__Keyboard$63.class new file mode 100755 index 0000000..e9622a2 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$63.class differ diff --git a/bin/sjgs/core/input/__Keyboard$64.class b/bin/sjgs/core/input/__Keyboard$64.class new file mode 100755 index 0000000..94fec1b Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$64.class differ diff --git a/bin/sjgs/core/input/__Keyboard$7.class b/bin/sjgs/core/input/__Keyboard$7.class new file mode 100755 index 0000000..cc85609 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$7.class differ diff --git a/bin/sjgs/core/input/__Keyboard$8.class b/bin/sjgs/core/input/__Keyboard$8.class new file mode 100755 index 0000000..d8d1da0 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$8.class differ diff --git a/bin/sjgs/core/input/__Keyboard$9.class b/bin/sjgs/core/input/__Keyboard$9.class new file mode 100755 index 0000000..b8058ed Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard$9.class differ diff --git a/bin/sjgs/core/input/__Keyboard.class b/bin/sjgs/core/input/__Keyboard.class new file mode 100755 index 0000000..a87c9f6 Binary files /dev/null and b/bin/sjgs/core/input/__Keyboard.class differ diff --git a/bin/sjgs/core/jython/Jython.class b/bin/sjgs/core/jython/Jython.class new file mode 100755 index 0000000..9ace33d Binary files /dev/null and b/bin/sjgs/core/jython/Jython.class differ diff --git a/bin/sjgs/core/jython/engine_imports.py b/bin/sjgs/core/jython/engine_imports.py new file mode 100755 index 0000000..47d54cd --- /dev/null +++ b/bin/sjgs/core/jython/engine_imports.py @@ -0,0 +1,46 @@ +### Java standard library imports +from java.lang.Math import * +from java.lang import Integer, Float, Double + +### engine imports +from sjgs.core import Engine as Engine +from sjgs.core import Camera as Camera +from sjgs.core import Handler as Handler + +import sjgs.core.input.Mouse as Mouse + +import sjgs.enums.Facing as Facing +import sjgs.enums.TickRate as TickRate +import sjgs.enums.Type as Type + +from sjgs.graphics.Colors import * +from sjgs.graphics import Colors + +from sjgs.base_objects import * + +import sjgs.sound.SoundPlayer as SoundPlayer + +import sjgs.physics.Physics as Physics +import sjgs.physics.structs.BoundingBox as BoundingBox +import sjgs.physics.structs.CollisionResponse as CollisionResponse + +from sjgs.utils.Utils import * +import sjgs.utils.Utils + +import sjgs.utils.tools.Timer as Timer + +import sjgs.utils.encryption.StrongCaesarCipher + +import sjgs.utils.data_structures.Stack as Stack +from sjgs.utils.data_structures.shapes import * +from sjgs.utils.data_structures.vectors import * +from sjgs.utils.data_structures.gaming import * +import sjgs.utils.data_structures.shapes.Rectangle as Rectangle +import sjgs.utils.data_structures.vectors.Point2f as Point2f +import sjgs.utils.data_structures.vectors.SimplePoint as SimplePoint +import sjgs.utils.data_structures.shapes.Line as Line + + +from sjgs.graphics.ui.InventorySystemSlot import EMPTY +import sjgs.graphics.ui.InventorySystem as InventorySystem +import sjgs.graphics.ui.InventorySystemSlot as InventorySystemSlot diff --git a/bin/sjgs/enums/Facing.class b/bin/sjgs/enums/Facing.class new file mode 100755 index 0000000..5864a64 Binary files /dev/null and b/bin/sjgs/enums/Facing.class differ diff --git a/bin/sjgs/enums/TickRate.class b/bin/sjgs/enums/TickRate.class new file mode 100755 index 0000000..20b46d7 Binary files /dev/null and b/bin/sjgs/enums/TickRate.class differ diff --git a/bin/sjgs/enums/Type.class b/bin/sjgs/enums/Type.class new file mode 100755 index 0000000..6ba904f Binary files /dev/null and b/bin/sjgs/enums/Type.class differ diff --git a/bin/sjgs/graphics/Animation.class b/bin/sjgs/graphics/Animation.class new file mode 100755 index 0000000..a58f14d Binary files /dev/null and b/bin/sjgs/graphics/Animation.class differ diff --git a/bin/sjgs/graphics/Colors.class b/bin/sjgs/graphics/Colors.class new file mode 100755 index 0000000..a11f9ca Binary files /dev/null and b/bin/sjgs/graphics/Colors.class differ diff --git a/bin/sjgs/graphics/backgrounds/Background.class b/bin/sjgs/graphics/backgrounds/Background.class new file mode 100755 index 0000000..c713d48 Binary files /dev/null and b/bin/sjgs/graphics/backgrounds/Background.class differ diff --git a/bin/sjgs/graphics/backgrounds/ParallaxBackground.class b/bin/sjgs/graphics/backgrounds/ParallaxBackground.class new file mode 100755 index 0000000..4e57ef5 Binary files /dev/null and b/bin/sjgs/graphics/backgrounds/ParallaxBackground.class differ diff --git a/bin/sjgs/graphics/lighting/Light.class b/bin/sjgs/graphics/lighting/Light.class new file mode 100755 index 0000000..0fd0690 Binary files /dev/null and b/bin/sjgs/graphics/lighting/Light.class differ diff --git a/bin/sjgs/graphics/lighting/LightsRenderer.class b/bin/sjgs/graphics/lighting/LightsRenderer.class new file mode 100755 index 0000000..6e15b77 Binary files /dev/null and b/bin/sjgs/graphics/lighting/LightsRenderer.class differ diff --git a/bin/sjgs/graphics/lighting/RadialLight.class b/bin/sjgs/graphics/lighting/RadialLight.class new file mode 100755 index 0000000..5591179 Binary files /dev/null and b/bin/sjgs/graphics/lighting/RadialLight.class differ diff --git a/bin/sjgs/graphics/ui/InventorySystem.class b/bin/sjgs/graphics/ui/InventorySystem.class new file mode 100755 index 0000000..008a64d Binary files /dev/null and b/bin/sjgs/graphics/ui/InventorySystem.class differ diff --git a/bin/sjgs/graphics/ui/InventorySystemSlot.class b/bin/sjgs/graphics/ui/InventorySystemSlot.class new file mode 100755 index 0000000..a3ea360 Binary files /dev/null and b/bin/sjgs/graphics/ui/InventorySystemSlot.class differ diff --git a/bin/sjgs/graphics/ui/Menu.class b/bin/sjgs/graphics/ui/Menu.class new file mode 100755 index 0000000..f421c36 Binary files /dev/null and b/bin/sjgs/graphics/ui/Menu.class differ diff --git a/bin/sjgs/graphics/ui/MenuButton.class b/bin/sjgs/graphics/ui/MenuButton.class new file mode 100755 index 0000000..7cf197a Binary files /dev/null and b/bin/sjgs/graphics/ui/MenuButton.class differ diff --git a/bin/sjgs/graphics/ui/__engine_inventory.py b/bin/sjgs/graphics/ui/__engine_inventory.py new file mode 100755 index 0000000..2b517a4 --- /dev/null +++ b/bin/sjgs/graphics/ui/__engine_inventory.py @@ -0,0 +1,100 @@ +def __engine_onLeftClick(inventory): + # SLOT SWAPPING! + # @param i: The slot you are currently holding + # @param e: The slot you are trying to click on + for i in inventory.getSlots(): + # FILTER UNTIL I == THE SLOT YOU'RE HOLDING + if not i.mouseClicked: continue + for e in inventory.getSlots(): + # IF THE SECOND SLOT CONTAINS THE MOUSE POINTER, SWAP! + if i != e and e.bounds.contains(Mouse.getClickX(), Mouse.getClickY()): + inventory.swap(i, e) + return # NOTE: YOU MUST RETURN HERE OR IT WONT WORK! + + # GRAPHICAL SLOT MOVING! + for i in inventory.getSlots(): + if i.isEmpty(): continue + # SET MOUSELCICKED TO TRUE + if not i.mouseClicked and i.bounds.contains(Mouse.getClickX(), Mouse.getClickY()): + inventory.resetMouseClicked() # ONLY WANT 1 ITEM TO BE MOUSE CLICKED AT A TIME + i.mouseClicked = True + break + + # IF HOLDING AN ITEM, AND CLICK OUTSIDE OF THE INVENTORY BOUNDS --- DROP + elif i.mouseClicked and not inventory.getBounds().contains(Mouse.getClickX(), Mouse.getClickY()): + i.mouseClicked = False + break + # ELSE IF YOU JUST CLICKED SOMEWHERE IN THE INVEN WITHOUT BEING ON A SLOT LIKE AN IDIOT + else: i.mouseClicked = False + + # FIXES BUGS -- ALWAYS RUN THIS + inventory.resetPositions() + +def __engine_add_item(itemId, quantity, inventory): + # DONT ADD ITEM IF IT IS THE NULL PLACEHOLDER ITEM + if itemId == EMPTY: return + + # CANT ADD ITEM IF THE INVEN IS FULL + if __engine_inventory_is_full(itemId, quantity, inventory): return + + # IF THE ITEM IS STACKABLE, RUN THIS LOOP + if inventory.isStackable(itemId): + for i in inventory.getSlots(): + if i.itemId == itemId and (i.quantity + quantity) <= inventory.getStackableAmount(itemId): + i.mouseClicked = False + i.quantity += quantity + inventory.resetPositions() + return + + # IF THE ITEM IS NOT STACKABLE, OR FAILED THE ABOVE LOOP, RUN THIS LOOP + for i in inventory.getSlots(): + if(i.isEmpty()): + i.mouseClicked = False + i.itemId = itemId + i.quantity = quantity + inventory.resetPositions() + return + +def __engine_remove_item(itemId, quantity, inventory): + for slot in inventory.getSlots(): + if slot.itemId == itemId: + temp = slot.quantity + slot.quantity -= quantity + quantity -= temp + slot.mouseClicked = False + + if slot.quantity <= 0: slot.reset() + + # if the amount of things to remove has been satisfied + if quantity <= 0: break + inventory.resetPositions() + +def __engine_remove_item_with_slot_number(itemId, quantity, slotNumber): + for i in inventory.getSlots(): + if i.slotNumber == slotNumber: + if i.itemId == itemId: + i.quantity -= quantity + i.mouseClicked = False + if i.quantity <= 0: slot.reset() + break + inventory.resetPositions() + +def __engine_inventory_is_full(itemId, quantity, inventory): + if inventory.isStackable(itemId): # IF ITEM IS STACKABLE, RUN THIS LOOP + for slot in inventory.getSlots(): + # CHECK IF THE (QUANTITY + THE ADDED QUANTITY) IS <= THE MAX QUANTITY + WOULD_BE_QUANTITY = slot.quantity + quantity + if slot.itemId == itemId and WOULD_BE_QUANTITY <= inventory.getStackableAmount(itemId): return False + + # IF IT IS NOT STACKABLE, OR THE ITEM FAILED THE FIRST LOOP, RUN THIS LOOP + for slot in inventory.getSlots(): + if slot.itemId == 0: return False + + # IF NONE OF THE ABOVE CONDITIONS COULD BE MET, THE INVENTORY MUST BE FULL + return True + +def __engine_inventory_contains(itemId, quantity, inventory): + count = 0 + for slot in inventory.getSlots(): + if slot.itemId == itemId: count += slot.quantity + return count >= quantity \ No newline at end of file diff --git a/bin/sjgs/physics/Physics.class b/bin/sjgs/physics/Physics.class new file mode 100755 index 0000000..d042da2 Binary files /dev/null and b/bin/sjgs/physics/Physics.class differ diff --git a/bin/sjgs/physics/__BulletPhysics.class b/bin/sjgs/physics/__BulletPhysics.class new file mode 100755 index 0000000..c9b04e5 Binary files /dev/null and b/bin/sjgs/physics/__BulletPhysics.class differ diff --git a/bin/sjgs/physics/__Calculators.class b/bin/sjgs/physics/__Calculators.class new file mode 100755 index 0000000..7ee76c5 Binary files /dev/null and b/bin/sjgs/physics/__Calculators.class differ diff --git a/bin/sjgs/physics/__Collision.class b/bin/sjgs/physics/__Collision.class new file mode 100755 index 0000000..564aae5 Binary files /dev/null and b/bin/sjgs/physics/__Collision.class differ diff --git a/bin/sjgs/physics/__Friction.class b/bin/sjgs/physics/__Friction.class new file mode 100755 index 0000000..a04c33a Binary files /dev/null and b/bin/sjgs/physics/__Friction.class differ diff --git a/bin/sjgs/physics/__GeneralCollision.class b/bin/sjgs/physics/__GeneralCollision.class new file mode 100755 index 0000000..ea7f14f Binary files /dev/null and b/bin/sjgs/physics/__GeneralCollision.class differ diff --git a/bin/sjgs/physics/__Gravity.class b/bin/sjgs/physics/__Gravity.class new file mode 100755 index 0000000..ff106b6 Binary files /dev/null and b/bin/sjgs/physics/__Gravity.class differ diff --git a/bin/sjgs/physics/__UpdatePosition.class b/bin/sjgs/physics/__UpdatePosition.class new file mode 100755 index 0000000..f24c5a2 Binary files /dev/null and b/bin/sjgs/physics/__UpdatePosition.class differ diff --git a/bin/sjgs/physics/structs/BoundingBox.class b/bin/sjgs/physics/structs/BoundingBox.class new file mode 100755 index 0000000..949fd81 Binary files /dev/null and b/bin/sjgs/physics/structs/BoundingBox.class differ diff --git a/bin/sjgs/physics/structs/CollisionResponse.class b/bin/sjgs/physics/structs/CollisionResponse.class new file mode 100755 index 0000000..c523aa5 Binary files /dev/null and b/bin/sjgs/physics/structs/CollisionResponse.class differ diff --git a/bin/sjgs/sound/MusicPlayer$SoundThread.class b/bin/sjgs/sound/MusicPlayer$SoundThread.class new file mode 100755 index 0000000..2a9a3f4 Binary files /dev/null and b/bin/sjgs/sound/MusicPlayer$SoundThread.class differ diff --git a/bin/sjgs/sound/MusicPlayer.class b/bin/sjgs/sound/MusicPlayer.class new file mode 100755 index 0000000..dd1baf2 Binary files /dev/null and b/bin/sjgs/sound/MusicPlayer.class differ diff --git a/bin/sjgs/sound/SoundPlayer.class b/bin/sjgs/sound/SoundPlayer.class new file mode 100755 index 0000000..706aefa Binary files /dev/null and b/bin/sjgs/sound/SoundPlayer.class differ diff --git a/bin/sjgs/utils/Utils.class b/bin/sjgs/utils/Utils.class new file mode 100755 index 0000000..2062ad5 Binary files /dev/null and b/bin/sjgs/utils/Utils.class differ diff --git a/bin/sjgs/utils/__Algorithms.class b/bin/sjgs/utils/__Algorithms.class new file mode 100755 index 0000000..da50d33 Binary files /dev/null and b/bin/sjgs/utils/__Algorithms.class differ diff --git a/bin/sjgs/utils/__ImageManipulation.class b/bin/sjgs/utils/__ImageManipulation.class new file mode 100755 index 0000000..c8bfe7d Binary files /dev/null and b/bin/sjgs/utils/__ImageManipulation.class differ diff --git a/bin/sjgs/utils/__IntersectionUtils.class b/bin/sjgs/utils/__IntersectionUtils.class new file mode 100755 index 0000000..2d54f53 Binary files /dev/null and b/bin/sjgs/utils/__IntersectionUtils.class differ diff --git a/bin/sjgs/utils/__MixMaxUtils.class b/bin/sjgs/utils/__MixMaxUtils.class new file mode 100755 index 0000000..bc923cf Binary files /dev/null and b/bin/sjgs/utils/__MixMaxUtils.class differ diff --git a/bin/sjgs/utils/__SerializationUtils.class b/bin/sjgs/utils/__SerializationUtils.class new file mode 100755 index 0000000..798c115 Binary files /dev/null and b/bin/sjgs/utils/__SerializationUtils.class differ diff --git a/bin/sjgs/utils/__TextFileManipulation.class b/bin/sjgs/utils/__TextFileManipulation.class new file mode 100755 index 0000000..e8143da Binary files /dev/null and b/bin/sjgs/utils/__TextFileManipulation.class differ diff --git a/bin/sjgs/utils/data_structures/Stack$Node.class b/bin/sjgs/utils/data_structures/Stack$Node.class new file mode 100755 index 0000000..c7a9800 Binary files /dev/null and b/bin/sjgs/utils/data_structures/Stack$Node.class differ diff --git a/bin/sjgs/utils/data_structures/Stack$StackIterator.class b/bin/sjgs/utils/data_structures/Stack$StackIterator.class new file mode 100755 index 0000000..7e30812 Binary files /dev/null and b/bin/sjgs/utils/data_structures/Stack$StackIterator.class differ diff --git a/bin/sjgs/utils/data_structures/Stack.class b/bin/sjgs/utils/data_structures/Stack.class new file mode 100755 index 0000000..43138a8 Binary files /dev/null and b/bin/sjgs/utils/data_structures/Stack.class differ diff --git a/bin/sjgs/utils/data_structures/gaming/QuadTree$Data.class b/bin/sjgs/utils/data_structures/gaming/QuadTree$Data.class new file mode 100755 index 0000000..b2da16a Binary files /dev/null and b/bin/sjgs/utils/data_structures/gaming/QuadTree$Data.class differ diff --git a/bin/sjgs/utils/data_structures/gaming/QuadTree$Func.class b/bin/sjgs/utils/data_structures/gaming/QuadTree$Func.class new file mode 100755 index 0000000..0587d13 Binary files /dev/null and b/bin/sjgs/utils/data_structures/gaming/QuadTree$Func.class differ diff --git a/bin/sjgs/utils/data_structures/gaming/QuadTree$Node.class b/bin/sjgs/utils/data_structures/gaming/QuadTree$Node.class new file mode 100755 index 0000000..184f4f9 Binary files /dev/null and b/bin/sjgs/utils/data_structures/gaming/QuadTree$Node.class differ diff --git a/bin/sjgs/utils/data_structures/gaming/QuadTree$NodeType.class b/bin/sjgs/utils/data_structures/gaming/QuadTree$NodeType.class new file mode 100755 index 0000000..ef3846b Binary files /dev/null and b/bin/sjgs/utils/data_structures/gaming/QuadTree$NodeType.class differ diff --git a/bin/sjgs/utils/data_structures/gaming/QuadTree.class b/bin/sjgs/utils/data_structures/gaming/QuadTree.class new file mode 100755 index 0000000..62cd094 Binary files /dev/null and b/bin/sjgs/utils/data_structures/gaming/QuadTree.class differ diff --git a/bin/sjgs/utils/data_structures/interfaces/ListInterface.class b/bin/sjgs/utils/data_structures/interfaces/ListInterface.class new file mode 100755 index 0000000..dd69e4a Binary files /dev/null and b/bin/sjgs/utils/data_structures/interfaces/ListInterface.class differ diff --git a/bin/sjgs/utils/data_structures/interfaces/StackInterface.class b/bin/sjgs/utils/data_structures/interfaces/StackInterface.class new file mode 100755 index 0000000..55d779e Binary files /dev/null and b/bin/sjgs/utils/data_structures/interfaces/StackInterface.class differ diff --git a/bin/sjgs/utils/data_structures/shapes/Circle.class b/bin/sjgs/utils/data_structures/shapes/Circle.class new file mode 100755 index 0000000..60010ea Binary files /dev/null and b/bin/sjgs/utils/data_structures/shapes/Circle.class differ diff --git a/bin/sjgs/utils/data_structures/shapes/Line.class b/bin/sjgs/utils/data_structures/shapes/Line.class new file mode 100755 index 0000000..8486107 Binary files /dev/null and b/bin/sjgs/utils/data_structures/shapes/Line.class differ diff --git a/bin/sjgs/utils/data_structures/shapes/Rectangle.class b/bin/sjgs/utils/data_structures/shapes/Rectangle.class new file mode 100755 index 0000000..eea5308 Binary files /dev/null and b/bin/sjgs/utils/data_structures/shapes/Rectangle.class differ diff --git a/bin/sjgs/utils/data_structures/shapes/Triangle.class b/bin/sjgs/utils/data_structures/shapes/Triangle.class new file mode 100755 index 0000000..9d549e6 Binary files /dev/null and b/bin/sjgs/utils/data_structures/shapes/Triangle.class differ diff --git a/bin/sjgs/utils/data_structures/vectors/Point2f.class b/bin/sjgs/utils/data_structures/vectors/Point2f.class new file mode 100755 index 0000000..a5f17af Binary files /dev/null and b/bin/sjgs/utils/data_structures/vectors/Point2f.class differ diff --git a/bin/sjgs/utils/data_structures/vectors/SimplePoint.class b/bin/sjgs/utils/data_structures/vectors/SimplePoint.class new file mode 100755 index 0000000..bbb9c77 Binary files /dev/null and b/bin/sjgs/utils/data_structures/vectors/SimplePoint.class differ diff --git a/bin/sjgs/utils/data_structures/vectors/Vector2f.class b/bin/sjgs/utils/data_structures/vectors/Vector2f.class new file mode 100755 index 0000000..4053777 Binary files /dev/null and b/bin/sjgs/utils/data_structures/vectors/Vector2f.class differ diff --git a/bin/sjgs/utils/encryption/CaesarCipher.class b/bin/sjgs/utils/encryption/CaesarCipher.class new file mode 100755 index 0000000..c5ec2de Binary files /dev/null and b/bin/sjgs/utils/encryption/CaesarCipher.class differ diff --git a/bin/sjgs/utils/encryption/EncryptionInterface.class b/bin/sjgs/utils/encryption/EncryptionInterface.class new file mode 100755 index 0000000..3f114b4 Binary files /dev/null and b/bin/sjgs/utils/encryption/EncryptionInterface.class differ diff --git a/bin/sjgs/utils/encryption/StrongCaesarCipher.class b/bin/sjgs/utils/encryption/StrongCaesarCipher.class new file mode 100755 index 0000000..4c395fe Binary files /dev/null and b/bin/sjgs/utils/encryption/StrongCaesarCipher.class differ diff --git a/bin/sjgs/utils/io/SaveFile.class b/bin/sjgs/utils/io/SaveFile.class new file mode 100755 index 0000000..0acc6ea Binary files /dev/null and b/bin/sjgs/utils/io/SaveFile.class differ diff --git a/bin/sjgs/utils/io/__HandlerSaveState.class b/bin/sjgs/utils/io/__HandlerSaveState.class new file mode 100755 index 0000000..cf33f89 Binary files /dev/null and b/bin/sjgs/utils/io/__HandlerSaveState.class differ diff --git a/bin/sjgs/utils/multithreading/Executable.class b/bin/sjgs/utils/multithreading/Executable.class new file mode 100755 index 0000000..b20d008 Binary files /dev/null and b/bin/sjgs/utils/multithreading/Executable.class differ diff --git a/bin/sjgs/utils/multithreading/Runner.class b/bin/sjgs/utils/multithreading/Runner.class new file mode 100755 index 0000000..40bef85 Binary files /dev/null and b/bin/sjgs/utils/multithreading/Runner.class differ diff --git a/bin/sjgs/utils/multithreading/ThreadPool$PooledThread.class b/bin/sjgs/utils/multithreading/ThreadPool$PooledThread.class new file mode 100755 index 0000000..708c0b4 Binary files /dev/null and b/bin/sjgs/utils/multithreading/ThreadPool$PooledThread.class differ diff --git a/bin/sjgs/utils/multithreading/ThreadPool.class b/bin/sjgs/utils/multithreading/ThreadPool.class new file mode 100755 index 0000000..46cb071 Binary files /dev/null and b/bin/sjgs/utils/multithreading/ThreadPool.class differ diff --git a/bin/sjgs/utils/pyutils/PyUtils.class b/bin/sjgs/utils/pyutils/PyUtils.class new file mode 100755 index 0000000..6ade75a Binary files /dev/null and b/bin/sjgs/utils/pyutils/PyUtils.class differ diff --git a/bin/sjgs/utils/tools/Timer.class b/bin/sjgs/utils/tools/Timer.class new file mode 100755 index 0000000..d8bd503 Binary files /dev/null and b/bin/sjgs/utils/tools/Timer.class differ diff --git a/bin/sjgs/world_generation/Action.class b/bin/sjgs/world_generation/Action.class new file mode 100755 index 0000000..d78bb99 Binary files /dev/null and b/bin/sjgs/world_generation/Action.class differ diff --git a/bin/sjgs/world_generation/TileMap.class b/bin/sjgs/world_generation/TileMap.class new file mode 100755 index 0000000..e09df24 Binary files /dev/null and b/bin/sjgs/world_generation/TileMap.class differ diff --git a/dep/Jython.jar b/dep/Jython.jar new file mode 100755 index 0000000..c494983 Binary files /dev/null and b/dep/Jython.jar differ diff --git a/dep/SJGS-JLayer.jar b/dep/SJGS-JLayer.jar new file mode 100755 index 0000000..74b828e Binary files /dev/null and b/dep/SJGS-JLayer.jar differ diff --git a/res/gregorian.ttf b/res/gregorian.ttf new file mode 100755 index 0000000..a1cccff Binary files /dev/null and b/res/gregorian.ttf differ diff --git a/res/ponderosa.ttf b/res/ponderosa.ttf new file mode 100755 index 0000000..89eab2d Binary files /dev/null and b/res/ponderosa.ttf differ diff --git a/src/sjgs/__example_games/__InventoryExample.java b/src/sjgs/__example_games/__InventoryExample.java new file mode 100755 index 0000000..483ae56 --- /dev/null +++ b/src/sjgs/__example_games/__InventoryExample.java @@ -0,0 +1,160 @@ +package sjgs.__example_games; + +import static sjgs.graphics.Colors.blue; +import static sjgs.graphics.Colors.orange; +import static sjgs.graphics.Colors.red; +import static sjgs.graphics.Colors.white; +import static sjgs.utils.Utils.rand; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import sjgs.core.Engine; +import sjgs.core.input.Mouse; +import sjgs.graphics.ui.InventorySystem; +import sjgs.graphics.ui.InventorySystemSlot; + +/** Welcome to a demonstration of the @InventorySystem class in Mitch's Game Engine! */ + +class __InventoryExample extends Engine { + + public __InventoryExample(final int WIDTH, final int HEIGHT, final String title) { + super(WIDTH, HEIGHT, title); + } + + // Create our engine! + private static __InventoryExample engine; + // Create our inventory! + private static ExampleInventory inventory; + + // Create the window for our engine, and initialize our engine itself while we're here. + public static void main(final String[] args) { + engine = new __InventoryExample(800, 600, "Inventory System Demonstration"); + } + + // Create our mouse input, which will also add itself to our engine that we're passing in. + @Override + protected void init() { + new MouseInput(this); + // Then we initialize our inventory + inventory = new ExampleInventory(getWidth() * 0.1f, getHeight() * 0.1f, getWidth() * 0.8f, getHeight() * 0.8f); + } + + // In our main tick method, we make sure to tick our new inventory + @Override + protected void tick() { inventory.tick(); } + + // Like wise in our main render method + @Override + protected void render(final Graphics2D g2d) { inventory.render(g2d); } + + // Lets create an interface full of itemId's for our inventory --- Note that '0' is reserved for empty slots + private static interface items { static final int CIRCLE = 1, SQUARE = 2, TRIANGLE = 3; } + + // INVENTORY SLOT CLASS! + private static class ExampleInventorySlot extends InventorySystemSlot implements items { + public ExampleInventorySlot(final float x, final float y, final float w, final float h, final int slotNumber) { super(x, y, w, h, slotNumber); } + + @Override + public void init() {} + // Here we set the center of the slot to our mouse if we have clicked on it + @Override + public void tick() { + if(mouseClicked) bounds.setLocation(Mouse.getX() - bounds.getHalfWidth(), Mouse.getY() - bounds.getHalfHeight()); + } + + // Render our slots! + @Override + public void render(final Graphics2D g2d) { + switch(itemId) { + case EMPTY: break; + case CIRCLE: g2d.setColor(orange); g2d.fillOval((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight()); break; + case SQUARE: g2d.setColor(red); bounds.drawFilled(g2d); break; + case TRIANGLE: g2d.setColor(blue); bounds.toTriangle().draw(g2d); break; + } + + // Here I draw the starting locations of the slots for clarity during the demonstration + g2d.setColor(Color.white); + g2d.drawRect((int)getStartingX(), (int)getStartingY(), (int)getWidth(), (int)getHeight()); + + // Here is where you would draw quantities, but for this demonstration all quantities are zero + if(quantity > 1) + g2d.drawString(""+quantity, getX(), getY() + getHalfHeight()); + } + + // Python methods in the superclass require this "baseReset". + // More advanced inventory systems may require you to write your own reset methods however. + @Override + public void reset() { baseReset(); } + } + + // INVENTORY CLASS! + private static class ExampleInventory extends InventorySystem implements items { + public ExampleInventory(final float x, final float y, final float width, final float height) { super(x, y, width, height); } + + // Here we create all our inventory slots! + @Override + public void init() { + final int w = 50, h = 50; + for(int i = 1; i < 6; i++) slots.add(new ExampleInventorySlot(engine.getWidth() * 0.3f, engine.getHeight()*0.1f + i*h, w, h, i - 1)); + for(int i = 1; i < 6; i++) slots.add(new ExampleInventorySlot(engine.getWidth() * 0.6f, engine.getHeight()*0.1f + i*h, w, h, i - 1)); + + // And fill them with random items + for(int i = 0; i < 10; i++) addItem(rand.nextInt(4)); + } + + // Tick all our slots + @Override + public void tick() { for(final InventorySystemSlot i : slots) i.tick(); } + + // Render all our slots, and draw the main inventory's bounds + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(white); + getBounds().draw(g2d); + + for(final InventorySystemSlot i : slots) i.render(g2d); + /* pro tip: running through again here like so will put the held item always above the others */ + for(final InventorySystemSlot i : slots) if(i.mouseClicked) { i.render(g2d); break; } + } + + @Override + public void destroy() {} + // Here you can write whatever logic you want to happen on clicks, however for now we use the base, standard click method. + @Override + public void onLeftClick() { baseOnLeftClick(); } + @Override + public boolean isStackable(final int itemId) { return false; } + @Override + public int getStackableAmount(final int itemId) { return 0; } + + @Override + public void swapSlots(final InventorySystemSlot i, final InventorySystemSlot e) { + baseSwapSlots(i, e); + } + + + } + + // Basic mouse input class so we have input + private static class MouseInput extends Mouse { + public MouseInput(final Engine engine) { super(engine); } + @Override + public void mouseMoved(final MouseEvent e) { + setLocation(e.getX(), e.getY()); + } + @Override + public void mouseClicked(final MouseEvent e) { + setClickLocation(e.getX(), e.getY()); + if(e.getButton() == 1) inventory.onLeftClick(); + } + @Override + public void mouseWheelMoved(final MouseWheelEvent arg0) {} + @Override + public void mousePressed(final MouseEvent e) {} + @Override + public void mouseReleased(final MouseEvent e) {} + } + + // And that's it! Very easy, simple implementation of an inventory class :) +} diff --git a/src/sjgs/__example_games/__LightingDemonstration.java b/src/sjgs/__example_games/__LightingDemonstration.java new file mode 100755 index 0000000..3014947 --- /dev/null +++ b/src/sjgs/__example_games/__LightingDemonstration.java @@ -0,0 +1,151 @@ +package sjgs.__example_games; + +import static sjgs.core.input.Keyboard.A; +import static sjgs.core.input.Keyboard.D; +import static sjgs.core.input.Keyboard.Q; +import static sjgs.core.input.Keyboard.SPACE; +import static sjgs.graphics.Colors.blue; +import static sjgs.graphics.Colors.red; +import java.awt.Color; +import java.awt.Graphics2D; +import sjgs.base_objects.BaseTile; +import sjgs.base_objects.PlayerBase; +import sjgs.core.Camera; +import sjgs.core.Engine; +import sjgs.core.Handler; +import sjgs.core.input.Keyboard; +import sjgs.enums.Facing; +import sjgs.graphics.lighting.Light; +import sjgs.graphics.lighting.LightsRenderer; +import sjgs.graphics.lighting.RadialLight; + +/** Weclome to the @Light demonstration from Mitch's Game Engine! */ + +class __LightingDemonstration extends Engine { + + public __LightingDemonstration(final int WIDTH, final int HEIGHT, final String title) { + super(WIDTH, HEIGHT, title); + } + + // as normal we create our engine, camera, and players + public static __LightingDemonstration engine; + public static Camera camera; + public static Player player; + + // create our window, initializing our engine... + public static void main(final String[] args) { + engine = new __LightingDemonstration(1280, 720, "Lighting Demonstration"); + } + + // initialize our player and camera, and here we create some lights, (see later) + @Override + protected void init() { + player = new Player(getWidth()/2, getHeight()/2, 32, 64); + camera = new Camera(this); + for(int i = 0; i < 100; i++) { + if(i % 10 == 0) new StaticLight(i*32, 575, 30, 1); + new Block(i*32, 600, 32, 32); + } + } + + // again, as usual we need to tick our camera, keyinput, and handler + // ... but here we're also going to tick all our lights! + @Override + protected void tick() { + camera.tick(player.getCenter(), getScaleFactor()); + KeyInput.tick(player); + Handler.tick(camera, getScaleFactor()); + for(final Light i : Handler.lights) i.tick(); + } + + // Render the handler, plus a nice white background. We also need to renderer the light manager + @Override + protected void render(final Graphics2D g2d) { + g2d.setColor(Color.white); + g2d.fillRect(0, 0, getWidth(), getHeight()); + Handler.render(g2d, camera, getScaleFactor()); + LightsRenderer.render(g2d, camera, engine); + } + + // nice little light class, implementing its own tick method to move themselves + private static class StaticLight extends RadialLight { + + public StaticLight(final float x, final float y, final float radius, final float intensity) { + super(x, y, radius, intensity); + } + + @Override + public void tick() { setX(getX() + 1); } + } + + // basic player class + private static class Player extends PlayerBase { + // ... but this time with its own light! + private final RadialLight light; + + public Player(final float x, final float y, final float w, final float h) { + super(x, y, w, h); + light = new RadialLight(getCenterX(), getCenterY(), getWidth() * 3, 1); + } + + @Override + protected void init() { } + + @Override + public void tick() { + applyPhysics().discard(); + // make sure to set your light to the new location each game advancement! + light.setLocation(getCenterX(), getCenterY()); + manageJumping(); + } + + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(blue); + getFullBounds().drawFilled(g2d); + } + + @Override + protected void destroy() {} + + } + + // basic blocks so we don't fall through the floor + private static class Block extends BaseTile { + + public Block(final int x, final int y, final int w, final int h) { + super(x, y, w, h, 0, 0); + } + @Override + public void init() { + dontApplyGravity(); + } + @Override + public void tick() { applyPhysics().discard(); } + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(red); + getBounds().draw(g2d); + } + @Override + public void destroy() {} + } + + // basic key input class + private static class KeyInput implements Keyboard { + final static float walkingVelocity = 3f; + static void tick(final PlayerBase player) { + if(D()) { player.setVelX(walkingVelocity); player.setFacing(Facing.RIGHT); } + else if(A()) { player.setVelX(-walkingVelocity); player.setFacing(Facing.LEFT); } + if(SPACE()) if(!player.getJumping()) { player.setJumping(true); player.setVelY(-15f); } + if(Q()) engine.exit(); + } + + } + + // AND THAT IS IT! Lighting can be such a complicated and frustrating subject, + // However with Mitch's Game Engine I strived to make the process as simple as possible + // Now, all you do is remember to call your light manager, set the lights to their new positions, + // and you're done! Have fun! + +} diff --git a/src/sjgs/__example_games/__PhysicsDemonstration.java b/src/sjgs/__example_games/__PhysicsDemonstration.java new file mode 100755 index 0000000..394ec8d --- /dev/null +++ b/src/sjgs/__example_games/__PhysicsDemonstration.java @@ -0,0 +1,279 @@ +package sjgs.__example_games; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.io.Serializable; +import sjgs.base_objects.BaseTile; +import sjgs.base_objects.Bullet; +import sjgs.base_objects.HardObject; +import sjgs.base_objects.PlayerBase; +import sjgs.core.DeveloperConsole; +import sjgs.core.Engine; +import sjgs.core.Handler; +import sjgs.core.input.Keyboard; +import sjgs.core.input.Mouse; +import sjgs.enums.Facing; +import sjgs.enums.Type; +import sjgs.graphics.Colors; +import sjgs.utils.Utils; +import sjgs.utils.io.SaveFile; +import sjgs.utils.tools.Timer; +//---------------------------------------------------------------------------------------------------// +class __PhysicsDemonstration extends Engine { + + public __PhysicsDemonstration(final int WIDTH, final int HEIGHT, final String title) { super(WIDTH, HEIGHT, title); } + + public static void main(final String[] args) { + engine = new __PhysicsDemonstration(1280, 720, "Physics Demonstration"); + } + + public static __PhysicsDemonstration engine; + public static ExamplePlayer player; + + @Override + protected void init() { + // disableFpsCap(); + setDoubleTickRate(); + new ExampleDevConsole(this); + new ExampleMouseInput(this); + generateWorld(); + } + + private void generateWorld() { + clearHandler(); + final String[] map = { + "t............................................t", + "t............................................t", + "t............................................t", + "t........................................rtttt", + "ttttttttttl.............................rttttt", + "tttttttttttl....p......................rtttttt", + "ttttttttttttl.........................rttttttt", + "tttttttttttttttttttttttttttttttttttttttttttttt", + }; + + final int level_width = map[0].length(); + final int TILE_SIZE = 40; + + for(int row = 1; row < map.length+1; row++) + for(int col = 1; col < level_width+1; col++) + switch(map[row-1].charAt(col-1)) { + case 't': new ExampleTile(TILE_SIZE*col, TILE_SIZE*row, TILE_SIZE, TILE_SIZE, 0, 0); break; + case 'l': new ExampleTile(TILE_SIZE*col, TILE_SIZE*row, TILE_SIZE, TILE_SIZE, 100, 0); break; + case 'r': new ExampleTile(TILE_SIZE*col, TILE_SIZE*row, TILE_SIZE, TILE_SIZE, 0, 100 ); break; + case 'p': player = new ExamplePlayer(TILE_SIZE*col, TILE_SIZE*row, TILE_SIZE, TILE_SIZE*1.5f); break; + } + } + + @Override + protected void tick() { + try { + if(DeveloperConsole.CONSOLE_OPEN) return; + ExampleKeyInput.tick(player); + camera.tick(player.getCenter(), getScaleFactor()); + Handler.tick(camera, getScaleFactor()); + } catch (final NullPointerException npe) { } + } + @Override + protected void render(Graphics2D g2d) { + Handler.render(g2d, camera, getScaleFactor()); + g2d = createG2D(); + g2d.setColor(Colors.white); + final float x = getWidth()*0.025f; + final float y = getHeight(); + g2d.drawString("Controls: ", x, y*0.85f); + g2d.drawString("----------------------------", x, y*0.861f); + g2d.drawString("Reset World = 'R'", x, y*0.875f); + g2d.drawString("Shoot = 'F' or left click", x, y*0.895f); + g2d.drawString("Spawn Tiles = 'E'", x, y*0.915f); + g2d.drawString("Jump = 'Space'", x, y*0.935f); + g2d.drawString("Zoom = 'Scroll Wheel'", x, y*0.955f); + g2d.drawString("Console = '~'", x, y*0.9775f); + } + + private static class ExamplePlayer extends PlayerBase { + + public ExamplePlayer(final float x, final float y, final float WIDTH, final float HEIGHT) { super(x, y, WIDTH, HEIGHT); } + + @Override + public void init() { } + + @Override + public void tick() { + applyPhysics().discard(); + manageJumping(); + } + + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(Colors.blue); + getFullBounds().drawFilled(g2d); + g2d.setColor(Colors.red); + getBounds().draw(g2d); + } + + @Override + public void destroy() { removeFromHandler(); } + } + + private static class ExampleTile extends BaseTile { + public ExampleTile(final int x, final int y, final int width, final int height, final int startingHeight, final int endingHeight) { + super(x, y, width, height, startingHeight, endingHeight); + } + @Override + public void init() { } + @Override + public void tick() { } + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(Colors.green); + drawTestBoundaries(g2d); + } + @Override + public void destroy() { Handler.stationary_hard_objects.remove(this); } + } + + private static class ExampleObject extends HardObject { + private final Timer timer; + private final Color color; + + public ExampleObject(final float x, final float y, final float width, final float height, final boolean mobile) { + super(x, y, width, height, mobile); + color = new Color(Utils.nextInt(256), Utils.nextInt(256), Utils.nextInt(256)); + timer = new Timer(500); + } + + @Override + public void init() { + getBounds().setVelX(Utils.nextFloat() * Utils.nextInt(12) + 1); + getBounds().setVelY(Utils.nextFloat() * Utils.nextInt(15) + 1); + if(Utils.COIN_FLIP()) getBounds().invertVelX(); + if(Utils.COIN_FLIP()) getBounds().invertVelY(); + } + + @Override + public void tick() { + applyPhysics(Type.PLAYER, Type.HARD_OBJECT, Type.BULLET).discard(); + if(timer.tick()) destroy(); + } + + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(color); + getBounds().draw(g2d); + } + + @Override + public void destroy() { removeFromHandler(); } + } + + private static class ExampleBullet extends Bullet { + + private final Color color; + + public ExampleBullet(final float x, final float y, final float width, final float height, final float velX, final float velY, final int elasticity, final int health_timer, final Color color) { + super(x, y, width, height, velX, velY, elasticity, health_timer); + this.color = color; + } + + @Override + public void init() { } + + @Override + public void tick() { + applyPhysics().discard(); + if(timer.tick()) destroy(); + } + + @Override + public void render(final Graphics2D g2d) { + g2d.setColor(color); + getBounds().draw(g2d); + } + + @Override + public void destroy() { removeFromHandler(); } + } + + + + private static class ExampleDevConsole extends DeveloperConsole { + public ExampleDevConsole(final Engine engine) { super(engine); } + private static ExampleSaveFile saveFile; + + @Override + protected void commands(final String action, final String item, final String value) { + switch(action) { + case "spawn": spawn(); break; + case "reset": engine.generateWorld(); break; + case "fps": System.out.println("FPS: " + engine.FPS +", " + "TPS: " + engine.TPS); break; + case "save": saveFile = new ExampleSaveFile(engine); break; + case "load": saveFile.load(engine); break; + } + } + + private void spawn() { + final int range = 10; + for(int i = 0 ; i < 1000; i++) { + final float velX = Utils.COIN_FLIP() ? -Utils.nextInt(range) : Utils.nextInt(range); + final float velY = Utils.COIN_FLIP() ? -Utils.nextInt(range) : Utils.nextInt(range); + final float x = Utils.COIN_FLIP() ? player.getCenter().x - Utils.nextInt(700) : player.getCenter().x + Utils.nextInt(700); + final float y = player.getCenter().y - Utils.nextInt(500) - 10; + + new ExampleBullet( x, y, 15 + Utils.nextInt(40), 15 + Utils.nextInt(40), + velX, velY, Utils.nextInt(100), 1000, new Color(Utils.nextInt(256), Utils.nextInt(256), Utils.nextInt(256)) + ); + } + } + private static class ExampleSaveFile extends SaveFile implements Serializable { + public ExampleSaveFile(final Engine engine) { super(engine); } + @Override + public void load(final Engine engine) { + loadEngineAndHandler(engine); + player = (ExamplePlayer)Handler.players.peek(); + } + } + } + + private static class ExampleKeyInput implements Keyboard { + static final float walkingVelocity = 3.5f; + static void tick(final PlayerBase player) { + if(DeveloperConsole.CONSOLE_OPEN) return; + if(Keyboard.D()) { player.setVelX(walkingVelocity); player.setFacing(Facing.RIGHT); } + else if(Keyboard.A()) { player.setVelX(-walkingVelocity); player.setFacing(Facing.LEFT); } + if(Keyboard.SPACE()) if(!player.getJumping()) { player.setJumping(true); player.setVelY(-15f); } + if(Keyboard.E()) new ExampleObject(player.getCenter().x, player.getCenter().y, 20, 20, true); + if(Keyboard.R()) engine.generateWorld(); + if(Keyboard.F()) { + final float velX = player.facingLeft() ? -15 : 15; + new ExampleBullet(player.getCenter().x, player.getCenter().y, 40, 40, velX, 0, 75, 225, Colors.orange); + } + if(Keyboard.Q()) engine.exit(); + } + } + + private static class ExampleMouseInput extends Mouse { + public ExampleMouseInput(final Engine engine) { super(engine); } + @Override + public void mouseWheelMoved(final MouseWheelEvent e) { + engine.setScaleFactor(engine.getScaleFactor() + -e.getPreciseWheelRotation() / 5f); + engine.setScaleFactor(Utils.clamp(engine.getScaleFactor(), 0.1f, 15f)); + } + @Override + public void mousePressed(final MouseEvent e) { + if(e.getButton() == 1) { + final float velX = player.facingLeft() ? -50 : 50; + new ExampleBullet(player.getCenter().x, player.getCenter().y, 40, 40, velX, 0, 35, 650, Colors.cyan); + } + } + @Override + public void mouseMoved(final MouseEvent e) { } + @Override + public void mouseClicked(final MouseEvent e) { } + @Override + public void mouseReleased(final MouseEvent e) { } + } + +} diff --git a/src/sjgs/base_objects/BaseTile.java b/src/sjgs/base_objects/BaseTile.java new file mode 100755 index 0000000..480f754 --- /dev/null +++ b/src/sjgs/base_objects/BaseTile.java @@ -0,0 +1,67 @@ +package sjgs.base_objects; + +import static sjgs.utils.Utils.brensenham; +import static sjgs.utils.Utils.exit; +import static sjgs.utils.Utils.isPercent; +import static sjgs.utils.Utils.print; +import java.awt.Graphics2D; +import java.io.Serializable; +import sjgs.utils.data_structures.vectors.SimplePoint; + +public abstract class BaseTile extends HardObject implements Serializable { + + private final SimplePoint[] slopePoints; + /** @param sh: The starting point at the left of the tile */ + /** @param eh: The ending point at the right of the tile */ + /** Both are measured from the floor upwards */ + private final int sh, eh; + + public BaseTile(final int x, final int y, final int w, final int h, final float startingHeightPercentage, final float endingHeightPercentage) { + super(x, y, w, h, false); + if(!isPercent(startingHeightPercentage / 100f) || !isPercent(endingHeightPercentage / 100f)) { print("Error: Tile angle height % out of range"); exit(); } + sh = (int)(getHeight() * (startingHeightPercentage / 100f)); eh = (int)(getHeight() * (endingHeightPercentage / 100f)); + + if(!(sh == 0 && eh == 0)) { + final int shX = (int)getX(); + final int shY = (int)(getY() + getHeight() - sh); + final int ehX = (int)(getX() + w); + final int ehY = (int)(getY() + getHeight() - eh); + + slopePoints = brensenham(shX, shY, ehX, ehY); + + } else slopePoints = null; + + + } + + @Override + public abstract void init(); + @Override + public abstract void tick(); + @Override + public abstract void render(Graphics2D g2d); + @Override + public abstract void destroy(); + + public boolean angled() { return slopePoints != null; } + + public SimplePoint[] getSlopePoints() { return slopePoints; } + + protected void drawTestBoundaries(final Graphics2D g2d) { + if(!angled()) getBounds().draw(g2d); + else { + // BOTTOM LINE + g2d.drawLine((int)getX(), (int)(getY()+getHeight()), (int)(getX()+getWidth()), (int)getY()+(int)getHeight()); + + // BOTTOM TO SH LINE + g2d.drawLine((int)getX(), (int)(getY()+getHeight()), (int)getX(), (int)(getY()+getHeight()) - sh); + + // SH TO EH LINE + g2d.drawLine((int)getX(), (int)(getY()+getHeight() - sh), (int)(getX() + getWidth()), (int)(getY()+getHeight()) - eh); + + // BOTTOM RIGHT TO EH LINE + g2d.drawLine((int)(getX() + getWidth()), (int)(getY()+getHeight()), (int)(getX() + getWidth()), (int)(getY()+getHeight()) - eh); + } + } + +} diff --git a/src/sjgs/base_objects/Bullet.java b/src/sjgs/base_objects/Bullet.java new file mode 100755 index 0000000..1734935 --- /dev/null +++ b/src/sjgs/base_objects/Bullet.java @@ -0,0 +1,43 @@ +package sjgs.base_objects; + +import java.awt.Graphics2D; +import java.io.Serializable; +import sjgs.core.Handler; +import sjgs.enums.Type; +import sjgs.utils.tools.Timer; + +public abstract class Bullet extends GameObject implements Serializable { + + public static final float MAX_ELASTICITY = 100, NO_ELASTICITY = 0; + + protected final Timer timer; + /** @elasticity: A percent value, (e.g. from 0.01 to 1.00), that is a multiplier for the amount + * of energy retained after a collision. */ + protected float elasticity; + + public Bullet(final float x, final float y, final float w, final float h, final float velX, final float velY, final int elasticity, final int health_timer) { + super(x, y, w, h, Type.BULLET); + setVelX(velX); + setVelY(velY); + this.elasticity = elasticity / 100f; + timer = new Timer(health_timer); + Handler.bullets.add(this); + } + + @Override + protected abstract void init(); + @Override + public abstract void tick(); + @Override + public abstract void render(Graphics2D g2d); + @Override + protected abstract void destroy(); + + + @Override + protected void removeFromHandler() { Handler.bullets.remove(this); } + + public float getElasticity() { return elasticity; } + public void setElasticity(final float elasticity) { this.elasticity = elasticity; } + +} diff --git a/src/sjgs/base_objects/GameObject.java b/src/sjgs/base_objects/GameObject.java new file mode 100755 index 0000000..8929ead --- /dev/null +++ b/src/sjgs/base_objects/GameObject.java @@ -0,0 +1,126 @@ +package sjgs.base_objects; + +import static sjgs.utils.pyutils.PyUtils.java2py; +import java.awt.Graphics2D; +import java.io.Serializable; +import org.python.core.PyFunction; +import org.python.core.PyObject; +import sjgs.enums.Facing; +import sjgs.enums.Type; +import sjgs.physics.Physics; +import sjgs.physics.structs.BoundingBox; +import sjgs.physics.structs.CollisionResponse; +import sjgs.utils.data_structures.shapes.Line; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; +import sjgs.utils.pyutils.PyUtils; + +public abstract class GameObject implements Serializable { + + private final BoundingBox bounds; + private final Physics physics; + public final PyObject self; + + public GameObject(final float x, final float y, final float w, final float h, final Type type) { + bounds = new BoundingBox(x, y, w, h, type); + physics = new Physics(); + init(); + self = java2py(this); + } + + protected abstract void init(); + public abstract void tick(); + public abstract void render(Graphics2D g2d); + protected abstract void destroy(); + protected abstract void removeFromHandler(); + + protected CollisionResponse applyPhysics() { return applyPhysics(Physics.getDefaultGravity(), Physics.getDefaultFriction(), Type.HARD_OBJECT); } + protected CollisionResponse applyPhysics(final Type ...args) { return applyPhysics(Physics.getDefaultGravity(), Physics.getDefaultFriction(), args); } + protected CollisionResponse applyPhysics(final float SPECIFIED_GRAVITY, final float SPECIFIED_FRICTION, final Type ...args) { + physics.updatePosition(this); + physics.applyFriction(this, SPECIFIED_FRICTION); + final CollisionResponse response = physics.collision(this, args); + physics.applyGravity(this, SPECIFIED_GRAVITY); + physics.calcGroundedAndOnSlope(this, response.collided_hard_objects); + return response; + } + + public boolean falling() { return getFalling(); } + public boolean getFalling() { return !getOnSlope() && !getGrounded() && getVelY() > 0; } + public PyObject getSelf() { return self; } + public boolean movingRight() { return getVelX() > 0; } + public boolean movingLeft() { return getVelX() < 0; } + public boolean movingDown() { return getVelY() > 0; } + public boolean movingUp() { return getVelY() < 0; } + public Physics getPhysics() { return physics; } // NOTE you should really never need to do this! + public boolean isMoving() { return getVelX() != 0 || getVelY() != 0; } + public void updatePosition() { physics.updatePosition(this); } + public CollisionResponse getCollidedObjects() { return physics.getCollidedObjects(this); } + public boolean useCustomGravity() { return bounds.useCustomGravity(); } + public void dontUseCustomGravity() { bounds.dontUseCustomGravity(); } + public void setCustomGravity(final float gravity) { bounds.setCustomGravity(gravity); } + public float getCustomGravity() { return getCustomGravity(); } + public boolean stopped() { return bounds.stopped(); } + public float getVelX() { return bounds.getVelX(); } + public float getVelY() { return bounds.getVelY(); } + public void setVelX(final float velX) { bounds.setVelX(velX); } + public void setVelY(final float velY) { bounds.setVelY(velY); } + public void setVelocity(final float velX, final float velY) { bounds.setVelocity(velX, velY); } + public float getArea() { return bounds.getArea(); } + public BoundingBox getBounds() { return bounds; } + public Rectangle getFullBounds() { return bounds.getFullBounds(); } + public Rectangle getLeftBounds() { return bounds.getLeftBounds(); } + public Rectangle getRightBounds() { return bounds.getRightBounds(); } + public Rectangle getTopBounds() { return bounds.getTopBounds(); } + public Rectangle getBottomBounds() { return bounds.getBottomBounds(); } + public float getWidth() { return bounds.getFullBounds().getWidth(); } + public float getHeight() { return bounds.getFullBounds().getHeight(); } + public float getHalfWidth() { return getWidth() * 0.5f; } + public float getHalfHeight() { return getHeight() * 0.5f; } + public void setWidth(final float w) { bounds.setWidth(w); } + public void setHeight(final float h) { bounds.setHeight(h); } + public void setSize(final float w, final float h) { bounds.setSize(w, h); } + public boolean getGrounded() { return bounds.getGrounded(); } + public boolean getOnSlope() { return bounds.getOnSlope(); } + public void setGrounded(final boolean b) { bounds.setGrounded(b); } + public void setOnSlope(final boolean b) { bounds.setOnSlope(b); } + public void dontApplyGravity() { bounds.setDontApplyGravity(true); } + public boolean getDontApplyGravity() { return bounds.getDontApplyGravity(); } + public void setDontApplyGravity(final boolean b) { bounds.setDontApplyGravity(b); } + public void toggleDontApplyGravity() { bounds.toggleDontApplyGravity(); } + public void dontApplyFriction() { bounds.setDontApplyFriction(true); } + public boolean getDontApplyFriction() { return bounds.getDontApplyFriction(); } + public void setDontApplyFriction(final boolean b) { bounds.setDontApplyFriction(b); } + public void toggleDontApplyFriction() { bounds.toggleDontApplyFriction(); } + public Point2f getLocation() { return bounds.getLocation(); } + public void setLocation(final float x, final float y) { bounds.setLocation(x, y); } + public void setLocation(final Point2f p) { bounds.setLocation(p.x, p.y); } + public void setLocation(final SimplePoint p) { bounds.setLocation(p.x, p.y); } + public void setX(final float x) { bounds.setX(x); } + public void setY(final float y) { bounds.setY(y); } + public float getX() { return bounds.getFullBounds().getX(); } + public float getY() { return bounds.getFullBounds().getY(); } + public float getCenterX() { return getX() + getHalfWidth(); } + public float getCenterY() { return getY() + getHalfHeight(); } + public Point2f getCenter() { return new Point2f(getX() + getHalfWidth(), getY() + getHalfHeight()); } + public void setCenter(final Point2f p) { setLocation(p.x - getWidth() / 2, p.y - getHeight() / 2); } + public void setCenter(final float x, final float y) { setLocation(x - getWidth() / 2, y - getHeight() / 2); } + public Facing getFacing() { return bounds.getFacing(); } + public boolean facingLeft() { return bounds.facingLeft(); } + public boolean facingRight() { return bounds.facingRight(); } + public void setFacing(final Facing facing) { bounds.setFacing(facing); } + public Type getType() { return bounds.getType(); } + + public PyFunction createPyFunction(String funcName) { return PyUtils.createPyFunction(funcName); } + + public Point2f getTopRight() { return getBounds().getTopRight(); } + public Point2f getTopLeft() { return getBounds().getTopLeft(); } + public Point2f getBottomRight() { return getBounds().getBottomRight(); } + public Point2f getBottomLeft() { return getBounds().getBottomLeft(); } + public Line getTop() { return getBounds().getTop(); } + public Line getBottom() { return getBounds().getBottom(); } + public Line getLeft() { return getBounds().getLeft(); } + public Line getRight() { return getBounds().getRight(); } + +} diff --git a/src/sjgs/base_objects/HardObject.java b/src/sjgs/base_objects/HardObject.java new file mode 100755 index 0000000..c816d2a --- /dev/null +++ b/src/sjgs/base_objects/HardObject.java @@ -0,0 +1,35 @@ + +package sjgs.base_objects; + +import java.awt.Graphics2D; +import java.io.Serializable; +import sjgs.core.Handler; +import sjgs.enums.Type; + +public abstract class HardObject extends GameObject implements Serializable { + + public final boolean mobile; + + public HardObject(final float x, final float y, final float w, final float h, final boolean mobile) { + super(x, y, w, h, Type.HARD_OBJECT); + this.mobile = mobile; + if(mobile) Handler.mobile_hard_objects.add(this); + else Handler.stationary_hard_objects.insert(this); + } + + @Override + protected abstract void init(); + @Override + public abstract void tick(); + @Override + public abstract void render(Graphics2D g2d); + @Override + protected abstract void destroy(); + + @Override + protected void removeFromHandler() { + if(mobile) Handler.mobile_hard_objects.remove(this); + else Handler.stationary_hard_objects.remove(this); + } + +} diff --git a/src/sjgs/base_objects/Mob.java b/src/sjgs/base_objects/Mob.java new file mode 100755 index 0000000..0ceec3b --- /dev/null +++ b/src/sjgs/base_objects/Mob.java @@ -0,0 +1,44 @@ + +package sjgs.base_objects; + +import java.awt.Graphics2D; +import java.io.Serializable; +import sjgs.core.Handler; +import sjgs.enums.Type; + +public abstract class Mob extends GameObject implements Serializable { + + protected float health, damage; + protected boolean attacking; + + public Mob(final float x, final float y, final float w, final float h) { + super(x, y, w, h, Type.MOB); + Handler.mobs.add(this); + } + + @Override + protected abstract void init(); + @Override + public abstract void tick(); + @Override + public abstract void render(Graphics2D g2d); + @Override + protected abstract void destroy(); + + protected boolean checkIfAlive() { if(health <= 0) destroy(); return health <= 0; } + + @Override + protected void removeFromHandler() { Handler.mobs.remove(this); } + + public void setAttacking(final boolean attacking) { this.attacking = attacking; } + public boolean getAttacking() { return attacking; } + + public void decrementHealth(final float decrement) { setHealth(getHalfHeight() - decrement); } + public void incrementHealth(final float increment) { setHealth(getHealth() + increment); } + public void setHealth(final float health) { this.health = health; } + public float getHealth() { return health; } + + public void setDamage(final float damage) { this.damage = damage; } + public float getDamage() { return damage; } + +} diff --git a/src/sjgs/base_objects/PlayerBase.java b/src/sjgs/base_objects/PlayerBase.java new file mode 100755 index 0000000..6c5a9f4 --- /dev/null +++ b/src/sjgs/base_objects/PlayerBase.java @@ -0,0 +1,51 @@ +package sjgs.base_objects; + +import java.awt.Graphics2D; +import java.io.Serializable; +import sjgs.core.Handler; +import sjgs.enums.Type; + +public abstract class PlayerBase extends GameObject implements Serializable { + + protected float health; + protected boolean jumping, attacking, lookingUp, lookingDown; + + public PlayerBase(final float x, final float y, final float w, final float h) { + super(x, y, w, h, Type.PLAYER); + Handler.addPlayer(this); + } + + @Override + protected abstract void init(); + @Override + public abstract void tick(); + @Override + public abstract void render(Graphics2D g2d); + @Override + protected abstract void destroy(); + + /** @manageJumping: Sets player to not be able to jump if the player is falling while not + * grounded, or has already jumped. Make sure you set the player's jumping variable to + * be true when he/she jumps in your keyinput class. */ + protected void manageJumping() { + if(jumping && getBounds().getGrounded() || getBounds().getOnSlope()) jumping = false; + } + + @Override + protected void removeFromHandler() { Handler.removePlayer(this); } + + public void setLookingUp(boolean b) { this.lookingUp = b; } + public boolean getLookingUp() { return lookingUp; } + public void setLookingDown(boolean b) { this.lookingDown = b; } + public boolean getLookingDown() { return lookingDown; } + public void setJumping(final boolean jumping) { this.jumping = jumping; } + public boolean getJumping() { return jumping; } + public void setAttacking(final boolean attacking) { this.attacking = attacking; } + public boolean getAttacking() { return attacking; } + + public void decrementHealth(final float decrement) { setHealth(getHalfHeight() - decrement); } + public void incrementHealth(final float increment) { setHealth(getHealth() + increment); } + public void setHealth(final float health) { this.health = health; } + public float getHealth() { return health; } + +} \ No newline at end of file diff --git a/src/sjgs/base_objects/SoftObject.java b/src/sjgs/base_objects/SoftObject.java new file mode 100755 index 0000000..026b9c3 --- /dev/null +++ b/src/sjgs/base_objects/SoftObject.java @@ -0,0 +1,35 @@ + +package sjgs.base_objects; + +import java.awt.Graphics2D; +import java.io.Serializable; +import sjgs.core.Handler; +import sjgs.enums.Type; + +public abstract class SoftObject extends GameObject implements Serializable { + + public final boolean mobile; + + public SoftObject(final float x, final float y, final float w, final float h, final boolean mobile) { + super(x, y, w, h, Type.SOFT_OBJECT); + this.mobile = mobile; + if(mobile) Handler.mobile_soft_objects.add(this); + else Handler.stationary_soft_objects.insert(this); + } + + @Override + protected abstract void init(); + @Override + public abstract void tick(); + @Override + public abstract void render(Graphics2D g2d); + @Override + protected abstract void destroy(); + + @Override + protected void removeFromHandler() { + if(mobile) Handler.mobile_soft_objects.remove(this); + else Handler.stationary_soft_objects.remove(this); + } + +} diff --git a/src/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py b/src/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py new file mode 100755 index 0000000..103f2d3 --- /dev/null +++ b/src/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py @@ -0,0 +1,43 @@ +# mob will travel around a given rectangle -- think like in early stages of metroid +# territory === given rectangle +def mob_travel_around_rectangle_ai(mob, territory, speed, clockWise): + fullBounds = mob.getFullBounds() + rightBounds = mob.getRightBounds() + leftBounds = mob.getLeftBounds() + topBounds = mob.getTopBounds() + bottomBounds = mob.getBottomBounds() + + top = territory.getTop() + right = territory.getRight() + left = territory.getLeft() + bottom = territory.getBottom() + + if clockWise: + if fullBounds.intersects(right) and not fullBounds.intersects(bottom): + mob.setVelocity(0, speed) + mob.setX(territory.pos.x + territory.getWidth()) + mob.setY(restrict(mob.getY(), territory.getY() - 2)) + elif fullBounds.intersects(top): + mob.setVelocity(speed, 0) + mob.setY(territory.pos.y - mob.getHeight()) + mob.setX(restrict(mob.getX(), territory.getX() - 1)) + elif fullBounds.intersects(left) and not fullBounds.intersects(top) and not topBounds.intersects(bottom): + mob.setVelocity(0, -speed) + mob.setX(territory.pos.x - mob.getHeight()) + elif fullBounds.intersects(bottom): + mob.setVelocity(-speed, 0) + mob.setY(territory.pos.y + 2 + mob.getHeight()) + else: + if fullBounds.intersects(right) and not fullBounds.intersects(top): + mob.setVelocity(0, -speed) + mob.setX(territory.pos.x + territory.getWidth()) + mob.setY(restrict(mob.getY(), territory.getY() - 2)) + elif fullBounds.intersects(top) and not fullBounds.intersects(left): + mob.setVelocity(-speed, 0) + mob.setY(territory.pos.y - mob.getHeight()) + elif fullBounds.intersects(bottom) and not fullBounds.intersects(right): + mob.setVelocity(speed, 0) + mob.setY(territory.pos.y + mob.getHeight() + 2) + elif fullBounds.intersects(left): + mob.setVelocity(0, speed) + mob.setX(territory.pos.x - mob.getHeight()) \ No newline at end of file diff --git a/src/sjgs/core/Camera.java b/src/sjgs/core/Camera.java new file mode 100755 index 0000000..7df57d6 --- /dev/null +++ b/src/sjgs/core/Camera.java @@ -0,0 +1,126 @@ +package sjgs.core; + +import static sjgs.utils.Utils.brensenham; +import static sjgs.utils.Utils.cinch; +import static sjgs.utils.Utils.converge; +import static sjgs.utils.Utils.cos; +import static sjgs.utils.Utils.sin; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; + +public class Camera { //TODO: camera acceleartion / delay and shake + + private final Rectangle bounds; + + private SimplePoint[] shakePoints; + private float shakeSpeed; + private int shakeIndex; + + private float acceleration, speedX, speedY, maxSpeed; + + private float minX, minY, maxX, maxY; + + public Camera(final Engine engine) { + bounds = new Rectangle(0, 0, engine.getWidth(), engine.getHeight()); + } + + public void tick(final Point2f target, final double scaleFactor) { + final float w = (float)(getWidth() / scaleFactor); + final float h = (float)(getHeight() / scaleFactor); + final float hw = w * 0.5f; + final float hh = h * 0.5f; + + float proposedX; + float proposedY; + final float tX = -target.x + hw; + final float tY = -target.y + hh; + + // IF WE'RE NOT SHAKING: + if(shakePoints == null) { + + // IF THERE'S NO ACCELERATION + if(acceleration <= 0) { + proposedX = tX; + proposedY = tY; + // ELSE IF THERE *IS* ACCELERATION + } else { + proposedX = converge(getX(), tX, speedX); + proposedY = converge(getY(), tY, speedY); + + if(getX() != tX) speedX = cinch(speedX + acceleration, maxSpeed); + else speedX = 0; + + if(getY() != tY) speedY = cinch(speedY + acceleration, maxSpeed); + else speedY = 0; + } + + + // ELSE IF WE *ARE* SHAKING + } else { + if(shakeIndex >= shakePoints.length - 1) shakePoints = null; + proposedX = shakePoints[shakeIndex].x; + proposedY = shakePoints[shakeIndex].y; + shakeIndex++; + } + + // IF THERE ARE BOUNDARIES SET + if(!(minX == 0 && minY == 0 && maxX == 0 && maxY == 0)) { + if(-proposedX < minX) setX(minX); + else if(-proposedX + w > maxX) setX(-(maxX - w)); + else setX(proposedX); + + if(-proposedY < minY) setY(minY); + else if(-proposedY + h > maxY) setY(-(maxY - h)); + else setY(proposedY); + // ELSE IF THERE *ISNT* BOUNDARIES SET + } else { + setX(proposedX); + setY(proposedY); + } + } + + public void changeSettings(final float screenWidth, final float screenHeight) { bounds.setSize(screenWidth, screenHeight); } + + public float getX() { return bounds.getX(); } + public float getY() { return bounds.getY(); } + public float getCenterX() { return bounds.getCenterX(); } + public float getCenterY() { return bounds.getCenterY(); } + public float getWidth() { return bounds.getWidth(); } + public float getHeight() { return bounds.getHeight(); } + public float getHalfWidth() { return bounds.getHalfWidth(); } + public float getHalfHeight() { return bounds.getHalfHeight(); } + public void setX(final float x) { bounds.setX(x); } + public void setY(final float y) { bounds.setY(y); } + public Point2f getPos() { return bounds.pos; } + public Point2f getCenter() { return bounds.getCenter(); } + public void setScreenWidth(final float screenWidth) { bounds.setWidth(screenWidth); } + public void setScreenHeight(final float screenHeight) { bounds.setHeight(screenHeight); } + + public void disableAcceleration() { acceleration = maxSpeed = -1; } + public void setAcceleration(final float acceleration, final float maxSpeed) { this.acceleration = acceleration; this.maxSpeed = maxSpeed; } + + public void setLimitsWithRect(final float x, final float y, final float width, final float height) { + minX = x; + minY = y; + maxX = x + width; + maxY = y + height; + } + + public void setLimits(final float minX, final float minY, final float maxX, final float maxY) { + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + /** @shake: Moves the center of the camera to a point away from the camera center based on + * the given distance and angle in radians. The transition is governed by the attack + * and fall durations. */ + public void shake(final float distance, final float theta, final float shakeSpeed) { + shakePoints = brensenham(getPos(), new Point2f(getX() + distance * cos(theta), getY() + distance * sin(theta))); + shakeIndex = 0; + this.shakeSpeed = shakeSpeed; + } + +} diff --git a/src/sjgs/core/DeveloperConsole.java b/src/sjgs/core/DeveloperConsole.java new file mode 100755 index 0000000..ed92328 --- /dev/null +++ b/src/sjgs/core/DeveloperConsole.java @@ -0,0 +1,157 @@ +package sjgs.core; + +import static sjgs.graphics.Colors.black; +import static sjgs.graphics.Colors.pastelRed; +import static sjgs.graphics.Colors.white; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GraphicsEnvironment; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.io.InputStream; +import java.util.LinkedList; + +public abstract class DeveloperConsole extends KeyAdapter { + + // Remember to add this to your engine.frame! + + private static StringBuilder sb; + private static LinkedList history; + private static int index; + public static boolean CONSOLE_OPEN; + + private static Font ponderosa_20; + private static Font gregorian48Bold; + + public DeveloperConsole(final Engine engine) { + sb = new StringBuilder(); + history = new LinkedList(); + + try { InputStream is1 = DeveloperConsole.class.getResourceAsStream("/gregorian.ttf"); + InputStream is2 = DeveloperConsole.class.getResourceAsStream("/ponderosa.ttf"); + ponderosa_20 = Font.createFont(Font.TRUETYPE_FONT, is2).deriveFont(Font.BOLD, 10.0f); + gregorian48Bold = Font.createFont(Font.TRUETYPE_FONT, is1).deriveFont(Font.BOLD, 48f); + is1.close(); is1 = null; is2.close(); is2 = null; + final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + ge.registerFont(gregorian48Bold); + ge.registerFont(ponderosa_20); + } catch (final Exception e) { e.printStackTrace(); } + engine.frame.addKeyListener(this); + } + + protected abstract void commands(String action, String item, String value); + + private synchronized void execute(final String command) { + if(command.length() <= 0) { exit(); return; } + + String action, item, value; + + // GET THE ACTION, IF THE ACTION IS A ONE-WORD PHRASE, ACTION = THE WHOLE COMMAND + try { action = command.substring(0, command.indexOf(" ")); } catch (final StringIndexOutOfBoundsException e) { action = command.toString(); } + + // GET THE ITEM, IF THERE IS NO AMOUNT, ITEM = JUST THE ITEM, IF THERE IS NO ITEM, ITEM = "" + try { final String tempItem = command.substring(command.indexOf(" ") + 1); item = tempItem.substring(0, tempItem.indexOf(" ")); } catch (final StringIndexOutOfBoundsException e) { + try { item = command.substring(command.indexOf(" ") + 1); } catch (final StringIndexOutOfBoundsException ee) { item = ""; } + } + + // GET THE VALUE ---- + try { final String temp = command.substring(command.indexOf(" ") + 1) ; + value = temp.substring(temp.indexOf(" ") + 1); + } catch (final StringIndexOutOfBoundsException ee) { value = ""; } + + item.replace(" ", ""); action.replace(" ", ""); value.replace(" ", ""); + //------------------------------------------------// + baseCommands(action, item, value); + commands(action, item, value); + //------------------------------------------------// + exit(); + } + + private static void baseCommands(final String action, @SuppressWarnings("unused") final String item, @SuppressWarnings("unused") final String value) { + switch(action) { + case "quit": exit(); break; + case "exit": exit(); break; + } + } + + @Override + public void keyPressed(final KeyEvent e) { + + if(e.getKeyChar() == '~') { if(!CONSOLE_OPEN) open(); else exit(); return; } + else if(!CONSOLE_OPEN) return; + else if(e.getKeyCode() == KeyEvent.VK_ESCAPE) { exit(); return; } + + + else if(e.getKeyCode() == KeyEvent.VK_UP) { + if(history.size() <= 0) return; + final String temp = sb.toString(); + sb = new StringBuilder(); + try { sb.append(history.get(index--)); } catch (final Exception ex) { + index++; + sb.append(temp); + } + } + + else if(e.getKeyCode() == KeyEvent.VK_DOWN) { + if(history.size() <= 0) return; + final String temp = sb.toString(); + sb = new StringBuilder(); + try { sb.append(history.get(++index)); } catch (final Exception ex) { + index--; + sb.append(temp); + } + } + + else if(e.getKeyCode() == KeyEvent.VK_ENTER) { + history.add(sb.toString()); + execute(sb.toString()); + sb = new StringBuilder(); + return; + } + + else if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { if(sb.length() > 0) sb.deleteCharAt(sb.length()-1); return; } + + else if(sb.length() < 67) { + switch(e.getKeyCode()) { + case KeyEvent.VK_BACK_SPACE: return; + case KeyEvent.VK_TAB: return; + case KeyEvent.VK_SHIFT: return; + case KeyEvent.VK_UP: return; + case KeyEvent.VK_DOWN: return; + case KeyEvent.VK_LEFT: return; + case KeyEvent.VK_RIGHT: return; + case KeyEvent.VK_CONTROL: return; + case KeyEvent.VK_WINDOWS: return; + case KeyEvent.VK_UNDEFINED: return; + case KeyEvent.VK_NUM_LOCK: return; + default: sb.append(e.getKeyChar()); + } + } + } + + public static void render(final Graphics g, final int width, final int height) { + if(!CONSOLE_OPEN) return; + + g.setColor(black); + g.fillRect(width/2 - width/4, height/2 - height/4, width/2, height/20); + + g.setColor(white); + g.setFont(ponderosa_20); + + g.drawString(sb.toString(), width/2 - width/4 + 10, height/2 - height/4 + 20); + + g.setColor(pastelRed); + g.setFont(gregorian48Bold); + g.drawString("sjgs console:", width/2 - width/4 + 2, height/2 - height/4 - 10); + } + + private static synchronized void open() { + sb = new StringBuilder(); + CONSOLE_OPEN = true; + } + + private static synchronized void exit() { + index = history.size() - 1; + CONSOLE_OPEN = false; + } +} diff --git a/src/sjgs/core/Engine.java b/src/sjgs/core/Engine.java new file mode 100755 index 0000000..4cebd58 --- /dev/null +++ b/src/sjgs/core/Engine.java @@ -0,0 +1,226 @@ +package sjgs.core; + +import static sjgs.graphics.Colors.black; +import static sjgs.graphics.Colors.white; +import static sjgs.utils.Utils.error; +import static sjgs.utils.pyutils.PyUtils.java2py; +import java.awt.Canvas; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.image.BufferStrategy; +import java.io.Serializable; +import javax.swing.JFrame; +import javax.swing.JPanel; +import org.python.core.PyObject; +import sjgs.core.input.__Keyboard; +import sjgs.core.jython.Jython; +import sjgs.physics.Physics; +import sjgs.utils.Utils; +import sjgs.utils.multithreading.Runner; +import sjgs.utils.multithreading.ThreadPool; + +public abstract class Engine extends Canvas implements Runnable, Serializable { + + private static final String engine_version = "SJGS v0.0.12"; + + /** @TICK_INTERVAL && @FPS_CAP: default no arg constructor gives 60 tps / fps */ + private double TICK_INTERVAL; + private double FRAME_RATE, FPS_CAP; + private double scaleFactor = 1d; + private boolean running; + protected int frames, ticks, FPS, TPS; + + // NOTE THE DEFAULTS! + private boolean multithreadedGameUpdating = false, multithreadedRendering = true, variableSleepRate = false; + + public final ThreadPool pool; + public final JFrame frame; + public final JPanel panel; + public final Camera camera; + + public final PyObject self; + + public Engine(final int WIDTH, final int HEIGHT, final String title) { + pool = new ThreadPool(); + frame = new JFrame(); + panel = new JPanel(); + + new Runner(() -> { + new Runner(() -> { new Physics().init(); }).run(); + new Runner(() -> { new Handler().init(); }).run(); + setFPS_CAP(60.0d); + TICK_INTERVAL = Utils.second / 60.0d; + error(getVersion() + "\n" + Utils.OS); + toggleDrawFPS(); + }).run(); + + new Jython().__init__(); + + createWindow(WIDTH, HEIGHT, title); + + camera = new Camera(this); + + init(); + + self = java2py(this); + + pool.runTask(this); + } + + private void createWindow(final int WIDTH, final int HEIGHT, final String title) { + new Runner(() -> { + setFocusTraversalKeysEnabled(false); /* NOTE YOU NEED THIS FOR TAB KEY TO WORK! */ + frame.setTitle(title); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setResizable(false); + }).run(); + frame.add(panel); frame.add(this); frame.pack(); + frame.setSize(WIDTH, HEIGHT); + frame.setLocationRelativeTo(null); + new __Keyboard().init(panel); + } + + //----------------------------------------------------------------// + protected abstract void init(); + protected abstract void tick(); + protected abstract void render(Graphics2D g2d); + //----------------------------------------------------------------// + + private boolean drawFPS, rendering; + private BufferStrategy bs; private Graphics g; private Graphics2D g2d; + public void engine_render() { + begin(); + drawBaseLayer(); + scale(); + // ================================ // + render(g2d); + // ================================ // + renderDevConsole(); + renderFPS(); + end(); + } + private void end() { + g2d.dispose(); g.dispose(); + g2d = null; g = null; + bs.show(); + rendering = false; + } + private void renderFPS() { if(drawFPS) drawFPS(); } + private void renderDevConsole() { + final Graphics2D consoleRenderer = createG2D(); + DeveloperConsole.render(consoleRenderer, getWidth(), getHeight()); + } + private void begin() { + if (bs == null) createBufferStrategy(3); + bs = getBufferStrategy(); + if (bs.getDrawGraphics() != null) g = bs.getDrawGraphics(); + if(g != null) g2d = (Graphics2D) g; + } + private void drawBaseLayer() { + g2d.setColor(black); + g2d.fillRect(0, 0, getWidth(), getHeight()); + } + private void drawFPS() { + final Graphics2D fps = createG2D(); + fps.setColor(white); + fps.drawString("FPS: " + FPS + " " + "TPS: " + TPS, 50, 50); + } + + public final void scale() { g2d.scale(scaleFactor, scaleFactor); } + + + + + + + /** @method createG2D: Creates a new g2d object, useful for when you need to reset + * your current g2d object, but can't destroy it. */ + public final Graphics2D createG2D() { + if (bs.getDrawGraphics() != null) g = bs.getDrawGraphics(); + return g != null ? (Graphics2D) g : null; + } + + @Override + public final void run() { + long now, tickThen, frameThen, fpsUpdateTimer; + now = tickThen = frameThen = System.nanoTime(); + fpsUpdateTimer = System.currentTimeMillis(); + final int SECOND = 1000; + double deltaR, deltaT; + int sleepTime; + final Runner ticker = new Runner(() -> { tick(); ticks++; }); + final Runner renderer = new Runner(() -> { engine_render(); frames++; }); + + frame.setVisible(true); + setVisible(true); + + running = true; + + // GAME LOOP + while (running) { + // GET TIME + now = System.nanoTime(); + + // TICK + if(now - tickThen > TICK_INTERVAL) { + if(multithreadedGameUpdating) pool.runTask( ticker ); + else { tick(); ticks++; } + tickThen = now; + } + + // RUN RENDERER IN THREADPOOL + if(!rendering && now - frameThen > FRAME_RATE) { + if(multithreadedRendering) pool.runTask(renderer); + else { engine_render(); frames++; } + frameThen = now; + rendering = true; + } + + // UPDATE FRAMES PER SECOND + if (System.currentTimeMillis() - fpsUpdateTimer > SECOND) { + FPS = frames; TPS = ticks; frames = ticks = 0; + fpsUpdateTimer += SECOND; + } + + + if(variableSleepRate) { + // FIND WHICH TIME IS SHORTER: + // ---- The time until next game update, + // ---- or the time until next render + // Take whichever is shorter, and sleep that length + now = System.nanoTime(); + deltaR = FRAME_RATE - (now - frameThen); + deltaT = TICK_INTERVAL - (now - tickThen); + sleepTime = (int) (deltaR < deltaT ? deltaR : deltaT) / 1_000_000 - 1; + if (sleepTime > 0) try { Thread.sleep(sleepTime); } catch (final InterruptedException e) { e.printStackTrace(); } + } + } + } + + protected int getScreenWidth() { return Utils.SCREEN_WIDTH; } + protected int getScreenHeight() { return Utils.SCREEN_HEIGHT; } + protected void clearHandler() { Handler.clearAll(); } + public void disableFpsCap() { setFPS_CAP(10_000); } + public double getScaleFactor() { return scaleFactor; } + public void setScaleFactor(final double scaleFactor) { this.scaleFactor = scaleFactor; } + public static final String getVersion() { return engine_version; } + public final int getFPS() { return FPS; } + public final int getTPS() { return TPS; } + public final double getTickRate() { return TICK_INTERVAL; } + public final void setTickRate(final double TICK_INTERVAL) { this.TICK_INTERVAL = TICK_INTERVAL; } + public final double getFPS_CAP() { return FPS_CAP; } + public final void setFPS_CAP(final double FPS_CAP) { this.FPS_CAP = FPS_CAP; FRAME_RATE = Utils.second / FPS_CAP; } + public final void setDoubleTickRate() { TICK_INTERVAL = Utils.second / 120d; new Physics().setDoubleTickRate(); } + public void exit() { System.gc(); running = false; System.exit(0); } + public final void toggleDrawFPS() { drawFPS = !drawFPS; } + public final boolean getDrawFps() { return drawFPS; } + public final void setDrawFps(final boolean drawFPS) { this.drawFPS = drawFPS; } + + public final void enableVariableSleepRate() { variableSleepRate = true; } + public final void enableMultithreadedGameUpdating() { multithreadedGameUpdating = true; } + public final void enableMultithreadedRendering() { multithreadedRendering = true; } + + public final void disableVariableSleepRate() { variableSleepRate = false; } + public final void disableMultithreadedGameUpdating() { multithreadedGameUpdating = false; } + public final void disableMultithreadedRendering() { multithreadedRendering = false; } +} diff --git a/src/sjgs/core/Handler.java b/src/sjgs/core/Handler.java new file mode 100755 index 0000000..d9f281a --- /dev/null +++ b/src/sjgs/core/Handler.java @@ -0,0 +1,98 @@ +package sjgs.core; + +import java.awt.Graphics2D; +import sjgs.base_objects.GameObject; +import sjgs.base_objects.PlayerBase; +import sjgs.graphics.lighting.Light; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.gaming.QuadTree; + +public final class Handler { + + public static QuadTree stationary_hard_objects, stationary_soft_objects; + public static Stack players, mobs, bullets, mobile_hard_objects, mobile_soft_objects; + public static Stack lights; + private static int TREE_OFFSET, TREE_BOUNDS; + + void init() { + TREE_OFFSET = 32; + TREE_BOUNDS = 5000; + stationary_hard_objects = new QuadTree(-TREE_BOUNDS, -TREE_BOUNDS, TREE_BOUNDS, TREE_BOUNDS); + stationary_soft_objects = new QuadTree(-TREE_BOUNDS, -TREE_BOUNDS, TREE_BOUNDS, TREE_BOUNDS); + + mobile_hard_objects = new Stack(); + mobile_soft_objects = new Stack(); + mobs = new Stack(); + bullets = new Stack(); + players = new Stack(); + + lights = new Stack(); + } + + /** @param scaleFactor: should be one if not using any scaling */ + public static void tick(final Camera camera, final double scaleFactor) { + final float minX = -camera.getX() - TREE_OFFSET; + final float minY = -camera.getY() - TREE_OFFSET; + final float maxX = (float)(-camera.getX() + camera.getWidth() / scaleFactor + TREE_OFFSET); + final float maxY = (float)(-camera.getY() + camera.getHeight() / scaleFactor + TREE_OFFSET); + + try { for(final GameObject g : stationary_hard_objects.search(minX, minY, maxX, maxY)) g.tick(); } catch (final Exception e) { e.printStackTrace(); } + try { for(final GameObject g : stationary_soft_objects.search(minX, minY, maxX, maxY)) g.tick(); } catch (final Exception e) { e.printStackTrace(); } + try { for(final GameObject g : mobile_hard_objects) g.tick(); } catch (final Exception e) { e.printStackTrace(); } + try { for(final GameObject g : mobile_soft_objects) g.tick(); } catch (final Exception e) { e.printStackTrace(); } + try { for(final GameObject g : bullets) g.tick(); } catch (final Exception e) { e.printStackTrace(); } + try { for(final GameObject g : mobs) g.tick(); } catch (final Exception e) { e.printStackTrace(); } + + try { for(final GameObject player : players) try { player.tick(); } catch(final Exception e) { e.printStackTrace(); } } catch (final Exception e) { e.printStackTrace(); } + } + + public static void render(final Graphics2D g2d, final Camera camera, final double scaleFactor) { + g2d.translate(camera.getX(), camera.getY()); + + final float minX = -camera.getX() - TREE_OFFSET; + final float minY = -camera.getY() - TREE_OFFSET; + final float maxX = (float)(-camera.getX() + camera.getWidth() / scaleFactor + TREE_OFFSET); + final float maxY = (float)(-camera.getY() + camera.getHeight() / scaleFactor + TREE_OFFSET); + + try { for(final GameObject g : stationary_hard_objects.search(minX, minY, maxX, maxY)) try { g.render(g2d); } catch (final Exception e) { e.printStackTrace(); } } catch (final Exception e) { e.printStackTrace(); } + try { for(final GameObject g : stationary_soft_objects.search(minX, minY, maxX, maxY)) try { g.render(g2d); } catch (final Exception e) { e.printStackTrace(); } } catch (final Exception e) { e.printStackTrace(); } + for(final GameObject g : mobile_hard_objects) try { g.render(g2d); } catch (final Exception e) { e.printStackTrace(); } + for(final GameObject g : mobile_soft_objects) try { g.render(g2d); } catch (final Exception e) { e.printStackTrace(); } + for(final GameObject g : mobs) try { g.render(g2d); } catch (final Exception e) { e.printStackTrace(); } + for(final GameObject g : bullets) try { g.render(g2d); } catch (final Exception e) { e.printStackTrace(); } + + try { for(final GameObject player : players) try { player.render(g2d); } catch (final Exception e) { e.printStackTrace(); } } catch (final Exception e) { e.printStackTrace(); } + g2d.translate(-camera.getX(), -camera.getY()); + // g2d.scale(-scaleFactor, -scaleFactor); + } + + public static void setBounds(final int _TREE_BOUNDS) { + TREE_BOUNDS = _TREE_BOUNDS; + final Stack tempHards = stationary_hard_objects.toStack(); + final Stack tempSofts = stationary_soft_objects.toStack(); + stationary_hard_objects.clear(); stationary_soft_objects.clear(); + stationary_hard_objects = new QuadTree(-TREE_BOUNDS, -TREE_BOUNDS, TREE_BOUNDS, TREE_BOUNDS); + stationary_soft_objects = new QuadTree(-TREE_BOUNDS, -TREE_BOUNDS, TREE_BOUNDS, TREE_BOUNDS); + for(final GameObject h : tempHards) stationary_hard_objects.insert(h); + for(final GameObject s : tempSofts) stationary_soft_objects.insert(s); + } + + public static void setTreeOffset(final int _TREE_OFFSET) { TREE_OFFSET = _TREE_OFFSET; } + public static int getTreeOffset() { return TREE_OFFSET; } + public static int getTreeBounds() { return TREE_BOUNDS; } + public static void addPlayer(final PlayerBase PLAYER) { players.push(PLAYER); } + public static void removePlayer(final PlayerBase PLAYER) { players.remove(PLAYER); } + public static void clearPlayers() { if(players != null) players.clear(); } + public static void clearBullets() { if(bullets != null) bullets.clear(); } + public static void clearMobs() { if(mobs != null) mobs.clear(); } + public static void clearSoftObjects() { if(stationary_soft_objects != null) stationary_soft_objects.clear(); if(mobile_soft_objects != null) mobile_soft_objects.clear(); } + public static void clearHardObjects() { if(stationary_hard_objects != null) stationary_hard_objects.clear(); if(mobile_hard_objects != null) mobile_hard_objects.clear(); } + public static void clearAll() { + clearPlayers(); + clearBullets(); + clearMobs(); + clearSoftObjects(); + clearHardObjects(); + } + +} \ No newline at end of file diff --git a/src/sjgs/core/input/Keyboard.java b/src/sjgs/core/input/Keyboard.java new file mode 100755 index 0000000..f9ce17b --- /dev/null +++ b/src/sjgs/core/input/Keyboard.java @@ -0,0 +1,55 @@ +package sjgs.core.input; + +import java.util.HashSet; + +public interface Keyboard { + + static final HashSet keysDown = __Keyboard.keysDown; + + // --------------------- KEY CODES ---------------------------------- // + static final int W=0, A=1, S=2, D=3, SPACE=4, TAB=5, E=11, Q=12, ESCAPE=13, F=14, + MINUS=15, EQUALS = 16, CTRL = 17, PLUS=18, ONE=6, TWO=7, THREE=8, + FOUR=9, FIVE=10, SIX=19, SEVEN=20, EIGHT=21, NINE=22, ZERO=23, R=24, + Z=25, X=26, C=27, V=28, B=29, G=30, T=31, M=32, UP=33, DOWN=34, RIGHT=35, LEFT=36; + // -------------------- END KEY CODES ------------------------------- // + + public static boolean W() { return keysDown.contains(W); } + public static boolean A() { return keysDown.contains(A); } + public static boolean S() { return keysDown.contains(S); } + public static boolean D() { return keysDown.contains(D); } + public static boolean SPACE() { return keysDown.contains(SPACE); } + public static boolean TAB() { return keysDown.contains(TAB); } + public static boolean E() { return keysDown.contains(E); } + public static boolean Q() { return keysDown.contains(Q); } + public static boolean ESCAPE() { return keysDown.contains(ESCAPE); } + public static boolean F() { return keysDown.contains(F); } + public static boolean MINUS() { return keysDown.contains(MINUS); } + public static boolean EQUALS() { return keysDown.contains(EQUALS); } + public static boolean CTRL() { return keysDown.contains(CTRL); } + public static boolean PLUS() { return keysDown.contains(PLUS); } + public static boolean ONE() { return keysDown.contains(ONE); } + public static boolean TWO() { return keysDown.contains(TWO); } + public static boolean THREE() { return keysDown.contains(THREE); } + public static boolean FOUR() { return keysDown.contains(FOUR); } + public static boolean FIVE() { return keysDown.contains(FIVE); } + public static boolean SIX() { return keysDown.contains(SIX); } + public static boolean SEVEN() { return keysDown.contains(SEVEN); } + public static boolean EIGHT() { return keysDown.contains(EIGHT); } + public static boolean NINE() { return keysDown.contains(NINE); } + public static boolean ZERO() { return keysDown.contains(ZERO); } + public static boolean R() { return keysDown.contains(R); } + public static boolean Z() { return keysDown.contains(Z); } + public static boolean X() { return keysDown.contains(X); } + public static boolean C() { return keysDown.contains(C); } + public static boolean V() { return keysDown.contains(V); } + public static boolean B() { return keysDown.contains(B); } + public static boolean G() { return keysDown.contains(G); } + public static boolean T() { return keysDown.contains(T); } + public static boolean M() { return keysDown.contains(M); } + public static boolean UP() { return keysDown.contains(UP); } + public static boolean DOWN() { return keysDown.contains(DOWN); } + public static boolean RIGHT() { return keysDown.contains(RIGHT); } + public static boolean LEFT() { return keysDown.contains(LEFT); } + + +} diff --git a/src/sjgs/core/input/Mouse.java b/src/sjgs/core/input/Mouse.java new file mode 100755 index 0000000..637fc61 --- /dev/null +++ b/src/sjgs/core/input/Mouse.java @@ -0,0 +1,56 @@ +package sjgs.core.input; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import sjgs.core.Engine; +import sjgs.utils.data_structures.vectors.Point2f; + +public abstract class Mouse implements MouseListener, MouseWheelListener, MouseMotionListener{ + + protected static final Point2f pos = new Point2f(0, 0); + protected static final Point2f clickPos = new Point2f(0, 0); + protected static final Point2f rightClickPos = new Point2f(0,0); + + public Mouse(final Engine engine) { + engine.addMouseListener(this); + engine.addMouseWheelListener(this); + engine.addMouseMotionListener(this); + } + + @Override + public abstract void mouseMoved(MouseEvent e); + @Override + public abstract void mouseWheelMoved(MouseWheelEvent arg0); + @Override + public abstract void mouseClicked(MouseEvent e); + @Override + public abstract void mousePressed(MouseEvent e); + @Override + public abstract void mouseReleased(MouseEvent e); + + @Override + public void mouseDragged(final MouseEvent e) { pos.setLocation(e.getX(), e.getY()); } + @Override + public void mouseEntered(final MouseEvent e) { pos.setLocation(e.getX(), e.getY()); } + @Override + public void mouseExited(final MouseEvent e) { pos.setLocation(e.getX(), e.getY()); } + + public static float getX() { return pos.x; } + public static float getY() { return pos.y; } + public static float getClickX() { return clickPos.x; } + public static float getClickY() { return clickPos.y; } + public static float getRightClickX() { return rightClickPos.x; } + public static float getRightClickY() { return rightClickPos.y; } + + public void setLocation(final int x, final int y) { pos.setLocation(x, y); } + public void setClickLocation(final int x, final int y) { clickPos.setLocation(x, y); } + public void setRightClickLocation(final int x, final int y) { rightClickPos.setLocation(x, y); } + + public static Point2f getClickPos() { return clickPos; } + public static Point2f getRightClickPos() { return rightClickPos; } + public static Point2f getMousePos() { return pos; } + +} diff --git a/src/sjgs/core/input/__Keyboard.java b/src/sjgs/core/input/__Keyboard.java new file mode 100755 index 0000000..24f9f51 --- /dev/null +++ b/src/sjgs/core/input/__Keyboard.java @@ -0,0 +1,383 @@ +package sjgs.core.input; + +import java.awt.event.ActionEvent; +import java.util.HashSet; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.KeyStroke; + +public final class __Keyboard implements Keyboard { + + // NOTE THIS IS ONLY TO BE USED FOR GAMES, TO BE USED IN REGULAR TYPING, A KEY ADAPTER WILL WORK MUCH BETTER + + static HashSet keysDown; + + public void init(final JPanel panel) { + keysDown = new HashSet(); + initWASD(panel); + initArrowKeys(panel); + initSpace(panel); + initEscape(panel); + initNumbers(panel); + initQ(panel); + initE(panel); + initR(panel); + initF(panel); + initZ(panel); + initX(panel); + initC(panel); + initV(panel); + initB(panel); + initG(panel); + initT(panel); + initM(panel); + } + + // *************** INITIALIZATION *************************************************************************************************** // + + + private static void initWASD(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + // ---- ADD WASD ------------------------------------ // + final Action walkUp = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(W)) keysDown.add(W); } }; + final Action walkDown = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(S)) keysDown.add(S); } }; + final Action walkLeft = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(A)) keysDown.add(A); } }; + final Action walkRight = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(D)) keysDown.add(D); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("W"), "walkUp"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("A"), "walkLeft"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("S"), "walkDown"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("D"), "walkRight"); + panel.getActionMap().put("walkUp", walkUp); + panel.getActionMap().put("walkDown", walkDown); + panel.getActionMap().put("walkLeft", walkLeft); + panel.getActionMap().put("walkRight", walkRight); + // --- END ADD WASD --------------------------------- // + + // ---- REMOVE WASD ----------------------------------// + final Action stopWalkUp = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(W)) keysDown.remove(W); } }; + final Action stopWalkDown = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(S)) keysDown.remove(S); } }; + final Action stopWalkLeft = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(A)) keysDown.remove(A); } }; + final Action stopWalkRight = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(D)) keysDown.remove(D); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released W"), "stopWalkUp"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released A"), "stopWalkLeft"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released S"), "stopWalkDown"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released D"), "stopWalkRight"); + panel.getActionMap().put("stopWalkUp", stopWalkUp); + panel.getActionMap().put("stopWalkDown", stopWalkDown); + panel.getActionMap().put("stopWalkLeft", stopWalkLeft); + panel.getActionMap().put("stopWalkRight", stopWalkRight); + // -- END REMOVE WASD ----------------------------------// + } + + private static void initQ(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addQ = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Q)) keysDown.add(Q); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("Q"), "addQ"); + panel.getActionMap().put("addQ", addQ); + final Action removeQ = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Q)) keysDown.remove(Q); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released Q"), "removeQ"); + panel.getActionMap().put("removeQ", removeQ); + } + + private static void initE(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addE = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(E)) keysDown.add(E); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("E"), "addE"); + panel.getActionMap().put("addE", addE); + final Action removeE = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(E)) keysDown.remove(E); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released E"), "removeE"); + panel.getActionMap().put("removeE", removeE); + } + + private static void initR(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addR = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(R)) keysDown.add(R); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("R"), "addR"); + panel.getActionMap().put("addR", addR); + final Action removeR = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(R)) keysDown.remove(R); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released R"), "removeR"); + panel.getActionMap().put("removeR", removeR); + } + + private static void initF(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addF = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(F)) keysDown.add(F); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("F"), "addF"); + panel.getActionMap().put("addF", addF); + final Action removeF = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(F)) keysDown.remove(F); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released F"), "removeF"); + panel.getActionMap().put("removeF", removeF); + } + + private static void initSpace(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action space = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(SPACE)) keysDown.add(SPACE); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("SPACE"), "space"); + panel.getActionMap().put("space", space); + final Action releasedSpace = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(SPACE)) keysDown.remove(SPACE); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released SPACE"), "releasedSpace"); + panel.getActionMap().put("releasedSpace", releasedSpace); + } + + private static void initEscape(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action escape = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(ESCAPE)) keysDown.add(ESCAPE); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("ESCAPE"), "escape"); + panel.getActionMap().put("escape", escape); + final Action releasedEscape = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(ESCAPE)) keysDown.remove(ESCAPE); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released ESCAPE"), "releasedEscape"); + panel.getActionMap().put("releasedEscape", releasedEscape); + } + + private static void initZ(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addZ = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Z)) keysDown.add(Z); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("Z"), "addZ"); + panel.getActionMap().put("addZ", addZ); + final Action removeZ = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Z)) keysDown.remove(Z); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released Z"), "removeZ"); + panel.getActionMap().put("removeZ", removeZ); + } + + private static void initX(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addX = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(X)) keysDown.add(X); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("X"), "addX"); + panel.getActionMap().put("addX", addX); + final Action removeX = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(X)) keysDown.remove(X); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released X"), "removeX"); + panel.getActionMap().put("removeX", removeX); + } + + private static void initC(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addC = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(C)) keysDown.add(C); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("C"), "addC"); + panel.getActionMap().put("addC", addC); + final Action removeC = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(C)) keysDown.remove(C); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released C"), "removeC"); + panel.getActionMap().put("removeC", removeC); + } + + private static void initV(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addV = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(V)) keysDown.add(V); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("V"), "addV"); + panel.getActionMap().put("addV", addV); + final Action removeV = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(V)) keysDown.remove(V); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released V"), "removeV"); + panel.getActionMap().put("removeV", removeV); + } + + private static void initB(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addB = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(B)) keysDown.add(B); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("B"), "addB"); + panel.getActionMap().put("addB", addB); + final Action removeB = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(B)) keysDown.remove(B); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released B"), "removeB"); + panel.getActionMap().put("removeB", removeB); + } + + private static void initG(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addG = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(G)) keysDown.add(G); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("G"), "addG"); + panel.getActionMap().put("addG", addG); + final Action removeG = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(G)) keysDown.remove(G); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released G"), "removeG"); + panel.getActionMap().put("removeG", removeG); + } + + private static void initT(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addT = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(T)) keysDown.add(T); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("T"), "addT"); + panel.getActionMap().put("addT", addT); + final Action removeT = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(T)) keysDown.remove(T); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released T"), "removeT"); + panel.getActionMap().put("removeT", removeT); + } + + private static void initM(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + final Action addM = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(M)) keysDown.add(M); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("M"), "addM"); + panel.getActionMap().put("addM", addM); + final Action removeM = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(M)) keysDown.remove(M); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released M"), "removeM"); + panel.getActionMap().put("removeM", removeM); + } + + private static void initNumbers(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + // -------------------------------- ADDS --------------------------------------- // + final Action add1 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.ONE)) keysDown.add(Keyboard.ONE); } }; + final Action add2 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.TWO)) keysDown.add(Keyboard.TWO); } }; + final Action add3 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.THREE)) keysDown.add(Keyboard.THREE); } }; + final Action add4 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.FOUR)) keysDown.add(Keyboard.FOUR); } }; + final Action add5 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.FIVE)) keysDown.add(Keyboard.FIVE); } }; + final Action add6 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.SIX)) keysDown.add(Keyboard.SIX); } }; + final Action add7 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.SEVEN)) keysDown.add(Keyboard.SEVEN); } }; + final Action add8 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.EIGHT)) keysDown.add(Keyboard.EIGHT); } }; + final Action add9 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.NINE)) keysDown.add(Keyboard.NINE); } }; + final Action add0 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(Keyboard.ZERO)) keysDown.add(Keyboard.ZERO); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("1"), "add1"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("2"), "add2"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("3"), "add3"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("4"), "add4"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("5"), "add5"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("6"), "add6"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("7"), "add7"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("8"), "add8"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("9"), "add9"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("0"), "add0"); + panel.getActionMap().put("add1", add1); + panel.getActionMap().put("add2", add2); + panel.getActionMap().put("add3", add3); + panel.getActionMap().put("add4", add4); + panel.getActionMap().put("add5", add5); + panel.getActionMap().put("add6", add6); + panel.getActionMap().put("add7", add7); + panel.getActionMap().put("add8", add8); + panel.getActionMap().put("add9", add9); + panel.getActionMap().put("add0", add0); + // ------------------------------ RELEASES ------------------------------------- // + final Action release1 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.ONE)) keysDown.remove(Keyboard.ONE); } }; + final Action release2 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.TWO)) keysDown.remove(Keyboard.TWO); } }; + final Action release3 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.THREE)) keysDown.remove(Keyboard.THREE); } }; + final Action release4 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.FOUR)) keysDown.remove(Keyboard.FOUR); } }; + final Action release5 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.FIVE)) keysDown.remove(Keyboard.FIVE); } }; + final Action release6 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.SIX)) keysDown.remove(Keyboard.SIX); } }; + final Action release7 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.SEVEN)) keysDown.remove(Keyboard.SEVEN); } }; + final Action release8 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.EIGHT)) keysDown.remove(Keyboard.EIGHT); } }; + final Action release9 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.NINE)) keysDown.remove(Keyboard.NINE); } }; + final Action release0 = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(Keyboard.ZERO)) keysDown.remove(Keyboard.ZERO); } }; + + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 1"), "release1"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 2"), "release2"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 3"), "release3"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 4"), "release4"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 5"), "release5"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 6"), "release6"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 7"), "release7"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 8"), "release8"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 9"), "release9"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released 0"), "release0"); + panel.getActionMap().put("release1", release1); + panel.getActionMap().put("release2", release2); + panel.getActionMap().put("release3", release3); + panel.getActionMap().put("release4", release4); + panel.getActionMap().put("release5", release5); + panel.getActionMap().put("release6", release6); + panel.getActionMap().put("release7", release7); + panel.getActionMap().put("release8", release8); + panel.getActionMap().put("release9", release9); + panel.getActionMap().put("release0", release0); + + + } + + private static void initArrowKeys(final JPanel panel) { + final int when = JComponent.WHEN_IN_FOCUSED_WINDOW; + // ---- ADD ARROW KEYS ------------------------------------ // + final Action ADD_UP = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(UP)) keysDown.add(UP); } }; + + + final Action ADD_DOWN = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(DOWN)) keysDown.add(DOWN); } }; + final Action ADD_LEFT = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(LEFT)) keysDown.add(LEFT); } }; + final Action ADD_RIGHT = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (!keysDown.contains(RIGHT)) keysDown.add(RIGHT); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("UP"), "UP"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("LEFT"), "LEFT"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("DOWN"), "DOWN"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("RIGHT"), "RIGHT"); + panel.getActionMap().put("UP", ADD_UP); + panel.getActionMap().put("LEFT", ADD_LEFT); + panel.getActionMap().put("DOWN", ADD_DOWN); + panel.getActionMap().put("RIGHT", ADD_RIGHT); + // --- END ADD ARROW KEYS --------------------------------- // + + // ---- REMOVE ARROW KEYS ----------------------------------// + final Action REMOVE_UP = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(UP)) keysDown.remove(UP); } }; + final Action REMOVE_DOWN = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(DOWN)) keysDown.remove(DOWN); } }; + final Action REMOVE_LEFT = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(LEFT)) keysDown.remove(LEFT); } }; + final Action REMOVE_RIGHT = new AbstractAction() { @Override + public void actionPerformed(final ActionEvent e) { if (keysDown.contains(RIGHT)) keysDown.remove(RIGHT); } }; + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released UP"), "RELEASEUP"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released LEFT"), "RELEASELEFT"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released DOWN"), "RELEASEDOWN"); + panel.getInputMap(when).put(KeyStroke.getKeyStroke("released RIGHT"), "RELEASERIGHT"); + panel.getActionMap().put("RELEASEUP", REMOVE_UP); + panel.getActionMap().put("RELEASEDOWN", REMOVE_DOWN); + panel.getActionMap().put("RELEASELEFT", REMOVE_LEFT); + panel.getActionMap().put("RELEASERIGHT", REMOVE_RIGHT); + // -- END REMOVE ARROW KEYS ----------------------------------// + } + // ********************************************************************************************************************************** // + +} diff --git a/src/sjgs/core/jython/Jython.java b/src/sjgs/core/jython/Jython.java new file mode 100755 index 0000000..5a9828f --- /dev/null +++ b/src/sjgs/core/jython/Jython.java @@ -0,0 +1,37 @@ +package sjgs.core.jython; + +import static sjgs.utils.Utils.readTextFileAsString; +import org.python.util.PythonInterpreter; +import sjgs.graphics.ui.InventorySystem; +import sjgs.utils.pyutils.PyUtils; + +public final class Jython { + + public static final PythonInterpreter pi = new PythonInterpreter(); + + public void __init__() { + //final long then = System.nanoTime(); + initialize(); + imports(); + loadMethodsIntoInterpretor(); + createPyFuncs(); + //pi.exec("print " + "'Jython / Python initialized --- Time taken: " + Utils.df.format((System.nanoTime() - then) / Utils.second) + " seconds'"); + } + + // INITIALIZES INTERP WITH SYSTEM INFORMATION + private static void initialize() { PyUtils.initializePySystem(); } + + // IMPORTS ALL NECESSARY JAVA CLASSES FOR INTERP + private static void imports() { pi.exec(readTextFileAsString("/sjgs/core/jython/engine_imports.py")); } + + // RUNS THE MODULES THROUGH THE INTERP TO LOAD THE NAMES OF FUNCS + private static void loadMethodsIntoInterpretor() { + pi.exec(readTextFileAsString("/sjgs/graphics/ui/__engine_inventory.py")); + pi.exec(readTextFileAsString("/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py")); + } + + private static void createPyFuncs() { + InventorySystem.__engine_init_pyfuncs(); + } + +} diff --git a/src/sjgs/core/jython/engine_imports.py b/src/sjgs/core/jython/engine_imports.py new file mode 100755 index 0000000..47d54cd --- /dev/null +++ b/src/sjgs/core/jython/engine_imports.py @@ -0,0 +1,46 @@ +### Java standard library imports +from java.lang.Math import * +from java.lang import Integer, Float, Double + +### engine imports +from sjgs.core import Engine as Engine +from sjgs.core import Camera as Camera +from sjgs.core import Handler as Handler + +import sjgs.core.input.Mouse as Mouse + +import sjgs.enums.Facing as Facing +import sjgs.enums.TickRate as TickRate +import sjgs.enums.Type as Type + +from sjgs.graphics.Colors import * +from sjgs.graphics import Colors + +from sjgs.base_objects import * + +import sjgs.sound.SoundPlayer as SoundPlayer + +import sjgs.physics.Physics as Physics +import sjgs.physics.structs.BoundingBox as BoundingBox +import sjgs.physics.structs.CollisionResponse as CollisionResponse + +from sjgs.utils.Utils import * +import sjgs.utils.Utils + +import sjgs.utils.tools.Timer as Timer + +import sjgs.utils.encryption.StrongCaesarCipher + +import sjgs.utils.data_structures.Stack as Stack +from sjgs.utils.data_structures.shapes import * +from sjgs.utils.data_structures.vectors import * +from sjgs.utils.data_structures.gaming import * +import sjgs.utils.data_structures.shapes.Rectangle as Rectangle +import sjgs.utils.data_structures.vectors.Point2f as Point2f +import sjgs.utils.data_structures.vectors.SimplePoint as SimplePoint +import sjgs.utils.data_structures.shapes.Line as Line + + +from sjgs.graphics.ui.InventorySystemSlot import EMPTY +import sjgs.graphics.ui.InventorySystem as InventorySystem +import sjgs.graphics.ui.InventorySystemSlot as InventorySystemSlot diff --git a/src/sjgs/enums/Facing.java b/src/sjgs/enums/Facing.java new file mode 100755 index 0000000..45d08ac --- /dev/null +++ b/src/sjgs/enums/Facing.java @@ -0,0 +1,7 @@ +package sjgs.enums; + +public enum Facing { + + LEFT, RIGHT, ABOVE, BELOW, NONE + +} diff --git a/src/sjgs/enums/TickRate.java b/src/sjgs/enums/TickRate.java new file mode 100755 index 0000000..9aaf43c --- /dev/null +++ b/src/sjgs/enums/TickRate.java @@ -0,0 +1,7 @@ +package sjgs.enums; + +public enum TickRate { + + _60, _120 + +} diff --git a/src/sjgs/enums/Type.java b/src/sjgs/enums/Type.java new file mode 100755 index 0000000..0464f90 --- /dev/null +++ b/src/sjgs/enums/Type.java @@ -0,0 +1,7 @@ +package sjgs.enums; + +public enum Type { + + BULLET, HARD_OBJECT, MOB, PLAYER, SOFT_OBJECT, NONE + +} diff --git a/src/sjgs/graphics/Animation.java b/src/sjgs/graphics/Animation.java new file mode 100755 index 0000000..259f9e9 --- /dev/null +++ b/src/sjgs/graphics/Animation.java @@ -0,0 +1,100 @@ +package sjgs.graphics; + +import static sjgs.utils.Utils.invertImage; +import static sjgs.utils.Utils.reverseImage; +import static sjgs.utils.Utils.rotateImageLeft; +import static sjgs.utils.Utils.rotateImageRight; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.image.BufferedImage; +import sjgs.physics.structs.BoundingBox; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; + +public class Animation { + + /** @param speed : the number of ticks needed to advance each frame + * @param timer : the index of the current tick amount + * @param currentFrame : the index of the currently displaying image */ + + private int speed; + public int currentFrame, timer; + private final BufferedImage[] images; + + public Animation(final int speed, final BufferedImage... args) { + this.speed = speed; images = new BufferedImage[args.length]; + for (int i = 0; i < args.length; i++) images[i] = args[i]; + } + + public Animation(final int speed, final Stack args) { + this.speed = speed; images = new BufferedImage[args.size()]; + for (int i = 0; i < args.size(); i++) images[i] = args.get(i); + } + + public Animation(final int speed, final Image... args) { + this.speed = speed; images = new BufferedImage[args.length]; + for (int i = 0; i < args.length; i++) images[i] = Utils.imageToBufferedImage(args[i]); + } + + public void runAnimation() { if (++timer > speed) nextFrame(); } + + public void playAnimationOnce() { + if (currentFrame != images.length - 1 && ++timer > speed) nextFrame(); + } + + public void nextFrame() { + if (++currentFrame >= images.length) restartAnimation(); + else timer = 0; + } + + public void restartAnimation() { currentFrame = timer = 0; } + + public void drawAnimation(final Graphics2D g2d, final Point2f p){ g2d.drawImage(images[currentFrame], (int) p.x, (int) p.y, null); } + public void drawAnimation(final Graphics2D g2d, final SimplePoint p){ g2d.drawImage(images[currentFrame], p.x, p.y, null); } + public void drawAnimation(final Graphics2D g2d, final Point p){ g2d.drawImage(images[currentFrame], p.x, p.y, null); } + public void drawAnimation(final Graphics2D g2d, final double x, final double y) { g2d.drawImage(images[currentFrame], (int) x, (int) y, null); } + public void drawAnimation(final Graphics2D g2d, final float x, final float y) { g2d.drawImage(images[currentFrame], (int) x, (int) y, null); } + public void drawAnimation(final Graphics2D g2d, final int x, final int y) { g2d.drawImage(images[currentFrame], x, y, null); } + public void drawAnimation(final Graphics2D g2d, final Rectangle r) { g2d.drawImage(images[currentFrame], (int)r.getPos().x, (int)r.getPos().y, null); } + public void drawAnimation(final Graphics2D g2d, final BoundingBox b) { g2d.drawImage(images[currentFrame], (int)b.getX(), (int)b.getY(), null); } + + public BufferedImage getLastFrame() { return images[images.length - 1]; } + + public int size() { return images.length; } + + public BufferedImage[] getImages() { return images; } + + public void setSpeed(final int speed) { this.speed = speed; } + + @Override + public Animation clone() { return new Animation(speed, images); } + + public Animation getReverse() { + final BufferedImage[] sprites = new BufferedImage[images.length]; + for(int i = 0; i < images.length; i++) sprites[i] = reverseImage(images[i]); + return new Animation(speed, sprites); + } + + public Animation getInverted() { + final BufferedImage[] sprites = new BufferedImage[images.length]; + for(int i = 0; i < images.length; i++) sprites[i] = invertImage(images[i]); + return new Animation(speed, sprites); + } + + public Animation getRotatedRight() { + final BufferedImage[] sprites = new BufferedImage[images.length]; + for(int i = 0; i < images.length; i++) sprites[i] = rotateImageRight(images[i]); + return new Animation(speed, sprites); + } + + public Animation getRotatedLeft() { + final BufferedImage[] sprites = new BufferedImage[images.length]; + for(int i = 0; i < images.length; i++) sprites[i] = rotateImageLeft(images[i]); + return new Animation(speed, sprites); + } + +} diff --git a/src/sjgs/graphics/Colors.java b/src/sjgs/graphics/Colors.java new file mode 100755 index 0000000..80bae62 --- /dev/null +++ b/src/sjgs/graphics/Colors.java @@ -0,0 +1,24 @@ +package sjgs.graphics; + +import java.awt.Color; +import sjgs.utils.Utils; + +public class Colors { + + public static final Color red = Color.red, + green = Color.green, + black = Color.black, + white = Color.white, + blue = Color.blue, + orange = Color.orange, + purple = Color.magenta, + pink = Color.pink, + yellow = Color.yellow, + gray = Color.gray, + darkGray = Color.darkGray, + cyan = Color.cyan; + + public static final Color pastelRed = new Color(255, 80, 50), + voidColor = Utils.voidColor; + +} \ No newline at end of file diff --git a/src/sjgs/graphics/backgrounds/Background.java b/src/sjgs/graphics/backgrounds/Background.java new file mode 100755 index 0000000..86be195 --- /dev/null +++ b/src/sjgs/graphics/backgrounds/Background.java @@ -0,0 +1,55 @@ +package sjgs.graphics.backgrounds; + +import static sjgs.utils.Utils.exit; +import static sjgs.utils.Utils.print; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import sjgs.core.Camera; +import sjgs.utils.data_structures.vectors.SimplePoint; + +public class Background { + + private final BufferedImage image; + private final float scrollX, scrollY; + private final SimplePoint start; + private final boolean loop; + + // NOTE a background that shouldn't move with that player, that is to be completely static, should have a scrollPercentage of 0 + public Background(final BufferedImage image, final float x, final float y, final float scrollPercentageX, final float scrollPercentageY, final boolean shouldLoop) { + this.image = image; + if(scrollPercentageX > 100 || scrollPercentageX < 0 || scrollPercentageY > 100 || scrollPercentageY < 0) { print("Incorrect scroll %"); exit(); } + scrollX = scrollPercentageX / 100f; + scrollY = scrollPercentageY / 100f; + start = new SimplePoint((int)x, (int)y); + loop = shouldLoop; + } + + public void render(final Graphics2D g2d, final Camera camera, @SuppressWarnings("unused") final double scaleFactor) { + final int x = start.x + (int)(camera.getX() * scrollX); + final int y = start.y + (int)(camera.getY() * scrollY); + + + g2d.drawImage(image, x, y, null); + + + // NOTE THIS IS CURRENTLY BROKEN: + + // int screenCovered = x; + // start with nothing drawn, at the camera X + // continue to redraw the background until the full screen is covered + // do { + // // set clip if it would go over + // if(screenCovered + image.getWidth() > x + camera.getWidth() / scaleFactor) { + // final int lengthNeeded = (int) ((x + camera.getWidth() / scaleFactor) - screenCovered); + // final Graphics2D copy = (Graphics2D) g2d.create(); + // copy.setClip(screenCovered, y, lengthNeeded, image.getHeight()); + // copy.drawImage(image, screenCovered, y, null); + // } else g2d.drawImage(image, screenCovered, y, null); + // + // + // screenCovered += image.getWidth(); + // } while(loop && screenCovered < x + camera.getWidth() / scaleFactor); + + } + +} diff --git a/src/sjgs/graphics/backgrounds/ParallaxBackground.java b/src/sjgs/graphics/backgrounds/ParallaxBackground.java new file mode 100755 index 0000000..96af081 --- /dev/null +++ b/src/sjgs/graphics/backgrounds/ParallaxBackground.java @@ -0,0 +1,17 @@ +package sjgs.graphics.backgrounds; + +import java.awt.Graphics2D; +import sjgs.core.Camera; + +public class ParallaxBackground { + + private final Background[] backgrounds; + + // sort these later so no need to worry about order + public ParallaxBackground(final Background ...args) { backgrounds = args; } + + public void render(final Graphics2D g2d, final Camera camera, final double scaleFactor) { + for(final Background b : backgrounds) b.render(g2d, camera, scaleFactor); + } + +} diff --git a/src/sjgs/graphics/lighting/Light.java b/src/sjgs/graphics/lighting/Light.java new file mode 100755 index 0000000..9cd4745 --- /dev/null +++ b/src/sjgs/graphics/lighting/Light.java @@ -0,0 +1,32 @@ +package sjgs.graphics.lighting; + +import java.awt.Graphics2D; +import sjgs.core.Camera; +import sjgs.core.Engine; +import sjgs.utils.data_structures.vectors.Point2f; + +public abstract class Light { + + protected final float intensity; + protected final Point2f center; + + public Light(final float x, final float y, final float intensity) { + this.intensity = intensity; + center = new Point2f(x, y); + } + + abstract void update(Graphics2D lightsRenderer, Camera camera, Engine engine); + + public void tick() { } + public void destroy() { } + + + public float getX() { return center.x; } + public float getY() { return center.y; } + public Point2f getCenter() { return center; } + public float getIntensity() { return intensity; } + + public void setX(final float x) { center.setX(x); } + public void setY(final float y) { center.setY(y); } + public void setLocation(final float x, final float y) { setX(x); setY(y); } +} diff --git a/src/sjgs/graphics/lighting/LightsRenderer.java b/src/sjgs/graphics/lighting/LightsRenderer.java new file mode 100755 index 0000000..f8f4152 --- /dev/null +++ b/src/sjgs/graphics/lighting/LightsRenderer.java @@ -0,0 +1,31 @@ +package sjgs.graphics.lighting; + +import static sjgs.graphics.Colors.black; +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.ConcurrentModificationException; +import sjgs.core.Camera; +import sjgs.core.Engine; +import sjgs.core.Handler; + +public class LightsRenderer { + + public static void render(final Graphics2D g2d, final Camera camera, final Engine engine){ + final BufferedImage lightmap = new BufferedImage((int) (engine.getWidth() * 1.1), (int) (engine.getHeight() * 1.1), BufferedImage.TYPE_INT_ARGB); + + final Graphics2D lightsRenderer = (Graphics2D) lightmap.getGraphics(); + + lightsRenderer.setColor(black); + lightsRenderer.fillRect(0, 0, lightmap.getWidth(), lightmap.getHeight()); + lightsRenderer.setComposite(AlphaComposite.DstOut); + + try{ for(final Light light : Handler.lights) light.update(lightsRenderer, camera, engine); } + catch (final ConcurrentModificationException cme){ /* happens when adding / removing lights, ignore */ } + + lightsRenderer.dispose(); + + g2d.drawImage(lightmap, 0, 0, null); + } + +} diff --git a/src/sjgs/graphics/lighting/RadialLight.java b/src/sjgs/graphics/lighting/RadialLight.java new file mode 100755 index 0000000..b335711 --- /dev/null +++ b/src/sjgs/graphics/lighting/RadialLight.java @@ -0,0 +1,44 @@ +package sjgs.graphics.lighting; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Point; +import java.awt.RadialGradientPaint; +import java.awt.image.BufferedImage; +import sjgs.core.Camera; +import sjgs.core.Engine; +import sjgs.core.Handler; + +public class RadialLight extends Light { + + private final BufferedImage lightImage; + protected final float radius; + + public RadialLight(final float x, final float y, final float radius, final float intensity) { + super(x, y, intensity); + this.radius = radius; + + /******** DRAW THE LIGHT IMAGE **********************************************************/ + final Color[] color = { new Color(0, 0, 0, intensity), new Color(0, 0, 0, 0) }; + lightImage = new BufferedImage((int)(radius*2), (int)(radius*2), BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2d = (Graphics2D) lightImage.getGraphics(); + final float[] distance = { 0f, 1f }; + g2d.setPaint(new RadialGradientPaint(new Point((int)radius, (int)radius), radius, distance, color)); + g2d.fillOval(0, 0, (int)(radius*2), (int)(radius*2)); + g2d.dispose(); + /***************************************************************************************/ + + Handler.lights.add(this); + } + + @Override + public void update(final Graphics2D lightsRenderer, final Camera camera, final Engine engine){ + lightsRenderer.drawImage(lightImage.getScaledInstance((int)(lightImage.getWidth() * engine.getScaleFactor()), + (int)(lightImage.getHeight() * engine.getScaleFactor()), Image.SCALE_FAST), + (int)((center.x + camera.getX()) * engine.getScaleFactor()) - (int)(radius * engine.getScaleFactor()), + (int)((center.y + camera.getY()) * engine.getScaleFactor()) - (int)(radius * engine.getScaleFactor()), null); + } + + public float getRadius() { return radius; } +} diff --git a/src/sjgs/graphics/ui/InventorySystem.java b/src/sjgs/graphics/ui/InventorySystem.java new file mode 100755 index 0000000..c67aad1 --- /dev/null +++ b/src/sjgs/graphics/ui/InventorySystem.java @@ -0,0 +1,86 @@ +package sjgs.graphics.ui; + +import static sjgs.core.jython.Jython.pi; +import static sjgs.utils.pyutils.PyUtils.One; +import static sjgs.utils.pyutils.PyUtils.True; +import static sjgs.utils.pyutils.PyUtils.int2py; +import static sjgs.utils.pyutils.PyUtils.java2py; +import java.awt.Graphics2D; +import org.python.core.PyFunction; +import org.python.core.PyObject; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Rectangle; + +public abstract class InventorySystem { + + protected final Rectangle INVENTORY_BOUNDS; + protected Stack slots; + protected final PyObject self; + + public InventorySystem(final float x, final float y, final float width, final float height) { + INVENTORY_BOUNDS = new Rectangle(x, y, width, height); + slots = new Stack(); + self = java2py(this); + init(); + } + + public abstract void init(); + public abstract void tick(); + public abstract void render(Graphics2D g2d); + public abstract void destroy(); + public abstract void onLeftClick(); // NOTE: you must put 'baseOnLeftClick()' in this method! + public abstract void swapSlots(final InventorySystemSlot i, final InventorySystemSlot e); + public abstract boolean isStackable(int itemId); + public abstract int getStackableAmount(int itemId); + + public void addItem(final int itemId, final int quantity) { addItem.__call__(int2py(itemId), int2py(quantity), self); } + public void addItem(final int itemId) { addItem.__call__(int2py(itemId), One, self); } + public void removeItemWithSlotNumber(final int itemId, final int quantity, final int slotNumber) { + removeItemWithSlotNumber.__call__(int2py(itemId), int2py(quantity), int2py(slotNumber), self); + } + public void removeItem(final int itemId, final int quantity) { removeItem.__call__(int2py(itemId), int2py(quantity), self); } + public void removeItem(final int itemId) { removeItem.__call__(int2py(itemId), One, self); } + + public void resetPositions() { for(final InventorySystemSlot i : slots) if(!i.mouseClicked) i.resetPosition(); } + + + // swaps the values from this slot to the other slot and vice versa + public void baseSwapSlots(final InventorySystemSlot i, final InventorySystemSlot e) { + final int tempId = i.itemId; + final int tempQ = i.quantity; + i.itemId = e.itemId; + i.quantity = e.quantity; + e.itemId = tempId; + e.quantity = tempQ; + e.mouseClicked = false; + if(i.isEmpty()) i.mouseClicked = false; + resetPositions(); + } + + // NOTE YOU MUST USE THIS! + public void baseOnLeftClick() { baseOnLeftClick.__call__(self); } + + public void clearInventory() { for (final InventorySystemSlot i : slots) i.reset(); } + public void resetMouseClicked() { for (final InventorySystemSlot i : slots) i.mouseClicked = false; } + + public boolean isFull(final int itemId, final int quantity) { return isFull.__call__(int2py(itemId), int2py(quantity), self) == True; } + public boolean contains(final int itemId, final int quantity) { return contains.__call__(int2py(itemId), int2py(quantity), self) == True; } + + public Stack getSlots() { return slots; } + public float getWidth() { return INVENTORY_BOUNDS.getWidth(); } + public float getHeight() { return INVENTORY_BOUNDS.getHeight(); } + public float getX() { return INVENTORY_BOUNDS.getX(); } + public float getY() { return INVENTORY_BOUNDS.getY(); } + public Rectangle getBounds() { return INVENTORY_BOUNDS; } + + //=======================================================================================================// + private static PyFunction isFull, contains, baseOnLeftClick, addItem, removeItem, removeItemWithSlotNumber; + public static void __engine_init_pyfuncs() { + isFull = pi.get("__engine_inventory_is_full", PyFunction.class); + contains = pi.get("__engine_inventory_contains", PyFunction.class); + baseOnLeftClick = pi.get("__engine_onLeftClick", PyFunction.class); + addItem = pi.get("__engine_add_item", PyFunction.class); + removeItem = pi.get("__engine_remove_item", PyFunction.class); + removeItemWithSlotNumber = pi.get("__engine_remove_item_with_slot_number", PyFunction.class); + } +} diff --git a/src/sjgs/graphics/ui/InventorySystemSlot.java b/src/sjgs/graphics/ui/InventorySystemSlot.java new file mode 100755 index 0000000..4f3fbe8 --- /dev/null +++ b/src/sjgs/graphics/ui/InventorySystemSlot.java @@ -0,0 +1,55 @@ +package sjgs.graphics.ui; + +import java.awt.Graphics2D; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; + +public abstract class InventorySystemSlot { + + public static final int EMPTY = 0; + + public final Point2f startingPoint; + public final Rectangle bounds; + public boolean mouseClicked; + public int itemId, quantity, slotNumber; + + + public InventorySystemSlot(final float x, final float y, final float w, final float h, final int slotNumber) { + bounds = new Rectangle(x, y, w, h); + this.slotNumber = slotNumber; + startingPoint = new Point2f(x, y); + init(); + } + + public abstract void init(); + public abstract void tick(); + public abstract void render(Graphics2D g2d); + public abstract void reset(); + + protected void baseReset() { + itemId = quantity = 0; + bounds.setX(startingPoint.x); + bounds.setY(startingPoint.y); + } + + public void resetPosition() { + bounds.setX(startingPoint.x); + bounds.setY(startingPoint.y); + } + + public void setStartingPoint(final Point2f p) { startingPoint.setLocation(p.getX(), p.getY()); } + public void setStartingPoint(final float x, final float y) { startingPoint.setLocation(x, y); } + public float getStartingX() { return startingPoint.getX(); } + public float getStartingY() { return startingPoint.getY(); } + + public float getX() { return bounds.getX(); } + public float getY() { return bounds.getY(); } + public float getWidth() { return bounds.getWidth(); } + public float getHeight() { return bounds.getHeight(); } + public float getHalfHeight() { return getHeight() * 0.5f; } + public float getHalfWidth() { return getWidth() * 0.5f; } + + public boolean isEmpty() { return itemId == 0 && quantity == 0; } + + public void setLocation(final float x, final float y) { bounds.setLocation(x, y); } +} \ No newline at end of file diff --git a/src/sjgs/graphics/ui/Menu.java b/src/sjgs/graphics/ui/Menu.java new file mode 100755 index 0000000..4397d1a --- /dev/null +++ b/src/sjgs/graphics/ui/Menu.java @@ -0,0 +1,15 @@ +package sjgs.graphics.ui; + +import java.awt.Graphics2D; +import sjgs.utils.data_structures.Stack; + +public abstract class Menu { + + public Stack buttons; + + public abstract void init(); + public abstract void tick(); + public abstract void render(Graphics2D g2d); + public abstract void destroy(); + +} diff --git a/src/sjgs/graphics/ui/MenuButton.java b/src/sjgs/graphics/ui/MenuButton.java new file mode 100755 index 0000000..8fb581b --- /dev/null +++ b/src/sjgs/graphics/ui/MenuButton.java @@ -0,0 +1,40 @@ +package sjgs.graphics.ui; + +import java.awt.Graphics2D; +import sjgs.core.input.Mouse; +import sjgs.graphics.Animation; +import sjgs.utils.data_structures.shapes.Rectangle; + +/** @class: USAGE - Create a Menu class to hold a stack of your menu buttons, along + * with any other functions you deem to need. Then, in your also created MouseInput class, + * (which should be extending Mouse...), loop through all your menu buttons on each click. + * + * Render your list of menu buttons in your Engine's render method. */ +public abstract class MenuButton { + + private final Rectangle bounds; + public final Animation animation; + + public MenuButton(final float x, final float y, final float w, final float h, final Animation animation) { + bounds = new Rectangle(x, y, w, h); + this.animation = animation; + } + + public MenuButton(final float x, final float y, final float w, final float h) { + bounds = new Rectangle(x, y, w, h); + animation = null; + } + + public abstract void tick(); + public abstract void render(Graphics2D g2d); + public abstract void onClick(); + public abstract void onHover(); + + public float getX() { return bounds.getX(); } + public float getY() { return bounds.getY(); } + public float getWidth() { return bounds.getWidth(); } + public float getHeight() { return bounds.getHeight(); } + public Rectangle getBounds() { return bounds; } + + public boolean containsMouse() { return bounds.contains(Mouse.getX(), Mouse.getY()); } +} diff --git a/src/sjgs/graphics/ui/__engine_inventory.py b/src/sjgs/graphics/ui/__engine_inventory.py new file mode 100755 index 0000000..2b517a4 --- /dev/null +++ b/src/sjgs/graphics/ui/__engine_inventory.py @@ -0,0 +1,100 @@ +def __engine_onLeftClick(inventory): + # SLOT SWAPPING! + # @param i: The slot you are currently holding + # @param e: The slot you are trying to click on + for i in inventory.getSlots(): + # FILTER UNTIL I == THE SLOT YOU'RE HOLDING + if not i.mouseClicked: continue + for e in inventory.getSlots(): + # IF THE SECOND SLOT CONTAINS THE MOUSE POINTER, SWAP! + if i != e and e.bounds.contains(Mouse.getClickX(), Mouse.getClickY()): + inventory.swap(i, e) + return # NOTE: YOU MUST RETURN HERE OR IT WONT WORK! + + # GRAPHICAL SLOT MOVING! + for i in inventory.getSlots(): + if i.isEmpty(): continue + # SET MOUSELCICKED TO TRUE + if not i.mouseClicked and i.bounds.contains(Mouse.getClickX(), Mouse.getClickY()): + inventory.resetMouseClicked() # ONLY WANT 1 ITEM TO BE MOUSE CLICKED AT A TIME + i.mouseClicked = True + break + + # IF HOLDING AN ITEM, AND CLICK OUTSIDE OF THE INVENTORY BOUNDS --- DROP + elif i.mouseClicked and not inventory.getBounds().contains(Mouse.getClickX(), Mouse.getClickY()): + i.mouseClicked = False + break + # ELSE IF YOU JUST CLICKED SOMEWHERE IN THE INVEN WITHOUT BEING ON A SLOT LIKE AN IDIOT + else: i.mouseClicked = False + + # FIXES BUGS -- ALWAYS RUN THIS + inventory.resetPositions() + +def __engine_add_item(itemId, quantity, inventory): + # DONT ADD ITEM IF IT IS THE NULL PLACEHOLDER ITEM + if itemId == EMPTY: return + + # CANT ADD ITEM IF THE INVEN IS FULL + if __engine_inventory_is_full(itemId, quantity, inventory): return + + # IF THE ITEM IS STACKABLE, RUN THIS LOOP + if inventory.isStackable(itemId): + for i in inventory.getSlots(): + if i.itemId == itemId and (i.quantity + quantity) <= inventory.getStackableAmount(itemId): + i.mouseClicked = False + i.quantity += quantity + inventory.resetPositions() + return + + # IF THE ITEM IS NOT STACKABLE, OR FAILED THE ABOVE LOOP, RUN THIS LOOP + for i in inventory.getSlots(): + if(i.isEmpty()): + i.mouseClicked = False + i.itemId = itemId + i.quantity = quantity + inventory.resetPositions() + return + +def __engine_remove_item(itemId, quantity, inventory): + for slot in inventory.getSlots(): + if slot.itemId == itemId: + temp = slot.quantity + slot.quantity -= quantity + quantity -= temp + slot.mouseClicked = False + + if slot.quantity <= 0: slot.reset() + + # if the amount of things to remove has been satisfied + if quantity <= 0: break + inventory.resetPositions() + +def __engine_remove_item_with_slot_number(itemId, quantity, slotNumber): + for i in inventory.getSlots(): + if i.slotNumber == slotNumber: + if i.itemId == itemId: + i.quantity -= quantity + i.mouseClicked = False + if i.quantity <= 0: slot.reset() + break + inventory.resetPositions() + +def __engine_inventory_is_full(itemId, quantity, inventory): + if inventory.isStackable(itemId): # IF ITEM IS STACKABLE, RUN THIS LOOP + for slot in inventory.getSlots(): + # CHECK IF THE (QUANTITY + THE ADDED QUANTITY) IS <= THE MAX QUANTITY + WOULD_BE_QUANTITY = slot.quantity + quantity + if slot.itemId == itemId and WOULD_BE_QUANTITY <= inventory.getStackableAmount(itemId): return False + + # IF IT IS NOT STACKABLE, OR THE ITEM FAILED THE FIRST LOOP, RUN THIS LOOP + for slot in inventory.getSlots(): + if slot.itemId == 0: return False + + # IF NONE OF THE ABOVE CONDITIONS COULD BE MET, THE INVENTORY MUST BE FULL + return True + +def __engine_inventory_contains(itemId, quantity, inventory): + count = 0 + for slot in inventory.getSlots(): + if slot.itemId == itemId: count += slot.quantity + return count >= quantity \ No newline at end of file diff --git a/src/sjgs/physics/Physics.java b/src/sjgs/physics/Physics.java new file mode 100755 index 0000000..f08f1c0 --- /dev/null +++ b/src/sjgs/physics/Physics.java @@ -0,0 +1,52 @@ +package sjgs.physics; + +import sjgs.base_objects.GameObject; +import sjgs.base_objects.HardObject; +import sjgs.enums.TickRate; +import sjgs.enums.Type; +import sjgs.physics.structs.CollisionResponse; +import sjgs.utils.data_structures.Stack; + +public final class Physics { + + public void updatePosition(final GameObject obj) { __UpdatePosition.updatePosition(obj); } + public void applyFriction(final GameObject obj, final float friction_decrement) { __Friction.applyFriction(obj, friction_decrement); } + public CollisionResponse collision(final GameObject obj, final Type ...args) { return __Collision.collision(obj, args); } + public void applyGravity(final GameObject obj, final float gravity) { __Gravity.applyGravity(obj, gravity); } + public void calcGroundedAndOnSlope(final GameObject obj, final Stack collided_hard_objects) { __Calculators.calcGroundedAndOnSlope(obj, collided_hard_objects); } + + public CollisionResponse getCollidedObjects(final GameObject obj) { return __Collision.getCollidedObjects(obj); } + + public static void init(final float user_supplied_default_gravity, final float user_supplied_terminal_velocity, final float user_supplied_default_friction) { + __Gravity.setDefaultGravity(user_supplied_default_gravity); + __Gravity.setTerminalVelocity(user_supplied_terminal_velocity); + __Friction.setDefaultFriction(user_supplied_default_friction); + } + + public void init() { + final float default_gravity = 0.75f, default_terminal_velocity = 10f, default_friction = 0.1f; + __Gravity.setDefaultGravity(default_gravity); + __Gravity.setTerminalVelocity(default_terminal_velocity); + __Friction.setDefaultFriction(default_friction); + TPS = TickRate._60; + } + + private static TickRate TPS; + + static TickRate getTickRate() { return TPS; } + public void setDoubleTickRate() { TPS = TickRate._120; } + + public static void setUpHillFrictionMultiplier(final float f) { __Friction.setOnSlopeFrictionMultiplier(f); } + public static void disableGravity() { __Gravity.disableGravity(); } + public static void enableGravity() { __Gravity.enableGravity(); } + public static void toggleGravity() { __Gravity.toggleGravity(); } + + public static void disableFriction() { __Friction.disableFriction(); } + public static void enableFriction() { __Friction.enableFriction(); } + public static void toggleFriction() { __Friction.toggleFriction(); } + + public static float getTerminalVelocity() { return __Gravity.getTerminalVelocity(); } + public static float getDefaultGravity() { return __Gravity.getDefaultGravity(); } + public static float getDefaultFriction() { return __Friction.getDefaultFriction(); } + +} diff --git a/src/sjgs/physics/__BulletPhysics.java b/src/sjgs/physics/__BulletPhysics.java new file mode 100755 index 0000000..b1504a6 --- /dev/null +++ b/src/sjgs/physics/__BulletPhysics.java @@ -0,0 +1,42 @@ +package sjgs.physics; + +import static sjgs.utils.Utils.calcMostIntersecting; +import sjgs.base_objects.Bullet; +import sjgs.base_objects.GameObject; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.shapes.Rectangle; + +class __BulletPhysics { + + static void calcBulletCollision(final Bullet obj, final GameObject g) { + + final float velX = obj.getVelX(); + final float velY = obj.getVelY(); + final float ep = obj.getElasticity(); + + switch(Utils.intDirection(g.getCenter(), obj.getCenter())) { + case 1: obj.setVelY(-velY * ep); obj.setY(g.getY() - obj.getHeight()); break; + case 3: obj.setVelX(-velX * ep); obj.setX(g.getX() + g.getWidth() - 1); break; // NOTE THE - 1 is VERY IMPORTANT! + case 5: obj.setVelY(-velY * ep); obj.setY(g.getY() + g.getHeight()); break; + case 7: obj.setVelX(-velX * ep); obj.setX(g.getX() - obj.getWidth()); break; + + case 2: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getBottomBounds(), obj.getLeftBounds()); + if(r == obj.getBottomBounds()) { obj.setVelY(-velY * ep); obj.setY(g.getY() - obj.getHeight()); } + else if(r == obj.getLeftBounds()) { obj.setVelX(-velX * ep); obj.setX(g.getX() + g.getWidth()); } + break; } + case 4: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getTopBounds(), obj.getLeftBounds()); + if(r == obj.getTopBounds()) { obj.setVelY(-velY * ep); obj.setY(g.getY() + g.getHeight()); } + else if(r == obj.getLeftBounds()) { obj.setVelX(-velX * ep); obj.setX(g.getX() + g.getWidth()); } + break; } + case 6: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getTopBounds(), obj.getRightBounds()); + if(r == obj.getTopBounds()) { obj.setVelY(-velY * ep); obj.setY(g.getY() + g.getHeight()); } + else if(r == obj.getRightBounds()) { obj.setVelX(-velX * ep); obj.setX(g.getX() - obj.getWidth()); } + break; } + case 8: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getBottomBounds(), obj.getRightBounds()); + if(r == obj.getBottomBounds()) { obj.setVelY(-velY * ep); obj.setY(g.getY() - obj.getHeight()); } + else if(r == obj.getRightBounds()) { obj.setVelX(-velX * ep); obj.setX(g.getX() - obj.getWidth()); } + break; } + } + } + +} diff --git a/src/sjgs/physics/__Calculators.java b/src/sjgs/physics/__Calculators.java new file mode 100755 index 0000000..042b440 --- /dev/null +++ b/src/sjgs/physics/__Calculators.java @@ -0,0 +1,38 @@ +package sjgs.physics; + +import static sjgs.utils.Utils.cinch; +import sjgs.base_objects.BaseTile; +import sjgs.base_objects.GameObject; +import sjgs.base_objects.HardObject; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.vectors.SimplePoint; + +class __Calculators { + + static void calcGroundedAndOnSlope(final GameObject obj, final Stack collided_hard_objects) { + obj.setGrounded(false); obj.setOnSlope(false); + + for (final HardObject ho : collided_hard_objects) { + if (ho.getFullBounds().intersects(obj.getBottomBounds())) { + obj.setGrounded(true); + if (ho instanceof BaseTile) { + final BaseTile t = (BaseTile) ho; + if(t.angled()) { + obj.setOnSlope(true); + for(final SimplePoint p : t.getSlopePoints()) + if(obj.getFullBounds().contains(p)) + obj.setY(p.y - obj.getHeight()); + } + } + } + } + + if(obj.getGrounded() && !obj.getOnSlope()) obj.setVelY(cinch(obj.getVelY(), 0)); + } + + + // static float calcMomentum(BoundingBox bounds) { + // return (bounds.getV + bounds.getVelY()) / sqrtOf2; + // } + +} diff --git a/src/sjgs/physics/__Collision.java b/src/sjgs/physics/__Collision.java new file mode 100755 index 0000000..d498870 --- /dev/null +++ b/src/sjgs/physics/__Collision.java @@ -0,0 +1,76 @@ +package sjgs.physics; + +import sjgs.base_objects.GameObject; +import sjgs.core.Handler; +import sjgs.enums.Type; +import sjgs.physics.structs.CollisionResponse; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Rectangle; + +class __Collision { + + /** @class Collision: + * + * GOALS: + * 1: Find all objects that are near the given bounds by searching through the + * Handler's quad trees. + * 2: Find all objects that actually intersect with said bounds, after narrowing down the search list, (1). + * 3: Provide default collision methods for use with this collision response, that can be used by the + * user if he or she chooses. If not, the user can implement his or her own collision methods, using + * the collection of objects that has been found to be collided. + */ + + + /** @param bounds: the bounding box being passed in from the object + * @param args: The different kinds of objects that hard collision SHOULD be + * ran against. */ + public static CollisionResponse collision(final GameObject obj, final Type ...args) { + final CollisionResponse all_collided_objects = getCollidedObjects(obj); + + final Stack types = new Stack(); + for(final Type i : args) types.push(i); + + if(types.size() > 0) { + if(types.contains(Type.HARD_OBJECT)) __GeneralCollision.default_hard_collision_against_hard_objects(obj, all_collided_objects.collided_hard_objects); + if(types.contains(Type.MOB)) __GeneralCollision.default_hard_collision_against_mobs(obj, all_collided_objects.collided_mobs); + if(types.contains(Type.SOFT_OBJECT)) __GeneralCollision.default_hard_collision_against_soft_objects(obj, all_collided_objects.collided_soft_objects); + if(types.contains(Type.BULLET)) __GeneralCollision.default_hard_collision_against_bullets(obj, all_collided_objects.collided_bullets); + if(types.contains(Type.PLAYER)) __GeneralCollision.default_hard_collision_against_players(obj, all_collided_objects.collided_players); + } else __GeneralCollision.default_hard_collision_against_hard_objects(obj, all_collided_objects.collided_hard_objects); + + return all_collided_objects; + } + + + /** @getCollidedObjects: searches through the quad trees to find all objects around the bound's area. + * Then creates a collision response containing stacks of all objects that do + * indeed intersect with the bounding box. */ + static CollisionResponse getCollidedObjects(final GameObject obj) { + /** @param OFFSET_MULTIPLIER: small mult here helps the quad tree search, fixes rare bugs */ + final float OFFSET_MULTIPLIER = 1.25f; + /** @param OFFSET: Restricting the tree offset here as to prevent very small objects from not getting their collided objects */ + final float OFFSET = Utils.restrict(Utils.biggest(obj.getWidth(), obj.getHeight()) * OFFSET_MULTIPLIER, 5f); + final float x = obj.getCenterX(); + final float y = obj.getCenterY(); + + final Stack hard_objects = new Stack<>(); + final Stack soft_objects = new Stack<>(); + final Stack bullets = new Stack<>(); + final Stack mobs = new Stack<>(); + + final Rectangle r = obj.getFullBounds(); + + for(final GameObject g : Handler.mobile_hard_objects) if(r.intersects(g.getFullBounds())) hard_objects.push(g); + hard_objects.combine(Handler.stationary_hard_objects.search(x + -OFFSET, y + -OFFSET, x + OFFSET, y + OFFSET)); + + for(final GameObject g : Handler.mobile_soft_objects) if(r.intersects(g.getFullBounds())) soft_objects.push(g); + soft_objects.combine(Handler.stationary_soft_objects.search(x + -OFFSET, y + -OFFSET, x + OFFSET, y + OFFSET)); + + for(final GameObject g : Handler.bullets) if(r.intersects(g.getFullBounds())) bullets.push(g); + for(final GameObject g : Handler.mobs) if(r.intersects(g.getFullBounds())) mobs.push(g); + + return new CollisionResponse(obj, hard_objects, mobs, bullets, soft_objects); + } + +} diff --git a/src/sjgs/physics/__Friction.java b/src/sjgs/physics/__Friction.java new file mode 100755 index 0000000..0633876 --- /dev/null +++ b/src/sjgs/physics/__Friction.java @@ -0,0 +1,54 @@ +package sjgs.physics; + +import static sjgs.utils.Utils.abs; +import sjgs.base_objects.GameObject; + +class __Friction { + + private static boolean apply_friction = true; + + static float onSlopeFrictionMultiplier = 2f; + + private static float DEFAULT_FRICTION; + + static void applyFriction(final GameObject obj) { applyFriction(obj, DEFAULT_FRICTION); } + + public static void applyFriction(final GameObject obj, final float friction_decrement) { + if(!apply_friction || obj.getDontApplyFriction()) return; + + if(obj.getGrounded()) runFriction(obj, friction_decrement); + + // run it again if going uphill, 3x friction + if(obj.getOnSlope() && obj.getGrounded()) { + for(int i = 0 ; i < onSlopeFrictionMultiplier; i++) + runFriction(obj, friction_decrement); + } + } + + private static void runFriction(final GameObject obj, float friction_decrement) { + + switch(Physics.getTickRate()) { + case _60: break; + case _120: friction_decrement *= 0.5f; break; + } + + if(obj.getVelX() != 0 && abs(obj.getVelX()) > friction_decrement) + obj.setVelX(obj.getVelX() > 0 ? obj.getVelX() - friction_decrement : obj.getVelX() + friction_decrement); + else obj.setVelX(0); + if(obj.getVelY() != 0 && abs(obj.getVelY()) > friction_decrement) + obj.setVelY(obj.getVelY() > 0 ? obj.getVelY() - friction_decrement : obj.getVelY() + friction_decrement); + else obj.setVelY(0); + } + + static float getDefaultFriction() { return DEFAULT_FRICTION; } + static void setDefaultFriction(final float f) { DEFAULT_FRICTION = f; } + static void setOnSlopeFrictionMultiplier(final float f) { onSlopeFrictionMultiplier = f; } + + static void disableFriction() { apply_friction = false; } + static void enableFriction() { apply_friction = true; } + static void toggleFriction() { apply_friction = !apply_friction; } + static boolean getDontApplyFriction() { return !apply_friction; } + static void setDontApplyFriction(final boolean b) { apply_friction = !b; } + + +} diff --git a/src/sjgs/physics/__GeneralCollision.java b/src/sjgs/physics/__GeneralCollision.java new file mode 100755 index 0000000..f84d801 --- /dev/null +++ b/src/sjgs/physics/__GeneralCollision.java @@ -0,0 +1,96 @@ +package sjgs.physics; + +import static sjgs.utils.Utils.calcMostIntersecting; +import static sjgs.utils.Utils.cinch; +import static sjgs.utils.Utils.restrict; +import sjgs.base_objects.BaseTile; +import sjgs.base_objects.Bullet; +import sjgs.base_objects.GameObject; +import sjgs.base_objects.HardObject; +import sjgs.base_objects.Mob; +import sjgs.base_objects.PlayerBase; +import sjgs.base_objects.SoftObject; +import sjgs.enums.Type; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.SimplePoint; + +class __GeneralCollision { + + private static void calcDefaultHardCollision(final GameObject obj, final GameObject g) { + + if(obj.getType() == Type.BULLET) { __BulletPhysics.calcBulletCollision((Bullet)obj, g); return; } + + final float velX = obj.getVelX(); + final float velY = obj.getVelY(); + + switch(Utils.intDirection(g.getCenter(), obj.getCenter())) { + case 1: obj.setVelY(cinch(velY, 0)); obj.setY(g.getY() - obj.getHeight()); break; + case 3: obj.setVelX(restrict(velX, 0)); obj.setX(g.getX() + g.getWidth() - 1); break; // NOTE THE - 1 is VERY IMPORTANT! + case 5: obj.setVelY(restrict(velY, 0)); obj.setY(g.getY() + g.getHeight()); break; + case 7: obj.setVelX(cinch(velX, 0)); obj.setX(g.getX() - obj.getWidth()); break; + + case 2: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getBottomBounds(), obj.getLeftBounds()); + if(r == obj.getBottomBounds()) { obj.setVelY(cinch(velY, 0)); obj.setY(g.getY() - obj.getHeight()); } + else if(r == obj.getLeftBounds()) { obj.setVelX(restrict(velX, 0)); obj.setX(g.getX() + g.getWidth()); } + break; } + case 4: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getTopBounds(), obj.getLeftBounds()); + if(r == obj.getTopBounds()) { obj.setVelY(restrict(velY, 0)); obj.setY(g.getY() + g.getHeight()); } + else if(r == obj.getLeftBounds()) { obj.setVelX(restrict(velX, 0)); obj.setX(g.getX() + g.getWidth()); } + break; } + case 6: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getTopBounds(), obj.getRightBounds()); + if(r == obj.getTopBounds()) { obj.setVelY(restrict(velY, 0)); obj.setY(g.getY() + g.getHeight()); } + else if(r == obj.getRightBounds()) { obj.setVelX(cinch(velX, 0)); obj.setX(g.getX() - obj.getWidth()); } + break; } + case 8: { final Rectangle r = calcMostIntersecting(g.getFullBounds(), obj.getBottomBounds(), obj.getRightBounds()); + if(r == obj.getBottomBounds()) { obj.setVelY(cinch(velY, 0)); obj.setY(g.getY() - obj.getHeight()); } + else if(r == obj.getRightBounds()) { obj.setVelX(cinch(velX, 0)); obj.setX(g.getX() - obj.getWidth()); } + break; } + } + } + + //--------------------------------- TILE COLLISION --------------------------------------------------------// + static void default_hard_collision_against_hard_objects(final GameObject obj, final Stack collided_hard_objects) { + final Stack rects = new Stack<>(); + + for(final HardObject ho : collided_hard_objects) { + if(ho instanceof BaseTile) { + final BaseTile t = (BaseTile)ho; + + if(t.angled()) { + for(final SimplePoint p : t.getSlopePoints()) + if(obj.getFullBounds().contains(p)) + obj.setY(p.y - obj.getHeight()); + } else rects.add(ho.getFullBounds()); + } + } + + final Rectangle mostIntersected = calcMostIntersecting(obj.getFullBounds(), rects); + for(final HardObject ho : collided_hard_objects) if(ho.getFullBounds() == mostIntersected) calcDefaultHardCollision(obj, ho); + } + // --------------------------------- MOB COLLISION ------------------------------------------------------- // + static void default_hard_collision_against_mobs(final GameObject obj, final Stack collided_mobs) { + for(final Mob m : collided_mobs) { if(m.getBounds() == obj.getBounds()) continue; + calcDefaultHardCollision(obj, m); + } + } + // -------------------------------- SCENERY COLLISION ---------------------------------------------------- // + static void default_hard_collision_against_soft_objects(final GameObject obj, final Stack collided_mobs) { + for(final SoftObject s : collided_mobs) { if(s.getBounds() == obj.getBounds()) continue; + calcDefaultHardCollision(obj, s); + } + } + // -------------------------------- BULLET COLLISION ----------------------------------------------------- // + static void default_hard_collision_against_bullets(final GameObject obj, final Stack collided_bullets) { + for(final Bullet b : collided_bullets) { if(b.getBounds() == obj.getBounds()) continue; + calcDefaultHardCollision(obj, b); + } + } + // -------------------------------- PLAYER COLLISION ----------------------------------------------------- // + static void default_hard_collision_against_players(final GameObject obj, final Stack collided_players) { + for(final PlayerBase p : collided_players) { if(p.getBounds() == obj.getBounds()) continue; + calcDefaultHardCollision(obj, p); + } + } +} diff --git a/src/sjgs/physics/__Gravity.java b/src/sjgs/physics/__Gravity.java new file mode 100755 index 0000000..0135be3 --- /dev/null +++ b/src/sjgs/physics/__Gravity.java @@ -0,0 +1,33 @@ +package sjgs.physics; + +import static sjgs.utils.Utils.cinch; +import sjgs.base_objects.GameObject; + +class __Gravity { + + private static boolean GRAVITY_DISABLED; + private static float DEFAULT_GRAVITY, TERMINAL_VELOCITY; + + static void applyGravity(final GameObject obj, float gravity) { + if(GRAVITY_DISABLED || obj.getDontApplyGravity()) return; + + if(obj.useCustomGravity()) gravity = obj.getCustomGravity(); + + switch(Physics.getTickRate()) { + case _60: break; + case _120: gravity *= 0.5f; break; + } + + obj.setVelY(cinch(obj.getVelY() + gravity, TERMINAL_VELOCITY)); + } + + static float getTerminalVelocity() { return TERMINAL_VELOCITY; } + static float getDefaultGravity() { return DEFAULT_GRAVITY; } + static void setDefaultGravity(final float g) { DEFAULT_GRAVITY = g; } + static void setTerminalVelocity(final float t) { TERMINAL_VELOCITY = t; } + + static void disableGravity() { GRAVITY_DISABLED = true; } + static void enableGravity() { GRAVITY_DISABLED = false; } + static void toggleGravity() { GRAVITY_DISABLED = !GRAVITY_DISABLED; } + +} diff --git a/src/sjgs/physics/__UpdatePosition.java b/src/sjgs/physics/__UpdatePosition.java new file mode 100755 index 0000000..f5490fc --- /dev/null +++ b/src/sjgs/physics/__UpdatePosition.java @@ -0,0 +1,29 @@ +package sjgs.physics; + +import static sjgs.utils.Utils.sqrtOf2; +import sjgs.base_objects.GameObject; + +class __UpdatePosition { + + private static int step = 1; + + static void updatePosition(final GameObject obj) { + + float tempVelX = obj.getVelX(); + float tempVelY = obj.getVelY(); + + // ADJUST FOR SMOOTH, EVEN DIAGONAL MOVEMENT, (fast pythagorous method) + if(obj.getVelX() == obj.getVelY() && obj.getVelX() != 0 && obj.getVelY() != 0) { + tempVelX /= sqrtOf2; + tempVelY /= sqrtOf2; + } + + switch(Physics.getTickRate()) { + case _60: obj.setLocation(obj.getX() + tempVelX, obj.getY() + tempVelY); + break; + case _120: obj.setLocation(obj.getX() + tempVelX*0.5f, obj.getY() + tempVelY*0.5f); + break; + } + + } +} diff --git a/src/sjgs/physics/structs/BoundingBox.java b/src/sjgs/physics/structs/BoundingBox.java new file mode 100755 index 0000000..adeb24d --- /dev/null +++ b/src/sjgs/physics/structs/BoundingBox.java @@ -0,0 +1,154 @@ +package sjgs.physics.structs; + +import java.awt.Graphics2D; +import sjgs.enums.Facing; +import sjgs.enums.Type; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.shapes.Line; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; +import sjgs.utils.data_structures.vectors.Vector2f; + +public class BoundingBox { + + /** @type: The kind of object that this bounding box is attached to */ + private final Type type; + private Facing facing = Facing.NONE; // note they always start out @ none + private final Rectangle fullBounds, leftBounds, rightBounds, topBounds, bottomBounds; + private float LONG, SMALL; + private final Vector2f velocity; + private float gravity; + private boolean useCustomGravity; + + // ---------- booleans for the physics interpreter ----------- // + private boolean dontApplyGravity, grounded, onSlope, dontApplyFriction; + // ---------------------------------------------------------- // + + public BoundingBox(final float x, final float y, final float WIDTH, final float HEIGHT, final Type type) { + this.type = type; + velocity = new Vector2f(0,0); + getLS(WIDTH, HEIGHT); + fullBounds = new Rectangle(0, 0, 0, 0); + leftBounds = new Rectangle(0, 0, 0, 0); + rightBounds = new Rectangle(0, 0, 0, 0); + topBounds = new Rectangle(0, 0, 0, 0); + bottomBounds = new Rectangle(0, 0, 0, 0); + setSize(WIDTH, HEIGHT); + setLocation(x, y); + } + public BoundingBox(final float x, final float y, final float WIDTH, final float HEIGHT, final float velX, final float velY, final Type type) { + this.type = type; + velocity = new Vector2f(velX, velY); + getLS(WIDTH, HEIGHT); + fullBounds = new Rectangle(0, 0, 0, 0); + leftBounds = new Rectangle(0, 0, 0, 0); + rightBounds = new Rectangle(0, 0, 0, 0); + topBounds = new Rectangle(0, 0, 0, 0); + bottomBounds = new Rectangle(0, 0, 0, 0); + setSize(WIDTH, HEIGHT); + setLocation(x, y); + } + + @Override + public BoundingBox clone() { + final BoundingBox clone = new BoundingBox(getX(), getY(), getWidth(), getHeight(), getVelX(), getVelY(), type); + clone.onSlope = onSlope; + clone.grounded = grounded; + return clone; + } + + @SuppressWarnings("unused") + private void getLS(final float w, final float h) { + switch(type) { + default: LONG = 1f/3f; SMALL = 1f/9f; + } + } + + public void setLocation(final float x, final float y) { + fullBounds.setLocation(x, y); + leftBounds.setLocation(x, y + (getHeight() - leftBounds.height)/2); + rightBounds.setLocation(x+getWidth() - rightBounds.width, y + (getHeight() - leftBounds.height)/2); + topBounds.setLocation(x+(getWidth() - topBounds.width)/2, y); + bottomBounds.setLocation(x+(getWidth() - topBounds.width)/2, y+getHeight()-bottomBounds.height); + } + + public void setSize(final float w, final float h) { + fullBounds.setSize(w, h); + leftBounds.setSize(Utils.restrict(w*SMALL, 1), Utils.restrict(h*LONG, 1)); + rightBounds.setSize(Utils.restrict(w*SMALL, 1), Utils.restrict(h*LONG, 1)); + topBounds.setSize(Utils.restrict(w*LONG, 1), Utils.restrict(h*SMALL, 1)); + bottomBounds.setSize(Utils.restrict(w*LONG, 1), Utils.restrict(h*SMALL, 1)); + } + + public void draw(final Graphics2D g2d) { + fullBounds.draw(g2d); + leftBounds.draw(g2d); + rightBounds.draw(g2d); + topBounds.draw(g2d); + bottomBounds.draw(g2d); + } + + public void drawFilled(final Graphics2D g2d) { g2d.fillRect((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight()); } + + + public void dontUseCustomGravity() { useCustomGravity = false; gravity = 0; } + public void setCustomGravity(final float gravity) { useCustomGravity = true; this.gravity = gravity; } + public float getCustomGravity() { return gravity; } + public boolean useCustomGravity() { return useCustomGravity; } + public boolean stopped() { return getVelX() == 0 && getVelY() == 0; } + public void invertVelX() { velocity.invertX(); } + public void invertVelY() { velocity.invertY(); } + public float getVelX() { return velocity.getX(); } + public float getVelY() { return velocity.getY(); } + public void setVelX(final float velX) { velocity.setX(velX); } + public void setVelY(final float velY) { velocity.setY(velY); } + public void setVelocity(final float velX, final float velY) { velocity.setXAndY(velX, velY); } + public float getArea() { return fullBounds.getArea(); } + public Point2f getLocation() { return new Point2f(getX(), getY()); } + public void setCenter(final float x, final float y) { setLocation(x - getHalfWidth(), y - getHalfHeight()); } + public void setCenter(final Point2f p) { setCenter(p.x, p.y); } + public void setCenter(final SimplePoint p) { setCenter(p.x, p.y); } + public float getHalfWidth() { return getWidth() * 0.5f; } + public float getHalfHeight() { return getHeight() * 0.5f; } + public boolean getDontApplyGravity() { return dontApplyGravity; } + public void setDontApplyGravity(final boolean b) { dontApplyGravity = b; } + public void toggleDontApplyGravity() { dontApplyGravity = !dontApplyGravity; } + public boolean getDontApplyFriction() { return dontApplyFriction; } + public void setDontApplyFriction(final boolean b) { dontApplyFriction = b; } + public void toggleDontApplyFriction() { dontApplyFriction = !dontApplyFriction; } + public boolean facingLeft() { return facing == Facing.LEFT; } + public boolean facingRight() { return facing == Facing.RIGHT; } + public Facing getFacing() { return facing; } + public void setFacing(final Facing facing) { this.facing = facing; } + public Rectangle getFullBounds() { return fullBounds; } + public Rectangle getLeftBounds() { return leftBounds; } + public Rectangle getRightBounds() { return rightBounds; } + public Rectangle getTopBounds() { return topBounds; } + public Rectangle getBottomBounds() { return bottomBounds; } + public boolean getGrounded() { return grounded; } + public void setGrounded(final boolean grounded) { this.grounded = grounded; } + public boolean getOnSlope() { return onSlope; } + public void setOnSlope(final boolean onSlope) { this.onSlope = onSlope; } + public Type getType() { return type; } + public Point2f getCenter() { return fullBounds.getCenter(); } + public Point2f getPosition() { return fullBounds.pos; } + public float getX() { return fullBounds.pos.x; } + public float getY() { return fullBounds.pos.y; } + public float getWidth() { return fullBounds.width; } + public float getHeight() { return fullBounds.height; } + public void setX(final float x) { setLocation(x, getY()); } + public void setY(final float y) { setLocation(getX(), y); } + public void setWidth(final float w) { setSize(w, getHeight()); } + public void setHeight(final float h) { setSize(getWidth(), h); } + + public Point2f getTopRight() { return fullBounds.getTopRight(); } + public Point2f getTopLeft() { return fullBounds.getTopLeft(); } + public Point2f getBottomRight() { return fullBounds.getBottomRight(); } + public Point2f getBottomLeft() { return fullBounds.getBottomLeft(); } + public Line getTop() { return fullBounds.getTop(); } + public Line getBottom() { return fullBounds.getBottom(); } + public Line getLeft() { return fullBounds.getLeft(); } + public Line getRight() { return fullBounds.getRight(); } + +} diff --git a/src/sjgs/physics/structs/CollisionResponse.java b/src/sjgs/physics/structs/CollisionResponse.java new file mode 100755 index 0000000..f3316b3 --- /dev/null +++ b/src/sjgs/physics/structs/CollisionResponse.java @@ -0,0 +1,116 @@ + +package sjgs.physics.structs; + +import sjgs.base_objects.BaseTile; +import sjgs.base_objects.Bullet; +import sjgs.base_objects.GameObject; +import sjgs.base_objects.HardObject; +import sjgs.base_objects.Mob; +import sjgs.base_objects.PlayerBase; +import sjgs.base_objects.SoftObject; +import sjgs.core.Handler; +import sjgs.enums.Type; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Rectangle; + +public final class CollisionResponse { + + public Stack collided_hard_objects; + public Stack collided_soft_objects; + public Stack collided_mobs; + public Stack collided_bullets; + public Stack collided_players; + + public CollisionResponse(final GameObject obj, Stack hard_objects, Stack mobs, Stack bullets, Stack soft_objects) { + + try { + // CREATE STACKS + collided_hard_objects = new Stack(); + collided_mobs = new Stack(); + collided_bullets = new Stack(); + collided_soft_objects = new Stack(); + collided_players = new Stack(); + Stack tempHardObjects = new Stack(); + Stack tempMobs = new Stack(); + Stack tempBullets = new Stack(); + Stack tempSoftObjects = new Stack(); + Stack tempPlayers = new Stack(); + + // CONVERT GENERICS TO USEABLE OBJECTS + for(final GameObject g : hard_objects) tempHardObjects.push((HardObject)g); + for(final GameObject g : mobs) tempMobs.push((Mob)g); + for(final GameObject g : bullets) tempBullets.push((Bullet)g); + for(final GameObject g : soft_objects) tempSoftObjects.push((SoftObject)g); + for(final GameObject g : Handler.players) tempPlayers.push((PlayerBase)g); + + // REFINE SEARCHED STACKS FOR COLLISION + final Rectangle r = obj.getFullBounds(); + + // NOTE THE != BOUNDS CHECKS IF THE TWO ARE NOT THE SAME ENTITY + for(final HardObject i : tempHardObjects) if(i.getBounds() != obj.getBounds() && r.intersects(i.getFullBounds())) collided_hard_objects.push(i); + for(final Mob i : tempMobs) if(i.getBounds() != obj.getBounds() && r.intersects(i.getFullBounds())) collided_mobs.push(i); + for(final Bullet i : tempBullets) if(i.getBounds() != obj.getBounds() && r.intersects(i.getFullBounds())) collided_bullets.push(i); + for(final SoftObject i : tempSoftObjects) if(i.getBounds() != obj.getBounds() && r.intersects(i.getFullBounds())) collided_soft_objects.push(i); + for(final PlayerBase i : tempPlayers) if(i.getBounds() != obj.getBounds() && r.intersects(i.getFullBounds())) collided_players.push(i); + + // NULL JUNK FOR MEMORY + hard_objects.clear(); mobs.clear(); bullets.clear(); soft_objects.clear(); + hard_objects = mobs = bullets = soft_objects = null; + tempHardObjects.clear(); tempMobs.clear(); tempBullets.clear(); tempSoftObjects.clear(); tempPlayers.clear(); + tempHardObjects = null; tempMobs = null; tempBullets = null; tempSoftObjects = null; tempPlayers = null; + } catch (final Exception e) { + /* nulls / class casts / concurrent mods... + * all kinds of shenanigans happen when saving / loading. + * Just catch them. */ + e.printStackTrace(); + } + + } + + /** @method isEmpty: return true if all the stacks pertaining to the args are null or empty. + * If no args were passed, assume all stacks are meant to be checked */ + public boolean isEmpty(final Type ...args) { + final boolean hards = collided_hard_objects == null || collided_hard_objects.isEmpty(); + final boolean softs = collided_soft_objects == null || collided_soft_objects.isEmpty(); + final boolean mobs = collided_mobs == null || collided_mobs.isEmpty(); + final boolean bullets = collided_bullets == null || collided_bullets.isEmpty(); + final boolean players = collided_players == null || collided_players.isEmpty(); + + if(args.length == 0) return hards == softs == mobs == mobs == bullets == players; + + final Stack bools = new Stack(); + + for(final Type t : args) { + if(t == Type.HARD_OBJECT) bools.push(hards); + else if(t == Type.SOFT_OBJECT) bools.push(softs); + else if(t == Type.MOB) bools.push(mobs); + else if(t == Type.BULLET) bools.push(bullets); + else if(t == Type.PLAYER) bools.push(players); + } + + for(final Boolean b : bools) if(b != true) return false; + + return true; + } + + public void discard() { + collided_hard_objects.clear(); + collided_mobs.clear(); + collided_bullets.clear(); + collided_soft_objects.clear(); + collided_players.clear(); + + collided_hard_objects = null; + collided_mobs = null; + collided_bullets = null; + collided_soft_objects = null; + collided_players = null; + } + + public Stack getTiles() { + final Stack tiles = new Stack(); + for(final HardObject o : collided_hard_objects) if(o instanceof BaseTile) tiles.push((BaseTile)o); + return tiles; + } + +} diff --git a/src/sjgs/sound/MusicPlayer.java b/src/sjgs/sound/MusicPlayer.java new file mode 100755 index 0000000..cf170f1 --- /dev/null +++ b/src/sjgs/sound/MusicPlayer.java @@ -0,0 +1,112 @@ +package sjgs.sound; + +import java.io.IOException; +import java.io.InputStream; +import javazoom.jl.decoder.JavaLayerException; +import javazoom.jl.player.FactoryRegistry; +import javazoom.jl.player.JavaSoundAudioDevice; +import javazoom.jl.player.advanced.AdvancedPlayer; +import javazoom.jl.player.advanced.PlaybackListener; + +// NOTE: This class needs the JLayer.jar in your main project in order to function! + +public class MusicPlayer extends PlaybackListener { + + private AdvancedPlayer player; + private SoundThread thread; + private JavaSoundAudioDevice device; + private InputStream stream; + private String filename; + private final float gain; + private final boolean loop; + + private boolean paused; + + public MusicPlayer(final String filename, final float gain, final boolean loop) { + this.filename = filename; this.gain = gain; this.loop = loop; + createAdvancedPlayer(); + } + public MusicPlayer(final String filename, final boolean loop) { + this.filename = filename; gain = 0; this.loop = loop; + createAdvancedPlayer(); + } + + private void createAdvancedPlayer() { + try { + final JavaSoundAudioDevice device = (JavaSoundAudioDevice) FactoryRegistry.systemRegistry().createAudioDevice(); + device.createSource(); + device.setGain(gain); + stream = SoundPlayer.class.getResourceAsStream(filename); + player = new AdvancedPlayer(stream, device); + } catch (final Exception e) { e.printStackTrace(); } + player.setPlayBackListener(this); + } + + public void play() { + thread = new SoundThread(this, loop, filename); + thread.start(); + paused = false; + } + + public void pause() { + thread.stop(); + paused = true; + } + + public void togglePause() { + if(paused) play(); else pause(); + } + + public void reset() { createAdvancedPlayer(); } + + // REMEMBER TO CALL THIS FOR RESOURCE LEAKS!!!! + public void destroy() { + thread.stop(); + thread = null; + // Not familiar with JLayer's API, but this seems to throw a null pointer occasionally? + try { device.flush(); device.close(); } catch (final NullPointerException npe) { } + try { stream.close(); } catch (final IOException e) { e.printStackTrace(); } + player.close(); + player = null; + filename = null; + device = null; + stream = null; + } + + private void runThread() { + try { player.play(); // will play from start if not paused before, else it will start @ pause position + createAdvancedPlayer(); + } catch (final JavaLayerException e) { + e.printStackTrace(); + } + } + + public boolean paused() { return paused; } + public String getFilename() { return filename; } + + //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------// + private static class SoundThread extends Thread { + + private final boolean loop; + private final MusicPlayer player; + + public SoundThread(final MusicPlayer player, final boolean loop, final String filename) { + this.loop = loop; + this.player = player; + setName(filename); + } + + @Override + public void run() { + do { + + player.runThread(); + + } while(loop); + + player.destroy(); + } + + } + +} \ No newline at end of file diff --git a/src/sjgs/sound/SoundPlayer.java b/src/sjgs/sound/SoundPlayer.java new file mode 100755 index 0000000..e0a1c4a --- /dev/null +++ b/src/sjgs/sound/SoundPlayer.java @@ -0,0 +1,42 @@ +package sjgs.sound; + +import java.io.InputStream; +import javazoom.jl.player.FactoryRegistry; +import javazoom.jl.player.JavaSoundAudioDevice; +import javazoom.jl.player.advanced.AdvancedPlayer; +import javazoom.jl.player.advanced.PlaybackListener; +import sjgs.utils.multithreading.Runner; + +// NOTE: This class needs the JLayer.jar in your main project in order to function! + +public final class SoundPlayer extends PlaybackListener { + + private static final SoundPlayer PLAYBACK_LISTENER = new SoundPlayer(); + + public static void play(final String filename) { play(filename, 0); } + + /** @method play: Plays an mp3 audio file with given resource stream name. + * gain can be a value from -80 to 6. No argument assumes no gain */ + public static void play(final String filename, final float gain) { + new Runner(() -> { + try { + JavaSoundAudioDevice device = (JavaSoundAudioDevice) FactoryRegistry.systemRegistry().createAudioDevice(); + device.createSource(); + device.setGain(gain); + InputStream stream = SoundPlayer.class.getResourceAsStream(filename); + AdvancedPlayer player = new AdvancedPlayer(stream, device); + player.setPlayBackListener(PLAYBACK_LISTENER); + player.play(); + // --------- // + device.flush(); + device.close(); + player.close(); + stream.close(); + device = null; + stream = null; + player = null; + } catch (final Exception e) { e.printStackTrace(); } + }, "Sound Player: " + filename).start(); + } + +} \ No newline at end of file diff --git a/src/sjgs/utils/Utils.java b/src/sjgs/utils/Utils.java new file mode 100755 index 0000000..1879933 --- /dev/null +++ b/src/sjgs/utils/Utils.java @@ -0,0 +1,281 @@ +package sjgs.utils; + +import java.awt.Color; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.text.DecimalFormat; +import java.util.Random; +import javax.swing.JOptionPane; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Circle; +import sjgs.utils.data_structures.shapes.Line; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; + +/** @author: Mitch Weaver 2016 */ + +public final class Utils { + + /********************** @COMMONLY_USED_VARIABLES ********************************/ + public static final Random rand = new Random(); // No need to create more randoms for everything, can just always use this one + public static final String OS = "Running on: " + System.getProperty("os.name"); + public static final float sqrtOf2 = sqrt(2); // used for a lot of things, saved as not to need to calc it + public static final double second = 1_000_000_000.0d; // 1 second in nanoseconds (1 billion) + public static final float PI = (float)Math.PI; // in float form for convenience + public static final float E = (float)Math.E; // in float form for convenience + public static final int _2147483647 = Integer.MAX_VALUE; + public static final float ulp = Math.ulp(0.0f); // smallest possible floating point number + public static final Color voidColor = __ImageManipulation.voidColor; + public static final String userHomeDir = __SerializationUtils.userHomeDir; + public static final String alphabet = "abcdefghijklmnopqrstuvwxyz"; + public static final int SCREEN_WIDTH = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getWidth(); + public static final int SCREEN_HEIGHT = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getHeight(); + /*******************************************************************************/ + + /***************************** @DEGREES_AND_RADIANS *****************************/ + public static final float radian = PI / 180f; + public static final float _45toRadians = toRadians(45), _90toRadians = _45toRadians*2, _180toRadians = _90toRadians*2; + public static final float toDegrees(final float theta) { return theta * 180 / PI; } + public static final double toDegrees(final double theta) { return theta * 180 / PI; } + public static final float toRadians(final float degrees) { return degrees * radian; } + public static final double toRadians(final double degrees) { return degrees * radian; } + public static final float sin(final float theta) { return (float)Math.sin(theta); } + public static final float cos(final float theta) { return (float)Math.cos(theta); } + public static final float tan(final float theta) { return (float)Math.tan(theta); } + public static final float atan(final float theta) { return (float)Math.atan(theta); } + public static final float atan2(final float y, final float x) { return (float)Math.atan2(y, x); } // NOTE: these are in reverse order, as is standard + public static final float getTheta(final float x, final float y) { return atan2(y, x); } // for those that can't remember its atan2, (lol) + /******************************************************************************/ + + /***************************** @DECIMAL_FORMATS ********************************/ + public static final DecimalFormat dff = new DecimalFormat("0.##"); + public static final DecimalFormat df = new DecimalFormat("0.#"); + /******************************************************************************/ + + /******************************* @CLAMPS ************************************/ + public static final int clamp(int input, final int floor, final int ceiling){ if(input < floor) input = floor; else if(input > ceiling) input = ceiling; return input; } + public static final float clamp(float input, final float floor, final float ceiling){ if(input < floor) input = floor; else if(input > ceiling) input = ceiling; return input; } + public static final double clamp(double input, final double floor, final double ceiling){ if(input < floor) input = floor; else if(input > ceiling) input = ceiling; return input; } + public static final int cinch(final int input, final int ceiling) { return input < ceiling ? input : ceiling; } + public static final float cinch(final float input, final float ceiling) { return input < ceiling ? input : ceiling; } + public static final double cinch(final double input, final double ceiling) { return input < ceiling ? input : ceiling; } + public static final int restrict(final int input, final int floor) { return input > floor ? input : floor; } + public static final float restrict(final float input, final float floor) { return input > floor ? input : floor; } + public static final double restrict(final double input, final double floor) { return input > floor ? input : floor; } + /** @method converge: Steps the input towards the target. If the input as excessed the target, clamp. */ + public static final int converge(final int input, final int target, final int step) { return isNegative(target) ? restrict(input - step, target) : cinch(input + step, target); } + public static final float converge(final float input, final float target, final float step) { return isNegative(target) ? restrict(input - step, target) : cinch(input + step, target); } + public static final double converge(final double input, final double target, final double step) { return isNegative(target) ? restrict(input - step, target) : cinch(input + step, target); } + /**************************************************************************/ + + /************************* @POWERS *****************************************/ + public static final int square(final int foo) { return foo*foo; } + public static final float square(final float foo) { return foo*foo; } + public static final double square(final double foo) { return foo*foo; } + public static final int cube(final int foo) { return foo*foo*foo; } + public static final float cube(final float foo) { return foo*foo*foo; } + public static final double cube(final double foo) { return foo*foo*foo; } + public static final int pow(int foo, final int bar) { for(int i = 0; i < bar; i++) foo*=foo; return foo; } + public static final float pow(float foo, final int bar) { for(int i = 0; i < bar; i++) foo*=foo; return foo; } + public static final double pow(double foo, final int bar) { for(int i = 0; i < bar; i++) foo*=foo; return foo; } + /**************************************************************************/ + + /********************** @TEXT_FILE_MANIPULATION *****************************/ + public static final int getNumLinesFromTextFile(final String path) { return __TextFileManipulation.getNumLinesFromTextFile(path); } + public static final String[] makeStringArrayFromLinesOfTextFile(final String path) { return __TextFileManipulation.makeStringArrayFromLinesOfTextFile(path); } + public static final StringBuilder[] makeStrinBuilderArrayFromLinesOfTextFile(final String path) { return __TextFileManipulation.makeStringBuilderArrayFromLinesOfTextFile(path); } + public static final String readTextFileAsString(final String filepath){ return __TextFileManipulation.readTextFileAsString(filepath); } + public static final StringBuilder readTextFileAsStringBuilder(final String path){ return new StringBuilder(__TextFileManipulation.readTextFileAsString(path)); } + public static final char[] readTextFileAsCharArray(final String path) { return __TextFileManipulation.readTextFileAsString(path).toCharArray(); } + /****************************************************************************/ + + /********************** @IMAGE_MANIPULATION *********************************/ + /** @method removeVoidColor ~ default no color arg is (255, 0, 255) for pink void color */ + public static final BufferedImage reverseImage(final BufferedImage image) { return __ImageManipulation.reverseImage(image); } + public static final BufferedImage invertImage(final BufferedImage image) { return __ImageManipulation.invertImage(image); } + public static final BufferedImage rotateImageRight(final BufferedImage image) { return __ImageManipulation.rotateImageRight(image); } + public static final BufferedImage rotateImageLeft(final BufferedImage image) { return __ImageManipulation.rotateImageLeft(image); } + public static final BufferedImage imageToBufferedImage(final Image image) { return __ImageManipulation.imageToBufferedImage(image); } + public static final BufferedImage loadImage(final String path) { return __ImageManipulation.loadImage(path); } + /** @method grabSprite: Note col and rol start @ 0, this is for ease of use when using loops. */ + public static final BufferedImage grabSprite(final BufferedImage image, final int col, final int row, final int width, final int height){ return __ImageManipulation.grabSprite(image, col, row, width, height); } + public static final BufferedImage grabSprite(final Image image, final int col, final int row, final int width, final int height){ return __ImageManipulation.grabSprite(imageToBufferedImage(image), col, row, width, height); } + public static final BufferedImage removeVoidColor(final BufferedImage image, final Color voidColor) { return __ImageManipulation.removeVoidColor(image, voidColor); } + public static final BufferedImage removeVoidColor(final BufferedImage image) { return removeVoidColor(image, voidColor); } + /** @method optimizeImage: Note all the above methods call this by default. */ + public static final BufferedImage optimizeImage(final BufferedImage image) { return __ImageManipulation.optimizeImage(image); } + /**************************************************************************************/ + + /*************************** @MISC_GETTER_METHODS ***********************************/ + public static final boolean isEven(final int foo) { return foo % 2 == 0; } public static final boolean isEven(final long foo) { return foo % 2 == 0; } + public static final boolean isEven(final short foo){ return foo % 2 == 0; } public static final boolean isEven(final byte foo) { return foo % 2 == 0; } + public static final boolean isOdd(final int foo) { return foo % 2 != 0; } public static final boolean isOdd(final long foo) { return foo % 2 != 0; } + public static final boolean isOdd(final short foo) { return foo % 2 != 0; } public static final boolean isOdd(final byte foo) { return foo % 2 != 0; } + public static final boolean isNegative(final int foo) { return foo < 0; } public static final boolean isPositive(final int foo) { return foo >= 0; } + public static final boolean isNegative(final float foo) { return foo < 0; } public static final boolean isPositive(final float foo) { return foo >= 0; } + public static final boolean isNegative(final double foo) { return foo < 0; } public static final boolean isPositive(final double foo) { return foo >= 0; } + public static final boolean bothNegative(final int foo, final int bar) { return isNegative(foo) && isNegative(bar); } + public static final boolean bothNegative(final float foo, final float bar) { return isNegative(foo) && isNegative(bar); } + public static final boolean bothNegative(final double foo, final double bar) { return isNegative(foo) && isNegative(bar); } + public static final boolean bothPositive(final int foo, final int bar) { return isPositive(foo) && isPositive(bar); } + public static final boolean bothPositive(final float foo, final float bar) { return isPositive(foo) && isPositive(bar); } + public static final boolean bothPositive(final double foo, final double bar) { return isPositive(foo) && isPositive(bar); } + public static final boolean isPercent(final float foo) { return foo >= 0 && foo <= 99.999f; } + public static final boolean isPercent(final double foo) { return foo >= 0 && foo <= 99.999f; } + /************************************************************************************/ + + /************************** @ROTATION ************************************************/ + public static final Point rotatePoint(final Point p, final double theta) { return new Point((int)(p.x * Math.cos(theta) - p.y * Math.sin(theta)), (int)(p.x * Math.sin(theta) + p.y * Math.cos(theta)));} + public static final Point2f rotatePoint(final Point2f p, final double theta){ return new Point2f(p.x * Math.cos(theta) - p.y * Math.sin(theta), p.x * Math.sin(theta) + p.y * Math.cos(theta));} + public static final float rotateX(final int x, final int y, final double theta) { return (float)(x * Math.cos(theta) - y * Math.sin(theta)); } + public static final float rotateY(final int x, final int y, final double theta) { return (float)(x * Math.sin(theta) + y * Math.cos(theta)); } + public static final float rotateX(final float x, final float y, final double theta) { return (float)(x * Math.cos(theta) - y * Math.sin(theta)); } + public static final float rotateY(final float x, final float y, final double theta) { return (float)(x * Math.sin(theta) + y * Math.cos(theta)); } + public static final double rotateX(final double x, final double y, final double theta) { return x * Math.cos(theta) - y * Math.sin(theta); } + public static final double rotateY(final double x, final double y, final double theta) { return x * Math.sin(theta) + y * Math.cos(theta); } + /************************************************************************************/ + + /************************** @ABSOLUTE_VALUE ******************************************/ + public static final int abs(final int value) { return value >= 0 ? value : value * -1; } + public static final float abs(final float value) { return value >= 0 ? value : value * -1f; } + public static final double abs(final double value) { return value >= 0 ? value : value * -1d; } + public static final long abs(final long value) { return value >= 0 ? value : value * -1; } + /************************************************************************************/ + + /*************************** @FAST_SQUARE_ROOT *************************************/ + // evil floating point bit level hacking + // what the fuck? + public static final float sqrt(final float foo) { return (float)sqrt((double)foo); } + public static final double sqrt(final double foo) { final double sqrt = Double.longBitsToDouble( ( Double.doubleToLongBits( foo )-(1l<<52)>>1 ) + ( 1l<<61 ) ); return (sqrt + foo/sqrt)/2.0d; } + /**********************************************************************************/ + + /************************************** @PYTHAGORAS **********************************/ + public static final float pythagoras(final int foo, final int bar){ return sqrt(square(foo) + square(bar)); } + public static final float pythagoras(final float foo, final float bar){ return sqrt(square(foo) + square(bar)); } + public static final double pythagoras(final double foo, final double bar){ return sqrt(square(foo) + square(bar)); } + /************************************************************************************/ + + /**************************************** @POINT_DISTANCE *************************************************************************/ + public static final float distance(final Point2f foo, final Point2f bar){ return Utils.sqrt(Utils.square(foo.y - bar.y) + Utils.square(foo.x - bar.x)); } + public static final float distance(final Point foo, final Point bar){ return Utils.sqrt(Utils.square(foo.y - bar.y) + Utils.square(foo.x - bar.x)); } + public static final float distance(final float x1, final float y1, final float x2, final float y2){ return Utils.sqrt(Utils.square(y1 - y2) + Utils.square(x1 - x2)); } + public static final float distance(final int x1, final int y1, final int x2, final int y2){ return Utils.sqrt(Utils.square(y1 - y2) + Utils.square(x1 - x2)); } + /******************************************************************************************************************************************/ + + /************************************** @POINT_DIRECTION **********************************************************************/ + /** @direction: returns the angle in radians that point is from another */ + public static final float direction(final Point2f foo, final Point2f bar){ return foo.direction(bar); } + public static final int intDirection(final Point2f foo, final Point2f bar) { + double angle = toDegrees(atan2(bar.y - foo.y, bar.x - foo.x)); if(angle < 0) angle+=360; + if(angle > 247.5 && angle < 292.5) return 1; if(angle > 67.5 && angle < 112.5) return 5; + if(angle > 292.5 && angle < 337.5) return 2; if(angle > 112.5 && angle < 157.5) return 6; + if(angle > 337.5 || angle < 22.5) return 3; if(angle > 157.5 && angle < 202.5) return 7; + if(angle > 22.5 && angle < 67.5) return 4; if(angle > 202.5 && angle < 247.5) return 8; return 1; + } + /*****************************************************************************************************************************************/ + + /************************************** @MISC ***********************************************************/ + public static final synchronized int getNumProcessors() { return Runtime.getRuntime().availableProcessors(); } + public static final float nextUlp(final float input) { return input + ulp; } + public static final double nextUlp(final double input) { return input + ulp; } + public static final void print(final E e) { System.out.println(e); } + public static final void error(final E e) { System.err.println(e); } + public static final void print(final E[] arr) { for(final E e : arr) System.out.println(e); } + public static final void dialog(final E e) { JOptionPane.showMessageDialog(null, e); } + public static final void exit() { System.exit(0); } + public static final void quit() { exit(); } + /********************************************************************************************************/ + + /************************************* @SERIALIZATION ****************************************************/ + public static final synchronized void saveObject(final Object obj, final String path){ __SerializationUtils.saveObject(obj, path); } + public static final synchronized Object readObject(final String path){ return __SerializationUtils.readObject(path); } + /** NOTE: Unlike the other methods that load things as resource streams, + * @writeStringToFile must use a file writer, which doesnt use a stream. + * Do not put the '/' in front of your path! */ + public static final synchronized void writeStringToFile(final String string, final String path) { __SerializationUtils.writeStringToFile(string, path); } + /*********************************************************************************************************/ + + /************************************ @IMAGE_RGB_MANIPULATION ********************************************/ + public static final int unpackRed(final int pixel) { return pixel >> 16 & 0xff; } + public static final int unpackGreen(final int pixel) { return pixel >> 8 & 0xff; } + public static final int unpackBlue(final int pixel) { return pixel & 0xff; } + public static final boolean isTransparent(final int pixel) { return pixel == voidColor.getRGB() || pixel>>24 == 0x00; } + public static final int getTransparentPixel() { return 0x00; } + /********************************************************************************************************/ + + /************************* @RANDOM_CHANCES **************************************************************/ + public static final boolean COIN_FLIP() { return rand.nextBoolean(); } + public static final boolean ONE_PERCENT() { return rand.nextInt(100) == 0; } + public static final boolean ONE_IN_A_THOUSAND() { return rand.nextInt(1_000) == 0; } + public static final boolean ONE_IN_A_MILLION() { return rand.nextInt(1_000_000) == 0; } + public static final boolean roll(final int bound) { return rand.nextInt(bound) == 0; } + public static final int nextInt(final int bound) { return rand.nextInt(bound); } + public static final float nextFloat() { return rand.nextFloat(); } + public static final double nextDouble() { return rand.nextDouble(); } + public static final int nextInt(final int floor, final int ceiling) { return restrict(nextInt(ceiling+1), floor); } + public static final byte nextByte() { return (byte)nextInt(-128, 128); } + /********************************************************************************************************/ + + /******************************** @MAX_AND_MIN ******************************************************/ + public static final int max(final int ...args) { return __MixMaxUtils.biggest(args); } + public static final float max(final float ...args) { return __MixMaxUtils.biggest(args); } + public static final double max(final double ...args) { return __MixMaxUtils.biggest(args); } + public static final int biggest(final int ...args) { return __MixMaxUtils.biggest(args); } + public static final float biggest(final float ...args) { return __MixMaxUtils.biggest(args); } + public static final double biggest(final double ...args) { return __MixMaxUtils.biggest(args); } + public static final int min(final int ...args) { return __MixMaxUtils.smallest(args); } + public static final float min(final float ...args) { return __MixMaxUtils.smallest(args); } + public static final double min(final double ...args) { return __MixMaxUtils.smallest(args); } + public static final int smallest(final int ...args) { return __MixMaxUtils.smallest(args); } + public static final float smallest(final float ...args) { return __MixMaxUtils.smallest(args); } + public static final double smallest(final double ...args) { return __MixMaxUtils.smallest(args); } + /********************************************************************************************************/ + + /********************************** @ROUNDING ***********************************************************/ + public static final float round(final float i) { return isPositive(i) ? truncate(i + 0.5f) : truncate(i - 0.5f); } + public static final double round(final double i) { return isPositive(i) ? truncate(i + 0.5f) : truncate(i - 0.5f); } + public static final float truncate(final float input) { return (int)input; } + public static final double truncate(final double input) { return (int)input; } + public static final float floor(final float input) { return truncate(input); } + public static final double floor(final double input) { return truncate(input); } + public static final float ceil(final float input) { return truncate(input + 0.5f); } + public static final double ceil(final double input) { return truncate(input + 0.5f); } + /********************************************************************************************************/ + + + /****************************** @INTERSECTION_UTILS ******************************************************/ + /** @calcMostIntersecting: Takes in a rectangle to check, and any number of other rectangles. + * Returns the rect from args that intersects with rect the most. + * If there is a tie, it will return a random rectangle from the answers. */ + public static final Rectangle calcMostIntersecting(final Rectangle rect, final Rectangle ...args) { return __IntersectionUtils.calcMostIntersecting(rect, args); } + public static final Rectangle calcMostIntersecting(final Rectangle rect, final Stack args) { return __IntersectionUtils.calcMostIntersecting(rect, args); } + /** @fudgeRectangleIntersection: returns if the rectangles collide given the tolerance amount */ + public static final boolean fudgeRectIntersection(final Rectangle r1, final Rectangle r2, final float fudge_amount) { return __IntersectionUtils.fudgeRectIntersect(r1, r2, fudge_amount); } + public static final float calcArea(final float x1, final float y1, final float x2, final float y2) { return (x2 - x1) * (y2 - y1); } + public static final boolean intersects(final Point2f center, final float radius, final Rectangle rect) { return __IntersectionUtils.intersects(center, radius, rect); } + public static final boolean intersects(final Circle circle, final Rectangle rect) { return __IntersectionUtils.intersects(circle, rect); } + public static final boolean intersects(final Rectangle rect, final Circle circle) { return __IntersectionUtils.intersects(circle, rect); } + public static final boolean intersects(final Circle c1, final Circle c2){ return c1.intersects(c2); } + public static final boolean intersects(final Circle c1, final Point2f center2, final float radius2){ return c1.intersects(center2, radius2); } + public static final boolean intersects(final Point2f c1, final float r1, final Point2f c2, final float r2){ return c1.distance(c2) <= r1 + r2; } + public static final boolean intersects(final Line l1, final Line l2) { return l1.intersects(l2); } + public static final boolean intersects(final Point2f p1, final Point2f p2, final Point2f q1, final Point2f q2) { return new Line(p1, p2).intersects(new Line(q1, q2)); } + public static final boolean contains(final Rectangle r, final Point2f p) { return r.contains(p); } + public static final boolean contains(final Rectangle r, final SimplePoint p) { return r.contains(p); } + public static final boolean contains(final Point2f center, final float radius, final Point2f p){ return __IntersectionUtils.contains(center, radius, p); } + public static final boolean contains(final Point2f center, final float radius, final float x, final float y){ return __IntersectionUtils.contains(center, radius, x, y); } + /********************************************************************************************************/ + + /************************************* @ALGORITHMS ******************************************************/ + public static final SimplePoint[] brensenham(final SimplePoint p1, final SimplePoint p2) { return __Algorithms.brensenham(p1, p2); } + public static final SimplePoint[] brensenham(final Point2f p1, final Point2f p2) { return __Algorithms.brensenham(p1, p2); } + public static final SimplePoint[] brensenham(final int x1, final int y1, final int x2, final int y2) { return __Algorithms.brensenham(x1, y1, x2, y2); } + public static int greatestCommonDivisor(final int p, final int q) { return q == 0 ? p : greatestCommonDivisor(q, p % q); } + /********************************************************************************************************/ + + + +} \ No newline at end of file diff --git a/src/sjgs/utils/__Algorithms.java b/src/sjgs/utils/__Algorithms.java new file mode 100755 index 0000000..e28334e --- /dev/null +++ b/src/sjgs/utils/__Algorithms.java @@ -0,0 +1,67 @@ +package sjgs.utils; + +import static sjgs.utils.Utils.abs; +import java.util.ArrayList; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; + +class __Algorithms { + + static SimplePoint[] brensenham(final SimplePoint p1, final SimplePoint p2) { + final ArrayList points = new ArrayList(); + + // BRENSENHAM the line across + final int dx = abs(p2.x-p1.x), sx = p1.x= dy) { err += dy; p1.x += sx; } /* e_xy+e_x > 0 */ + if (e2 <= dx) { err += dx; p1.y += sy; } /* e_xy+e_y < 0 */ + } + + return points.toArray(new SimplePoint[points.size()]); + } + + static SimplePoint[] brensenham(final Point2f p1, final Point2f p2) { + final ArrayList points = new ArrayList(); + + // BRENSENHAM the line across + final int dx = (int)abs(p2.x-p1.x), sx = p1.x= dy) { err += dy; p1.x += sx; } /* e_xy+e_x > 0 */ + if (e2 <= dx) { err += dx; p1.y += sy; } /* e_xy+e_y < 0 */ + } + + return points.toArray(new SimplePoint[points.size()]); + } + + static SimplePoint[] brensenham(int x1, int y1, final int x2, final int y2) { + final ArrayList points = new ArrayList(); + + // BRENSENHAM the line across + final int dx = abs(x2-x1), sx = x1= dy) { err += dy; x1 += sx; } /* e_xy+e_x > 0 */ + if (e2 <= dx) { err += dx; y1 += sy; } /* e_xy+e_y < 0 */ + } + + return points.toArray(new SimplePoint[points.size()]); + } + +} diff --git a/src/sjgs/utils/__ImageManipulation.java b/src/sjgs/utils/__ImageManipulation.java new file mode 100755 index 0000000..201ab55 --- /dev/null +++ b/src/sjgs/utils/__ImageManipulation.java @@ -0,0 +1,97 @@ +package sjgs.utils; + +import static sjgs.utils.Utils.dialog; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.InputStream; +import javax.imageio.ImageIO; + +class __ImageManipulation { + + static BufferedImage optimizeImage(final BufferedImage image) { + // obtain the current system graphical settings + final GraphicsConfiguration gfx_config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + + /* if image is already compatible and optimized for current system + * settings, simply return it */ + if (image.getColorModel().equals(gfx_config.getColorModel())) return image; + + // image is not optimized, so create a new image that is + final BufferedImage new_image = gfx_config.createCompatibleImage(image.getWidth(), image.getHeight(), image.getTransparency()); + + // get the graphics context of the new image to draw the old image on + final Graphics2D g2d = (Graphics2D) new_image.getGraphics(); + + // actually draw the image and dispose of context no longer needed + g2d.drawImage(image, 0, 0, null); + g2d.dispose(); + + // return the new optimized image + return new_image; + } + + static final Color voidColor = new Color(255, 0, 255); + + //----------------------------------------------------------------------------------------------------------------------------------------------// + static BufferedImage reverseImage(final BufferedImage image) { /* (flips image horizontally) */ + final BufferedImage mirrorImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); /* note, you need ARGB */ + for (int y = 0; y < image.getHeight(); y++) + for (int x = 0, reverseX = image.getWidth() - 1; x < image.getWidth(); x++, reverseX--) + mirrorImage.setRGB(reverseX, y, image.getRGB(x, y)); + return optimizeImage(mirrorImage); + } + static BufferedImage rotateImageRight(final BufferedImage image) { + final BufferedImage rotatedImage = new BufferedImage(image.getHeight(), image.getWidth(), image.getType()); + for(int i=0; i < image.getWidth(); i++ ) + for(int j=0; j < image.getHeight(); j++ ) + rotatedImage.setRGB( image.getHeight()-1-j, i, image.getRGB(i,j)); + return optimizeImage(rotatedImage); + } + // I know this is really bad but the above was so much headache i said fuck it, it works. + static BufferedImage rotateImageLeft(final BufferedImage image) { + return optimizeImage(rotateImageRight(rotateImageRight(rotateImageRight(image)))); + } + static BufferedImage invertImage(final BufferedImage image) { /* (flips image horizontally) */ + return optimizeImage(rotateImageRight(rotateImageRight(image))); + } + //----------------------------------------------------------------------------------------------------------------------------------------------// + static BufferedImage imageToBufferedImage(Image image) { + final BufferedImage buffered = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + buffered.getGraphics().drawImage(image, 0, 0, null); image = null; + return optimizeImage(buffered); + } + + static BufferedImage loadImage(final String path) { /* loads as resource to work in jars */ + try { InputStream is = Utils.class.getResourceAsStream(path); + final BufferedImage image = ImageIO.read(is); is.close(); is = null; return optimizeImage(removeVoidColor(image, voidColor)); + } catch (final Exception e) { e.printStackTrace(); dialog("Utils --- loadImage --- Failed + \n + Contact the developer."); } + return null; + } + + static BufferedImage removeVoidColor(final BufferedImage image, final Color voidColor) { + for(int i = 0; i < image.getWidth(); i++) + for(int j = 0; j < image.getHeight(); j++){ + final int RGB = image.getRGB(i, j); + final int red = convertRed(RGB); + final int green = convertGreen(RGB); + final int blue = convertBlue(RGB); + if(red == voidColor.getRed() && green == voidColor.getGreen() && blue == voidColor.getBlue()) + image.setRGB(i, j, voidColor.getRGB()&0x00ffffff); + } + return optimizeImage(image); + } + + static final BufferedImage grabSprite(final BufferedImage image, final int col, final int row, final int width, final int height) { + return optimizeImage(removeVoidColor(image.getSubimage((col+1) * width - width, (row+1) * height - height, width, height), voidColor)); + } + + /************************************ IMAGE RGB MANIPULATION ********************************************/ + static final int convertRed(final int pixel){ return pixel >> 16 & 0xff; } + static final int convertGreen(final int pixel){ return pixel >> 8 & 0xff; } + static final int convertBlue(final int pixel){ return pixel & 0xff; } + /********************************************************************************************************/ +} diff --git a/src/sjgs/utils/__IntersectionUtils.java b/src/sjgs/utils/__IntersectionUtils.java new file mode 100755 index 0000000..2909cd6 --- /dev/null +++ b/src/sjgs/utils/__IntersectionUtils.java @@ -0,0 +1,59 @@ +package sjgs.utils; + +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.shapes.Circle; +import sjgs.utils.data_structures.shapes.Rectangle; +import sjgs.utils.data_structures.vectors.Point2f; + +class __IntersectionUtils { + + static Rectangle calcMostIntersecting(final Rectangle rect, final Rectangle ...args) { + if(args.length == 0) return null; if(args.length == 1) return args[0]; + final Stack rects = new Stack(); + for(final Rectangle r : args) if(r != null && rect.intersects(r)) rects.push(r); + if(rects.size() == 0) return null; + final float[] areas = new float[rects.size()]; + for(int i = 0; i < rects.size(); i++) areas[i] = rect.getIntersectingArea(rects.get(i)); + final float largest_area = Utils.max(areas); + final Stack answers = new Stack(); + for(int i = 0; i < areas.length; i++) if(areas[i] == largest_area) answers.push(rects.get(i)); + if(answers.size() == 0) return null; + return answers.get(Utils.rand.nextInt(answers.size())); + } + + static Rectangle calcMostIntersecting(final Rectangle rect, final Stack args) { + if(args.size() == 0) return null; if(args.size() == 1) return args.getFirst(); + final Stack rects = new Stack(); + for(final Rectangle r : args) if(r != null && rect.intersects(r)) rects.push(r); + if(rects.size() == 0) return null; + final float[] areas = new float[rects.size()]; + for(int i = 0; i < rects.size(); i++) areas[i] = rect.getIntersectingArea(rects.get(i)); + final float largest_area = Utils.max(areas); + final Stack answers = new Stack(); + for(int i = 0; i < areas.length; i++) if(areas[i] == largest_area) answers.push(rects.get(i)); + if(answers.size() == 0) return null; + return answers.get(Utils.rand.nextInt(answers.size())); + } + + static boolean fudgeRectIntersect(final Rectangle r1, final Rectangle r2, final float fudge_amount) { + return !(r1.pos.x + r1.width + fudge_amount < r2.pos.x || // if this is LEFT of r + r1.pos.x - fudge_amount > r2.pos.x + r2.width || // if this is RIGHT of r + r1.pos.y + r1.height + fudge_amount < r2.pos.y || // if this is BELOW r + r1.pos.y - fudge_amount > r2.pos.y + r2.height); // if this is ABOVE r + } + + // CIRCLES AND RECTS + static boolean intersects(final Circle circle, final Rectangle rect) { + return intersects(circle.center, circle.radius, rect); + } + static boolean intersects(final Point2f center, final float radius, final Rectangle rect){ + return Utils.square(center.x - Utils.clamp(center.x, rect.pos.x, rect.pos.x + rect.width)) + + Utils.square(center.y - Utils.clamp(center.y, rect.pos.y, rect.pos.y + rect.height)) + < Utils.square(radius); + } + + // Un-made circles and Point2fs + static boolean contains(final Point2f center, final float radius, final Point2f p){ return Utils.square(p.x - center.x) + Utils.square(p.y - center.y) < Utils.square(radius); } + static boolean contains(final Point2f center, final float radius, final float x, final float y){ return Utils.square(x - center.x) + Utils.square(y - center.y) < Utils.square(radius); } + +} diff --git a/src/sjgs/utils/__MixMaxUtils.java b/src/sjgs/utils/__MixMaxUtils.java new file mode 100755 index 0000000..bce2000 --- /dev/null +++ b/src/sjgs/utils/__MixMaxUtils.java @@ -0,0 +1,66 @@ +package sjgs.utils; + +class __MixMaxUtils { + + static final int biggest(final int ...args) { + if(args.length == 0) { System.err.println("ERROR: Utils.biggest --- args.length == 0"); System.exit(1); } + else if(args.length == 1) return args[0]; + + int max = args[0]; + for(int i = 1; i < args.length; i++) if(args[i] > max) max = args[i]; + return max; + } + + static final float biggest(final float ...args) { + if(args.length == 0) { System.err.println("ERROR: Utils.biggest --- args.length == 0"); System.exit(1); } + else if(args.length == 1) return args[0]; + + float max = args[0]; + for(int i = 1; i < args.length; i++) if(args[i] > max) max = args[i]; + return max; + } + + static final double biggest(final double ...args) { + if(args.length == 0) { System.err.println("ERROR: Utils.biggest --- args.length == 0"); System.exit(1); } + else if(args.length == 1) return args[0]; + + double max = args[0]; + for(int i = 1; i < args.length; i++) if(args[i] > max) max = args[i]; + return max; + } + + static final int smallest(final int ...args) { + if(args.length == 0) { System.err.println("ERROR: Utils.smallest --- args.length == 0"); System.exit(1); } + else if(args.length == 1) return args[0]; + + int min = args[0]; + for(int i = 1; i < args.length; i++) if(args[i] < min) min = args[i]; + return min; + } + + static final float smallest(final float ...args) { + if(args.length == 0) { System.err.println("ERROR: Utils.smallest --- args.length == 0"); System.exit(1); } + else if(args.length == 1) return args[0]; + + float min = args[0]; + for(int i = 1; i < args.length; i++) if(args[i] < min) min = args[i]; + return min; + } + + static final double smallest(final double ...args) { + if(args.length == 0) { System.err.println("ERROR: Utils.smallest --- args.length == 0"); System.exit(1); } + else if(args.length == 1) return args[0]; + + double min = args[0]; + for(int i = 1; i < args.length; i++) if(args[i] < min) min = args[i]; + return min; + } + + static final int max(final int ...args) { return biggest(args); } + static final float max(final float ...args) { return biggest(args); } + static final double max(final double ...args) { return biggest(args); } + static final int min(final int ...args) { return smallest(args); } + static final float min(final float ...args) { return smallest(args); } + static final double min(final double ...args) { return smallest(args); } + +} diff --git a/src/sjgs/utils/__SerializationUtils.java b/src/sjgs/utils/__SerializationUtils.java new file mode 100755 index 0000000..f11dbf5 --- /dev/null +++ b/src/sjgs/utils/__SerializationUtils.java @@ -0,0 +1,35 @@ +package sjgs.utils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +class __SerializationUtils { + + static final String userHomeDir = System.getProperty("user.home"); + + static synchronized void saveObject(final Object obj, final String path){ + try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(path))); + oos.writeObject(obj); oos.close(); oos = null; + } catch (final Exception e) { e.printStackTrace(); System.exit(1); } + } + + static synchronized Object readObject(final String path){ + try { InputStream is = __SerializationUtils.class.getResourceAsStream(path); + ObjectInputStream oos = new ObjectInputStream(is); + final Object object = oos.readObject(); + oos.close(); oos = null; + is.close(); is = null; + return object; + } catch (final Exception e) { e.printStackTrace(); System.exit(1); return null; } + } + + static synchronized void writeStringToFile(final String string, final String path) { + try (FileWriter fw = new FileWriter(new File(path))) { + fw.write(string); + } catch (final Exception e) { e.printStackTrace(); } + } +} diff --git a/src/sjgs/utils/__TextFileManipulation.java b/src/sjgs/utils/__TextFileManipulation.java new file mode 100755 index 0000000..bc78da1 --- /dev/null +++ b/src/sjgs/utils/__TextFileManipulation.java @@ -0,0 +1,57 @@ +package sjgs.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Scanner; +import javax.swing.JOptionPane; + +class __TextFileManipulation { + + static int getNumLinesFromTextFile(final String path) { /* loads as resource to work in jars */ + int count = 0; + try { final InputStream stream = __TextFileManipulation.class.getResourceAsStream(path); + final Scanner scanner = new Scanner(stream); + while (scanner.hasNextLine()) { scanner.nextLine(); count++; } + stream.close(); scanner.close(); + } catch (final Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Text Files Failed To Load --- Utils.java"); } + return count; + } + + static String[] makeStringArrayFromLinesOfTextFile(final String path) { /* loads as resource to work in jars */ + final String[] lines = new String[getNumLinesFromTextFile(path)]; + try { final InputStream stream = __TextFileManipulation.class.getResourceAsStream(path); + final Scanner scanner = new Scanner(stream); + for (int i = 0; scanner.hasNextLine(); i++) lines[i] = scanner.nextLine(); + stream.close(); scanner.close(); + } catch (final Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Text Files Failed To Load --- Utils.java"); } + return lines; + } + + static StringBuilder[] makeStringBuilderArrayFromLinesOfTextFile(final String path) { /* loads as resource to work in jars */ + final StringBuilder[] lines = new StringBuilder[getNumLinesFromTextFile(path)]; + try { final InputStream stream = __TextFileManipulation.class.getResourceAsStream(path); + final Scanner scanner = new Scanner(stream); + for (int i = 0; scanner.hasNextLine(); i++) lines[i] = new StringBuilder(scanner.nextLine()); + stream.close(); scanner.close(); + } catch (final Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Text Files Failed To Load --- Utils.java"); } + return lines; + } + + static String readTextFileAsString(final String path){ + InputStream stream = null; + // NOTICE: Depending on what was used for making the jar, you *may* or *may not* have a /src/ + // super directory, or it may be placed alongside your class files with anything that + // wasn't a *.java file during compile time. Fear not, as this will catch both of these + // cases should they be an issue. + try { stream = __TextFileManipulation.class.getResourceAsStream(path); } catch (final Exception e) { + stream = __TextFileManipulation.class.getResourceAsStream("/src/" + path); + } + Scanner file = new Scanner(stream); + final StringBuilder sb = new StringBuilder(); + while(file.hasNextLine()) sb.append(file.nextLine() + "\n"); // NOTE: Preserves new line characters! + try { stream.close(); file.close(); } catch (final IOException e) { e.printStackTrace(); System.exit(1); } + if(sb.toString().length() == 0) System.err.println("PROBLEM: TEXT FILE APPEARS TO BE BLANK? -- Utils.class"); + file.close(); file = null; stream = null; + return sb.toString(); + } +} diff --git a/src/sjgs/utils/data_structures/Stack.java b/src/sjgs/utils/data_structures/Stack.java new file mode 100755 index 0000000..a0e25de --- /dev/null +++ b/src/sjgs/utils/data_structures/Stack.java @@ -0,0 +1,131 @@ +package sjgs.utils.data_structures; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.NoSuchElementException; +import sjgs.utils.data_structures.interfaces.StackInterface; + +/** @class: A very powerful SinglyLinkedList based data structure. */ +public class Stack implements StackInterface { + + private Node top; + private int size; + + public Stack(final E ...args) { combine(args); } + public Stack(final Stack args) { combine(args); } + + @Override + public int size() { return size; } + @Override + public E peek() { return !isEmpty() ? top.data : null; } + @Override + public E get(final int index){ + final int target = size - index - 1; + if(isEmpty() || target < 0 || index < 0) throw new NoSuchElementException(); + Node current = top; + for(int i = 0; i < target; i++) current = current.prev; + return current.data; + } + + @Override + public void push(final E e) { top = new Node(top, e); size++; } + + @Override + public E pop() { + if (isEmpty()) return null; + final E answer = top.data; + top = --size == 0 ? null : top.prev; + return answer; + } + + @Override + public void remove(final E e) { + if(isEmpty()) throw new NoSuchElementException(); + + try { + Node current = top; + int depth = size - 1; + + while(current.data != e) { current = current.prev; --depth; } + + if(get(depth) != null) remove(depth); else throw new NoSuchElementException(); + } catch (final NullPointerException npe) { /* no element to remove? */ } + } + + @Override + public E remove(final int index){ + final int target = size - index - 1; + if(isEmpty() || target < 0 || index < 0) throw new NoSuchElementException(); + final Stack temp = new Stack(); + for(int i = 0; i < target; i++) temp.push(pop()); + final E answer = pop(); + while(!temp.isEmpty()) push(temp.pop()); + return answer; + } + + @Override + public Stack clone() { + final Stack clone = new Stack(); + for(final E e : this) clone.push(e); + return clone; + } + + public Stack> split() { return split(2); } + public Stack> split(final int parts) { + if(size < parts) throw new NoSuchElementException(); + // CREATE STACK OF STACKS + final Stack> stacks = new Stack>(); + for(int i = 0; i < parts; i++) stacks.push(new Stack()); + + // FILL A TEMP STACK WITH CURRENT STACKS GOODS + final Stack temp = new Stack(); + for(int i = 0; i < size; i++) temp.push(get(i)); + + // FILL EACH STACK IN STACK OF STACKS WITH EQUAL PARTS + for(int i = 0; i < parts; i++) + for(int j = 0; j < size / parts; j++) + stacks.get(i).push(temp.pop()); + + // IF SIZE IS ODD, THIS WILL CATCH THE STRAGLER + while(!temp.isEmpty()) stacks.peek().push(temp.pop()); + + return stacks; + } + + @Override + public Iterator iterator() { return new StackIterator(); } + public class StackIterator implements Iterator, Serializable { + private Node current; + private E temp; /* avoid unnecessary mass object creation */ + public StackIterator() { super(); current = top; } + @Override + public boolean hasNext() { return current != null; } + @Override + public E next() { + if (!hasNext()) throw new NoSuchElementException(); + temp = current.data; + current = current.prev; + return temp; + } + } + + @Override + public String toString() { + if(isEmpty()) return "STACK IS EMPTY"; + Node temp = top; final StringBuilder sb = new StringBuilder(); + sb.append("("); + for(int i = 0; i < size; i++, temp = temp.prev){ + sb.append(temp.data); + if(i != size - 1) sb.append(", "); + } return sb.toString() + ")"; + } + + // ----------------- NODE CLASS ------------------------------------------------- // + private static class Node implements Serializable { + public final E data; + public final Node prev; + public Node(final Node prev, final E data) { this.prev = prev; this.data = data; } + } + // -------------- END NODE CLASS ------------------------------------------------- // + +} diff --git a/src/sjgs/utils/data_structures/gaming/QuadTree.java b/src/sjgs/utils/data_structures/gaming/QuadTree.java new file mode 100755 index 0000000..de33807 --- /dev/null +++ b/src/sjgs/utils/data_structures/gaming/QuadTree.java @@ -0,0 +1,231 @@ +package sjgs.utils.data_structures.gaming; + +import static sjgs.utils.Utils.COIN_FLIP; +import static sjgs.utils.Utils.rand; +import java.io.Serializable; +import sjgs.base_objects.GameObject; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.Stack; + +/** @class: NOTE: This data structure is ONLY to be used for PURELY STATIC objects. + * This implementation does NOT have the ability to continually update + * the objects inside it. It loses the reference to said objects. + * With this in mind, this will work great for tiles and scenery, however + * this will *NOT* work for things like bullet collision, etc. */ + +public final class QuadTree implements Serializable { + + private final Node root; + private int size = 0; + + public QuadTree(final float minX, final float minY, final float maxX, final float maxY) { + root = new Node(minX, minY, maxX - minX, maxY - minY, null); + } + + // ----------------------------- PUBLIC METHODS ------------------------------------------------------------------ // + + public void insert(final GameObject value) { + float x = value.getX(), y = value.getY(); + while(contains(x, y)) { + x = COIN_FLIP() ? x + rand.nextInt(Utils._2147483647) * 0.000_000_000_1f : x - rand.nextInt(Utils._2147483647) * 0.000_000_000_1f; + y = COIN_FLIP() ? y + rand.nextInt(Utils._2147483647) * 0.000_000_000_1f : y - rand.nextInt(Utils._2147483647) * 0.000_000_000_1f; + } + if (x < root.getX() || y < root.getY() || x > root.getX() + root.getWidth() || y > root.getY() + root.getHeight()) Utils.print("Out of bounds : (" + x + ", " + y + ")"); + else if (insert(root, new Data(x, y, value))) size++; + } + + /** @method remove: returns the success rate */ + public boolean remove(final GameObject g) { return remove(g.getX(), g.getY()) != null; } + public boolean isEmpty() { return root.getNodeType() == NodeType.EMPTY; } + public int size() { return size; } + + public void clear() { + root.nw = root.ne = root.sw = root.se = null; + root.setNodeType(NodeType.EMPTY); + root.setData(null); size = 0; + } + + public Stack search(final float xmin, final float ymin, final float xmax, final float ymax) { + final Stack stack = new Stack(); + try { navigate(root,(node) -> { final Data pt = node.getData(); + if (!(pt.getX() < xmin || pt.getX() > xmax || pt.getY() < ymin || pt.getY() > ymax)) stack.push(node.getData().getGameObject()); + }, xmin, ymin, xmax, ymax); } catch (final Exception e) { } + return stack; + } + + public Stack toStack() { + final Stack stack = new Stack(); + traverse(root, (node) -> stack.push(node.getData().getGameObject())); + return stack; + } + + @Override + public QuadTree clone() { + final Stack temp = toStack(); + final QuadTree clone = new QuadTree(root.getX(), root.getY(), root.getWidth(), root.getHeight()); + for(final GameObject g : temp) clone.insert(g); + return clone; + } + + // -------------------------------- END PUBLIC METHODS ---------------------------------------------------------------- // + + private GameObject remove(final float x, final float y) { + final Node node = find(root, x, y); + if (node != null) { + final GameObject value = node.getData().getGameObject(); + node.setData(null); + node.setNodeType(NodeType.EMPTY); + balance(node); + size--; + return value; + } else return null; + } + + private static void navigate(final Node node, final Func func, final float xmin, final float ymin, final float xmax, final float ymax) { + switch (node.getNodeType()) { + case LEAF: func.call(node); break; + case POINTER: + if (intersects(xmin, ymax, xmax, ymin, node.ne)) navigate(node.ne, func, xmin, ymin, xmax, ymax); + if (intersects(xmin, ymax, xmax, ymin, node.se)) navigate(node.se, func, xmin, ymin, xmax, ymax); + if (intersects(xmin, ymax, xmax, ymin, node.sw)) navigate(node.sw, func, xmin, ymin, xmax, ymax); + if (intersects(xmin, ymax, xmax, ymin, node.nw)) navigate(node.nw, func, xmin, ymin, xmax, ymax); break; + } + } + + private GameObject get(final float x, final float y) { + final Node node = find(root, x, y); + return node != null ? node.getData().getGameObject() : null; + } + private boolean contains(final float x, final float y) { return get(x, y) != null; } + + private static boolean intersects(final float left, final float bottom, final float right, final float top, final Node node) { + return !(node.getX() > right || node.getX() + node.getWidth() < left || node.getY() > bottom || node.getY() + node.getHeight() < top); + } + + private static void traverse(final Node node, final Func func) { + switch (node.getNodeType()) { + case LEAF: func.call(node); break; + + case POINTER: traverse(node.ne, func); + traverse(node.se, func); + traverse(node.sw, func); + traverse(node.nw, func); break; + } + } + + private static Node find(final Node node, final float x, final float y) { + switch (node.getNodeType()) { + case LEAF: return node.getData().getX() == x && node.getData().getY() == y ? node : null; + + case POINTER: return find(getQuadrantForData(node, x, y), x, y); + } return null; + } + + private boolean insert(final Node parent, final Data data) { + switch (parent.getNodeType()) { + case EMPTY: setDataForNode(parent, data); return true; + case LEAF: + if (parent.getData().getX() == data.getX() && parent.getData().getY() == data.getY()) { + setDataForNode(parent, data); + return false; + } else { + split(parent); + return insert(parent, data); + } + default: return insert(getQuadrantForData(parent, data.getX(), data.getY()), data); + } + } + + private void split(final Node node) { + final Data oldData = node.getData(); + node.setData(null); + node.setNodeType(NodeType.POINTER); + + final float x = node.getX(); + final float y = node.getY(); + final float hw = node.getWidth() / 2; + final float hh = node.getHeight() / 2; + + node.nw = new Node(x, y, hw, hh, node); + node.ne = new Node(x + hw, y, hw, hh, node); + node.sw = new Node(x, y + hh, hw, hh, node); + node.se = new Node(x + hw, y + hh, hw, hh, node); + + insert(node, oldData); + } + + private static void balance(final Node node) { + if(node.getNodeType() == NodeType.POINTER) { + Node firstLeaf = null; + + if (node.nw.getNodeType() != NodeType.EMPTY) firstLeaf = node.nw; // note here it starts @ nw, calc'ing CLOCKWISE + + if (node.ne.getNodeType() != NodeType.EMPTY && firstLeaf != null) firstLeaf = node.ne; + else if (node.sw.getNodeType() != NodeType.EMPTY && firstLeaf != null) firstLeaf = node.sw; + else if (node.se.getNodeType() != NodeType.EMPTY && firstLeaf != null) firstLeaf = node.se; + else if (firstLeaf == null) { + node.setNodeType(NodeType.EMPTY); + node.nw = node.ne = node.sw = node.se = null; + } + else if (firstLeaf.getNodeType() != NodeType.POINTER) { + node.setNodeType(NodeType.LEAF); + node.nw = node.ne = node.sw = node.se = null; + node.setData(firstLeaf.getData()); + } + } + + if (node.getParent() != null) balance(node.getParent()); + } + + private static Node getQuadrantForData(final Node parent, final float x, final float y) { + final float mx = parent.getX() + parent.getWidth() / 2f; + final float my = parent.getY() + parent.getHeight() / 2f; + if (x < mx) return y < my ? parent.nw : parent.sw; else return y < my ? parent.ne : parent.se; + } + + private static void setDataForNode(final Node node, final Data data) { + if (node.getNodeType() == NodeType.POINTER) Utils.print("Can not set data for node of type POINTER"); + else { node.setNodeType(NodeType.LEAF); node.setData(data); } + } + + private static interface Func { void call(Node node); } + private static enum NodeType { EMPTY, LEAF, POINTER } + + private static class Node implements Serializable { + + private final float x, y, w, h; + private final Node parent; + private Data data; + private NodeType nodetype = NodeType.EMPTY; + private Node nw, ne, sw, se; + + public Node(final float x, final float y, final float w, final float h, final Node parent) { + this.x = x; this.y = y; this.w = w; this.h = h; + this.parent = parent; + } + + private float getX() { return x; } + private float getY() { return y; } + private float getWidth() { return w; } + private float getHeight() { return h; } + private Node getParent() { return parent; } + private void setData(final Data data) { this.data = data; } + private Data getData() { return data; } + private void setNodeType(final NodeType nodetype) { this.nodetype = nodetype; } + private NodeType getNodeType() { return nodetype; } + } + + private static class Data implements Serializable { + private final float x, y; + private final GameObject game_object; + + public Data(final float x, final float y, final GameObject game_object) { + this.x = x; this.y = y; this.game_object = game_object; + } + + private float getX() { return x; } + private float getY() { return y; } + private GameObject getGameObject() { return game_object; } + } + +} diff --git a/src/sjgs/utils/data_structures/interfaces/ListInterface.java b/src/sjgs/utils/data_structures/interfaces/ListInterface.java new file mode 100755 index 0000000..706c9d1 --- /dev/null +++ b/src/sjgs/utils/data_structures/interfaces/ListInterface.java @@ -0,0 +1,37 @@ +package sjgs.utils.data_structures.interfaces; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public interface ListInterface extends Iterable, Serializable { + + public abstract int size(); + public abstract void add(E e); + public abstract void remove(E e); + public abstract E remove(int index); + public abstract E get(int index); + + default void clear() { while(!isEmpty()) removeFirst(); } + default boolean contains(final E e){ for(final E i : this) if (i == e) return true; return false; } + default E getFirst(){ return !isEmpty() ? get(0) : null; } + default E removeFirst() { return !isEmpty() ? remove(0) : null; } + default boolean isEmpty() { return size() == 0; } + + default E[] toArray(){ + final E[] arr = (E[])new Object[size()]; + for(int i = 0; i < size(); i++) arr[i] = get(i); + return arr; + } + + default void insert(final E e) { add(e); } + + default E first() { return get(0); } + + default void writeToFile(final String path) { + try { final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(path))); oos.writeObject(this); oos.close(); + } catch (final Exception e) { e.printStackTrace(); System.exit(1); } + } + +} diff --git a/src/sjgs/utils/data_structures/interfaces/StackInterface.java b/src/sjgs/utils/data_structures/interfaces/StackInterface.java new file mode 100755 index 0000000..1729cfe --- /dev/null +++ b/src/sjgs/utils/data_structures/interfaces/StackInterface.java @@ -0,0 +1,67 @@ +package sjgs.utils.data_structures.interfaces; + +import static sjgs.utils.Utils.nextInt; +import java.io.File; +import java.io.FileOutputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.Stack; + +public interface StackInterface extends Iterable, Serializable { + + public abstract int size(); + public abstract void push(E e); + public abstract E pop(); + public abstract E peek(); + public abstract E get(int index); + public abstract void remove(E e); + public abstract E remove(int index); + @Override + public abstract String toString(); + + default E first() { return getFirst(); } + default E getFirst(){ return !isEmpty() ? get(0) : null; } + default E getLast() { return peek(); } + default boolean contains(final E e){ for(final E i : this) if (i == e) return true; return false; } + + default E removeFirst() { return remove(0); } + + default void clear(){ while(!isEmpty()) pop(); } + + default void writeToFile(final String path) { + try { final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(path))); oos.writeObject(this); oos.close(); + } catch (final Exception e) { e.printStackTrace(); System.exit(1); } + } + + default void combine(final Stack stack) { for(final E e : stack) push(e); } + default void combine(final Stack ...args) { for(final Stack s : args) combine(s); } + default void combine(final E[] arr) { for (final E element : arr) + push(element); } + default void combine(final E[] ...args) { for(final E[] a : args) combine(a); } + + default E[] toArray(){ + final E[] arr = (E[])new Object[size()]; + for(int i = 0; i < size(); i++) arr[i] = get(i); + return arr; + } + + default void reverse(){ + final Stack temp = new Stack(); + while(!isEmpty()) temp.push(removeFirst()); + while(!temp.isEmpty()) push(temp.pop()); + } + + default void shuffle() { + final Stack temp = new Stack(); + while(!isEmpty()) temp.push(pop()); + while(!temp.isEmpty()) push(temp.remove(nextInt(temp.size()))); + } + + default void print() { if(isEmpty()) { Utils.print("STACK IS EMPTY"); return; } for(final E e : this) Utils.print(e); } + default boolean isEmpty() { return size() == 0; } + default void insert(final E e) { push(e); } + default void add(final E e) { push(e); } + default E top() { return peek(); } + +} diff --git a/src/sjgs/utils/data_structures/shapes/Circle.java b/src/sjgs/utils/data_structures/shapes/Circle.java new file mode 100755 index 0000000..9046d9f --- /dev/null +++ b/src/sjgs/utils/data_structures/shapes/Circle.java @@ -0,0 +1,41 @@ +package sjgs.utils.data_structures.shapes; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import sjgs.utils.Utils; +import sjgs.utils.data_structures.vectors.Point2f; + +public class Circle { + + public Point2f center; + public float radius; + + public Circle(final Point2f center, final float radius){ this.center = center; this.radius = radius; } + + public Rectangle squareBounds(){ return new Rectangle((int)(center.x - radius), (int)(center.y - radius), (int)radius, (int)radius); } + + public void draw(final Graphics2D g2d){ g2d.drawOval((int)(center.x - radius), (int)(center.y - radius), (int)diameter(), (int)diameter()); } + public void drawFilled(final Graphics2D g2d){ g2d.fillOval((int)(center.x - radius), (int)(center.y - radius), (int)diameter(), (int)diameter()); } + + public boolean contains(final Point2f p){ return Utils.square(p.x - center.x) + Utils.square(p.y - center.y) < Utils.square(radius); } + public boolean contains(final Point p){ return Utils.square(p.x - center.x) + Utils.square(p.y - center.y) < Utils.square(radius); } + public boolean contains(final int x, final int y){ return Utils.square(x - center.x) + Utils.square(y - center.y) < Utils.square(radius); } + public boolean contains(final float x, final float y){ return Utils.square(x - center.x) + Utils.square(y - center.y) < Utils.square(radius); } + + public float getWidth(){ return radius*2; } + public float getHeight(){ return radius*2; } + public float diameter(){ return radius*2; } + + @Override + public String toString(){ return "radius: " + Utils.df.format(radius) + ", " + "center: " + center; } + + public boolean intersects(final Circle c) { + return center.distance(c.center) <= radius + c.radius; + } + + public boolean intersects(final Point2f center2, final float r2) { + return center.distance(center2) <= radius + r2; + } + +} diff --git a/src/sjgs/utils/data_structures/shapes/Line.java b/src/sjgs/utils/data_structures/shapes/Line.java new file mode 100755 index 0000000..ab4d41e --- /dev/null +++ b/src/sjgs/utils/data_structures/shapes/Line.java @@ -0,0 +1,63 @@ +package sjgs.utils.data_structures.shapes; + +import static sjgs.utils.Utils.max; +import static sjgs.utils.Utils.min; +import java.awt.Graphics2D; +import sjgs.utils.data_structures.vectors.Point2f; + +public class Line { + + public final Point2f p1, p2; + public final float angle; + + public Line(final Point2f p1, final Point2f p2) { + this.p1 = p1; this.p2 = p2; + angle = p1.direction(p2); + } + + public Line(final float x1, final float y1, final float x2, final float y2) { + p1 = new Point2f(x1, y1); p2 = new Point2f(x2, y2); + angle = p1.direction(p2); + } + + public void draw(final Graphics2D g2d) { + g2d.drawLine((int)p1.x, (int)p1.y, (int)p2.x, (int)p2.y); + } + + public boolean intersects(final Line l) { return doIntersect(p1, p2, l.p1, l.p2); } + + + // ----------------- INTERSECTION HELPERS ------------------------------------------------------------------------------------ // + private boolean onSegment(final Point2f p, final Point2f q, final Point2f r) { + return q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) && q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y); + } + + private int orientation(final Point2f p, final Point2f q, final Point2f r) { + final float val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + return val == 0 ? 0 : val > 0? 1: 2; // colinear + } + + private boolean doIntersect(final Point2f p1, final Point2f q1, final Point2f p2, final Point2f q2) + { + // Find the four orientations needed for general and + // special cases + final int o1 = orientation(p1, q1, p2); + final int o2 = orientation(p1, q1, q2); + final int o3 = orientation(p2, q2, p1); + final int o4 = orientation(p2, q2, q1); + + // Special Cases + // p1, q1 and p2 are colinear and p2 lies on segment p1q1 + return o1 != o2 && o3 != o4 || + o1 == 0 && onSegment(p1, p2, q1) || + // p1, q1 and p2 are colinear and q2 lies on segment p1q1 + o2 == 0 && onSegment(p1, q2, q1) || + // p2, q2 and p1 are colinear and p1 lies on segment p2q2 + o3 == 0 && onSegment(p2, p1, q2) || + // p2, q2 and q1 are colinear and q1 lies on segment p2q2 + o4 == 0 && onSegment(p2, q1, q2); + } + // ---------------- END INTERSECTION HELPERS ------------------------------------------------------------------------------------ // + + +} diff --git a/src/sjgs/utils/data_structures/shapes/Rectangle.java b/src/sjgs/utils/data_structures/shapes/Rectangle.java new file mode 100755 index 0000000..4c6850b --- /dev/null +++ b/src/sjgs/utils/data_structures/shapes/Rectangle.java @@ -0,0 +1,120 @@ +package sjgs.utils.data_structures.shapes; + +import static sjgs.utils.Utils.clamp; +import static sjgs.utils.Utils.max; +import static sjgs.utils.Utils.min; +import static sjgs.utils.Utils.square; +import java.awt.Graphics2D; +import java.awt.Point; +import sjgs.utils.data_structures.vectors.Point2f; +import sjgs.utils.data_structures.vectors.SimplePoint; + +public class Rectangle { + + public float width, height; + public Point2f pos; + + public Rectangle(final float x, final float y, final float width, final float height) { + pos = new Point2f(x, y); this.width = width; this.height = height; + } + + public Rectangle(final Point2f pos, final float width, final float height) { + this.pos = new Point2f(pos.x, pos.y); this.width = width; this.height = height; + } + + public Rectangle(final Point2f tl, final Point2f tr, final Point2f bl, @SuppressWarnings("unused") final Point2f br) { + pos = tl; + width = tr.x - tl.x; + height = bl.y - tl.y; + } + + public boolean intersectsWithCircle(final Circle c) { + return square(c.center.x - clamp(c.center.x, pos.x, pos.x + width)) + square(c.center.y - clamp(c.center.y, pos.y, pos.y + height)) < square(c.radius); + } + + public boolean intersects(final Rectangle r) { + return !(pos.x + width < r.pos.x || // if this is LEFT of r + pos.x > r.pos.x + r.width || // if this is RIGHT of r + pos.y + height < r.pos.y || // if this is BELOW r + pos.y > r.pos.y + r.height); // if this is ABOVE r + } + + public boolean intersects(final Line line) { + return line.intersects(getTop()) || line.intersects(getRight()) || line.intersects(getBottom()) || line.intersects(getLeft()); + } + + public float getIntersectingArea(final Rectangle r) { + if(!intersects(r)) return 0; + + final float newWidth = min(pos.x + width, r.pos.x + r.width) - max(pos.x, r.pos.x); + final float newHeight = min(pos.y + height, r.pos.y + r.height) - max(pos.y, r.pos.y); + + return newWidth * newHeight; + } + + public boolean contains(final Point2f p) { + if(!(p.x > pos.x && p.x < pos.x + width)) return false; if(!(p.y > pos.y && p.y < pos.y + height)) return false; return true; + } + + public boolean contains(final SimplePoint p) { + if(!(p.x > pos.x && p.x < pos.x + width)) return false; if(!(p.y > pos.y && p.y < pos.y + height)) return false; return true; + } + + public boolean contains(final Point p) { + if(!(p.x > pos.x && p.x < pos.x + width)) return false; if(!(p.y > pos.y && p.y < pos.y + height)) return false; return true; + } + + public boolean contains(final float x, final float y) { + if(!(x > pos.x && x < pos.x + width)) return false; if(!(y > pos.y && y < pos.y + height)) return false; return true; + } + + public boolean contains(final int x, final int y) { + if(!(x > pos.x && x < pos.x + width)) return false; if(!(y > pos.y && y < pos.y + height)) return false; return true; + } + + public boolean isSquare() { return width == height; } + + public void draw(final Graphics2D g2d) { g2d.drawRect((int)pos.x, (int)pos.y, (int)width, (int)height); } + public void drawFilled(final Graphics2D g2d) { g2d.fillRect((int)pos.x, (int)pos.y, (int)width, (int)height); } + + public Triangle toTriangle() { + return new Triangle(new Point2f(getX(), getY() + getHeight()), + new Point2f(getX() + getHalfWidth(), getY()), + new Point2f(getX() + getWidth(), getY() + getHeight())); + } + + @Override + public Rectangle clone() { return new Rectangle(getX(), getY(), getWidth(), getHeight()); } + @Override + public String toString() { return "x: " + getX() + ", y: " + getY() + ", w: " + getWidth() + ", h: " + getHeight(); } + + public void setLocation(final float x, final float y) { pos.setLocation(x, y); } + public void setSize(final float w, final float h) { width = w; height = h; } + public float getWidth() { return width; } + public void setWidth(final float width) { this.width = width; } + public float getHeight() { return height; } + public void setHeight(final float height) { this.height = height; } + public float getHalfWidth() { return width * 0.5f; } + public float getHalfHeight() { return height * 0.5f; } + public Point2f getPos() { return pos; } + public void setPos(final Point2f pos) { this.pos = pos; } + public Point2f getCenter() { return new Point2f(pos.x + getHalfWidth(), pos.y + getHalfHeight()); } + public float getCenterX() { return pos.x + width*0.5f; } + public float getCenterY() { return pos.y + height*0.5f; } + public float getArea() { return width * height; } + public float getX() { return pos.x; } + public float getY() { return pos.y; } + public void setX(final float x) { pos.x = x; } + public void setY(final float y) { pos.y = y; } + + public Point2f getTopLeft() { return pos; } + public Point2f getTopRight() { return new Point2f(getX() + getWidth(), getY()); } + public Point2f getBottomRight() { return new Point2f(getX() + getWidth(), getY() + getHeight()); } + public Point2f getBottomLeft() { return new Point2f(getX(), getY() + getHeight()); } + + public Line getTop() { return new Line(getTopLeft(), getTopRight()); } + public Line getBottom() { return new Line(getBottomLeft(), getBottomRight()); } + public Line getLeft() { return new Line(getBottomLeft(), getTopLeft()); } + public Line getRight() { return new Line(getTopRight(), getBottomRight()); } + +} diff --git a/src/sjgs/utils/data_structures/shapes/Triangle.java b/src/sjgs/utils/data_structures/shapes/Triangle.java new file mode 100755 index 0000000..e72d698 --- /dev/null +++ b/src/sjgs/utils/data_structures/shapes/Triangle.java @@ -0,0 +1,24 @@ +package sjgs.utils.data_structures.shapes; + +import java.awt.Graphics2D; +import sjgs.utils.data_structures.vectors.Point2f; + +public class Triangle { + + /** points go from bottom left corner @ [0], clockwise */ + public final Point2f[] points; + + public Triangle(final Point2f a, final Point2f b, final Point2f c) { + points = new Point2f[3]; + points[0] = new Point2f(a.getX(), a.getY()); + points[1] = new Point2f(b.getX(), b.getY()); + points[2] = new Point2f(c.getX(), c.getY()); + } + + public void draw(final Graphics2D g2d) { + g2d.drawLine((int)points[0].x, (int)points[0].y, (int)points[1].x, (int)points[1].y); + g2d.drawLine((int)points[1].x, (int)points[1].y, (int)points[2].x, (int)points[2].y); + g2d.drawLine((int)points[2].x, (int)points[2].y, (int)points[0].x, (int)points[0].y); + } + +} diff --git a/src/sjgs/utils/data_structures/vectors/Point2f.java b/src/sjgs/utils/data_structures/vectors/Point2f.java new file mode 100755 index 0000000..52b1c50 --- /dev/null +++ b/src/sjgs/utils/data_structures/vectors/Point2f.java @@ -0,0 +1,56 @@ +package sjgs.utils.data_structures.vectors; + +import static sjgs.utils.Utils.atan2; +import java.awt.Graphics2D; +import java.awt.Point; +import sjgs.utils.Utils; + +public class Point2f { + + public float x, y; + + public Point2f(final float x, final float y) { this.x = x; this.y = y; } + public Point2f(final double x, final double y) { this.x = (float)x; this.y = (float)y;} + public Point2f(final int x, final int y) { this.x = x; this.y = y;} + public Point2f(final long x, final long y) { this.x = x; this.y = y;} + public Point2f() { x = 0f; y = 0f; } + public Point2f(final Point2f p) { x = p.x; y = p.y; } + public Point2f(final Point p) { x = p.x; y = p.y; } + public Point2f(final SimplePoint p) { x = p.x; y = p.y; } + + public void setLocation(final float x, final float y){ this.x = x; this.y = y; } + + public void rotate(final double theta) { + final float temp = Utils.rotateX(x, y, theta); + y = Utils.rotateY(x, y, theta); + x = temp; + } + + public float distance(final Point2f p){ return Utils.sqrt(Utils.square(y - p.y) + Utils.square(x - p.x)); } + public float distance(final Point p){ return Utils.sqrt(Utils.square(y - p.y) + Utils.square(x - p.x)); } + public float distance(final SimplePoint p){ return Utils.sqrt(Utils.square(y - p.y) + Utils.square(x - p.x)); } + public int distance(final int x, final int y){ return (int)Utils.sqrt(Utils.square(this.y - y) + Utils.square(this.x - x)); } + public float distance(final float x, final float y){ return Utils.sqrt(Utils.square(this.y - y) + Utils.square(this.x - x)); } + public double distance(final double x, final double y){ return Utils.sqrt(Utils.square(this.y - y) + Utils.square(this.x - x)); } + public long distance(final long x, final long y){ return (long)Utils.sqrt(Utils.square(this.y - y) + Utils.square(this.x - x)); } + + // NOTE: returns the angle in radians! + public final float direction(final Point2f p){ return atan2(p.y - y, p.x - x); } + + public Point toPoint(){ return new Point((int)x, (int)y); } + public SimplePoint toSimplePoint() { return new SimplePoint((int)x, (int)y); } + + public void draw(final Graphics2D g2d){ g2d.drawString(".", x - 2, y); } // need the -2, not sure why but this is correct! + @Override + public String toString(){ return "(" + Utils.df.format(x) + ", " + Utils.df.format(y) + ")"; } + + @Override + public Point2f clone() { return new Point2f(this); } + + public float getX() { return x; } + public float getY() { return y; } + public void setX(final float x) { this.x = x; } + public void setY(final float y) { this.y = y; } + + +} diff --git a/src/sjgs/utils/data_structures/vectors/SimplePoint.java b/src/sjgs/utils/data_structures/vectors/SimplePoint.java new file mode 100755 index 0000000..1cece15 --- /dev/null +++ b/src/sjgs/utils/data_structures/vectors/SimplePoint.java @@ -0,0 +1,15 @@ +package sjgs.utils.data_structures.vectors; + +public class SimplePoint { + + public int x, y; + + public SimplePoint(final int x, final int y) { this.x = x; this.y = y; } + public SimplePoint() {} + + public void setLocation(final int x, final int y) { this.x = x; this.y = y; } + + @Override + public SimplePoint clone() { return new SimplePoint(x, y); } + +} diff --git a/src/sjgs/utils/data_structures/vectors/Vector2f.java b/src/sjgs/utils/data_structures/vectors/Vector2f.java new file mode 100755 index 0000000..892d50e --- /dev/null +++ b/src/sjgs/utils/data_structures/vectors/Vector2f.java @@ -0,0 +1,39 @@ +package sjgs.utils.data_structures.vectors; + +import static sjgs.utils.Utils.atan2; +import static sjgs.utils.Utils.cos; +import static sjgs.utils.Utils.sin; + +public class Vector2f { + + /** @class Vector2f is just a vector, essentially its a copy of Point2f. + * However, I feel the names and variables make this class more explicit, + * and makes it easier to use than just two Point2f's for pos and vel, for example. */ + + private float x, y; + + public Vector2f(final float x, final float y) { this.x = x; this.y = y; } + public Vector2f(final float theta) { setXYtoTheta(theta); } + + public void add(final Vector2f vect) { x += vect.x; y += vect.y; } + public void subtract(final Vector2f vect) { x -= vect.x; y -= vect.y; } + + public float getX() { return x; } + public float getY() { return y; } + public void setX(final float x) { this.x = x; } + public void setY(final float y) { this.y = y; } + public void setXAndY(final float x, final float y) { this.x = x; this.y = y; } + + @Override + public Vector2f clone() { return new Vector2f(x, y); } + @Override + public String toString() { return "v1: " + x + ", v2: " + y; } + + public void invertY() { y = -y; } + public void invertX() { x = -x; } + public void invertXandY() { x = -x; y = -y; } + + public float getTheta() { return atan2(y, x); } + public void setXYtoTheta(final float theta) { x = cos(theta); y = sin(theta); } + +} \ No newline at end of file diff --git a/src/sjgs/utils/encryption/CaesarCipher.java b/src/sjgs/utils/encryption/CaesarCipher.java new file mode 100755 index 0000000..5802531 --- /dev/null +++ b/src/sjgs/utils/encryption/CaesarCipher.java @@ -0,0 +1,57 @@ +package sjgs.utils.encryption; + +import static sjgs.utils.Utils.alphabet; +import static sjgs.utils.Utils.nextByte; +import static sjgs.utils.Utils.nextInt; +import sjgs.utils.Utils; + +public class CaesarCipher implements EncryptionInterface { + + private final byte[] message; + private int key; + + public CaesarCipher(final String message) { + this.message = message.getBytes(); + } + + public String encrypt(int key) { + if(key < 1 || key > 26) { + Utils.print("INVALID KEY!"); + return "INVALID KEY!"; + } + this.key = --key; translate(key); + return getMessage(); + } + + /** @encrypt: default no arg generates a random key */ + @Override + public String encrypt() { + key = nextInt(25) + 1; + translate(key); + return getMessage(); + } + @Override + public String decrypt() { translate(-key); return getMessage(); } + + private String translate(final int k) { + for(int i = 0; i < message.length; i++) + if (Character.isLowerCase(message[i])) message[i] = rotate(message[i], k); + return new String(message); + } + + private byte rotate(final byte c, final int key) { + for (int i = 0; i < 26; i++) + if (c == alphabet.charAt(i)) return (byte)alphabet.charAt((i + key + 26) % 26); + Utils.print("ERROR! We shouldn't be here... -- CaeserCipher.class"); return c; + } + + /** @method shred: Randomizes current data */ + @Override + public void shred() { + for(int i = 0; i < message.length; i++) message[i] = nextByte(); + } + + @Override + public String toString() { return new String(message); } + +} diff --git a/src/sjgs/utils/encryption/EncryptionInterface.java b/src/sjgs/utils/encryption/EncryptionInterface.java new file mode 100755 index 0000000..909946a --- /dev/null +++ b/src/sjgs/utils/encryption/EncryptionInterface.java @@ -0,0 +1,16 @@ +package sjgs.utils.encryption; + +import sjgs.utils.Utils; + +public interface EncryptionInterface { + + public abstract String decrypt(); + public abstract String encrypt(); + public abstract void shred(); + @Override + public abstract String toString(); + + default String getMessage() { return toString(); } + default void print() { Utils.print(getMessage()); } + +} diff --git a/src/sjgs/utils/encryption/StrongCaesarCipher.java b/src/sjgs/utils/encryption/StrongCaesarCipher.java new file mode 100755 index 0000000..40b4154 --- /dev/null +++ b/src/sjgs/utils/encryption/StrongCaesarCipher.java @@ -0,0 +1,45 @@ +package sjgs.utils.encryption; + +/** @class: This is essentially a CaeserCipher for every character + * in the encrypted message. Much more secure and more + * truly "encrypted". Each letter in the message has + * its own randomly generated key */ +public class StrongCaesarCipher implements EncryptionInterface { + + private final CaesarCipher[] message; + + public StrongCaesarCipher(final String message) { + this.message = new CaesarCipher[message.length()]; + for(int i = 0; i < message.length(); i++) + this.message[i] = new CaesarCipher(""+message.charAt(i)); + } + + @Override + public String decrypt() { + for (final CaesarCipher element : message) + element.decrypt(); + return getMessage(); + } + + @Override + public String encrypt() { + for (final CaesarCipher element : message) + element.encrypt(); + return getMessage(); + } + + @Override + public void shred() { for (final CaesarCipher element : message) + element.shred(); } + + @Override + public String getMessage() { return toString(); } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + for (final CaesarCipher element : message) + sb.append(element.toString()); + return sb.toString(); + } +} diff --git a/src/sjgs/utils/io/SaveFile.java b/src/sjgs/utils/io/SaveFile.java new file mode 100755 index 0000000..110d7e8 --- /dev/null +++ b/src/sjgs/utils/io/SaveFile.java @@ -0,0 +1,36 @@ +package sjgs.utils.io; + +import java.io.Serializable; +import sjgs.core.Engine; + +public abstract class SaveFile extends __HandlerSaveState implements Serializable { + + // ----------- engine variables -------------- // + private final double engineTickInterval, engineFpsCap; + private final boolean engineDrawFPS; + // ------------------------------------------- // + + public SaveFile(final Engine engine) { + super(); + engineTickInterval = engine.getTickRate(); + engineFpsCap = engine.getFPS_CAP(); + engineDrawFPS = engine.getDrawFps(); + } + + public abstract void load(Engine engine); + + private void loadIntoEngine(final Engine engine) { + engine.setDrawFps(engineDrawFPS); + engine.setTickRate(engineTickInterval); + engine.setFPS_CAP(engineFpsCap); + } + + // returns success status + protected boolean loadEngineAndHandler(final Engine engine) { + try { loadIntoEngine(engine); + loadIntoHandler(); + return true; + } catch (final Exception e) { e.printStackTrace(); return false; } + } + +} \ No newline at end of file diff --git a/src/sjgs/utils/io/__HandlerSaveState.java b/src/sjgs/utils/io/__HandlerSaveState.java new file mode 100755 index 0000000..b5934c2 --- /dev/null +++ b/src/sjgs/utils/io/__HandlerSaveState.java @@ -0,0 +1,51 @@ + +package sjgs.utils.io; + +import java.io.Serializable; +import sjgs.base_objects.GameObject; +import sjgs.core.Handler; +import sjgs.utils.data_structures.Stack; +import sjgs.utils.data_structures.gaming.QuadTree; + +/** @HandlerSaveState: This is just for ease of use. Isn't entirely necessary. + * Just zips up all the @Handler data to be passed around. + * Easy to use! Just two no arg calls, the @constructor and + * then @method loadIntoHandler() */ + +class __HandlerSaveState implements Serializable { + + private final QuadTree stationary_hard_objects, stationary_soft_objects; + private final Stack players, mobs, bullets, mobile_hard_objects, mobile_soft_objects; + private final int TREE_OFFSET, TREE_BOUNDS; + + public __HandlerSaveState() { + stationary_hard_objects = Handler.stationary_hard_objects.clone(); + stationary_soft_objects = Handler.stationary_soft_objects.clone(); + players = Handler.players.clone(); + mobs = Handler.mobs.clone(); + bullets = Handler.bullets.clone(); + mobile_hard_objects = Handler.mobile_hard_objects.clone(); + mobile_soft_objects = Handler.mobile_soft_objects.clone(); + TREE_OFFSET = Handler.getTreeOffset(); + TREE_BOUNDS = Handler.getTreeBounds(); + + } + + protected boolean loadIntoHandler() { + try { Handler.clearAll(); + + Handler.stationary_hard_objects = stationary_hard_objects; + Handler.stationary_soft_objects = stationary_soft_objects; + Handler.players = players; + Handler.mobs = mobs; + Handler.bullets = bullets; + Handler.mobile_hard_objects = mobile_hard_objects; + Handler.mobile_soft_objects = mobile_soft_objects; + Handler.setBounds(TREE_BOUNDS); + Handler.setTreeOffset(TREE_OFFSET); + + return true; + + } catch (final Exception e) { e.printStackTrace(); return false; } + } +} \ No newline at end of file diff --git a/src/sjgs/utils/multithreading/Executable.java b/src/sjgs/utils/multithreading/Executable.java new file mode 100755 index 0000000..a07ea22 --- /dev/null +++ b/src/sjgs/utils/multithreading/Executable.java @@ -0,0 +1,3 @@ +package sjgs.utils.multithreading; + +public interface Executable { void execute(); } diff --git a/src/sjgs/utils/multithreading/Runner.java b/src/sjgs/utils/multithreading/Runner.java new file mode 100755 index 0000000..599332a --- /dev/null +++ b/src/sjgs/utils/multithreading/Runner.java @@ -0,0 +1,21 @@ +package sjgs.utils.multithreading; + +public class Runner extends Thread { + + private final Executable e; + + public Runner(final Executable e) { + super(); + this.e = e; + } + + public Runner(final Executable e, final String name) { + super(); + this.e = e; + setName(name); + } + + @Override + public void run() { try { e.execute(); } catch (final Exception e) { e.printStackTrace(); } } + +} diff --git a/src/sjgs/utils/multithreading/ThreadPool.java b/src/sjgs/utils/multithreading/ThreadPool.java new file mode 100755 index 0000000..912e96d --- /dev/null +++ b/src/sjgs/utils/multithreading/ThreadPool.java @@ -0,0 +1,47 @@ +package sjgs.utils.multithreading; + +import java.util.ArrayList; +import sjgs.utils.Utils; + +public class ThreadPool extends ThreadGroup { + + private final ArrayList taskQueue; + + public ThreadPool() { + super("ThreadPool"); + taskQueue = new ArrayList(); + setDaemon(true); + for (int i = 0; i < Utils.getNumProcessors(); i++) new PooledThread(this).start(); + } + + private synchronized Runnable getTask() { + while (taskQueue.isEmpty()) try { wait(); } catch (final InterruptedException e) { e.printStackTrace(); } + + return taskQueue.remove(0); + } + + public synchronized void runTask(final Runnable task) { + taskQueue.add(task); + notify(); + } + + private static class PooledThread extends Thread { + + private final ThreadPool pool; + + public PooledThread(final ThreadPool pool) { + super(pool, "PooledThread"); + this.pool = pool; + } + + @Override + public void run() { + while (!isInterrupted()) { + final Runnable task = pool.getTask(); + + try { task.run(); } catch (final Exception e) { e.printStackTrace(); } + } + } + } + +} diff --git a/src/sjgs/utils/pyutils/PyUtils.java b/src/sjgs/utils/pyutils/PyUtils.java new file mode 100755 index 0000000..f8e3747 --- /dev/null +++ b/src/sjgs/utils/pyutils/PyUtils.java @@ -0,0 +1,38 @@ +package sjgs.utils.pyutils; + + +import static sjgs.core.jython.Jython.pi; +import java.io.InputStream; +import org.python.core.Py; +import org.python.core.PyBoolean; +import org.python.core.PyFloat; +import org.python.core.PyFunction; +import org.python.core.PyInteger; +import org.python.core.PyObject; +import org.python.core.PySystemState; +import sjgs.core.jython.Jython; +import sjgs.utils.Utils; + +public class PyUtils { + + public static final PyBoolean True = Py.True, False = Py.False; + public static final PyInteger One = Py.One, Zero = Py.Zero; + + public static final synchronized void initializePySystem() { PySystemState.initialize(System.getProperties(), System.getProperties()); } + + public static final void execPyScript(final String filename) { + InputStream in = Utils.class.getResourceAsStream(filename); + Jython.pi.execfile(filename); + try { in.close(); in = null; } catch (final Exception e) { e.printStackTrace(); } + } + + public static PyFunction createPyFunction(String funcName) { return pi.get(funcName, PyFunction.class); } + + public static PyObject java2py(final Object o) { return Py.java2py(o); } + public static PyInteger int2py(final int i) { return new PyInteger(i); } + public static PyFloat float2py(final float f) { return new PyFloat(f); } + public static PyBoolean bool2py(final boolean b) { return b ? True : False; } + + public static Object tojava(final PyObject o, final Class c) { return Py.tojava(o, c); } + +} diff --git a/src/sjgs/utils/tools/Timer.java b/src/sjgs/utils/tools/Timer.java new file mode 100755 index 0000000..64e1dcb --- /dev/null +++ b/src/sjgs/utils/tools/Timer.java @@ -0,0 +1,26 @@ +package sjgs.utils.tools; + +public class Timer { + + // NOTE THESE VARIABLES ARE BASED ON HAVING A 60 TPS TICK METHOD! + public static final int SECOND = 60, MINUTE = SECOND*60; + + private final int duration; + private int timeRemaining; + private boolean paused; + + public Timer(final int duration) { this.duration = timeRemaining = duration; } + + public boolean tick() { return paused ? false : --timeRemaining <= 0; } + + public void reset() { timeRemaining = duration; } + + public void pause() { paused = true; } + + public void resume() { paused = false; } + + public void toggle() { paused = !paused; } + + public void destroy() { timeRemaining = 0; paused = false; } + +} diff --git a/src/sjgs/world_generation/Action.java b/src/sjgs/world_generation/Action.java new file mode 100755 index 0000000..c28b3c8 --- /dev/null +++ b/src/sjgs/world_generation/Action.java @@ -0,0 +1,7 @@ +package sjgs.world_generation; + +public interface Action { + + public abstract void run(int x, int y); + +} diff --git a/src/sjgs/world_generation/TileMap.java b/src/sjgs/world_generation/TileMap.java new file mode 100755 index 0000000..3b4f270 --- /dev/null +++ b/src/sjgs/world_generation/TileMap.java @@ -0,0 +1,52 @@ +package sjgs.world_generation; + +import static sjgs.graphics.Colors.voidColor; +import static sjgs.utils.Utils.loadImage; +import static sjgs.utils.Utils.print; +import static sjgs.utils.Utils.unpackBlue; +import static sjgs.utils.Utils.unpackGreen; +import static sjgs.utils.Utils.unpackRed; +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.util.HashMap; + +public class TileMap { + + private final HashMap table; + private final BufferedImage map; + private final int TILE_SIZE; + + public TileMap(final BufferedImage image, final int TILE_SIZE) { + map = image; + this.TILE_SIZE = TILE_SIZE; + table = new HashMap(); + } + /** @constructor: can also take a param as a string to load the image for you! */ + public TileMap(final String image_path, final int TILE_SIZE) { + map = loadImage(image_path); + this.TILE_SIZE = TILE_SIZE; + table = new HashMap(); + } + + public void setColorAction(final Color color, final Action action) { table.put(color, action); } + + public void generateWorld() { + try { + + for (int i = 0; i < map.getHeight(); i++) + for (int j = 0; j < map.getWidth(); j++) { + final int pixel = map.getRGB(i, j); + + final Color color = new Color(unpackRed(pixel), unpackGreen(pixel), unpackBlue(pixel)); + + // grab the Action from the HashMap, make the i, j be the x,y of the Action + if(color != voidColor) table.get(color).run(i, j); + } + + } catch (final ArrayIndexOutOfBoundsException e) { + print("The image must be square to be used as a TileMap." + "\n" + + "Hint: Use the void color to fill the rest of the square."); + } + } + +} \ No newline at end of file