Bläddra i källkod

Merge branch 'master' of git.hammerle.me:kjhammerle/path-game into tilemap

Kajetan Johannes Hammerle 5 år sedan
förälder
incheckning
1e08688965

+ 8 - 0
resources/config.txt

@@ -0,0 +1,8 @@
+Up Key: 87
+Down Key: 83
+Left Key: 65
+Right Key: 68
+Zoom In Key: 73
+Zoom Out Key: 79
+Confirm Key: 257
+Escape Key: 256

+ 0 - 0
res/energyBar.png → resources/energyBar.png


+ 0 - 0
res/energyBarGrey.png → resources/energyBarGrey.png


+ 45 - 40
src/pathgame/PathGame.java

@@ -3,35 +3,35 @@ package pathgame;
 import me.hammerle.snuviengine.api.IGame;
 import me.hammerle.snuviengine.api.Renderer;
 import pathgame.algorithm.TravellingSalesAlg;
+import pathgame.gameplay.Camera;
 import pathgame.gameplay.Gamestate;
 import pathgame.gameplay.Gamestates;
 import pathgame.gameplay.Keys;
-import pathgame.rendering.TileMapRenderer;
-import pathgame.tilemap.TileMap;
-import pathgame.tilemap.TileMapGenerator;
+import pathgame.gameplay.Level;
 import pathgame.gameplay.Player;
+import pathgame.rendering.TileMapRenderer;
 import pathgame.gameplay.menu.Menu;
 import pathgame.rendering.HUDRenderer;
 import pathgame.rendering.MenuRenderer;
 import pathgame.rendering.PlayerRenderer;
 import pathgame.rendering.TileRenderer;
+import pathgame.tilemap.TileMap;
 
 public class PathGame implements IGame
 {
+
     private final Gamestate gamestate = new Gamestate();
 
-    private final TileMapRenderer mapRenderer = new TileMapRenderer();
-    private TileMap map = TileMapGenerator.getMap(50, 50, 15);
+    private final Level level = new Level();
 
     private final PlayerRenderer playerRenderer = new PlayerRenderer();
-    private final Player player = new Player(10, 10);
+    private final TileMapRenderer mapRenderer = new TileMapRenderer();
 
     private final Menu menu = new Menu();
     private final MenuRenderer menuRenderer = new MenuRenderer();
     private final HUDRenderer hudRenderer = new HUDRenderer();
 
-    private float lastScale = 1.0f;
-    private float scale = 1.0f;
+    private final Camera cam = new Camera();
 
     public PathGame()
     {
@@ -40,40 +40,43 @@ public class PathGame implements IGame
     @Override
     public void tick()
     {
-        map.tick();
+        cam.tick(level);
+
+        level.getMap().tick();
         mapRenderer.tick();
         if(gamestate.getState() == Gamestates.GAMEPLAY)
         {
-            player.tick(map);
+            level.getPlayer().tick(level.getMap());
+            if(level.getPlayer().isMoving())
+            {
+                cam.reset();
+            }
         }
-        menu.tick(gamestate);
+        menu.tick(gamestate, level);
 
-        lastScale = scale;
-        if(Keys.ZOOM_IN_KEY.isDown())
-        {
-            scale *= 1.1f;
-        }
-        else if(Keys.ZOOM_OUT_KEY.isDown())
-        {
-            scale /= 1.1f;
-        }
-        
         if(Keys.TEST_KEY.getTime() == 1)
         {
-            map = TileMapGenerator.getMap(50, 50, 15);
-            System.out.println(map.getNumberOfTowns());
-            TravellingSalesAlg.calcSalesPathLen(map);
+            level.nextLevel();
+            TravellingSalesAlg.calcSalesPathLen(level.getMap());
         }
     }
 
     @Override
     public void renderTick(Renderer r, float lag)
     {
-        float interScale = lastScale + (scale - lastScale) * lag;
+        TileMap map = level.getMap();
+        Player player = level.getPlayer();
+
+        float zoomRestrictionX = r.getViewWidth() / (map.getWidth() * TileRenderer.TILE_SIZE);
+        float zoomRestrictionY = (r.getViewHeight() - HUDRenderer.OFFSET_Y) / (map.getHeight() * TileRenderer.TILE_SIZE);
+
+        cam.limitScale(Math.max(zoomRestrictionX, zoomRestrictionY));
+        float interScale = cam.getInterpolatedScale(lag);
+
         mapRenderer.setScale(interScale);
 
-        float offX = getMapOffsetX(r, lag, interScale);
-        float offY = getMapOffsetY(r, lag, interScale);
+        float offX = getMapOffsetX(map, player, r, lag, interScale);
+        float offY = getMapOffsetY(map, player, r, lag, interScale) + HUDRenderer.OFFSET_Y;
 
         mapRenderer.renderTick(map, r, false, offX, offY);
         switch(gamestate.getState())
@@ -85,44 +88,46 @@ public class PathGame implements IGame
             case MENU:
                 menuRenderer.renderTick(r, lag, menu);
                 break;
-
         }
     }
 
-    private float getMapOffsetX(Renderer r, float lag, float interScale)
+    private float getMapOffsetX(TileMap map, Player player, Renderer r, float lag, float interScale)
     {
         float ix = (player.getLastX() + (player.getX() - player.getLastX()) * lag) * interScale * TileRenderer.TILE_SIZE;
         float offX = (-ix + r.getViewWidth() * 0.5f) - TileRenderer.TILE_SIZE * 0.5f * interScale;
 
-        if(offX < -mapRenderer.getWidth(map) + r.getViewWidth())
+        float minOffX = -mapRenderer.getWidth(map) + r.getViewWidth();
+        if(offX < minOffX)
         {
-            return -mapRenderer.getWidth(map) + r.getViewWidth();
+            return cam.getCamOffsetX(minOffX, minOffX, lag, interScale);
         }
         else if(offX > 0.0f)
         {
-            return 0.0f;
+            return cam.getCamOffsetX(0.0f, minOffX, lag, interScale);
         }
-        return offX;
+        return cam.getCamOffsetX(offX, minOffX, lag, interScale);
     }
 
-    private float getMapOffsetY(Renderer r, float lag, float interScale)
+    private float getMapOffsetY(TileMap map, Player player, Renderer r, float lag, float interScale)
     {
+        float viewHeight = r.getViewHeight() - HUDRenderer.OFFSET_Y;
         float iy = (player.getLastY() + (player.getY() - player.getLastY()) * lag) * interScale * TileRenderer.TILE_SIZE;
-        float offY = (-iy + r.getViewHeight() * 0.5f) - TileRenderer.TILE_SIZE * 0.5f * interScale;
+        float offY = (-iy + viewHeight * 0.5f) - TileRenderer.TILE_SIZE * 0.5f * interScale;
 
-        if(offY < -mapRenderer.getHeight(map) + r.getViewHeight())
+        float minOffY = -mapRenderer.getHeight(map) + viewHeight;
+        if(offY < minOffY)
         {
-            return -mapRenderer.getHeight(map) + r.getViewHeight();
+            return cam.getCamOffsetY(minOffY, minOffY, lag, interScale);
         }
         else if(offY > 0.0f)
         {
-            return 0.0f;
+            return cam.getCamOffsetY(0.0f, minOffY, lag, interScale);
         }
-        return offY;
+        return cam.getCamOffsetY(offY, minOffY, lag, interScale);
     }
 
     @Override
     public void onStop()
     {
     }
-}
+}

