瀏覽代碼

Merge remote-tracking branch 'origin/master' into algorithm

Leon Palluch 5 年之前
父節點
當前提交
60eb49f02b

+ 12 - 89
src/pathgame/PathGame.java

@@ -3,35 +3,23 @@ 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.gameplay.Level;
-import pathgame.gameplay.Player;
-import pathgame.rendering.TileMapRenderer;
 import pathgame.gameplay.menu.Menu;
-import pathgame.rendering.HUDRenderer;
+import pathgame.rendering.LevelRenderer;
 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 Level level = new Level();
-
-    private final PlayerRenderer playerRenderer = new PlayerRenderer();
-    private final TileMapRenderer mapRenderer = new TileMapRenderer();
-
+    private final LevelRenderer levelRenderer = new LevelRenderer();
+    
     private final Menu menu = new Menu();
     private final MenuRenderer menuRenderer = new MenuRenderer();
-    private final HUDRenderer hudRenderer = new HUDRenderer();
-
-    private final Camera cam = new Camera();
 
     public PathGame()
     {
@@ -40,20 +28,11 @@ public class PathGame implements IGame
     @Override
     public void tick()
     {
-        cam.tick(level, gamestate);
-
-        level.getMap().tick();
-        mapRenderer.tick();
-        if(gamestate.getState() == Gamestates.GAMEPLAY)
-        {
-            level.getPlayer().tick(level.getMap());
-            if(level.getPlayer().isMoving())
-            {
-                cam.reset();
-            }
-        }
+        level.tick(gamestate);
+        levelRenderer.tick(level, gamestate);
+        
         menu.tick(gamestate, level);
-
+        
         if(Keys.TEST_KEY.getTime() == 1)
         {
             level.nextLevel();
@@ -66,73 +45,17 @@ public class PathGame implements IGame
     {
         if(gamestate.is(Gamestates.MENU))
         {
-            lag = 0.0f;
-        }
-        
-        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(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())
-        {
-            case GAMEPLAY:
-                playerRenderer.renderTick(map, mapRenderer, r, player, lag, offX, offY);
-                hudRenderer.renderTick(r, player, lag);
-                break;
-            case MENU:
-                menuRenderer.renderTick(r, lag, menu);
-                break;
-        }
-    }
-
-    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;
-
-        float minOffX = -mapRenderer.getWidth(map) + r.getViewWidth();
-        if(offX < minOffX)
-        {
-            return cam.getCamOffsetX(minOffX, minOffX, lag, interScale);
-        }
-        else if(offX > 0.0f)
-        {
-            return cam.getCamOffsetX(0.0f, minOffX, lag, interScale);
-        }
-        return cam.getCamOffsetX(offX, minOffX, lag, 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 + viewHeight * 0.5f) - TileRenderer.TILE_SIZE * 0.5f * interScale;
-
-        float minOffY = -mapRenderer.getHeight(map) + viewHeight;
-        if(offY < minOffY)
-        {
-            return cam.getCamOffsetY(minOffY, minOffY, lag, interScale);
+            levelRenderer.renderTick(r, 0.0f, level, gamestate);
+            menuRenderer.renderTick(r, 0.0f, menu);
         }
-        else if(offY > 0.0f)
+        else
         {
-            return cam.getCamOffsetY(0.0f, minOffY, lag, interScale);
+            levelRenderer.renderTick(r, lag, level, gamestate);
         }
-        return cam.getCamOffsetY(offY, minOffY, lag, interScale);
     }
 
     @Override
     public void onStop()
     {
     }
-}
+}

+ 38 - 4
src/pathgame/gameplay/Level.java

@@ -8,18 +8,38 @@ public final class Level
     private final Player player = new Player();
     private int level = 1;
     private TileMap map = null;
-    
+    private boolean showScoreMenu = false;
+    private boolean showAfterScore = false;
+
     public Level()
     {
         reset();
     }
