initial commit
This commit is contained in:
160
src/sjgs/__example_games/__InventoryExample.java
Executable file
160
src/sjgs/__example_games/__InventoryExample.java
Executable file
@@ -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 :)
|
||||
}
|
||||
151
src/sjgs/__example_games/__LightingDemonstration.java
Executable file
151
src/sjgs/__example_games/__LightingDemonstration.java
Executable file
@@ -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!
|
||||
|
||||
}
|
||||
279
src/sjgs/__example_games/__PhysicsDemonstration.java
Executable file
279
src/sjgs/__example_games/__PhysicsDemonstration.java
Executable file
@@ -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) { }
|
||||
}
|
||||
|
||||
}
|
||||
67
src/sjgs/base_objects/BaseTile.java
Executable file
67
src/sjgs/base_objects/BaseTile.java
Executable file
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
43
src/sjgs/base_objects/Bullet.java
Executable file
43
src/sjgs/base_objects/Bullet.java
Executable file
@@ -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; }
|
||||
|
||||
}
|
||||
126
src/sjgs/base_objects/GameObject.java
Executable file
126
src/sjgs/base_objects/GameObject.java
Executable file
@@ -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(); }
|
||||
|
||||
}
|
||||
35
src/sjgs/base_objects/HardObject.java
Executable file
35
src/sjgs/base_objects/HardObject.java
Executable file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
44
src/sjgs/base_objects/Mob.java
Executable file
44
src/sjgs/base_objects/Mob.java
Executable file
@@ -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; }
|
||||
|
||||
}
|
||||
51
src/sjgs/base_objects/PlayerBase.java
Executable file
51
src/sjgs/base_objects/PlayerBase.java
Executable file
@@ -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; }
|
||||
|
||||
}
|
||||
35
src/sjgs/base_objects/SoftObject.java
Executable file
35
src/sjgs/base_objects/SoftObject.java
Executable file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
43
src/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py
Executable file
43
src/sjgs/base_objects/mob_ai/mob_travel_around_rectangle.py
Executable file
@@ -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())
|
||||
126
src/sjgs/core/Camera.java
Executable file
126
src/sjgs/core/Camera.java
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
157
src/sjgs/core/DeveloperConsole.java
Executable file
157
src/sjgs/core/DeveloperConsole.java
Executable file
@@ -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<String> 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<String>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
226
src/sjgs/core/Engine.java
Executable file
226
src/sjgs/core/Engine.java
Executable file
@@ -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; }
|
||||
}
|
||||
98
src/sjgs/core/Handler.java
Executable file
98
src/sjgs/core/Handler.java
Executable file
@@ -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<GameObject> players, mobs, bullets, mobile_hard_objects, mobile_soft_objects;
|
||||
public static Stack<Light> 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<GameObject>();
|
||||
mobile_soft_objects = new Stack<GameObject>();
|
||||
mobs = new Stack<GameObject>();
|
||||
bullets = new Stack<GameObject>();
|
||||
players = new Stack<GameObject>();
|
||||
|
||||
lights = new Stack<Light>();
|
||||
}
|
||||
|
||||
/** @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<GameObject> tempHards = stationary_hard_objects.toStack();
|
||||
final Stack<GameObject> 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();
|
||||
}
|
||||
|
||||
}
|
||||
55
src/sjgs/core/input/Keyboard.java
Executable file
55
src/sjgs/core/input/Keyboard.java
Executable file
@@ -0,0 +1,55 @@
|
||||
package sjgs.core.input;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public interface Keyboard {
|
||||
|
||||
static final HashSet<Integer> 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); }
|
||||
|
||||
|
||||
}
|
||||
56
src/sjgs/core/input/Mouse.java
Executable file
56
src/sjgs/core/input/Mouse.java
Executable file
@@ -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; }
|
||||
|
||||
}
|
||||
383
src/sjgs/core/input/__Keyboard.java
Executable file
383
src/sjgs/core/input/__Keyboard.java
Executable file
@@ -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<Integer> keysDown;
|
||||
|
||||
public void init(final JPanel panel) {
|
||||
keysDown = new HashSet<Integer>();
|
||||
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 ----------------------------------//
|
||||
}
|
||||
// ********************************************************************************************************************************** //
|
||||
|
||||
}
|
||||
37
src/sjgs/core/jython/Jython.java
Executable file
37
src/sjgs/core/jython/Jython.java
Executable file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
46
src/sjgs/core/jython/engine_imports.py
Executable file
46
src/sjgs/core/jython/engine_imports.py
Executable file
@@ -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
|
||||
7
src/sjgs/enums/Facing.java
Executable file
7
src/sjgs/enums/Facing.java
Executable file
@@ -0,0 +1,7 @@
|
||||
package sjgs.enums;
|
||||
|
||||
public enum Facing {
|
||||
|
||||
LEFT, RIGHT, ABOVE, BELOW, NONE
|
||||
|
||||
}
|
||||
7
src/sjgs/enums/TickRate.java
Executable file
7
src/sjgs/enums/TickRate.java
Executable file
@@ -0,0 +1,7 @@
|
||||
package sjgs.enums;
|
||||
|
||||
public enum TickRate {
|
||||
|
||||
_60, _120
|
||||
|
||||
}
|
||||
7
src/sjgs/enums/Type.java
Executable file
7
src/sjgs/enums/Type.java
Executable file
@@ -0,0 +1,7 @@
|
||||
package sjgs.enums;
|
||||
|
||||
public enum Type {
|
||||
|
||||
BULLET, HARD_OBJECT, MOB, PLAYER, SOFT_OBJECT, NONE
|
||||
|
||||
}
|
||||
100
src/sjgs/graphics/Animation.java
Executable file
100
src/sjgs/graphics/Animation.java
Executable file
@@ -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<BufferedImage> 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);
|
||||
}
|
||||
|
||||
}
|
||||
24
src/sjgs/graphics/Colors.java
Executable file
24
src/sjgs/graphics/Colors.java
Executable file
@@ -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;
|
||||
|
||||
}
|
||||
55
src/sjgs/graphics/backgrounds/Background.java
Executable file
55
src/sjgs/graphics/backgrounds/Background.java
Executable file
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
17
src/sjgs/graphics/backgrounds/ParallaxBackground.java
Executable file
17
src/sjgs/graphics/backgrounds/ParallaxBackground.java
Executable file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
32
src/sjgs/graphics/lighting/Light.java
Executable file
32
src/sjgs/graphics/lighting/Light.java
Executable file
@@ -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); }
|
||||
}
|
||||
31
src/sjgs/graphics/lighting/LightsRenderer.java
Executable file
31
src/sjgs/graphics/lighting/LightsRenderer.java
Executable file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
44
src/sjgs/graphics/lighting/RadialLight.java
Executable file
44
src/sjgs/graphics/lighting/RadialLight.java
Executable file
@@ -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; }
|
||||
}
|
||||
86
src/sjgs/graphics/ui/InventorySystem.java
Executable file
86
src/sjgs/graphics/ui/InventorySystem.java
Executable file
@@ -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<InventorySystemSlot> 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<InventorySystemSlot>();
|
||||
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<InventorySystemSlot> 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);
|
||||
}
|
||||
}
|
||||
55
src/sjgs/graphics/ui/InventorySystemSlot.java
Executable file
55
src/sjgs/graphics/ui/InventorySystemSlot.java
Executable file
@@ -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); }
|
||||
}
|
||||
15
src/sjgs/graphics/ui/Menu.java
Executable file
15
src/sjgs/graphics/ui/Menu.java
Executable file
@@ -0,0 +1,15 @@
|
||||
package sjgs.graphics.ui;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import sjgs.utils.data_structures.Stack;
|
||||
|
||||
public abstract class Menu {
|
||||
|
||||
public Stack<MenuButton> buttons;
|
||||
|
||||
public abstract void init();
|
||||
public abstract void tick();
|
||||
public abstract void render(Graphics2D g2d);
|
||||
public abstract void destroy();
|
||||
|
||||
}
|
||||
40
src/sjgs/graphics/ui/MenuButton.java
Executable file
40
src/sjgs/graphics/ui/MenuButton.java
Executable file
@@ -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()); }
|
||||
}
|
||||
100
src/sjgs/graphics/ui/__engine_inventory.py
Executable file
100
src/sjgs/graphics/ui/__engine_inventory.py
Executable file
@@ -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
|
||||
52
src/sjgs/physics/Physics.java
Executable file
52
src/sjgs/physics/Physics.java
Executable file
@@ -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<HardObject> 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(); }
|
||||
|
||||
}
|
||||
42
src/sjgs/physics/__BulletPhysics.java
Executable file
42
src/sjgs/physics/__BulletPhysics.java
Executable file
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
38
src/sjgs/physics/__Calculators.java
Executable file
38
src/sjgs/physics/__Calculators.java
Executable file
@@ -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<HardObject> 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;
|
||||
// }
|
||||
|
||||
}
|
||||
76
src/sjgs/physics/__Collision.java
Executable file
76
src/sjgs/physics/__Collision.java
Executable file
@@ -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<Type> types = new Stack<Type>();
|
||||
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<GameObject> hard_objects = new Stack<>();
|
||||
final Stack<GameObject> soft_objects = new Stack<>();
|
||||
final Stack<GameObject> bullets = new Stack<>();
|
||||
final Stack<GameObject> 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);
|
||||
}
|
||||
|
||||
}
|
||||
54
src/sjgs/physics/__Friction.java
Executable file
54
src/sjgs/physics/__Friction.java
Executable file
@@ -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; }
|
||||
|
||||
|
||||
}
|
||||
96
src/sjgs/physics/__GeneralCollision.java
Executable file
96
src/sjgs/physics/__GeneralCollision.java
Executable file
@@ -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<HardObject> collided_hard_objects) {
|
||||
final Stack<Rectangle> 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<Mob> 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<SoftObject> 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<Bullet> 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<PlayerBase> collided_players) {
|
||||
for(final PlayerBase p : collided_players) { if(p.getBounds() == obj.getBounds()) continue;
|
||||
calcDefaultHardCollision(obj, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/sjgs/physics/__Gravity.java
Executable file
33
src/sjgs/physics/__Gravity.java
Executable file
@@ -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; }
|
||||
|
||||
}
|
||||
29
src/sjgs/physics/__UpdatePosition.java
Executable file
29
src/sjgs/physics/__UpdatePosition.java
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
154
src/sjgs/physics/structs/BoundingBox.java
Executable file
154
src/sjgs/physics/structs/BoundingBox.java
Executable file
@@ -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(); }
|
||||
|
||||
}
|
||||
116
src/sjgs/physics/structs/CollisionResponse.java
Executable file
116
src/sjgs/physics/structs/CollisionResponse.java
Executable file
@@ -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<HardObject> collided_hard_objects;
|
||||
public Stack<SoftObject> collided_soft_objects;
|
||||
public Stack<Mob> collided_mobs;
|
||||
public Stack<Bullet> collided_bullets;
|
||||
public Stack<PlayerBase> collided_players;
|
||||
|
||||
public CollisionResponse(final GameObject obj, Stack<GameObject> hard_objects, Stack<GameObject> mobs, Stack<GameObject> bullets, Stack<GameObject> soft_objects) {
|
||||
|
||||
try {
|
||||
// CREATE STACKS
|
||||
collided_hard_objects = new Stack<HardObject>();
|
||||
collided_mobs = new Stack<Mob>();
|
||||
collided_bullets = new Stack<Bullet>();
|
||||
collided_soft_objects = new Stack<SoftObject>();
|
||||
collided_players = new Stack<PlayerBase>();
|
||||
Stack<HardObject> tempHardObjects = new Stack<HardObject>();
|
||||
Stack<Mob> tempMobs = new Stack<Mob>();
|
||||
Stack<Bullet> tempBullets = new Stack<Bullet>();
|
||||
Stack<SoftObject> tempSoftObjects = new Stack<SoftObject>();
|
||||
Stack<PlayerBase> tempPlayers = new Stack<PlayerBase>();
|
||||
|
||||
// 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<Boolean> bools = new Stack<Boolean>();
|
||||
|
||||
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<BaseTile> getTiles() {
|
||||
final Stack<BaseTile> tiles = new Stack<BaseTile>();
|
||||
for(final HardObject o : collided_hard_objects) if(o instanceof BaseTile) tiles.push((BaseTile)o);
|
||||
return tiles;
|
||||
}
|
||||
|
||||
}
|
||||
112
src/sjgs/sound/MusicPlayer.java
Executable file
112
src/sjgs/sound/MusicPlayer.java
Executable file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
42
src/sjgs/sound/SoundPlayer.java
Executable file
42
src/sjgs/sound/SoundPlayer.java
Executable file
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
281
src/sjgs/utils/Utils.java
Executable file
281
src/sjgs/utils/Utils.java
Executable file
@@ -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 <E> void print(final E e) { System.out.println(e); }
|
||||
public static final <E> void error(final E e) { System.err.println(e); }
|
||||
public static final <E> void print(final E[] arr) { for(final E e : arr) System.out.println(e); }
|
||||
public static final <E> 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<Rectangle> 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); }
|
||||
/********************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
}
|
||||
67
src/sjgs/utils/__Algorithms.java
Executable file
67
src/sjgs/utils/__Algorithms.java
Executable file
@@ -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<SimplePoint> points = new ArrayList<SimplePoint>();
|
||||
|
||||
// BRENSENHAM the line across
|
||||
final int dx = abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1;
|
||||
final int dy = -abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1;
|
||||
int err = dx+dy, e2; /* error value e_xy */
|
||||
|
||||
while(true){
|
||||
points.add(new SimplePoint(p1.x, p1.y));
|
||||
if (p1.x==p2.x && p1.y==p2.y) break;
|
||||
e2 = 2*err;
|
||||
if (e2 >= 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<SimplePoint> points = new ArrayList<SimplePoint>();
|
||||
|
||||
// BRENSENHAM the line across
|
||||
final int dx = (int)abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1;
|
||||
final int dy = (int)-abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1;
|
||||
int err = dx+dy, e2; /* error value e_xy */
|
||||
|
||||
while(true){
|
||||
points.add(new SimplePoint((int)p1.x, (int)p1.y));
|
||||
if (p1.x==p2.x && p1.y==p2.y) break;
|
||||
e2 = 2*err;
|
||||
if (e2 >= 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<SimplePoint> points = new ArrayList<SimplePoint>();
|
||||
|
||||
// BRENSENHAM the line across
|
||||
final int dx = abs(x2-x1), sx = x1<x2 ? 1 : -1;
|
||||
final int dy = -abs(y2-y1), sy = y1<y2 ? 1 : -1;
|
||||
int err = dx+dy, e2; /* error value e_xy */
|
||||
|
||||
while(true){
|
||||
points.add(new SimplePoint(x1, y1));
|
||||
if (x1==x2 && y1==y2) break;
|
||||
e2 = 2*err;
|
||||
if (e2 >= 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()]);
|
||||
}
|
||||
|
||||
}
|
||||
97
src/sjgs/utils/__ImageManipulation.java
Executable file
97
src/sjgs/utils/__ImageManipulation.java
Executable file
@@ -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; }
|
||||
/********************************************************************************************************/
|
||||
}
|
||||
59
src/sjgs/utils/__IntersectionUtils.java
Executable file
59
src/sjgs/utils/__IntersectionUtils.java
Executable file
@@ -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<Rectangle> rects = new Stack<Rectangle>();
|
||||
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<Rectangle> answers = new Stack<Rectangle>();
|
||||
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<Rectangle> args) {
|
||||
if(args.size() == 0) return null; if(args.size() == 1) return args.getFirst();
|
||||
final Stack<Rectangle> rects = new Stack<Rectangle>();
|
||||
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<Rectangle> answers = new Stack<Rectangle>();
|
||||
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); }
|
||||
|
||||
}
|
||||
66
src/sjgs/utils/__MixMaxUtils.java
Executable file
66
src/sjgs/utils/__MixMaxUtils.java
Executable file
@@ -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); }
|
||||
|
||||
}
|
||||
35
src/sjgs/utils/__SerializationUtils.java
Executable file
35
src/sjgs/utils/__SerializationUtils.java
Executable file
@@ -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(); }
|
||||
}
|
||||
}
|
||||
57
src/sjgs/utils/__TextFileManipulation.java
Executable file
57
src/sjgs/utils/__TextFileManipulation.java
Executable file
@@ -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();
|
||||
}
|
||||
}
|
||||
131
src/sjgs/utils/data_structures/Stack.java
Executable file
131
src/sjgs/utils/data_structures/Stack.java
Executable file
@@ -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<E> implements StackInterface<E> {
|
||||
|
||||
private Node<E> top;
|
||||
private int size;
|
||||
|
||||
public Stack(final E ...args) { combine(args); }
|
||||
public Stack(final Stack<E> 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<E> 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<E>(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<E> 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<E> temp = new Stack<E>();
|
||||
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<E> clone() {
|
||||
final Stack<E> clone = new Stack<E>();
|
||||
for(final E e : this) clone.push(e);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public Stack<Stack<E>> split() { return split(2); }
|
||||
public Stack<Stack<E>> split(final int parts) {
|
||||
if(size < parts) throw new NoSuchElementException();
|
||||
// CREATE STACK OF STACKS
|
||||
final Stack<Stack<E>> stacks = new Stack<Stack<E>>();
|
||||
for(int i = 0; i < parts; i++) stacks.push(new Stack<E>());
|
||||
|
||||
// FILL A TEMP STACK WITH CURRENT STACKS GOODS
|
||||
final Stack<E> temp = new Stack<E>();
|
||||
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<E> iterator() { return new StackIterator(); }
|
||||
public class StackIterator implements Iterator<E>, Serializable {
|
||||
private Node<E> 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<E> 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<E> implements Serializable {
|
||||
public final E data;
|
||||
public final Node<E> prev;
|
||||
public Node(final Node<E> prev, final E data) { this.prev = prev; this.data = data; }
|
||||
}
|
||||
// -------------- END NODE CLASS ------------------------------------------------- //
|
||||
|
||||
}
|
||||
231
src/sjgs/utils/data_structures/gaming/QuadTree.java
Executable file
231
src/sjgs/utils/data_structures/gaming/QuadTree.java
Executable file
@@ -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<GameObject> search(final float xmin, final float ymin, final float xmax, final float ymax) {
|
||||
final Stack<GameObject> stack = new Stack<GameObject>();
|
||||
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<GameObject> toStack() {
|
||||
final Stack<GameObject> stack = new Stack<GameObject>();
|
||||
traverse(root, (node) -> stack.push(node.getData().getGameObject()));
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QuadTree clone() {
|
||||
final Stack<GameObject> 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; }
|
||||
}
|
||||
|
||||
}
|
||||
37
src/sjgs/utils/data_structures/interfaces/ListInterface.java
Executable file
37
src/sjgs/utils/data_structures/interfaces/ListInterface.java
Executable file
@@ -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<E> extends Iterable<E>, 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); }
|
||||
}
|
||||
|
||||
}
|
||||
67
src/sjgs/utils/data_structures/interfaces/StackInterface.java
Executable file
67
src/sjgs/utils/data_structures/interfaces/StackInterface.java
Executable file
@@ -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<E> extends Iterable<E>, 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<E> stack) { for(final E e : stack) push(e); }
|
||||
default void combine(final Stack<E> ...args) { for(final Stack<E> 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<E> temp = new Stack<E>();
|
||||
while(!isEmpty()) temp.push(removeFirst());
|
||||
while(!temp.isEmpty()) push(temp.pop());
|
||||
}
|
||||
|
||||
default void shuffle() {
|
||||
final Stack<E> temp = new Stack<E>();
|
||||
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(); }
|
||||
|
||||
}
|
||||
41
src/sjgs/utils/data_structures/shapes/Circle.java
Executable file
41
src/sjgs/utils/data_structures/shapes/Circle.java
Executable file
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
63
src/sjgs/utils/data_structures/shapes/Line.java
Executable file
63
src/sjgs/utils/data_structures/shapes/Line.java
Executable file
@@ -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 ------------------------------------------------------------------------------------ //
|
||||
|
||||
|
||||
}
|
||||
120
src/sjgs/utils/data_structures/shapes/Rectangle.java
Executable file
120
src/sjgs/utils/data_structures/shapes/Rectangle.java
Executable file
@@ -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()); }
|
||||
|
||||
}
|
||||
24
src/sjgs/utils/data_structures/shapes/Triangle.java
Executable file
24
src/sjgs/utils/data_structures/shapes/Triangle.java
Executable file
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
56
src/sjgs/utils/data_structures/vectors/Point2f.java
Executable file
56
src/sjgs/utils/data_structures/vectors/Point2f.java
Executable file
@@ -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; }
|
||||
|
||||
|
||||
}
|
||||
15
src/sjgs/utils/data_structures/vectors/SimplePoint.java
Executable file
15
src/sjgs/utils/data_structures/vectors/SimplePoint.java
Executable file
@@ -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); }
|
||||
|
||||
}
|
||||
39
src/sjgs/utils/data_structures/vectors/Vector2f.java
Executable file
39
src/sjgs/utils/data_structures/vectors/Vector2f.java
Executable file
@@ -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); }
|
||||
|
||||
}
|
||||
57
src/sjgs/utils/encryption/CaesarCipher.java
Executable file
57
src/sjgs/utils/encryption/CaesarCipher.java
Executable file
@@ -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); }
|
||||
|
||||
}
|
||||
16
src/sjgs/utils/encryption/EncryptionInterface.java
Executable file
16
src/sjgs/utils/encryption/EncryptionInterface.java
Executable file
@@ -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()); }
|
||||
|
||||
}
|
||||
45
src/sjgs/utils/encryption/StrongCaesarCipher.java
Executable file
45
src/sjgs/utils/encryption/StrongCaesarCipher.java
Executable file
@@ -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();
|
||||
}
|
||||
}
|
||||
36
src/sjgs/utils/io/SaveFile.java
Executable file
36
src/sjgs/utils/io/SaveFile.java
Executable file
@@ -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; }
|
||||
}
|
||||
|
||||
}
|
||||
51
src/sjgs/utils/io/__HandlerSaveState.java
Executable file
51
src/sjgs/utils/io/__HandlerSaveState.java
Executable file
@@ -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<GameObject> 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; }
|
||||
}
|
||||
}
|
||||
3
src/sjgs/utils/multithreading/Executable.java
Executable file
3
src/sjgs/utils/multithreading/Executable.java
Executable file
@@ -0,0 +1,3 @@
|
||||
package sjgs.utils.multithreading;
|
||||
|
||||
public interface Executable { void execute(); }
|
||||
21
src/sjgs/utils/multithreading/Runner.java
Executable file
21
src/sjgs/utils/multithreading/Runner.java
Executable file
@@ -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(); } }
|
||||
|
||||
}
|
||||
47
src/sjgs/utils/multithreading/ThreadPool.java
Executable file
47
src/sjgs/utils/multithreading/ThreadPool.java
Executable file
@@ -0,0 +1,47 @@
|
||||
package sjgs.utils.multithreading;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import sjgs.utils.Utils;
|
||||
|
||||
public class ThreadPool extends ThreadGroup {
|
||||
|
||||
private final ArrayList<Runnable> taskQueue;
|
||||
|
||||
public ThreadPool() {
|
||||
super("ThreadPool");
|
||||
taskQueue = new ArrayList<Runnable>();
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
38
src/sjgs/utils/pyutils/PyUtils.java
Executable file
38
src/sjgs/utils/pyutils/PyUtils.java
Executable file
@@ -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 <T> Object tojava(final PyObject o, final Class<T> c) { return Py.tojava(o, c); }
|
||||
|
||||
}
|
||||
26
src/sjgs/utils/tools/Timer.java
Executable file
26
src/sjgs/utils/tools/Timer.java
Executable file
@@ -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; }
|
||||
|
||||
}
|
||||
7
src/sjgs/world_generation/Action.java
Executable file
7
src/sjgs/world_generation/Action.java
Executable file
@@ -0,0 +1,7 @@
|
||||
package sjgs.world_generation;
|
||||
|
||||
public interface Action {
|
||||
|
||||
public abstract void run(int x, int y);
|
||||
|
||||
}
|
||||
52
src/sjgs/world_generation/TileMap.java
Executable file
52
src/sjgs/world_generation/TileMap.java
Executable file
@@ -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<Color, Action> 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<Color, Action>();
|
||||
}
|
||||
/** @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<Color, Action>();
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user