+ 125 - 0
src/pathgame/gameplay/Camera.java

@@ -0,0 +1,125 @@
+package pathgame.gameplay;
+
+public class Camera
+{
+
+    private final static int CAM_SPEED = 64;
+
+    private float lastScale = 1.0f;
+    private float scale = 1.0f;
+
+    private float lastCamOffsetX = 0.0f;
+    private float lastCamOffsetY = 0.0f;
+    private float camOffsetX = 0.0f;
+    private float camOffsetY = 0.0f;
+
+    public void tick(Level level)
+    {
+        lastCamOffsetX = camOffsetX;
+        lastCamOffsetY = camOffsetY;
+        lastScale = scale;
+
+        if(Keys.ZOOM_IN_KEY.isDown())
+        {
+            scale *= 1.1f;
+        }
+        else if(Keys.ZOOM_OUT_KEY.isDown())
+        {
+            scale /= 1.1f;
+        }
+
+        if(!level.getPlayer().isMoving())
+        {
+            if(Keys.CAM_UP_KEY.isDown())
+            {
+                camOffsetY += CAM_SPEED;
+            }
+            if(Keys.CAM_DOWN_KEY.isDown())
+            {
+                camOffsetY -= CAM_SPEED;
+            }
+            if(Keys.CAM_LEFT_KEY.isDown())
+            {
+                camOffsetX += CAM_SPEED;
+            }
+            if(Keys.CAM_RIGHT_KEY.isDown())
+            {
+                camOffsetX -= CAM_SPEED;
+            }
+        }
+    }
+
+    public void limitScale(float zoomRestriction)
+    {
+        if(scale <= zoomRestriction)
+        {
+            scale = zoomRestriction;
+        }
+        if(lastScale <= zoomRestriction)
+        {
+            lastScale = zoomRestriction;
+        }
+
+    }
+    
+    public void reset()
+    {
+        camOffsetX = 0.0f;
+        camOffsetY = 0.0f;
+        lastCamOffsetX = 0.0f;
+        lastCamOffsetY = 0.0f;
+    }
+
+    public float getInterpolatedScale(float lag)
+    {
+        return lastScale + (scale - lastScale) * lag;
+    }
+    
+    public float getCamOffsetX(float offX, float minOffX, float lag, float interScale)
+    {
+        float interCamX = lastCamOffsetX + (camOffsetX - lastCamOffsetX) * lag;
+        if(offX + interCamX > 0.0f)
+        {
+            camOffsetX = -offX;
+            if(lastCamOffsetX > camOffsetX)
+            {
+                lastCamOffsetX = camOffsetX;
+            }
+            interCamX = lastCamOffsetX + (camOffsetX - lastCamOffsetX) * lag;
+        }
+        if(offX + interCamX < minOffX)
+        {
+            camOffsetX = minOffX - offX;
+            if(lastCamOffsetX < camOffsetX)
+            {
+                lastCamOffsetX = camOffsetX;
+            }
+            interCamX = lastCamOffsetX + (camOffsetX - lastCamOffsetX) * lag;
+        }
+        return offX + interCamX;
+    }
+    
+    public float getCamOffsetY(float offY, float minOffY, float lag, float interScale)
+    {
+        float interCamY = lastCamOffsetY + (camOffsetY - lastCamOffsetY) * lag;
+        if(offY + interCamY > 0.0f)
+        {
+            camOffsetY = -offY;
+            if(lastCamOffsetY > camOffsetY)
+            {
+                lastCamOffsetY = camOffsetY;
+            }
+            interCamY = lastCamOffsetY + (camOffsetY - lastCamOffsetY) * lag;
+        }
+        if(offY + interCamY < minOffY)
+        {
+            camOffsetY = minOffY - offY;
+            if(lastCamOffsetY < camOffsetY)
+            {
+                lastCamOffsetY = camOffsetY;
+            }
+            interCamY = lastCamOffsetY + (camOffsetY - lastCamOffsetY) * lag;
+        }
+        return offY + interCamY;
+    }
+}