-    
+
+    public void tick(Gamestate gamestate)
+    {
+        map.tick();
+        if(gamestate.is(Gamestates.GAMEPLAY) && !showScoreMenu)
+        {
+            player.tick(map);
+        }
+        if(gamestate.is(Gamestates.GAMEPLAY) && !showScoreMenu && (player.hasLost() || player.hasWon()))
+        {
+            showScoreMenu = true;
+        }
+        else if(showScoreMenu && Keys.CONFIRM_KEY.getTime() == 1)
+        {
+            showScoreMenu = false;
+            showAfterScore = true;
+        }
+    }
+
     public void nextLevel()
     {
         level++;
         reset();
     }
-    
+
     public void reset()
     {
         player.reset();
@@ -42,4 +62,18 @@ public final class Level
     {
         return level;
     }
-}
+    
+    public boolean getShowAfterScore()
+    {
+        return showAfterScore;
+    }
+    
+    public void setShowAfterScore(boolean show)
+    {
+        showAfterScore = show;
+    }
+    public boolean getShowScoreMenu()
+    {
+        return showScoreMenu; 
+    }
+}

+ 21 - 8
src/pathgame/gameplay/Player.java

@@ -2,12 +2,14 @@ package pathgame.gameplay;
 
 import java.util.Iterator;
 import java.util.LinkedList;
