Browse Source

Umherziehen, speichern und laden der Tiles möglich

Jan 6 months ago
parent
commit
a48b9ce17b

+ 156 - 17
src/main/java/controller/GameController.java

@@ -2,16 +2,21 @@ package controller;
 
 import controller.entity.EntityController;
 import controller.entity.VillagerController;
+import controller.factories.EntityFactory;
+import controller.factories.InteractiveTileFactory;
 import controller.tiles.interactive.*;
 import controller.tiles.interactive.upgradeable.*;
 import model.GameModel;
 import model.GameSaver;
 import model.entity.EntityModel;
+import model.entity.EntityType;
 import model.items.Item;
 import model.items.ITEM_NAME;
 import model.tiles.InteractiveTileModel;
+import model.tiles.InteractiveTileType;
 import util.GAMESTATE;
 import view.GamePanel;
+import view.tile.interactive.InteractiveTileView;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -28,6 +33,9 @@ public class GameController implements Runnable, Serializable {
     private transient GamePanel view;
     public transient ArrayList<EntityController> entityControllers;
     public transient ArrayList<InteractiveTileController> interactiveTileControllers;
+    private transient InteractiveTileController draggingTile;
+    private transient int residualShiftX, residualShiftY;
+
 
     public GameController() {
         this.keyHandler = new KeyHandler(this);
@@ -42,27 +50,27 @@ public class GameController implements Runnable, Serializable {
     }
 
     private void setupInteractiveTiles() {
-        LighthouseController lighthouse = new LighthouseController(this, setupInteractiveTileModel(20, 20));
+        LighthouseController lighthouse = new LighthouseController(this, setupInteractiveTileModel(20, 20, InteractiveTileType.LIGHTHOUSE));
         addInteractiveTile(lighthouse);
 
-        MineController mineController = new MineController(this, setupInteractiveTileModel(25,20));
+        MineController mineController = new MineController(this, setupInteractiveTileModel(25,20, InteractiveTileType.MINE));
         addInteractiveTile(mineController);
 
-        BarracksController barracksController = new BarracksController(this, setupInteractiveTileModel(26, 20));
+        BarracksController barracksController = new BarracksController(this, setupInteractiveTileModel(26, 20, InteractiveTileType.BARRACKS));
         addInteractiveTile(barracksController);
 
-        IronMineController ironMineController = new IronMineController(this, setupInteractiveTileModel(27, 20));
+        IronMineController ironMineController = new IronMineController(this, setupInteractiveTileModel(27, 20, InteractiveTileType.IRON_MINE));
         addInteractiveTile(ironMineController);
 
-        AnimalEnclosureController animal = new AnimalEnclosureController(this, setupInteractiveTileModel(28, 20));
+        AnimalEnclosureController animal = new AnimalEnclosureController(this, setupInteractiveTileModel(28, 20, InteractiveTileType.ANIMAL_ENCLOSURE));
         addInteractiveTile(animal);
 
-        SawmillController sawmillController = new SawmillController(this, setupInteractiveTileModel(29, 20));
+        SawmillController sawmillController = new SawmillController(this, setupInteractiveTileModel(29, 20, InteractiveTileType.SAWMILL));
         addInteractiveTile(sawmillController);
     }
 
     private void setupEntities(){
-        VillagerController villager = new VillagerController(this, setupEntityModel(22,20));
+        VillagerController villager = new VillagerController(this, setupEntityModel(22,20, EntityType.VILLAGER));
         addEntity(villager);
     }
 
@@ -74,14 +82,14 @@ public class GameController implements Runnable, Serializable {
         interactiveTileControllers.add(controller);
     }
 
-    private EntityModel setupEntityModel(int worldX, int worldY) {
-        EntityModel model = new EntityModel(worldX, worldY, getView().tileSize, getView().tileSize);
+    private EntityModel setupEntityModel(int worldX, int worldY, EntityType type) {
+        EntityModel model = new EntityModel(worldX, worldY, getView().tileSize, getView().tileSize, type);
         gameModel.addEntityModel(model);
         return model;
     }
 
-    public InteractiveTileModel setupInteractiveTileModel(int worldGridX, int worldGridY){
-        InteractiveTileModel model = new InteractiveTileModel(worldGridX, worldGridY);
+    public InteractiveTileModel setupInteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type){
+        InteractiveTileModel model = new InteractiveTileModel(worldGridX, worldGridY, type);
         gameModel.addInteractiveTileModel(model);
         return model;
     }
@@ -151,6 +159,7 @@ public class GameController implements Runnable, Serializable {
     }
 
     private void moveEntities() {
+        if(entityControllers == null) return;
         for(EntityController entityController : entityControllers){
             entityController.convertRepaintSpeedToMovementLogic();
         }
@@ -196,12 +205,6 @@ public class GameController implements Runnable, Serializable {
         return keyHandler;
     }
 
-
-    public void loadInteractiveTiles() {
-        interactiveTileControllers = new ArrayList<>();
-        setupInteractiveTiles();
-    }
-
     public void loadWorld(){
         if(view == null) this.view = new GamePanel(this);
         view.loadMap(worldPath);
@@ -209,4 +212,140 @@ public class GameController implements Runnable, Serializable {
     public void generateNewWorld() {
         view.generateNewWorld();
     }
+
+    public void handleTileShift(int dx, int dy) {
+        if (draggingTile == null) {
+            return;
+        }
+        // Accumulate residual pixel movement:
+        residualShiftX += dx;
+        residualShiftY += dy;
+
+        int tileSize = getView().tileSize;
+
+        // Compute whole-tile shifts:
+        int gridShiftX = residualShiftX / tileSize;
+        int gridShiftY = residualShiftY / tileSize;
+
+        if (gridShiftX == 0 && gridShiftY == 0) {
+            return; // not enough movement yet
+        }
+
+        // Subtract the used pixels, keep leftover:
+        residualShiftX -= gridShiftX * tileSize;
+        residualShiftY -= gridShiftY * tileSize;
+
+        // Now shift the stored tile model:
+        InteractiveTileModel model = draggingTile.getModel();
+        int oldX = model.getWorldGridX();
+        int oldY = model.getWorldGridY();
+        int newX = oldX + gridShiftX;
+        int newY = oldY + gridShiftY;
+
+        // OPTIONAL: check bounds/collisions before applying:
+        if (!isValidPosition(newX, newY)) {
+            // If invalid, you may want to revert residuals or clamp:
+            // e.g., undo the part of residual that caused invalid shift:
+            // residualShiftX += gridShiftX * tileSize;
+            // residualShiftY += gridShiftY * tileSize;
+            //System.out.printf("Cannot shift tile to (%d,%d): out of bounds or collision%n", newX, newY);
+            return;
+        }
+
+        model.setWorldGridX(newX);
+        model.setWorldGridY(newY);
+        //System.out.printf("Tile shifted from (%d, %d) to (%d, %d)%n", oldX, oldY, newX, newY);
+    }
+
+    private boolean isValidPosition(int newX, int newY) {
+        if (draggingTile == null) return false;
+
+        InteractiveTileModel model = draggingTile.getModel();
+        InteractiveTileView view = draggingTile.getView();
+
+        int width = view.getScaleX();  // how many tiles wide
+        int height = view.getScaleY(); // how many tiles high
+
+        // Check if tile stays within world bounds
+        if (newX < 0 || newY < 0 ||
+                newX + width > GamePanel.maxWorldCol ||
+                newY + height > GamePanel.maxWorldRow) {
+            return false;
+        }
+
+        // Check each tile the dragged tile would occupy
+        for (int x = newX; x < newX + width; x++) {
+            for (int y = newY; y < newY + height; y++) {
+                InteractiveTileController occupyingTile = getTileAt(x, y);
+                if (occupyingTile != null && occupyingTile != draggingTile) {
+                    return false; // collision
+                }
+            }
+        }
+
+        return true;
+    }
+
+    // Hilfsmethoden, um von Screen-Koordinaten in Weltkoordinaten umzurechnen
+    public int screenToWorldX(int screenX) {
+        return (int)((getView().camera.worldX + screenX - getView().camera.screenX) / getView().tileSize);
+    }
+
+    public int screenToWorldY(int screenY) {
+        return (int)((getView().camera.worldY + screenY - getView().camera.screenY) / getView().tileSize);
+    }
+
+    // Methode, um das Tile unter der aktuellen Weltposition zu bekommen
+    public InteractiveTileController getTileAt(int worldX, int worldY) {
+        for (InteractiveTileController tile : interactiveTileControllers) {
+            InteractiveTileModel model = tile.getModel();
+
+            if (   (worldX >= model.getWorldGridX()
+                    && worldX < model.getWorldGridX() + tile.getView().getScaleX()
+                    && worldY >= model.getWorldGridY()
+                    && worldY < model.getWorldGridY() + tile.getView().getScaleY())
+                    || (worldX == model.getWorldGridX() && worldY == model.getWorldGridY())) {
+                return tile;
+            }
+        }
+        return null;
+    }
+
+    public void setDraggingTile(InteractiveTileController tileAt) {
+        draggingTile = tileAt;
+    }
+
+    public void resetResidualShift() {
+        residualShiftX = 0;
+        residualShiftY = 0;
+    }
+    private void loadInteractiveTilesFromSave() {
+        interactiveTileControllers = new ArrayList<>();
+        for (InteractiveTileModel model : gameModel.getInteractiveTileModels()) {
+            InteractiveTileController controller = InteractiveTileFactory.createTile(this, model);
+            if (controller != null) {
+                addInteractiveTile(controller);
+            } else {
+                System.err.println("Unknown tile type: " + model.getTileType());
+            }
+        }
+    }
+
+    private void loadEntitiesFromSave() {
+        entityControllers = new ArrayList<>();
+        for (EntityModel model : gameModel.getEntityModels()) {
+            EntityController controller = EntityFactory.createEntity(this, model);
+            if (controller != null) {
+                addEntity(controller);
+            } else {
+                System.err.println("Unknown entity type: " + model.getEntityType());
+            }
+        }
+    }
+
+    public void loadGame() {
+        loadInteractiveTilesFromSave();
+        loadEntitiesFromSave();
+    }
+
 }

+ 23 - 21
src/main/java/controller/GameMouseListener.java

@@ -4,20 +4,15 @@ import util.GAMESTATE;
 import view.Camera;
 import view.GamePanel;
 
-import javax.imageio.ImageIO;
-import javax.tools.Tool;
+import javax.swing.*;
 import java.awt.*;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
 
 public class GameMouseListener implements MouseListener, MouseMotionListener {
-    private int startX;
-    private int startY;
-
+    private int lastY;
+    private int lastX;
     Camera camera;
     GamePanel gamePanel;
     GameController controller;
@@ -29,20 +24,19 @@ public class GameMouseListener implements MouseListener, MouseMotionListener {
     }
     @Override
     public void mouseDragged(MouseEvent e) {
-        if(gamePanel.gameState == GAMESTATE.PAUSED) return;
-        if(gamePanel.gameState == GAMESTATE.INVENTORY){
-
-        }else{
+        int diffY = e.getY() - lastX;
+        int diffX = e.getX() - lastY;
 
-            int diffY = startY - e.getY();
-            int diffX = startX - e.getX();
+        if(SwingUtilities.isLeftMouseButton(e)){
 
             camera.move(diffX, diffY);
             gamePanel.closeMenus();
 
-            startX = e.getX();
-            startY = e.getY();
+        }else if(SwingUtilities.isRightMouseButton(e)){
+            controller.handleTileShift(diffX, diffY);
         }
+        lastY = e.getX();
+        lastX = e.getY();
     }
 
     @Override
@@ -52,21 +46,29 @@ public class GameMouseListener implements MouseListener, MouseMotionListener {
 
     @Override
     public void mouseClicked(MouseEvent e) {
-        if(gamePanel.gameState == GAMESTATE.PLAY){
+        if(gamePanel.gameState == GAMESTATE.PLAY ){
             gamePanel.ui.handleClick(e.getX(), e.getY());
         }else if (gamePanel.gameState == GAMESTATE.INVENTORY && e.getButton() == MouseEvent.BUTTON1) {
             controller.handleInventoryClick(e.getX(), e.getY());
-        }else if(gamePanel.gameState == GAMESTATE.INVENTORY && e.getButton() == 1){
-            controller.handleInventoryClick(e.getX(), e.getY());
         }else if(gamePanel.gameState == GAMESTATE.PAUSED){
             gamePanel.ui.handleMenuClick(e.getX(), e.getY());
         }
+
+
     }
 
     @Override
     public void mousePressed(MouseEvent e) {
-        startX = e.getX();
-        startY = e.getY();
+        if (SwingUtilities.isRightMouseButton(e)) {
+            // Compute world coords of initial press:
+            int worldX = controller.screenToWorldX(e.getX());
+            int worldY = controller.screenToWorldY(e.getY());
+            controller.setDraggingTile(controller.getTileAt(worldX, worldY));
+            // Reset residuals:
+            controller.resetResidualShift();
+        }
+        lastY = e.getX();
+        lastX = e.getY();
     }
 
     @Override

+ 2 - 0
src/main/java/controller/InteractiveController.java

@@ -19,4 +19,6 @@ public interface InteractiveController {
     void click(int screenX, int screenY);
 
     void resize(int newTileSize);
+
+    void move(int screenX, int screenY);
 }

+ 3 - 1
src/main/java/controller/entity/VillagerController.java

@@ -7,7 +7,9 @@ import view.entity.VillagerView;
 import view.popUpMenu.EntityMenu;
 import view.popUpMenu.PopupMenu;
 
-public class VillagerController extends EntityController{
+import java.io.Serializable;
+
+public class VillagerController extends EntityController {
     private int amount = 1;
     public VillagerController(GameController controller, EntityModel model){
         super(model, null, controller);

+ 19 - 0
src/main/java/controller/factories/EntityFactory.java

@@ -0,0 +1,19 @@
+package controller.factories;
+
+import controller.GameController;
+import controller.entity.EntityController;
+import controller.entity.VillagerController;
+import controller.tiles.interactive.upgradeable.*;
+import model.entity.EntityModel;
+import model.entity.EntityType;
+
+public class EntityFactory {
+    public static EntityController createEntity(GameController controller, EntityModel model) {
+        EntityType type = model.getEntityType();
+
+        return switch (type) {
+            case VILLAGER -> new VillagerController(controller, model);
+            default -> null;
+        };
+    }
+}

+ 23 - 0
src/main/java/controller/factories/InteractiveTileFactory.java

@@ -0,0 +1,23 @@
+package controller.factories;
+
+import controller.GameController;
+import controller.tiles.interactive.InteractiveTileController;
+import controller.tiles.interactive.upgradeable.*;
+import model.tiles.InteractiveTileModel;
+import model.tiles.InteractiveTileType;
+
+public class InteractiveTileFactory {
+    public static InteractiveTileController createTile(GameController controller, InteractiveTileModel model) {
+        InteractiveTileType type = model.getTileType();
+
+        return switch (type) {
+            case LIGHTHOUSE -> new LighthouseController(controller, model);
+            case MINE -> new MineController(controller, model);
+            case BARRACKS -> new BarracksController(controller, model);
+            case IRON_MINE -> new IronMineController(controller, model);
+            case ANIMAL_ENCLOSURE -> new AnimalEnclosureController(controller, model);
+            case SAWMILL -> new SawmillController(controller, model);
+            default -> null;
+        };
+    }
+}

+ 8 - 1
src/main/java/controller/tiles/interactive/InteractiveTileController.java

@@ -88,6 +88,7 @@ public abstract class InteractiveTileController implements InteractiveController
     public int getTileSize(){
         return gameController.getView().tileSize;
     }
+
     public boolean getClicked(){
         return clicked;
     }
@@ -103,7 +104,13 @@ public abstract class InteractiveTileController implements InteractiveController
     public int getLevel() {
         return model.getLevel();
     }
-
+    public InteractiveTileView getView(){
+        return view;
+    }
+    public void move(int x, int y){
+        model.setWorldGridX(x);
+        model.setWorldGridY(y);
+    }
     @Override
     public void resize(int newTileSize) {
         view.resize(newTileSize);

+ 1 - 1
src/main/java/main/Main.java

@@ -20,7 +20,7 @@ public class Main {
 
         GamePanel gamePanel = gameController.getView();
 
-        gameController.loadInteractiveTiles();
+        gameController.loadGame();
 
         System.out.println("Starte Spiel...");
         JFrame window = new JFrame();

+ 9 - 0
src/main/java/model/GameModel.java

@@ -10,6 +10,7 @@ public class GameModel implements Serializable {
     private Inventory inventory;
     private ArrayList<InteractiveTileModel> interactiveTileModels = new ArrayList<>();
     private ArrayList<EntityModel> entityModels = new ArrayList<>();
+
     public GameModel() {
         inventory = new Inventory();
     }
@@ -22,6 +23,14 @@ public class GameModel implements Serializable {
         interactiveTileModels.add(model);
     }
 
+    public ArrayList<InteractiveTileModel> getInteractiveTileModels() {
+        return interactiveTileModels;
+    }
+
+    public ArrayList<EntityModel> getEntityModels(){
+        return entityModels;
+    }
+
     public void addEntityModel(EntityModel model) {
         entityModels.add(model);
     }

+ 9 - 2
src/main/java/model/entity/EntityModel.java

@@ -3,8 +3,10 @@ package model.entity;
 import view.GamePanel;
 
 import java.awt.*;
+import java.io.Serializable;
 
-public class EntityModel {
+public class EntityModel implements Serializable {
+    private EntityType type;
     public GamePanel gp;
 
     private Image optionalImage;
@@ -16,11 +18,12 @@ public class EntityModel {
     private boolean clicked;
     private int height, width;
 
-    public EntityModel(double worldX, double worldY, int width, int height){
+    public EntityModel(double worldX, double worldY, int width, int height, EntityType type){
         this.worldX = (int) worldX;
         this.worldY = (int) worldY;
         this.width = width;
         this.height = height;
+        this.type = type;
     }
 
     public double getWorldGridX() {
@@ -63,4 +66,8 @@ public class EntityModel {
     public void updateWidthAndHeight(int newTileSize) {
         height = newTileSize;
     }
+
+    public EntityType getEntityType() {
+        return type;
+    }
 }

+ 5 - 0
src/main/java/model/entity/EntityType.java

@@ -0,0 +1,5 @@
+package model.entity;
+
+public enum EntityType {
+    VILLAGER
+}

+ 14 - 1
src/main/java/model/tiles/InteractiveTileModel.java

@@ -9,12 +9,14 @@ public class InteractiveTileModel implements Serializable {
     private boolean clicked;
     private int level;
     private Item items;
+    private InteractiveTileType type;
 
-    public InteractiveTileModel(int worldGridX, int worldGridY) {
+    public InteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type) {
         this.worldGridX = worldGridX;
         this.worldGridY = worldGridY;
         this.clicked = false;
         this.level = 1;
+        this.type = type;
     }
     public int getLevel(){
         return level;
@@ -48,4 +50,15 @@ public class InteractiveTileModel implements Serializable {
         return items.takeItems(items.getCount());
     }
 
+    public void setWorldGridX(int snappedX) {
+        worldGridX = snappedX;
+    }
+
+    public void setWorldGridY(int snappedY) {
+        worldGridY = snappedY;
+    }
+
+    public InteractiveTileType getTileType() {
+        return type;
+    }
 }

+ 10 - 0
src/main/java/model/tiles/InteractiveTileType.java

@@ -0,0 +1,10 @@
+package model.tiles;
+
+public enum InteractiveTileType {
+    ANIMAL_ENCLOSURE,
+    BARRACKS,
+    IRON_MINE,
+    LIGHTHOUSE,
+    MINE,
+    SAWMILL,
+}

+ 10 - 2
src/main/java/view/Camera.java

@@ -45,8 +45,8 @@ public class Camera{
         float halfViewHeight = viewHeight / 2f;
 
         // 4. Proposed new camera center position
-        float newWorldX = (float) (worldX + x);
-        float newWorldY = (float) (worldY + y);
+        float newWorldX = (float) (worldX - x);
+        float newWorldY = (float) (worldY - y);
 
         // 5. Clamp the camera to world bounds so no outside area is visible
         newWorldX = clamp(newWorldX, halfViewWidth, worldWidth - halfViewWidth);
@@ -80,4 +80,12 @@ public class Camera{
             move(speed, 0);
         }
     }
+
+    public int getX() {
+        return worldX;
+    }
+
+    public int getY() {
+        return worldY;
+    }
 }

+ 6 - 6
src/main/java/view/GamePanel.java

@@ -2,6 +2,7 @@ package view;
 
 import controller.GameController;
 import controller.GameMouseListener;
+import controller.InteractiveController;
 import controller.MouseWheelZoom;
 import model.GameSaver;
 import model.Inventory;
@@ -18,7 +19,7 @@ import java.util.Arrays;
 public class GamePanel extends JPanel{
 
     //Screen Settings
-    final static int originalTileSize = 16;
+    public final int originalTileSize = 16;
     public final static int scale = 4;
 
     int fps = 60;
@@ -35,9 +36,6 @@ public class GamePanel extends JPanel{
     public final static int maxWorldCol = 100;
     public final static int maxWorldRow = 100;
 
-    public final int worldWidth = tileSize * maxWorldCol;
-    public final int worldHeight = tileSize * maxWorldRow;
-
     //System
     public UI ui = new UI(this);
     private Graphics2D g2;
@@ -45,7 +43,6 @@ public class GamePanel extends JPanel{
     public GAMESTATE gameState;
 
 
-
     public TileManager tileManager;
     public EntityManager entityManager;
     private PopupManager popupManager;
@@ -100,7 +97,6 @@ public class GamePanel extends JPanel{
         if (newTileSize < minTileSize || newTileSize > maxTileSize) {
             return;
         }
-
         tileSize = newTileSize;
 
         int newWorldWidth = tileSize * maxWorldCol;
@@ -146,4 +142,8 @@ public class GamePanel extends JPanel{
     public void generateNewWorld() {
         tileManager.generateNewWorld();
     }
+
+    public double getZoom() {
+        return originalTileSize/tileSize;
+    }
 }

+ 16 - 4
src/main/java/view/tile/interactive/InteractiveTileView.java

@@ -5,10 +5,7 @@ import model.Tile;
 import java.awt.*;
 import java.io.Serializable;
 
-import controller.GameController;
-import view.Camera;
 import view.popUpMenu.PopupMenu;
-import view.tile.ONCLICKTYPE;
 import view.tile.TileManager;
 
 public abstract class InteractiveTileView extends Tile implements Serializable {
@@ -68,11 +65,26 @@ public abstract class InteractiveTileView extends Tile implements Serializable {
         height = newTileSize * scaleY;
         width = newTileSize * scaleX;
     }
-
+    public int getScreenX(){
+        return screenX;
+    }
+    public int getScreenY(){
+        return screenY;
+    }
     public int getScaleX() {
         return scaleX;
     }
     public int getScaleY(){
         return scaleY;
     }
+
+    public void move(int x, int y) {
+        screenX += x;
+        screenY += y;
+    }
+
+    public void setScreenCoordinates(int screenX, int screenY) {
+        this.screenX = screenX;
+        this.screenY = screenY;
+    }
 }

+ 5 - 1
src/main/java/view/util/RenderingManager.java

@@ -1,9 +1,13 @@
 package view.util;
 
-import java.awt.Graphics2D;
+import controller.InteractiveController;
+
+import java.awt.*;
 
 public interface RenderingManager {
     void drawPopup(Graphics2D g2);
 
     void resize(int newTileSize);
+
+
 }