+ 65 - 8
src/pathgame/gameplay/Keys.java

@@ -1,18 +1,75 @@
 package pathgame.gameplay;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
 import me.hammerle.snuviengine.api.KeyBinding;
 import me.hammerle.snuviengine.api.KeyHandler;
 import org.lwjgl.glfw.GLFW;
 
 public class Keys
 {
-    public static final KeyBinding UP_KEY = KeyHandler.register(GLFW.GLFW_KEY_W);
-    public static final KeyBinding DOWN_KEY = KeyHandler.register(GLFW.GLFW_KEY_S);
-    public static final KeyBinding LEFT_KEY = KeyHandler.register(GLFW.GLFW_KEY_A);
-    public static final KeyBinding RIGHT_KEY = KeyHandler.register(GLFW.GLFW_KEY_D);
-    public static final KeyBinding ZOOM_IN_KEY = KeyHandler.register(GLFW.GLFW_KEY_I);
-    public static final KeyBinding ZOOM_OUT_KEY = KeyHandler.register(GLFW.GLFW_KEY_O);
-    public static final KeyBinding CONFIRM_KEY = KeyHandler.register(GLFW.GLFW_KEY_ENTER);
-    public static final KeyBinding ESCAPE_KEY = KeyHandler.register(GLFW.GLFW_KEY_ESCAPE);
+
+    public static final KeyBinding UP_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_W);
+    public static final KeyBinding DOWN_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_S);
+    public static final KeyBinding LEFT_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_A);
+    public static final KeyBinding RIGHT_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_D);
+    public static final KeyBinding ZOOM_IN_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_I);
+    public static final KeyBinding ZOOM_OUT_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_O);
+    public static final KeyBinding CONFIRM_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_ENTER);
+    public static final KeyBinding ESCAPE_KEY;// = KeyHandler.register(GLFW.GLFW_KEY_ESCAPE);
+    public static final KeyBinding CAM_UP_KEY = KeyHandler.register(GLFW.GLFW_KEY_UP);
+    public static final KeyBinding CAM_DOWN_KEY = KeyHandler.register(GLFW.GLFW_KEY_DOWN);
+    public static final KeyBinding CAM_LEFT_KEY = KeyHandler.register(GLFW.GLFW_KEY_LEFT);
+    public static final KeyBinding CAM_RIGHT_KEY = KeyHandler.register(GLFW.GLFW_KEY_RIGHT);
     public static final KeyBinding TEST_KEY = KeyHandler.register(GLFW.GLFW_KEY_T);
+
+    public static final KeyBinding[] KEYS;
+    public static final String[] KEYNAMES =
+    {
+        "Up Key", "Down Key", "Left Key", "Right Key", "Zoom In Key", "Zoom Out Key", "Confirm Key", "Escape Key", //"Cam Up Key", "Cam Down Key", "Cam Left Key", "Cam Right Key"
+    };
+
+    static
+    {
+        String line[] = new String[KEYNAMES.length];
+        File f = new File("resources/config.txt");
+        System.out.println(f.getName());
+        if(f.exists())
+        {
+            FileReader reader = null;
+            try
+            {
+                reader = new FileReader(f);
+                BufferedReader bReader = new BufferedReader(reader);
+                for(int i = 0; i < KEYNAMES.length; ++i)
+                {
+                    try
+                    {
+                        line[i] = bReader.readLine();
+                    }
+                    catch(IOException ex)
+                    {
+                    }
+                }
+            }
+            catch(FileNotFoundException ex)
+            {
+            }
+        }
+        UP_KEY = KeyHandler.register(Integer.parseInt(line[0].substring(line[0].indexOf(":") + 2, line[0].length())));
+        DOWN_KEY = KeyHandler.register(Integer.parseInt(line[1].substring(line[1].indexOf(":") + 2, line[1].length())));
+        LEFT_KEY = KeyHandler.register(Integer.parseInt(line[2].substring(line[2].indexOf(":") + 2, line[2].length())));
+        RIGHT_KEY = KeyHandler.register(Integer.parseInt(line[3].substring(line[3].indexOf(":") + 2, line[3].length())));
+        ZOOM_IN_KEY = KeyHandler.register(Integer.parseInt(line[4].substring(line[4].indexOf(":") + 2, line[4].length())));
+        ZOOM_OUT_KEY = KeyHandler.register(Integer.parseInt(line[5].substring(line[5].indexOf(":") + 2, line[5].length())));
+        CONFIRM_KEY = KeyHandler.register(Integer.parseInt(line[6].substring(line[6].indexOf(":") + 2, line[6].length())));
+        ESCAPE_KEY = KeyHandler.register(Integer.parseInt(line[7].substring(line[7].indexOf(":") + 2, line[7].length())));
+        KEYS = new KeyBinding[]
+        {
+            UP_KEY, DOWN_KEY, LEFT_KEY, RIGHT_KEY, ZOOM_IN_KEY, ZOOM_OUT_KEY, CONFIRM_KEY, ESCAPE_KEY, //CAM_UP_KEY, CAM_DOWN_KEY, CAM_LEFT_KEY, CAM_RIGHT_KEY
+        };
+    }
 }