+import me.hammerle.snuviengine.api.KeyBinding;
 import pathgame.tilemap.Tile;
 import pathgame.tilemap.TileMap;
 import pathgame.tilemap.Tiles;
 
 public class Player
 {
+
     private static final float SPEED = 0.125f;
 
     private PlayerAbilities abilities = PlayerAbilities.NORMAL;
@@ -21,6 +23,7 @@ public class Player
     private float velY = 0;
     private boolean isMoving = false;
     private int currSpeedSlowdown = 1;
+    private boolean isSailing = false;
 
     private int energySupply;
     private int energyUsed = 0;
@@ -72,7 +75,7 @@ public class Player
 
         int currentTileX = Math.round(x);
         int currentTileY = Math.round(y);
-        
+        //System.out.println(currentTileY + " " + y);
         //TODO: Bug beheben: Exception, wenn Spieler sofort an den unteren Levelrand geht (auch am rechten Levelrand)
         //ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
         //System.out.println(currentTileY);
@@ -82,7 +85,7 @@ public class Player
         currSpeedSlowdown = currentTile.getEnergyCost(abilities);
         lastX = x;
         lastY = y;
-        
+
         if(isOnTile())
         {
             velX = 0.0f;
@@ -96,25 +99,25 @@ public class Player
             isMoving = false;
         }
 
-        if(Keys.LEFT_KEY.isDown() && !isMoving && x > 0 && !map.getTile(currentTileX - 1, currentTileY).isBlockingMovement())
+        if(Keys.LEFT_KEY.isDown() && !isMoving && currentTileX > 0 && !map.getTile(currentTileX - 1, currentTileY).isBlockingMovement(this))
         {
             velX = -SPEED;
             isMoving = true;
             currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
-        else if(Keys.RIGHT_KEY.isDown() && !isMoving && x < map.getWidth() - 1 && !map.getTile(currentTileX + 1, currentTileY).isBlockingMovement())
+        else if(Keys.RIGHT_KEY.isDown() && !isMoving && currentTileX < map.getWidth() - 1 && !map.getTile(currentTileX + 1, currentTileY).isBlockingMovement(this))
         {
             velX = SPEED;
             isMoving = true;
             currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
-        else if(Keys.UP_KEY.isDown() && !isMoving && y > 0 && !map.getTile(currentTileX, currentTileY - 1).isBlockingMovement())
+        else if(Keys.UP_KEY.isDown() && !isMoving && currentTileY > 0 && !map.getTile(currentTileX, currentTileY - 1).isBlockingMovement(this))
         {
             velY = -SPEED;
             isMoving = true;
             currentTile.onLeave(this, map, currentTileX, currentTileY);
         }
-        else if(Keys.DOWN_KEY.isDown() && !isMoving && y < map.getHeight() - 1 && !map.getTile(currentTileX, currentTileY + 1).isBlockingMovement())
+        else if(Keys.DOWN_KEY.isDown() && !isMoving && currentTileY < map.getHeight() - 1 && !map.getTile(currentTileX, currentTileY + 1).isBlockingMovement(this))
         {
             velY = SPEED;
             isMoving = true;
@@ -197,7 +200,7 @@ public class Player
     {
         return objectivesAmount;
     }
-    
+
     public void setObjectivesAmount(int objectivesAmount)
     {
         this.objectivesAmount = objectivesAmount;
@@ -207,7 +210,7 @@ public class Player
     {
         return objectivesVisited;
     }
-    
+
     public void visitTown()
     {
         objectivesVisited++;
@@ -273,7 +276,17 @@ public class Player
     {
         return isMoving;
     }
+
+    public void switchSailing()
+    {
+        isSailing = !isSailing;
+    }
     
+    public boolean isSailing()
+    {
+        return isSailing;
+    }
+
     public Tile getCurrTile()
     {
         return currentTile;

+ 44 - 0
src/pathgame/gameplay/menu/AfterScoreMenu.java

@@ -0,0 +1,44 @@
+package pathgame.gameplay.menu;
+
+import pathgame.gameplay.Gamestates;
+
+public class AfterScoreMenu extends BaseMenu
+{
+
+    private final MenuButton[] options;
+
+    public AfterScoreMenu(int id, int mainId)
+    {
+        super(id);
+
+        options = new MenuButton[]
+        {
+            new MenuButton("Next Level", (gamestate, level) ->
+            {
+                level.nextLevel();
+                level.getPlayer().setAbilities(level.getPlayer().getAbilities());
+                gamestate.setState(Gamestates.GAMEPLAY);
+                level.setShowAfterScore(false);
+            }),
+            new MenuButton("Retry", (gamestate, level) ->
+            {
+                level.reset();
+                level.getPlayer().setAbilities(level.getPlayer().getAbilities());
+                gamestate.setState(Gamestates.GAMEPLAY);
+                level.setShowAfterScore(false);
+            }),
+            new MenuButton("Main Menu", (gamestate, level) ->
+            {
+                level.setShowAfterScore(false);
+                setReturnId(mainId);
+            }),
+        };
+    }
+
+    @Override
+    public MenuButton[] getOptions()
+    {
+        return options;
+    }
+
+}

+ 28 - 14
src/pathgame/gameplay/menu/Menu.java

@@ -11,7 +11,8 @@ public class Menu
     private final static int ESCAPE_ID;
     private final static int OPTION_ID;
     private final static int CHARACTER_ID;
-    
+    private final static int AFTER_SCORE_ID;
+
     static
     {
         int id = 0;
@@ -19,18 +20,20 @@ public class Menu
         ESCAPE_ID = id++;
         OPTION_ID = id++;
         CHARACTER_ID = id++;
+        AFTER_SCORE_ID = id++;
     }
-    
-    private final BaseMenu[] menus = new BaseMenu[] 
-    { 
-        new MainMenu(MAIN_ID, OPTION_ID, CHARACTER_ID), 
-        new EscMenu(ESCAPE_ID, MAIN_ID), 
-        new OptionMenu(OPTION_ID, MAIN_ID), 
-        new CharacterMenu(CHARACTER_ID, MAIN_ID) 
+
+    private final BaseMenu[] menus = new BaseMenu[]
+    {
+        new MainMenu(MAIN_ID, OPTION_ID, CHARACTER_ID),
+        new EscMenu(ESCAPE_ID, MAIN_ID),
+        new OptionMenu(OPTION_ID, MAIN_ID),
+        new CharacterMenu(CHARACTER_ID, MAIN_ID),
+        new AfterScoreMenu(AFTER_SCORE_ID, MAIN_ID)
     };
-    
+
     private int currentIndex = 0;
-    
+
     public void tick(Gamestate gamestate, Level level)
     {
         if(gamestate.getState() == Gamestates.MENU)
@@ -40,6 +43,11 @@ public class Menu
             {
                 gamestate.setState(Gamestates.GAMEPLAY);
             }
+            else if((currentIndex == OPTION_ID || currentIndex == CHARACTER_ID)
+                    && Keys.ESCAPE_KEY.getTime() == 1)
+            {
+                currentIndex = MAIN_ID;
+            }
         }
         else if(gamestate.getState() == Gamestates.GAMEPLAY && Keys.ESCAPE_KEY.getTime() == 1)
         {
@@ -47,23 +55,29 @@ public class Menu
             gamestate.setState(Gamestates.MENU);
             menus[currentIndex].resetIndex();
         }
+        else if(level.getShowAfterScore())
+        {
+            currentIndex = AFTER_SCORE_ID;
+            gamestate.setState(Gamestates.MENU);
+            menus[currentIndex].resetIndex();
+        }
     }
-    
+
     public MenuButton[] getOptions()
     {
         return menus[currentIndex].getOptions();
     }
-    
+
     public int getActiveIndex()
     {
         return menus[currentIndex].getActiveIndex();
     }
-    
+
     public boolean isOptionMenu()
     {
         return menus[currentIndex].isOptionMenu();
     }
-    
+
     public void showEscapeMenu()
     {
         currentIndex = ESCAPE_ID;

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

@@ -10,7 +10,6 @@ public class HUDRenderer
 {
     public static final float OFFSET_Y = 40;
     private static final Texture ENERGYBAR = new Texture("resources/energyBars.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)
     {
@@ -23,7 +22,6 @@ public class HUDRenderer
         renderEnergyBar(r, p);
         renderEnergyText(r, p);
         renderMinusEnergy(r, p, lag);
-
     }
 
     void renderHUDBackgound(Renderer r)
@@ -42,9 +40,7 @@ public class HUDRenderer
         r.setColorEnabled(true);
         r.setTextureEnabled(true);
 
-        //render ObjectiveTracker
         String objectiveTracker = String.valueOf(p.getObjectivesVisited()) + "/" + String.valueOf(p.getObjectivesAmount()) + " Towns";
-
         r.getFontRenderer().drawString(2, 6, objectiveTracker);
     }
 
@@ -70,11 +66,12 @@ public class HUDRenderer
         r.setBlendingEnabled(true);
 
         float energyPercent = 100 / (float) p.getEnergySupply() * (float) p.getEnergyLeft() / 100;
+        if(energyPercent<0)
+        {
+            energyPercent = 0;
+        }
         ENERGYBAR.bind();        
-        //ENERGYBARGREY.bind();
         r.getTextureRenderer().drawRectangle(100, 5, (r.getViewWidth() / 2 - 5), 17, 0, 0.0625f, 1, 0.0625f*2);
-
-        //ENERGYBAR.bind();
         r.getTextureRenderer().drawRectangle(100, 5, (((r.getViewWidth() / 2 - 5) - 100) * (energyPercent)) + 100, 17, 0, 0, 1 * energyPercent, 0.0625f);
 
     }

+ 96 - 0
src/pathgame/rendering/LevelRenderer.java

@@ -0,0 +1,96 @@
+package pathgame.rendering;
+
+import me.hammerle.snuviengine.api.Renderer;
+import pathgame.gameplay.Camera;
+import pathgame.gameplay.Gamestate;
+import pathgame.gameplay.Gamestates;
+import pathgame.gameplay.Level;
+import pathgame.gameplay.Player;
+import pathgame.tilemap.TileMap;
+
+public class LevelRenderer
+{
+    private final PlayerRenderer playerRenderer = new PlayerRenderer();
+    private final TileMapRenderer mapRenderer = new TileMapRenderer();
+    private final HUDRenderer hudRenderer = new HUDRenderer();
+    private final Camera cam = new Camera();
+    private final ScoreMenuRenderer scoreRenderer = new ScoreMenuRenderer();
+
+    public void tick(Level level, Gamestate gamestate)
+    {
+        cam.tick(level, gamestate);
+        mapRenderer.tick();
+        if(level.getPlayer().isMoving())
+        {
+            cam.reset();
+        }
+    }
+
+    public void renderTick(Renderer r, float lag, Level level, Gamestate gamestate)
+    {
+        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(map, player, r, lag, interScale);
+        float offY = getMapOffsetY(map, player, r, lag, interScale) + HUDRenderer.OFFSET_Y;
+
+        mapRenderer.renderTick(map, r, false, offX, offY);
+
+        if(gamestate.is(Gamestates.GAMEPLAY))
+        {
+            playerRenderer.renderTick(map, mapRenderer, r, player, lag, offX, offY);
+            if(!level.getShowScoreMenu())
+            {
+                hudRenderer.renderTick(r, player, lag);
+            }
+            else if(level.getShowScoreMenu())
+            {
+                scoreRenderer.renderTick(r, lag, level);
+            }
+        }
+
+    }
+
+    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;
+
+        float minOffX = -mapRenderer.getWidth(map) + r.getViewWidth();
+        if(offX < minOffX)
+        {
+            return cam.getCamOffsetX(minOffX, minOffX, lag, interScale);
+        }
+        else if(offX > 0.0f)
+        {
+            return cam.getCamOffsetX(0.0f, minOffX, lag, interScale);
+        }
+        return cam.getCamOffsetX(offX, minOffX, lag, 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 + viewHeight * 0.5f) - TileRenderer.TILE_SIZE * 0.5f * interScale;
+
+        float minOffY = -mapRenderer.getHeight(map) + viewHeight;
+        if(offY < minOffY)
+        {
+            return cam.getCamOffsetY(minOffY, minOffY, lag, interScale);
+        }
+        else if(offY > 0.0f)
+        {
+            return cam.getCamOffsetY(0.0f, minOffY, lag, interScale);
+        }
+        return cam.getCamOffsetY(offY, minOffY, lag, interScale);
+    }
+}

+ 4 - 2
src/pathgame/rendering/PlayerRenderer.java

@@ -66,8 +66,7 @@ public class PlayerRenderer
             yIndex = 0;
         }
         
-        
-        if(p.getCurrTile()== Tiles.DEEP_WATER) //TODO: check for shallowwater with ship port
+        if(p.isSailing())
         {
             yTexOff = 0.5f;
         }
@@ -76,6 +75,9 @@ public class PlayerRenderer
             xTexOff = 0.5f;
         }
         
+        float viewScale = r.getViewScale();
+        ix = (int) (ix * viewScale) / viewScale;
+        iy = (int) (iy * viewScale) / viewScale;
         
         r.getTextureRenderer().drawRectangle(ix, iy, ix + playerSize, iy + playerSize,
                 tIndex * 0.125f + xTexOff, yIndex * 0.125f + yTexOff,

+ 87 - 0
src/pathgame/rendering/ScoreMenuRenderer.java

@@ -0,0 +1,87 @@
+package pathgame.rendering;
+
+import me.hammerle.snuviengine.api.Renderer;
+import pathgame.gameplay.Level;
+
+public class ScoreMenuRenderer
+{
+    public void renderTick(Renderer r, float lag, Level level)
+    {
+        float windowWidth = r.getViewWidth();
+        float windowHeight = r.getViewHeight();
+        float paddingX = 30;
+        float paddingY = 50;
+        r.setMixColorEnabled(false);
+        r.setColorEnabled(true);
+        r.setTextureEnabled(false);
+        r.setBlendingEnabled(true);
+        r.getColorRenderer().drawRectangle(paddingX, paddingY, windowWidth - paddingX, windowHeight - paddingY, 0x90000000);
+
+        r.setTextureEnabled(true);
+        r.translateTo(0.0f, 0.0f);
+        float scale = scale(r, 1);
+
+        String message;
+
+        message = "&2" + String.valueOf(level.getPlayer().getEnergyUsed()) + "&f of &2"
+                + String.valueOf(level.getPlayer().getEnergySupply()) + "&f Energy used";
+        r.getFontRenderer().drawString((windowWidth * scale - getWidth(r, message)) / 2, (windowHeight * scale - getHeight(r, message)) / 2 - windowHeight * scale * 0.5f * 0.15f, message);
+
+        System.out.println((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply());
+        if((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply() < 0.5f)
+        {
+            message = "You were better than the algorithm!";
+        }
+        else if((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply() < 0.6f)
+        {
+            message = "Only 20% more energy use than the algorithm!";
+        }
+        else if((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply() < 0.75f)
+        {
+            message = "Only 50% more energy use than the algorithm!";
+        }
+        else if((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply() < 1)
+        {
+            message = "Only twice the energy use of the algorithm!";
+        }
+        else if((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply() > 1)
+        {
+            message = "More than twice the energy use of the algorithm!";
+        }
+
+        r.getFontRenderer().drawString((windowWidth * scale - getWidth(r, message)) / 2, (windowHeight * scale - getHeight(r, message)) / 2 - windowHeight * scale * 0.5f * (-0.15f), message);
+
+        scale = scale(r, 2);
+        if((float) level.getPlayer().getEnergyUsed() / level.getPlayer().getEnergySupply() < 1)
+        {
+
+            message = "Congratulations!";
+        }
+        else
+        {
+            message = "What a pity! Out of energy!";
+        }
+        r.getFontRenderer().drawString((windowWidth * scale - getWidth(r, message)) / 2, (windowHeight * scale - getHeight(r, message)) / 2, message);
+
+        message = "OK!";
+        r.getFontRenderer().drawString((windowWidth * scale - getWidth(r, message)) / 2, (windowHeight * scale - paddingY * scale - getHeight(r, message)) - 10, message);
+
+    }
+
+    private float getWidth(Renderer r, String s)
+    {
+        return r.getFontRenderer().getSize(s).getWidth();
+    }
+
+    private float getHeight(Renderer r, String s)
+    {
+        return r.getFontRenderer().getSize(s).getHeight();
+    }
+
+    private float scale(Renderer r, int scale)
+    {
+        r.scale(scale, scale);
+        r.updateMatrix();
+        return 1.0f / scale;
+    }
+}

+ 4 - 0
src/pathgame/rendering/TileMapRenderer.java

@@ -116,6 +116,10 @@ public class TileMapRenderer
             map.clean();
         }
         
+        float viewScale = r.getViewScale();
+        offX = (int) (offX * viewScale) / viewScale;
+        offY = (int) (offY * viewScale) / viewScale;
+        
         r.translateTo(offX, offY);
         r.scale(scale, scale);
         r.updateMatrix();

+ 25 - 4
src/pathgame/tilemap/Tile.java

@@ -17,6 +17,7 @@ public class Tile
         private Function<PlayerAbilities, Integer> speedUp = (pa) -> 0;
         private boolean canHostTown = true;
         private boolean blocksMovement = false;
+        private TileType type = TileType.LAND;
         
         private TileBuilder()
         {
@@ -57,9 +58,15 @@ public class Tile
             return this;
         }
         
+        public TileBuilder setType(TileType type)
+        {
+            this.type = type;
+            return this;
+        }
+        
         public Tile build()
         {
-            return new Tile(energyCost, forestReplaceChance, speedUp, canHostTown, blocksMovement);
+            return new Tile(energyCost, forestReplaceChance, speedUp, canHostTown, blocksMovement, type);
         }
     }
     
@@ -98,8 +105,10 @@ public class Tile
     private final Function<PlayerAbilities, Integer> speedUp;
     private final boolean canHostTown;
     private final boolean blocksMovement;
+    private final TileType type;
     
-    protected Tile(int energyCost, float forestReplaceChance, Function<PlayerAbilities, Integer> speedUp, boolean canHostTown, boolean blocksMovement)
+    protected Tile(int energyCost, float forestReplaceChance, Function<PlayerAbilities, Integer> speedUp, 
+            boolean canHostTown, boolean blocksMovement, TileType type)
     {
         id = addTile(this);
         this.energyCost = energyCost;
@@ -107,6 +116,7 @@ public class Tile
         this.speedUp = speedUp;
         this.canHostTown = canHostTown;
         this.blocksMovement = blocksMovement;
+        this.type = type;
     }
 
     /** Returns the id of the tile.
@@ -165,10 +175,21 @@ public class Tile
 
     /** Returns true if this tile blocks movement.
      *
+     * @param p the player
      * @return true if this tile blocks movement
      */
-    public boolean isBlockingMovement()
+    public boolean isBlockingMovement(Player p)
+    {
+        return blocksMovement || (p.isSailing() && type == TileType.LAND) || 
+                (!p.isSailing() && type == TileType.DEEP_WATER);
+    }
+    
+    /** Returns the type of the tile.
+     *
+     * @return the type of the tile
+     */
+    public TileType getType()
     {
-        return blocksMovement;
+        return type;
     }
 }

+ 17 - 0
src/pathgame/tilemap/TilePort.java

@@ -0,0 +1,17 @@
+package pathgame.tilemap;
+
+import pathgame.gameplay.Player;
+
+public class TilePort extends Tile
+{
+    public TilePort()
+    {
+        super(1, 0.0f, (pa) -> 0, false, false, TileType.PORT);
+    }
+
+    @Override
+    public void onEnter(Player p, TileMap map, int x, int y)
+    {
+        p.switchSailing();
+    }
+}

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

@@ -6,20 +6,18 @@ public class TileTown extends Tile
 {
     public TileTown()
     {
-        super(1, 0.0f, (pa) -> 0, false, false);
+        super(1, 0.0f, (pa) -> 0, false, false, TileType.LAND);
     }
 
     @Override
     public void onEnter(Player p, TileMap map, int x, int y)
     {
         p.visitTown();
-        System.out.println("Enter Town " + x + " " + y);
     }
 
     @Override
     public void onLeave(Player p, TileMap map, int x, int y)
     {
-        System.out.println("Leave Town " + x + " " + y);
         map.convertTown(x, y);
     }
 }

+ 6 - 0
src/pathgame/tilemap/TileType.java

@@ -0,0 +1,6 @@
+package pathgame.tilemap;
+
+public enum TileType
+{
+    PORT, LAND, SHALLOW_WATER, DEEP_WATER
+}

+ 3 - 5
src/pathgame/tilemap/Tiles.java

@@ -33,12 +33,14 @@ public class Tiles
             .setForestReplaceChance(0.0f)
             .setSpeedUp((pa) -> pa.getFasterShallowWater())
             .noTown()
+            .setType(TileType.SHALLOW_WATER)
             .build();
     public final static Tile DEEP_WATER = Tile.TileBuilder.create()
             .setEnergyCost(3)
             .setForestReplaceChance(0.0f)
             .setSpeedUp((pa) -> pa.getFasterDeepWater())
             .noTown()
+            .setType(TileType.DEEP_WATER)
             .build();
     public final static Tile HILL = Tile.TileBuilder.create()
             .setEnergyCost(3)
@@ -62,10 +64,7 @@ public class Tiles
         TOWN_BLOCKED_1, TOWN_BLOCKED_2, TOWN_BLOCKED_3, TOWN_BLOCKED_4
     };
     
-    public final static Tile PORT = Tile.TileBuilder.create()
-            .noTown()
-            .setForestReplaceChance(0.0f)
-            .build();
+    public final static Tile PORT = new TilePort();
     
     public final static Tile buildGrass()
     {
@@ -87,7 +86,6 @@ public class Tiles
         return Tile.TileBuilder.create()
                 .setForestReplaceChance(0.0f)
                 .noTown()
-                .noMovement()
                 .build();
     }
 }