浏览代码

PopupMenu fertig, Weltbeschränkung für Kamera hinzugefügt. Zoom und andere Abbruchmethoden für Menus hinzugefügt

Jan 7 月之前
父节点
当前提交
3addf67e84

+ 7 - 7
src/main/java/controller/GameController.java

@@ -8,6 +8,7 @@ import util.GAMESTATE;
 import view.GamePanel;
 import view.tile.interactive.Hut;
 
+import java.awt.*;
 import java.io.Serializable;
 
 public class GameController implements Runnable, Serializable {
@@ -93,13 +94,9 @@ public class GameController implements Runnable, Serializable {
             }
         }
     }
-
-    public void zoomIn() {
-        view.zoomInOut(1);
-    }
-
-    public void zoomOut() {
-        view.zoomInOut(-1);
+    public void zoomInOut(int i) {
+        view.zoomInOut(i);
+        view.closeMenus();
     }
 
     public void togglePauseOrExitInventory() {
@@ -126,6 +123,7 @@ public class GameController implements Runnable, Serializable {
         }
         return view;
     }
+
     public GameModel getModel() {
         if(gameModel == null) gameModel = new GameModel();
         return gameModel;
@@ -135,4 +133,6 @@ public class GameController implements Runnable, Serializable {
         if(keyHandler == null) keyHandler = new KeyHandler(this);
         return keyHandler;
     }
+
+
 }

+ 2 - 2
src/main/java/controller/KeyHandler.java

@@ -25,8 +25,8 @@ public class KeyHandler implements KeyListener {
             case KeyEvent.VK_A -> leftPressed = true;
             case KeyEvent.VK_S -> downPressed = true;
             case KeyEvent.VK_D -> rightPressed = true;
-            case KeyEvent.VK_UP -> controller.zoomIn();
-            case KeyEvent.VK_DOWN -> controller.zoomOut();
+            case KeyEvent.VK_UP -> controller.zoomInOut(1);
+            case KeyEvent.VK_DOWN -> controller.zoomInOut(-1);
             case KeyEvent.VK_ESCAPE -> controller.togglePauseOrExitInventory();
             case KeyEvent.VK_E -> controller.toggleInventory();
         }

+ 12 - 34
src/main/java/controller/MouseListener.java

@@ -1,12 +1,8 @@
 package controller;
 
-import model.Inventory;
-import model.Tile;
 import util.GAMESTATE;
 import view.Camera;
 import view.GamePanel;
-import view.InventoryView;
-import view.tile.interactive.InteractiveTile;
 import view.tile.TileManager;
 
 import java.awt.event.MouseEvent;
@@ -18,27 +14,26 @@ public class MouseListener extends MouseMotionAdapter implements java.awt.event.
 
     Camera camera;
     TileManager tileManager;
-    GamePanel gp;
-    InventoryView iView;
-    Inventory inventory;
+    GamePanel gamePanel;
     GameController controller;
 
-    public MouseListener(GameController controller, GamePanel gp, Camera camera, TileManager tm) {
+    public MouseListener(GameController controller, GamePanel gamePanel, Camera camera, TileManager tm) {
         this.controller = controller;
-        this.gp = gp;
+        this.gamePanel = gamePanel;
         this.camera = camera;
         this.tileManager = tm;
     }
     @Override
     public void mouseDragged(MouseEvent e) {
-        if(gp.gameState == GAMESTATE.PAUSED) return;
-        if(gp.gameState == GAMESTATE.INVENTORY){
+        if(gamePanel.gameState == GAMESTATE.PAUSED) return;
+        if(gamePanel.gameState == GAMESTATE.INVENTORY){
 
         }else{
             int diffY = startY - e.getY();
             int diffX = startX - e.getX();
 
             camera.move(diffX, diffY);
+            gamePanel.closeMenus();
 
             startX = e.getX();
             startY = e.getY();
@@ -47,14 +42,14 @@ public class MouseListener extends MouseMotionAdapter implements java.awt.event.
 
     @Override
     public void mouseClicked(MouseEvent e) {
-        if(gp.gameState == GAMESTATE.PLAY){
-            gp.ui.handleClick(e.getX(), e.getY());
-        }else if (gp.gameState == GAMESTATE.INVENTORY && e.getButton() == MouseEvent.BUTTON1) {
+        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(gp.gameState == GAMESTATE.INVENTORY && e.getButton() == 1){
+        }else if(gamePanel.gameState == GAMESTATE.INVENTORY && e.getButton() == 1){
             controller.handleInventoryClick(e.getX(), e.getY());
-        }else if(gp.gameState == GAMESTATE.PAUSED){
-            gp.ui.handleMenuClick(e.getX(), e.getY());
+        }else if(gamePanel.gameState == GAMESTATE.PAUSED){
+            gamePanel.ui.handleMenuClick(e.getX(), e.getY());
         }
     }
 
@@ -62,23 +57,6 @@ public class MouseListener extends MouseMotionAdapter implements java.awt.event.
     public void mousePressed(MouseEvent e) {
         startX = e.getX();
         startY = e.getY();
-
-        int worldX = (int) (startX + camera.worldX - camera.screenX);
-        int worldY = (int) (startY + camera.worldY - camera.screenY);
-
-        int tileCol = worldX / gp.tileSize;
-        int tileRow = worldY / gp.tileSize;
-
-        if (tileCol >= 0 && tileCol < gp.maxWorldCol &&
-                tileRow >= 0 && tileRow < gp.maxWorldRow) {
-
-            int tileIndex = tileManager.mapTileNum[tileCol][tileRow];
-            Tile tile = tileManager.tile[tileIndex];
-
-            if(tile instanceof InteractiveTile it) {
-                it.click(); // Consumer wird aufgerufen
-            }
-        }
     }
 
     @Override

+ 4 - 4
src/main/java/controller/MouseWheelZoom.java

@@ -6,15 +6,15 @@ import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 
 public class MouseWheelZoom implements MouseWheelListener {
-    GamePanel gp;
-    public MouseWheelZoom(GamePanel gamePanel){
-        gp = gamePanel;
+    GameController gameController;
+    public MouseWheelZoom(GameController gameController){
+        this.gameController = gameController;
     }
 
     @Override
     public void mouseWheelMoved(MouseWheelEvent e) {
         for(int i = 0; i < e.getScrollAmount(); i++){
-            gp.zoomInOut(-e.getWheelRotation());
+            gameController.zoomInOut(-e.getWheelRotation());
         }
     }
 }

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

@@ -18,8 +18,8 @@ public class Camera extends Entity {
     public Camera(GamePanel gamePanel, KeyHandler keyHandler){
         super(gamePanel);
         this.keyH = keyHandler;
-        screenX = gp.screenWidth/2 - gamePanel.tileSize/2;
-        screenY = gp.screenHeight/2 - gamePanel.tileSize/2;
+        screenX = gp.screenWidth/2;
+        screenY = gp.screenHeight/2;
         //getPlayerImage();
         setDefaultValues();
     }
@@ -37,28 +37,59 @@ public class Camera extends Entity {
         speed = 4;
     }
 
-    public void move(int x, int y){
-        worldY += y;
-        worldX += x;
+    public void move(int x, int y) {
+        // 1. Calculate world dimensions
+        int worldWidth = gp.maxWorldCol * gp.tileSize;
+        int worldHeight = gp.maxWorldRow * gp.tileSize;
+
+        // 2. Infer zoom factor
+        float zoom = (float) gp.tileSize / gp.originalTileSize;
+
+        // 3. Calculate visible screen size in world units
+        float viewWidth = gp.screenWidth +zoom;
+        float viewHeight = gp.screenHeight;
+
+        float halfViewWidth = viewWidth / 2f;
+        float halfViewHeight = viewHeight / 2f;
+
+        // 4. Proposed new camera center position
+        float newWorldX = worldX + x;
+        float newWorldY = worldY + y;
+
+        // 5. Clamp the camera to world bounds so no outside area is visible
+        newWorldX = clamp(newWorldX, halfViewWidth, worldWidth - halfViewWidth);
+        newWorldY = clamp(newWorldY, halfViewHeight, worldHeight - halfViewHeight);
+
+        // 6. Update position
+        worldX = (int) newWorldX;
+        worldY = (int) newWorldY;
+    }
+
+    private float clamp(float value, float min, float max) {
+        if (min > max) {
+            // This happens when zoomed out so much that the view is larger than the world.
+            // In that case, center the camera in the middle of the world.
+            return (min + max) / 2f;
+        }
+        return Math.max(min, Math.min(max, value));
     }
 
     public void update(){
         if(keyH.upPressed){
-            worldY -= speed;
+            move(0, -speed);
         }
         if(keyH.downPressed){
-            worldY += speed;
+            move(0, speed);
         }
         if(keyH.leftPressed){
-            worldX -= speed;
+            move(-speed, 0);
         }
         if(keyH.rightPressed){
-            worldX += speed;
+            move(speed, 0);
         }
     }
     public void draw(Graphics2D g2){
         g2.setColor(Color.WHITE);
-
         g2.drawImage(optionalPlayerImage, screenX, screenY, gp.tileSize, gp.tileSize, null);
     }
 }

+ 29 - 20
src/main/java/view/GamePanel.java

@@ -37,7 +37,7 @@ public class GamePanel extends JPanel{
 
     //System
     public UI ui = new UI(this);
-
+    private Graphics2D g2;
     // Game State
     public GAMESTATE gameState;
 
@@ -59,7 +59,7 @@ public class GamePanel extends JPanel{
         MouseListener mdl = new MouseListener(controller, this, camera, tileManager);
         this.addMouseListener(mdl);
         this.addMouseMotionListener(mdl);
-        this.addMouseWheelListener(new MouseWheelZoom(this));
+        this.addMouseWheelListener(new MouseWheelZoom(controller));
 
         this.setPreferredSize(new Dimension(screenWidth, screenHeight));
         this.setBackground(Color.BLACK);
@@ -70,31 +70,47 @@ public class GamePanel extends JPanel{
         gameState = GAMESTATE.PLAY;
     }
 
-    public void zoomInOut(int i){
-        if(gameState != GAMESTATE.PLAY){
+    public void zoomInOut(int i) {
+        if (gameState != GAMESTATE.PLAY) {
             return;
         }
-        int oldWorldWidth = tileSize * maxWorldCol;
-        if((tileSize >= originalTileSize*scale/4 && i < 0) || (tileSize < (originalTileSize * scale) && i > 0)){
-            tileSize += i;
+
+        int oldTileSize = tileSize;
+        int oldWorldWidth = oldTileSize * maxWorldCol;
+        int oldWorldHeight = oldTileSize * maxWorldRow;
+
+        int minTileSize = originalTileSize * scale / 4;
+        int maxTileSize = originalTileSize * scale;
+
+        // Only adjust tileSize within allowed bounds
+        int newTileSize = tileSize + i;
+        if (newTileSize < minTileSize || newTileSize > maxTileSize) {
+            return;
         }
 
+        tileSize = newTileSize;
+
         int newWorldWidth = tileSize * maxWorldCol;
+        int newWorldHeight = tileSize * maxWorldRow;
 
-        double multiplier = (double)newWorldWidth/oldWorldWidth;
-        double newCameraWorldX = camera.worldX * multiplier;
-        double newCameraWorldY = camera.worldY * multiplier;
+        // Adjust camera position relative to the new scale
+        double widthMultiplier = (double) newWorldWidth / oldWorldWidth;
+        double heightMultiplier = (double) newWorldHeight / oldWorldHeight;
 
-        camera.worldX = (int) newCameraWorldX;
-        camera.worldY = (int) newCameraWorldY;
+        camera.worldX = (int)(camera.worldX * widthMultiplier);
+        camera.worldY = (int)(camera.worldY * heightMultiplier);
     }
+    public void closeMenus(){
+        ui.closeMenus();
+    }
+
     public InventoryView getInventoryView(){
         return inventoryView;
     }
     @Override
     public void paintComponent(Graphics g) {
         super.paintComponent(g);
-        Graphics2D g2 = (Graphics2D) g;
+        g2 = (Graphics2D) g;
 
         tileManager.draw(g2);
         camera.draw(g2);
@@ -116,11 +132,4 @@ public class GamePanel extends JPanel{
         }
     }
 
-
-    public GameController getGameController() {
-        if(gameController == null){
-            gameController = new GameController();
-        }
-        return gameController;
-    }
 }

+ 24 - 6
src/main/java/view/UI.java

@@ -2,7 +2,9 @@ package view;
 
 import util.GAMESTATE;
 import view.components.Button;
+import view.popUpMenu.PopupMenu;
 import view.tile.interactive.InteractiveTile;
+import view.tile.interactive.ONCLICKTYPE;
 
 import java.awt.*;
 import java.util.ArrayList;
@@ -36,10 +38,20 @@ public class UI {
         }
     }
     public void handleClick(int screenX, int screenY){
-
         for (InteractiveTile tile : gp.tileManager.interactiveTiles) {
-            if (tile.isClicked(screenX, screenY, gp.camera)) {
-                tile.click();
+
+            if(tile.getClicked() && tile.getOnClickType() == ONCLICKTYPE.POPUP){
+                PopupMenu popupMenu = tile.getPopupMenu();
+                Button clickedButton = popupMenu.getClickedButton(screenX,screenY);
+                if(clickedButton != null){
+                    clickedButton.click();
+                }
+            }
+
+            if (tile.isClicked(screenX, screenY, gp.camera) && !tile.getClicked()) {
+                tile.click(screenX, screenY);
+            }else if(tile.getClicked()){
+                tile.unClick();
             }
         }
     }
@@ -75,17 +87,17 @@ public class UI {
         int resumeY = boxY + 100;
         int saveY = resumeY + buttonHeight + spacing;
         int exitY = resumeY + buttonHeight + buttonHeight + spacing + spacing;
-        Button resumeButton = new Button(buttonHeight, buttonWidth, "Continue", () -> {
+        Button resumeButton = new Button(buttonWidth, buttonHeight, "Continue", () -> {
             gp.gameState = GAMESTATE.PLAY;
         });
         drawAndRegisterButton(resumeButton, buttonX, resumeY);
 
-        Button exitButton = new Button(buttonHeight, buttonWidth, "Quit", () -> {
+        Button exitButton = new Button(buttonWidth, buttonHeight, "Quit", () -> {
             gp.gameState = GAMESTATE.QUIT;
         });
         drawAndRegisterButton(exitButton, buttonX, exitY);
 
-        Button saveButton = new Button(buttonHeight, buttonWidth, "Save", () -> {
+        Button saveButton = new Button(buttonWidth, buttonHeight, "Save", () -> {
             gp.gameState = GAMESTATE.SAVE;
         });
         drawAndRegisterButton(saveButton, buttonX, saveY);
@@ -100,4 +112,10 @@ public class UI {
         int length = (int)g2.getFontMetrics().getStringBounds(text, g2).getWidth();
         return gp.screenWidth/2 - length/2;
     }
+
+    public void closeMenus() {
+        for (InteractiveTile tile : gp.tileManager.interactiveTiles) {
+            tile.unClick();
+        }
+    }
 }

+ 12 - 3
src/main/java/view/components/Button.java

@@ -8,8 +8,9 @@ public class Button {
     private int width;
     private String text;
     private Runnable runnable;
+    private int offsetX = 0, offsetY = 0;
 
-    public Button(int height, int width, String text, Runnable c){
+    public Button(int width, int height, String text, Runnable c){
         this.height = height;
         this.width = width;
         this.text = text;
@@ -28,7 +29,10 @@ public class Button {
     public void click(){
         runnable.run();
     }
-
+    public void setOffset(int x, int y){
+        offsetX = x;
+        offsetY = y;
+    }
     public boolean wasClicked(int clickX, int clickY){
         if(clickX >= screenX && clickX <= screenX + width && clickY >= screenY && clickY <= screenY + height){
             return true;
@@ -41,7 +45,8 @@ public class Button {
         g2.setColor(Color.BLACK);
         FontMetrics fm = g2.getFontMetrics();
         int msgWidth = fm.stringWidth(text);
-        g2.drawString(text, screenX+ ((width - msgWidth) /2) + 1, screenY + 30);
+        int msgHeight = fm.getAscent();
+        g2.drawString(text, screenX + ((width - msgWidth) /2), screenY + ((height + msgHeight)/2) );
     }
 
     public void setDimensions(int height, int width){
@@ -54,4 +59,8 @@ public class Button {
         this.screenY = y;
     }
 
+    public void setRelativeScreenCoordinates(int x, int y) {
+        this.screenX = x + offsetX;
+        this.screenY = y + offsetY;
+    }
 }

+ 0 - 22
src/main/java/view/popUpMenu/PopUpTile.java

@@ -1,22 +0,0 @@
-package view.popUpMenu;
-
-import java.awt.*;
-
-public class PopUpTile {
-
-    public int overlayX;
-    public int overlayY;
-    public int overlayWidth;
-    public int overlayHeight;
-
-    public PopUpTile(Graphics2D g2, int x, int y, int width, int height) {
-        overlayX = x;
-        overlayY = y;
-        overlayWidth = width;
-        overlayHeight = height;
-
-        g2.setColor(new Color(0, 0, 0, 160)); // semi-transparent black
-        g2.fillRoundRect(overlayX, overlayY, overlayWidth, overlayHeight, 15, 15);
-    }
-
-}

+ 43 - 0
src/main/java/view/popUpMenu/PopupMenu.java

@@ -0,0 +1,43 @@
+package view.popUpMenu;
+
+import view.components.Button;
+
+import java.awt.*;
+import java.util.ArrayList;
+
+public abstract class PopupMenu {
+
+    public int overlayWidth;
+    public int overlayHeight;
+    public ArrayList<Button> buttonArrayList = new ArrayList<>();
+    public PopupMenu(int width, int height) {
+        overlayWidth = width;
+        overlayHeight = height;
+    }
+
+    public void addButton(Button button, int offsetX, int offsetY){
+        button.setOffset(offsetX, offsetY);
+        buttonArrayList.add(button);
+    }
+
+
+    public void draw(int x, int y, Graphics2D g2){
+        g2.setColor(Color.GRAY);
+        g2.fillRoundRect(x,y, overlayWidth, overlayHeight, 15, 15);
+        g2.setColor(Color.WHITE);
+        g2.drawRoundRect(x,y,overlayWidth,overlayHeight, 15, 15);
+
+        for (Button button : buttonArrayList){
+            button.setRelativeScreenCoordinates(x,y);
+            button.draw(g2);
+        }
+
+    }
+
+    public Button getClickedButton(int screenX, int screenY) {
+        for (Button button : buttonArrayList){
+            if(button.wasClicked(screenX, screenY)) return button;
+        }
+        return null;
+    }
+}

+ 15 - 0
src/main/java/view/popUpMenu/UpgradeMenu.java

@@ -0,0 +1,15 @@
+package view.popUpMenu;
+
+import view.components.Button;
+
+public class UpgradeMenu extends PopupMenu{
+    public UpgradeMenu(int width, int height) {
+        super(width, height);
+        addButton(new Button(60,20,"Upgrade",() -> {
+            System.out.println("Clicked");
+        }), 10, 10);
+        addButton(new Button(60,20,"Collect",() -> {
+            System.out.println("Clicked");
+        }), 10, 40);
+    }
+}

+ 11 - 9
src/main/java/view/tile/interactive/Hut.java

@@ -2,24 +2,26 @@ package view.tile.interactive;
 
 import controller.GameController;
 import view.Camera;
-import view.GamePanel;
-import view.popUpMenu.PopUpTile;
+import view.popUpMenu.PopupMenu;
+import view.popUpMenu.UpgradeMenu;
+
 import java.awt.*;
 
 public class Hut extends InteractiveTile {
 
     public Hut(int worldGridX, int worldGridY, GameController gc) {
-        super(worldGridX, worldGridY, gc.getView().tileSize, gc.getView().tileSize, () -> {
-            System.out.println("Hut clicked!");
-            // Add click logic here
-        }, gc);
+        super(worldGridX, worldGridY, gc.getView().tileSize, gc.getView().tileSize, gc);
+        PopupMenu popup = new UpgradeMenu(100, 100);
+
+        setPopupOnClick(popup);
     }
 
     @Override
-    public void draw(Graphics2D g2, Camera camera) {
-        // Convert world to screen coordinates
+    public void drawTile(Graphics2D g2, Camera camera) {
         int size = gameController.getView().tileSize;
         g2.setColor(new Color(0, 0, 0, 160));
-        g2.fillRoundRect(this.screenX, this.screenY, size, size, 15, 15);
+        setImage("/sprites/hut.png");
+        g2.drawImage(image, screenX, screenY, gameController.getView().tileSize, gameController.getView().tileSize, null);
+
     }
 }

+ 44 - 6
src/main/java/view/tile/interactive/InteractiveTile.java

@@ -4,7 +4,7 @@ import model.Tile;
 import java.awt.*;
 import controller.GameController;
 import view.Camera;
-import view.GamePanel;
+import view.popUpMenu.PopupMenu;
 
 public abstract class InteractiveTile extends Tile {
     public int worldGridX, worldGridY;
@@ -12,8 +12,12 @@ public abstract class InteractiveTile extends Tile {
     protected int width, height;
     protected Runnable onClick;
     protected GameController gameController;
+    protected ONCLICKTYPE onclicktype;
+    private PopupMenu popup;
+    private boolean clicked = false;
+    private int screenXClick, screenYClick;
 
-    public InteractiveTile(int worldGridX, int worldGridY, int width, int height, Runnable onClick, GameController gc) {
+    public InteractiveTile(int worldGridX, int worldGridY, int width, int height, GameController gc) {
         this.worldGridX = worldGridX;
         this.worldGridY = worldGridY;
 
@@ -22,12 +26,26 @@ public abstract class InteractiveTile extends Tile {
 
         this.width = width;
         this.height = height;
-        this.onClick = onClick;
         this.gameController = gc;
     }
 
-    public void click() {
-        onClick.run();
+    public void setPopupOnClick(PopupMenu popup){
+        onclicktype = ONCLICKTYPE.POPUP;
+        this.popup = popup;
+    }
+
+    public void setOnClick(Runnable onClick){
+        onclicktype = ONCLICKTYPE.RUNNABLE;
+        this.onClick = onClick;
+    }
+    public void click(int screenX, int screenY) {
+        if(onclicktype == ONCLICKTYPE.RUNNABLE){
+            onClick.run();
+        }else{
+            screenXClick = screenX;
+            screenYClick = screenY;
+            clicked = true;
+        }
     }
 
     public void updateCoordinates(){
@@ -41,5 +59,25 @@ public abstract class InteractiveTile extends Tile {
         return mouseWorldGridX == worldGridX &&  mouseWorldGridY == worldGridY;
     }
 
-    public abstract void draw(Graphics2D g2, Camera camera);
+    public abstract void drawTile(Graphics2D g2, Camera camera);
+
+    public void draw(Graphics2D g2, Camera camera){
+        drawTile(g2, camera);
+        if(onclicktype == ONCLICKTYPE.POPUP && clicked == true){
+            popup.draw(screenXClick, screenYClick, g2);
+        }
+    }
+    public ONCLICKTYPE getOnClickType(){
+        return onclicktype;
+    }
+    public PopupMenu getPopupMenu(){
+        return popup;
+    }
+
+    public boolean getClicked(){
+        return clicked;
+    }
+    public void unClick() {
+        clicked = false;
+    }
 }

+ 6 - 0
src/main/java/view/tile/interactive/ONCLICKTYPE.java

@@ -0,0 +1,6 @@
+package view.tile.interactive;
+
+public enum ONCLICKTYPE {
+    RUNNABLE,
+    POPUP
+}