+ 45 - 0
src/pathgame/gameplay/Level.java

@@ -0,0 +1,45 @@
+package pathgame.gameplay;
+
+import pathgame.tilemap.TileMap;
+import pathgame.tilemap.TileMapGenerator;
+
+public final class Level
+{
+    private final Player player = new Player();
+    private int level = 1;
+    private TileMap map = null;
+    
+    public Level()
+    {
+        reset();
+    }
+    
+    public void nextLevel()
+    {
+        level++;
+        reset();
+    }
+    
+    public void reset()
+    {
+        player.reset();
+        map = TileMapGenerator.getMap(5 + 5 * level, 5 + 5 * level, level, 2 + level);
+        player.setEnergySupply(100); // ToDo: insert value of algorithm
+        player.setObjectivesAmount(map.getNumberOfTowns());
+    }
+
+    public TileMap getMap()
+    {
+        return map;
+    }
+
+    public Player getPlayer()
+    {
+        return player;
+    }
+
+    public int getLevel()
+    {
+        return level;
+    }
+}

+ 65 - 17
src/pathgame/gameplay/Player.java

@@ -9,7 +9,7 @@ public class Player
 {
     private static final float SPEED = 0.125f;
 
-    private PlayerAbilities abilities;
+    private PlayerAbilities abilities = PlayerAbilities.NORMAL;
 
     private float lastX = 0;
     private float lastY = 0;
@@ -21,18 +21,14 @@ public class Player
     private boolean isMoving = false;
     private int currSpeedSlowdown = 1;
 
-    private final int energySupply;
+    private int energySupply;
     private int energyUsed = 0;
-    private final int objectivesAmount;
+    private int objectivesAmount;
     private int objectivesVisited = 0;
     private final LinkedList<MinusStepsValues> steps = new LinkedList<>();
-    //private int minusEnergy = 0;
 
-    public Player(int energySupply, int objectivesAmount)
+    public Player()
     {
-        this.energySupply = energySupply;
-        this.objectivesAmount = objectivesAmount;
-        abilities = PlayerAbilities.NORMAL;
     }
 
     public float getLastX()
@@ -54,7 +50,7 @@ public class Player
     {
         return y;
     }
-    
+
     private void tickSteps()
     {
         Iterator<MinusStepsValues> iter = steps.iterator();
@@ -71,11 +67,11 @@ public class Player
     public void tick(TileMap map)
     {
         tickSteps();
-        
+
         int currentTileX = Math.round(x);
         int currentTileY = Math.round(y);
         Tile currentTile = map.getTile(currentTileX, currentTileY);
-        
+
         currSpeedSlowdown = currentTile.getEnergyCost(abilities);
         lastX = x;
         lastY = y;
@@ -87,8 +83,6 @@ public class Player
             if(isMoving)
             {
                 currentTile.onEnter(this, map, currentTileX, currentTileY);
-                ++objectivesVisited;//TODO check for objective
-                //System.out.print(map.getTile((int)x,(int) y).getEnergyCost());
                 steps.addLast(new MinusStepsValues(currSpeedSlowdown));
                 energyUsed += currSpeedSlowdown;
             }
@@ -158,8 +152,6 @@ public class Player
             }
             moveY = Math.min(moveY, d);
         }
-
-        //System.out.println(moveX);
         x += moveX;
         y += moveY;
     }
@@ -198,24 +190,80 @@ public class Player
     {
         return objectivesAmount;
     }
+    
+    public void setObjectivesAmount(int objectivesAmount)
+    {
+        this.objectivesAmount = objectivesAmount;
+    }
 
     public int getObjectivesVisited()
     {
         return objectivesVisited;
     }
+    
+    public void visitTown()
+    {
+        objectivesVisited++;
+    }
 
     public LinkedList<MinusStepsValues> getLastSteps()
     {
         return steps;
     }
-    
+
     public void setAbilities(PlayerAbilities playerAbilities)
     {
         abilities = playerAbilities;
     }
-    
+
     public PlayerAbilities getAbilities()
     {
         return abilities;
     }
+
+    public void setEnergySupply(int energySupply)
+    {
+        this.energySupply = energySupply;
+    }
+
+    public boolean hasWon()
+    {
+        return objectivesVisited >= objectivesAmount;
+    }
+
+    public boolean hasLost()
+    {
+        return energyUsed >= energySupply;
+    }
+
+    public void reset(int energySupply, int objectivesAmount, PlayerAbilities abilities)
+    {
+        lastX = 0;
+        lastY = 0;
+        x = 0;
+        y = 0;
+
+        velX = 0;
+        velY = 0;
+        isMoving = false;
+        currSpeedSlowdown = 1;
+
+        energyUsed = 0;
+
+        objectivesVisited = 0;
+        steps.clear();
+        this.energySupply = energySupply;
+        this.objectivesAmount = objectivesAmount;
+        this.abilities = abilities;
+    }
+
+    public void reset()
+    {
+        reset(1000, 10, PlayerAbilities.NORMAL);
+    }
+
+    public boolean isMoving()
+    {
+        return isMoving;
+    }
 }

+ 19 - 7
src/pathgame/gameplay/PlayerAbilities.java

@@ -2,6 +2,7 @@ package pathgame.gameplay;
 
 public class PlayerAbilities
 {
+    private final String name;
     private final int fasterGrass;
     private final int fasterForest;
     private final int fasterShallowWater;
@@ -10,9 +11,10 @@ public class PlayerAbilities
     private final int fasterMountain;
     private final int fasterSwamp;
     
-    public PlayerAbilities(int fasterGrass, int fasterForest, int fasterShallowWater, 
+    public PlayerAbilities(String name, int fasterGrass, int fasterForest, int fasterShallowWater, 
             int fasterDeepWater, int fasterHill, int fasterMountain, int fasterSwamp)
     {
+        this.name = name;
         this.fasterGrass = fasterGrass;
         this.fasterForest = fasterForest;
         this.fasterShallowWater = fasterShallowWater;
@@ -22,12 +24,17 @@ public class PlayerAbilities
         this.fasterSwamp = fasterSwamp;
     }
 
-    public final static PlayerAbilities NORMAL = new PlayerAbilities(0, 0, 0, 0, 0, 0, 0);
-    public final static PlayerAbilities HIKER = new PlayerAbilities(0, 0, 0, 0, 1, 0, 0);
-    public final static PlayerAbilities CLIMBER = new PlayerAbilities(0, 0, 0, 0, 0, 1, 0);
-    public final static PlayerAbilities FOREST = new PlayerAbilities(0, 1, 0, 0, 0, 0, 0);
-    public final static PlayerAbilities SWIMMER = new PlayerAbilities(0, 0, 2, 0, 0, 0, 0);
-    public final static PlayerAbilities SAILOR = new PlayerAbilities(0, 0, 0, 1, 0, 0, 0);
+    public final static PlayerAbilities NORMAL = new PlayerAbilities("Normal", 0, 0, 0, 0, 0, 0, 0);
+    public final static PlayerAbilities HIKER = new PlayerAbilities("Hiker", 0, 0, 0, 0, 1, 0, 0);
+    public final static PlayerAbilities CLIMBER = new PlayerAbilities("Climber", 0, 0, 0, 0, 0, 1, 0);
+    public final static PlayerAbilities HUNTER = new PlayerAbilities("Hunter", 0, 1, 0, 0, 0, 0, 0);
+    public final static PlayerAbilities SWIMMER = new PlayerAbilities("Swimmer", 0, 0, 2, 0, 0, 0, 0);
+    public final static PlayerAbilities SAILOR = new PlayerAbilities("Sailor", 0, 0, 0, 1, 0, 0, 0);
+    
+    public final static PlayerAbilities[] ABILITIES = new PlayerAbilities[] 
+    {
+        NORMAL, HIKER, CLIMBER, HUNTER, SWIMMER, SAILOR
+    };
 
     public int getFasterGrass()
     {
@@ -63,4 +70,9 @@ public class PlayerAbilities
     {
         return fasterSwamp;
     }
+
+    public String getName()
+    {
+        return name;
+    }
 }

+ 4 - 3
src/pathgame/gameplay/menu/BaseMenu.java

@@ -2,12 +2,13 @@ package pathgame.gameplay.menu;
 
 import pathgame.gameplay.Gamestate;
 import pathgame.gameplay.Keys;
+import pathgame.gameplay.Level;
 
 public abstract class BaseMenu
 {
     private final int id;
     private int index = 0;
-    public abstract MenuOption[] getOptions();
+    public abstract MenuButton[] getOptions();
     private int returnId;
     
     public BaseMenu(int id)
@@ -25,7 +26,7 @@ public abstract class BaseMenu
         return false;
     }
     
-    public int tick(Gamestate gamestate)
+    public int tick(Gamestate gamestate, Level level)
     {
         returnId = id;
         if(isUpPressed())
@@ -39,7 +40,7 @@ public abstract class BaseMenu
         }
         else if(isEnterPressed())
         {
-            getOptions()[index].run(gamestate);
+            getOptions()[index].run(gamestate, level);
         }
         if(returnId != id)
         {

+ 40 - 0
src/pathgame/gameplay/menu/CharacterMenu.java

@@ -0,0 +1,40 @@
+package pathgame.gameplay.menu;
+
+import pathgame.gameplay.Gamestates;
+import pathgame.gameplay.PlayerAbilities;
+
+public class CharacterMenu extends BaseMenu
+{
+
+    private final MenuButton[] options;
+
+    public CharacterMenu(int id, int mainId)
+    {
+        super(id);
+        options = new MenuButton[PlayerAbilities.ABILITIES.length + 1];
+        for(int i = 0; i < options.length - 1; ++i)
+        {
+            options[i] = getAbilityOption(PlayerAbilities.ABILITIES[i]);
+        }
+        options[options.length - 1] = new MenuButton("Back", (gamestate) ->
+        {
+            setReturnId(mainId);
+        });
+    }
+
+    private static MenuButton getAbilityOption(PlayerAbilities pa)
+    {
+        return new MenuButton(pa.getName(), (gamestate, level) ->
+        {
+            level.reset();
+            level.getPlayer().setAbilities(pa);
+            gamestate.setState(Gamestates.GAMEPLAY);
+        });
+    }
+
+    @Override
+    public MenuButton[] getOptions()
+    {
+        return options;
+    }
+}

+ 6 - 6
src/pathgame/gameplay/menu/EscMenu.java

@@ -5,23 +5,23 @@ import pathgame.gameplay.Gamestates;
 
 public class EscMenu extends BaseMenu
 {
-    private final MenuOption[] options;
+    private final MenuButton[] options;
     
     public EscMenu(int id, int mainId)
     {
         super(id);
         
-        options = new MenuOption[] 
+        options = new MenuButton[] 
         {
-            new MenuOption("Continue", (gamestate) -> 
+            new MenuButton("Continue", (gamestate) -> 
             {
                 gamestate.setState(Gamestates.GAMEPLAY);
             }),
-            new MenuOption("Main Menu", (gamestate) -> 
+            new MenuButton("Main Menu", (gamestate) -> 
             {
                 setReturnId(mainId);
             }),
-            new MenuOption("Exit", (gamestate) -> 
+            new MenuButton("Exit", (gamestate) -> 
             {
                 Engine.stop();
             }),
@@ -29,7 +29,7 @@ public class EscMenu extends BaseMenu
     }
 
     @Override
-    public MenuOption[] getOptions()
+    public MenuButton[] getOptions()
     {
         return options;
     }

+ 8 - 9
src/pathgame/gameplay/menu/MainMenu.java

@@ -1,27 +1,26 @@
 package pathgame.gameplay.menu;
 
 import me.hammerle.snuviengine.api.Engine;
-import pathgame.gameplay.Gamestates;
 
 public class MainMenu extends BaseMenu
 {
-    private final MenuOption[] options;
+    private final MenuButton[] options;
     
-    public MainMenu(int id, int optionsId)
+    public MainMenu(int id, int optionsId, int charaterId)
     {
         super(id);
         
-        options = new MenuOption[] 
+        options = new MenuButton[] 
         {
-            new MenuOption("Start", (gamestate) -> 
+            new MenuButton("Start", (gamestate) -> 
             {
-                gamestate.setState(Gamestates.GAMEPLAY);
+                setReturnId(charaterId);
             }),
-            new MenuOption("Options", (gamestate) -> 
+            new MenuButton("Options", (gamestate) -> 
             {
                 setReturnId(optionsId);
             }),
-            new MenuOption("Exit", (gamestate) -> 
+            new MenuButton("Exit", (gamestate) -> 
             {
                 Engine.stop();
             })
@@ -29,7 +28,7 @@ public class MainMenu extends BaseMenu
     }
 
     @Override
-    public MenuOption[] getOptions()
+    public MenuButton[] getOptions()
     {
         return options;
     }

+ 9 - 5
src/pathgame/gameplay/menu/Menu.java

@@ -3,12 +3,14 @@ package pathgame.gameplay.menu;
 import pathgame.gameplay.Gamestate;
 import pathgame.gameplay.Gamestates;
 import pathgame.gameplay.Keys;
+import pathgame.gameplay.Level;
 
 public class Menu
 {
     private final static int MAIN_ID;
     private final static int ESCAPE_ID;
     private final static int OPTION_ID;
+    private final static int CHARACTER_ID;
     
     static
     {
@@ -16,22 +18,24 @@ public class Menu
         MAIN_ID = id++;
         ESCAPE_ID = id++;
         OPTION_ID = id++;
+        CHARACTER_ID = id++;
     }
     
     private final BaseMenu[] menus = new BaseMenu[] 
     { 
-        new MainMenu(MAIN_ID, OPTION_ID), 
+        new MainMenu(MAIN_ID, OPTION_ID, CHARACTER_ID), 
         new EscMenu(ESCAPE_ID, MAIN_ID), 
-        new OptionMenu(OPTION_ID, MAIN_ID) 
+        new OptionMenu(OPTION_ID, MAIN_ID), 
+        new CharacterMenu(CHARACTER_ID, MAIN_ID) 
     };
     
     private int currentIndex = 0;
     
-    public void tick(Gamestate gamestate)
+    public void tick(Gamestate gamestate, Level level)
     {
         if(gamestate.getState() == Gamestates.MENU)
         {
-            currentIndex = menus[currentIndex].tick(gamestate);
+            currentIndex = menus[currentIndex].tick(gamestate, level);
             if(currentIndex == ESCAPE_ID && Keys.ESCAPE_KEY.getTime() == 1)
             {
                 gamestate.setState(Gamestates.GAMEPLAY);
@@ -45,7 +49,7 @@ public class Menu
         }
     }
     
-    public MenuOption[] getOptions()
+    public MenuButton[] getOptions()
     {
         return menus[currentIndex].getOptions();
     }

+ 33 - 0
src/pathgame/gameplay/menu/MenuButton.java

@@ -0,0 +1,33 @@
+package pathgame.gameplay.menu;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import pathgame.gameplay.Gamestate;
+import pathgame.gameplay.Level;
+
+public class MenuButton
+{
+    private final String name;
+    private final BiConsumer<Gamestate, Level> r;
+    
+    public MenuButton(String name, BiConsumer<Gamestate, Level> r)
+    {
+        this.name = name;
+        this.r = r;
+    }
+    
+    public MenuButton(String name, Consumer<Gamestate> r)
+    {
+        this(name, (gamestate, level) -> r.accept(gamestate));
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+    
+    public void run(Gamestate gamestate, Level level)
+    {
+        r.accept(gamestate, level);
+    }
+}

+ 0 - 26
src/pathgame/gameplay/menu/MenuOption.java

@@ -1,26 +0,0 @@
-package pathgame.gameplay.menu;
-
-import java.util.function.Consumer;
-import pathgame.gameplay.Gamestate;
-
-public class MenuOption
-{
-    private final String name;
-    private final Consumer<Gamestate> r;
-    
-    public MenuOption(String name, Consumer<Gamestate> r)
-    {
-        this.name = name;
-        this.r = r;
-    }
-
-    public String getName()
-    {
-        return name;
-    }
-    
-    public void run(Gamestate gamestate)
-    {
-        r.accept(gamestate);
-    }
-}

+ 48 - 40
src/pathgame/gameplay/menu/OptionMenu.java

@@ -1,59 +1,67 @@
 package pathgame.gameplay.menu;
 
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import me.hammerle.snuviengine.api.KeyBinding;
 import me.hammerle.snuviengine.api.KeyHandler;
 import pathgame.gameplay.Keys;
 
 public class OptionMenu extends BaseMenu
 {
-    private final MenuOption[] options; 
-    
+
+    private final MenuButton[] options;
+
     public OptionMenu(int id, int mainId)
     {
         super(id);
-        
-        options = new MenuOption[] 
+        int menuLength = Keys.KEYS.length;
+        options = new MenuButton[menuLength + 1];
+        for(int i = 0; i < menuLength; ++i)
         {
-            new MenuOption("Up Key", (gamestate) -> 
-            {
-                KeyHandler.rebind(Keys.UP_KEY);
-            }),
-            new MenuOption("Down Key", (gamestate) -> 
-            {
-                KeyHandler.rebind(Keys.DOWN_KEY);
-            }),
-            new MenuOption("Left Key", (gamestate) -> 
-            {
-                KeyHandler.rebind(Keys.LEFT_KEY);
-            }),
-            new MenuOption("Right Key", (gamestate) -> 
-            {
-                KeyHandler.rebind(Keys.RIGHT_KEY);
-            }),
-            new MenuOption("Escape Key", (gamestate) -> 
-            {
-                KeyHandler.rebind(Keys.ESCAPE_KEY);
-            }),
-            new MenuOption("Confirm Key", (gamestate) -> 
-            {
-                KeyHandler.rebind(Keys.CONFIRM_KEY);
-            }),
-            new MenuOption("Zoom In Key", (gamestate) -> 
+            options[i] = getButton(Keys.KEYNAMES[i], Keys.KEYS[i]);
+        }
+        options[menuLength] = new MenuButton("Back to Main Menu", (gamestate) ->
+        {
+            File f = new File("resources/config.txt");
+            if(!f.exists())
             {
-                KeyHandler.rebind(Keys.ZOOM_IN_KEY);
-            }),
-            new MenuOption("Zoom Out Key", (gamestate) -> 
+                try
+                {
+                    f.createNewFile();
+                }
+                catch(IOException ex)
+                {
+                }
+            }
+            FileWriter writer = null;
+            try
             {
-                KeyHandler.rebind(Keys.ZOOM_OUT_KEY);
-            }),
-            new MenuOption("Back to Main Menu", (gamestate) -> 
+                writer = new FileWriter(f);
+                int x = 0;
+                for(int i = 0; i < Keys.KEYS.length; ++i)
+                {
+                    writer.append(Keys.KEYNAMES[i] + ": " + String.valueOf(Keys.KEYS[i].getKey()) + "\n");
+                }
+                writer.close();
+            }
+            catch(IOException ex)
             {
-                setReturnId(mainId);
-            }),
-        };
+            }
+            setReturnId(mainId);
+        });
+    }
+
+    private MenuButton getButton(String name, KeyBinding key)
+    {
+        return new MenuButton(name, (gamestate) ->
+        {
+            KeyHandler.rebind(key);
+        });
     }
 
     @Override
-    public MenuOption[] getOptions()
+    public MenuButton[] getOptions()
     {
         return options;
     }
@@ -63,4 +71,4 @@ public class OptionMenu extends BaseMenu
     {
         return true;
     }
-}
+}

+ 4 - 3
src/pathgame/rendering/HUDRenderer.java

@@ -8,8 +8,9 @@ import pathgame.gameplay.Player;
 
 public class HUDRenderer
 {
-    private static final Texture ENERGYBAR = new Texture("res/energyBar.png");
-    private static final Texture ENERGYBARGREY = new Texture("res/energyBarGrey.png");
+    public static final float OFFSET_Y = 40;
+    private static final Texture ENERGYBAR = new Texture("resources/energyBar.png");
+    private static final Texture ENERGYBARGREY = new Texture("resources/energyBarGrey.png");
 
     public void renderTick(Renderer r, Player p, float lag)//TileMap map, TileMapRenderer map, float lag, float offX, float offY)
     {
@@ -32,7 +33,7 @@ public class HUDRenderer
         r.setTextureEnabled(false);
         r.setBlendingEnabled(true);
 
-        r.getColorRenderer().drawRectangle(0, 0, r.getViewWidth(), 20, 0x33_00_00_00);//ABGR
+        r.getColorRenderer().drawRectangle(0, 0, r.getViewWidth(), 20, 0xFF_00_00_00);//ABGR
     }
 
     void renderObjectiveTracker(Renderer r, Player p)

+ 7 - 19
src/pathgame/rendering/MenuRenderer.java

@@ -4,23 +4,11 @@ import me.hammerle.snuviengine.api.KeyBinding;
 import me.hammerle.snuviengine.api.Renderer;
 import pathgame.gameplay.Keys;
 import pathgame.gameplay.menu.Menu;
-import pathgame.gameplay.menu.MenuOption;
+import pathgame.gameplay.menu.MenuButton;
 
 public class MenuRenderer
 {
-    private final KeyBinding[] keys = new KeyBinding[]
-    {
-        Keys.UP_KEY,
-        Keys.DOWN_KEY,
-        Keys.LEFT_KEY,
-        Keys.RIGHT_KEY,
-        Keys.ESCAPE_KEY,
-        Keys.CONFIRM_KEY,
-        Keys.ZOOM_IN_KEY,
-        Keys.ZOOM_OUT_KEY
-    };
-
-    private final float keyWidths[] = new float[keys.length];
+    private final float keyWidths[] = new float[Keys.KEYS.length];
 
     public void renderTick(Renderer r, float lag, Menu menu)
     {
@@ -30,7 +18,7 @@ public class MenuRenderer
         r.updateMatrix();
         scale = 1.0f / scale;
 
-        MenuOption[] options = menu.getOptions();
+        MenuButton[] options = menu.getOptions();
 
         float lastGap = 10.0f;
         float baseBoxHeight = 300.0f * scale;
@@ -47,7 +35,7 @@ public class MenuRenderer
         r.setTextureEnabled(false);
         r.setBlendingEnabled(true);
 
-        r.getColorRenderer().drawRectangle(windowWidth * 0.10f, y - textBoxPaddingY * 0.5f, windowWidth * 0.90f, y + textBoxHeight + textBoxPaddingY * 0.5f, 0x33000000);
+        r.getColorRenderer().drawRectangle(windowWidth * 0.10f, y - textBoxPaddingY * 0.5f, windowWidth * 0.90f, y + textBoxHeight + textBoxPaddingY * 0.5f, 0x50000000);
 
         r.setTextureEnabled(true);
 
@@ -64,9 +52,9 @@ public class MenuRenderer
         else
         {
             float max = Float.MIN_VALUE;
-            for(int i = 0; i < keys.length; i++)
+            for(int i = 0; i < Keys.KEYS.length; i++)
             {
-                keyWidths[i] = r.getFontRenderer().getSize(getKeyName(keys[i])).getWidth();
+                keyWidths[i] = r.getFontRenderer().getSize(getKeyName(Keys.KEYS[i])).getWidth();
                 if(keyWidths[i] > max)
                 {
                     max = keyWidths[i];
@@ -77,7 +65,7 @@ public class MenuRenderer
             {
                 boolean active = menu.getActiveIndex() == i;
                 renderText(options[i].getName(), active, r, windowWidth, y, true);
-                r.getFontRenderer().drawString(windowWidth * 0.85f - max * 0.5f - keyWidths[i] * 0.5f, y, addColor(getKeyName(keys[i]), active));
+                r.getFontRenderer().drawString(windowWidth * 0.85f - max * 0.5f - keyWidths[i] * 0.5f, y, addColor(getKeyName(Keys.KEYS[i]), active));
                 y += step;
             }
             y += lastGap;

+ 6 - 7
src/pathgame/rendering/PlayerRenderer.java

@@ -20,7 +20,6 @@ public class PlayerRenderer
         r.translateTo(0.0f, 0.0f);
         r.updateMatrix();
 
-        //TODO: insert animations
         float yIndex;
         float baseX = (p.getLastX() + (p.getX() - p.getLastX()) * lag);
         float ix = baseX * mapR.getScale() * TileRenderer.TILE_SIZE + offX;
@@ -38,25 +37,25 @@ public class PlayerRenderer
         {
             //go right
             yIndex = 2;
-            tIndex = checkForAnimationIndex(baseX, 2);
+            tIndex = checkForAnimationIndex(baseX);
         }
         else if(p.getVelX() < 0)
         {
             //go left
             yIndex = 1;
-            tIndex = checkForAnimationIndex(baseX, 2);
+            tIndex = checkForAnimationIndex(baseX);
         }
         else if(p.getVelY() > 0)
         {
             //go down
             yIndex = 0;
-            tIndex = checkForAnimationIndex(baseY, 2);
+            tIndex = checkForAnimationIndex(baseY);
         }
         else if(p.getVelY() < 0)
         {
             //go up
             yIndex = 3;
-            tIndex = checkForAnimationIndex(baseY, 2);
+            tIndex = checkForAnimationIndex(baseY);
         }
         else
         {
@@ -67,8 +66,8 @@ public class PlayerRenderer
                 tIndex * 0.25f, yIndex * 0.25f, (tIndex + 1) * 0.25f, yIndex * 0.25f + 0.25f);
     }
 
-    private int checkForAnimationIndex(float base, int speed)
+    private int checkForAnimationIndex(float base)
     {
-        return (int) (Math.ceil(base / (0.125f / speed)) / 3)%4;
+        return ((int) (base * 4 * 2)) % 4;
     }
 }

+ 1 - 0
src/pathgame/tilemap/TileTown.java

@@ -12,6 +12,7 @@ public class TileTown extends Tile
     @Override
     public void onEnter(Player p, TileMap map, int x, int y)
     {
+        p.visitTown();
         System.out.println("Enter Town " + x + " " + y);
     }