|
|
@@ -8,6 +8,7 @@ import controller.tiles.interactive.*;
|
|
|
import controller.tiles.interactive.upgradeable.*;
|
|
|
import model.GameModel;
|
|
|
import model.GameSaver;
|
|
|
+import model.Inventory;
|
|
|
import model.entity.EntityModel;
|
|
|
import model.entity.EntityType;
|
|
|
import model.items.Item;
|
|
|
@@ -21,331 +22,585 @@ import view.tile.interactive.InteractiveTileView;
|
|
|
import java.io.Serializable;
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
+/**
|
|
|
+ * Controls the main game loop, input handling, entities, and interactive tiles.
|
|
|
+ */
|
|
|
public class GameController implements Runnable, Serializable {
|
|
|
+
|
|
|
public final String worldPath = "gamefiles/worlds/world_0.txt";
|
|
|
private GameModel gameModel;
|
|
|
private boolean running = true;
|
|
|
public final int fps = 60;
|
|
|
|
|
|
-
|
|
|
private transient KeyHandler keyHandler;
|
|
|
private transient Thread gameThread;
|
|
|
+ private transient RessourceManager ressourceManager;
|
|
|
private transient GamePanel view;
|
|
|
public transient ArrayList<EntityController> entityControllers;
|
|
|
public transient ArrayList<InteractiveTileController> interactiveTileControllers;
|
|
|
private transient InteractiveTileController draggingTile;
|
|
|
private transient int residualShiftX, residualShiftY;
|
|
|
+ private boolean gameActive;
|
|
|
|
|
|
-
|
|
|
+ /**
|
|
|
+ * Constructs a GameController, sets up model, view, input, inventory, entities, and interactive tiles.
|
|
|
+ */
|
|
|
public GameController() {
|
|
|
- this.keyHandler = new KeyHandler(this);
|
|
|
- this.gameModel = new GameModel();
|
|
|
- this.view = new GamePanel(this);
|
|
|
- entityControllers = new ArrayList<>();
|
|
|
- interactiveTileControllers = new ArrayList<>();
|
|
|
- setStartInventory();
|
|
|
- setupInteractiveTiles();
|
|
|
- setupEntities();
|
|
|
+ initModel();
|
|
|
+ initView();
|
|
|
+ initInputHandler();
|
|
|
+ initControllerLists();
|
|
|
+ initializeStartInventory();
|
|
|
+ initializeInteractiveTiles();
|
|
|
+ initializeEntities();
|
|
|
+ initResourceManager();
|
|
|
view.loadMap(worldPath);
|
|
|
}
|
|
|
|
|
|
- private void setupInteractiveTiles() {
|
|
|
- LighthouseController lighthouse = new LighthouseController(this, setupInteractiveTileModel(20, 20, InteractiveTileType.LIGHTHOUSE));
|
|
|
- addInteractiveTile(lighthouse);
|
|
|
-
|
|
|
- MineController mineController = new MineController(this, setupInteractiveTileModel(25,20, InteractiveTileType.MINE));
|
|
|
- addInteractiveTile(mineController);
|
|
|
-
|
|
|
- BarracksController barracksController = new BarracksController(this, setupInteractiveTileModel(26, 20, InteractiveTileType.BARRACKS));
|
|
|
- addInteractiveTile(barracksController);
|
|
|
-
|
|
|
- IronMineController ironMineController = new IronMineController(this, setupInteractiveTileModel(27, 20, InteractiveTileType.IRON_MINE));
|
|
|
- addInteractiveTile(ironMineController);
|
|
|
+ /**
|
|
|
+ * Creates a new ResourceManager
|
|
|
+ */
|
|
|
+ private void initResourceManager() {
|
|
|
+ ressourceManager = new RessourceManager(this);
|
|
|
+ ressourceManager.start();
|
|
|
+ }
|
|
|
|
|
|
- AnimalEnclosureController animal = new AnimalEnclosureController(this, setupInteractiveTileModel(28, 20, InteractiveTileType.ANIMAL_ENCLOSURE));
|
|
|
- addInteractiveTile(animal);
|
|
|
+ /**
|
|
|
+ * Initializes the GameModel.
|
|
|
+ */
|
|
|
+ private void initModel() {
|
|
|
+ this.gameModel = new GameModel();
|
|
|
+ }
|
|
|
|
|
|
- SawmillController sawmillController = new SawmillController(this, setupInteractiveTileModel(29, 20, InteractiveTileType.SAWMILL));
|
|
|
- addInteractiveTile(sawmillController);
|
|
|
+ /**
|
|
|
+ * Initializes the GamePanel view.
|
|
|
+ */
|
|
|
+ private void initView() {
|
|
|
+ this.view = new GamePanel(this);
|
|
|
}
|
|
|
|
|
|
- private void setupEntities(){
|
|
|
- VillagerController villager = new VillagerController(this, setupEntityModel(22,20, EntityType.VILLAGER));
|
|
|
- addEntity(villager);
|
|
|
+ /**
|
|
|
+ * Initializes the key handler.
|
|
|
+ */
|
|
|
+ private void initInputHandler() {
|
|
|
+ this.keyHandler = new KeyHandler(this);
|
|
|
}
|
|
|
|
|
|
- private void addEntity(EntityController entityController) {
|
|
|
- entityControllers.add(entityController);
|
|
|
+ /**
|
|
|
+ * Initializes lists for entity and interactive tile controllers.
|
|
|
+ */
|
|
|
+ private void initControllerLists() {
|
|
|
+ entityControllers = new ArrayList<>();
|
|
|
+ interactiveTileControllers = new ArrayList<>();
|
|
|
}
|
|
|
|
|
|
- private void addInteractiveTile(InteractiveTileController controller) {
|
|
|
- interactiveTileControllers.add(controller);
|
|
|
+ /**
|
|
|
+ * Populates the starting inventory with basic items.
|
|
|
+ */
|
|
|
+ private void initializeStartInventory() {
|
|
|
+ Inventory inv = getModel().getInventory();
|
|
|
+ inv.addToInventory(new Item(ITEM_NAME.stone));
|
|
|
+ inv.addToInventory(new Item(ITEM_NAME.wood));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets up predefined interactive tiles in the world.
|
|
|
+ */
|
|
|
+ private void initializeInteractiveTiles() {
|
|
|
+ addInteractiveTileController(new LighthouseController(this,
|
|
|
+ createInteractiveTileModel(20, 20, InteractiveTileType.LIGHTHOUSE)));
|
|
|
+ addInteractiveTileController(new MineController(this,
|
|
|
+ createInteractiveTileModel(25, 20, InteractiveTileType.MINE)));
|
|
|
+ addInteractiveTileController(new BarracksController(this,
|
|
|
+ createInteractiveTileModel(26, 20, InteractiveTileType.BARRACKS)));
|
|
|
+ addInteractiveTileController(new IronMineController(this,
|
|
|
+ createInteractiveTileModel(27, 20, InteractiveTileType.IRON_MINE)));
|
|
|
+ addInteractiveTileController(new AnimalEnclosureController(this,
|
|
|
+ createInteractiveTileModel(28, 20, InteractiveTileType.ANIMAL_ENCLOSURE)));
|
|
|
+ addInteractiveTileController(new SawmillController(this,
|
|
|
+ createInteractiveTileModel(29, 20, InteractiveTileType.SAWMILL)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets up predefined entities in the world.
|
|
|
+ */
|
|
|
+ private void initializeEntities() {
|
|
|
+ addEntityController(new VillagerController(this,
|
|
|
+ createEntityModel(22, 20, EntityType.VILLAGER)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Adds an EntityController to the controller list.
|
|
|
+ *
|
|
|
+ * @param entityController the entity controller to add
|
|
|
+ */
|
|
|
+ private void addEntityController(EntityController entityController) {
|
|
|
+ entityControllers.add(entityController);
|
|
|
}
|
|
|
|
|
|
- private EntityModel setupEntityModel(int worldX, int worldY, EntityType type) {
|
|
|
- EntityModel model = new EntityModel(worldX, worldY, getView().tileSize, getView().tileSize, type);
|
|
|
- gameModel.addEntityModel(model);
|
|
|
+ /**
|
|
|
+ * Adds an InteractiveTileController to the controller list.
|
|
|
+ *
|
|
|
+ * @param tileController the interactive tile controller to add
|
|
|
+ */
|
|
|
+ private void addInteractiveTileController(InteractiveTileController tileController) {
|
|
|
+ interactiveTileControllers.add(tileController);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates and registers an EntityModel in the GameModel.
|
|
|
+ *
|
|
|
+ * @param worldX X position in world grid
|
|
|
+ * @param worldY Y position in world grid
|
|
|
+ * @param type type of entity
|
|
|
+ * @return the created EntityModel
|
|
|
+ */
|
|
|
+ private EntityModel createEntityModel(int worldX, int worldY, EntityType type) {
|
|
|
+ int size = getView().tileSize;
|
|
|
+ EntityModel model = new EntityModel(worldX, worldY, size, size, type);
|
|
|
+ getModel().addEntityModel(model);
|
|
|
return model;
|
|
|
}
|
|
|
|
|
|
- public InteractiveTileModel setupInteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type){
|
|
|
+ /**
|
|
|
+ * Creates and registers an InteractiveTileModel in the GameModel.
|
|
|
+ *
|
|
|
+ * @param worldGridX X grid coordinate
|
|
|
+ * @param worldGridY Y grid coordinate
|
|
|
+ * @param type type of interactive tile
|
|
|
+ * @return the created InteractiveTileModel
|
|
|
+ */
|
|
|
+ public InteractiveTileModel createInteractiveTileModel(int worldGridX, int worldGridY, InteractiveTileType type) {
|
|
|
InteractiveTileModel model = new InteractiveTileModel(worldGridX, worldGridY, type);
|
|
|
- gameModel.addInteractiveTileModel(model);
|
|
|
+ getModel().addInteractiveTileModel(model);
|
|
|
return model;
|
|
|
}
|
|
|
- private void setStartInventory() {
|
|
|
- gameModel.getInventory().addToInventory(new Item(ITEM_NAME.stone));
|
|
|
- gameModel.getInventory().addToInventory(new Item(ITEM_NAME.water));
|
|
|
- gameModel.getInventory().addToInventory(new Item(ITEM_NAME.wood));
|
|
|
- }
|
|
|
|
|
|
- public void setView(GamePanel gp){
|
|
|
- view = gp;
|
|
|
+ /**
|
|
|
+ * Sets the GamePanel view.
|
|
|
+ *
|
|
|
+ * @param gp the GamePanel to set
|
|
|
+ */
|
|
|
+ public void setView(GamePanel gp) {
|
|
|
+ this.view = gp;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Handles a click on the inventory UI.
|
|
|
+ *
|
|
|
+ * @param x screen x-coordinate of click
|
|
|
+ * @param y screen y-coordinate of click
|
|
|
+ */
|
|
|
public void handleInventoryClick(int x, int y) {
|
|
|
int slot = view.getInventoryView().getClickedInventorySlot(x, y);
|
|
|
- gameModel.getInventory().select(slot);
|
|
|
+ getModel().getInventory().select(slot);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Starts the main game loop and resource manager thread.
|
|
|
+ */
|
|
|
public void startGameLoop() {
|
|
|
- gameThread = new Thread(this);
|
|
|
+ gameActive = true;
|
|
|
+ gameThread = new Thread(this, "GameLoopThread");
|
|
|
gameThread.start();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Stops the main game loop.
|
|
|
+ */
|
|
|
public void stopGameLoop() {
|
|
|
- running = false;
|
|
|
+ gameActive = false;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Performs update logic once per frame.
|
|
|
+ * Updates camera or handles save state depending on game state.
|
|
|
+ */
|
|
|
public void update() {
|
|
|
- if (view.gameState == GAMESTATE.PLAY || view.gameState == GAMESTATE.INVENTORY) {
|
|
|
- view.camera.update();
|
|
|
- }
|
|
|
- if(view.gameState == GAMESTATE.SAVE){
|
|
|
- GameSaver.saveGame(this);
|
|
|
- view.gameState = GAMESTATE.PLAY;
|
|
|
+ GAMESTATE state = view.gameState;
|
|
|
+ if (state == GAMESTATE.PLAY || state == GAMESTATE.INVENTORY) {
|
|
|
+ updateCamera();
|
|
|
+ } else if (state == GAMESTATE.SAVE) {
|
|
|
+ performSaveAndResume();
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Updates the camera position.
|
|
|
+ */
|
|
|
+ private void updateCamera() {
|
|
|
+ view.camera.update();
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * Saves the game and returns to PLAY state.
|
|
|
+ */
|
|
|
+ private void performSaveAndResume() {
|
|
|
+ GameSaver.saveGame(this);
|
|
|
+ view.gameState = GAMESTATE.PLAY;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * The main run loop implementing Runnable.
|
|
|
+ * Controls timing for updates and rendering.
|
|
|
+ */
|
|
|
@Override
|
|
|
public void run() {
|
|
|
+ runGameLoop();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Implements the game loop timing logic based on fps.
|
|
|
+ */
|
|
|
+ private void runGameLoop() {
|
|
|
double drawInterval = 1_000_000_000.0 / fps;
|
|
|
double delta = 0;
|
|
|
long lastTime = System.nanoTime();
|
|
|
- long currentTime;
|
|
|
long timer = 0;
|
|
|
int drawCount = 0;
|
|
|
|
|
|
while (running) {
|
|
|
- currentTime = System.nanoTime();
|
|
|
+ long currentTime = System.nanoTime();
|
|
|
delta += (currentTime - lastTime) / drawInterval;
|
|
|
timer += (currentTime - lastTime);
|
|
|
lastTime = currentTime;
|
|
|
|
|
|
if (delta >= 1) {
|
|
|
- update(); // Logic update
|
|
|
- view.repaint(); // Triggers paintComponent in view
|
|
|
- moveEntities();
|
|
|
+ if(gameActive){
|
|
|
+ update();
|
|
|
+ moveAllEntities();
|
|
|
+ }
|
|
|
+ view.repaint();
|
|
|
delta--;
|
|
|
drawCount++;
|
|
|
}
|
|
|
|
|
|
if (timer >= 1_000_000_000) {
|
|
|
+ // Could log fps: drawCount
|
|
|
drawCount = 0;
|
|
|
timer = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void moveEntities() {
|
|
|
- if(entityControllers == null) return;
|
|
|
- for(EntityController entityController : entityControllers){
|
|
|
+ /**
|
|
|
+ * Invokes movement logic on all entity controllers.
|
|
|
+ */
|
|
|
+ private void moveAllEntities() {
|
|
|
+ if (entityControllers == null) return;
|
|
|
+ for (EntityController entityController : entityControllers) {
|
|
|
entityController.convertRepaintSpeedToMovementLogic();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void zoomInOut(int i) {
|
|
|
- view.zoomInOut(i);
|
|
|
+ /**
|
|
|
+ * Zooms camera in or out and closes any open menus.
|
|
|
+ *
|
|
|
+ * @param amount positive to zoom in, negative to zoom out
|
|
|
+ */
|
|
|
+ public void zoomInOut(int amount) {
|
|
|
+ view.zoomInOut(amount);
|
|
|
view.closeMenus();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Toggles between PLAY and PAUSED or exits INVENTORY state.
|
|
|
+ */
|
|
|
public void togglePauseOrExitInventory() {
|
|
|
- if (view.gameState == GAMESTATE.INVENTORY) {
|
|
|
+ GAMESTATE state = view.gameState;
|
|
|
+ if (state == GAMESTATE.INVENTORY) {
|
|
|
view.gameState = GAMESTATE.PLAY;
|
|
|
- } else if (view.gameState == GAMESTATE.PLAY) {
|
|
|
+ } else if (state == GAMESTATE.PLAY) {
|
|
|
view.gameState = GAMESTATE.PAUSED;
|
|
|
- } else if (view.gameState == GAMESTATE.PAUSED) {
|
|
|
+ } else if (state == GAMESTATE.PAUSED) {
|
|
|
view.gameState = GAMESTATE.PLAY;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Toggles the inventory UI: enters or exits INVENTORY state.
|
|
|
+ * Deselects inventory item when closing.
|
|
|
+ */
|
|
|
public void toggleInventory() {
|
|
|
if (view.gameState == GAMESTATE.INVENTORY) {
|
|
|
view.gameState = GAMESTATE.PLAY;
|
|
|
- gameModel.getInventory().deselect();
|
|
|
+ getModel().getInventory().deselectAll();
|
|
|
} else if (view.gameState == GAMESTATE.PLAY) {
|
|
|
view.gameState = GAMESTATE.INVENTORY;
|
|
|
}
|
|
|
}
|
|
|
- public GamePanel getView(){
|
|
|
- if(view == null){
|
|
|
- setView(new GamePanel(this));
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the GamePanel view, creating if necessary.
|
|
|
+ *
|
|
|
+ * @return the GamePanel
|
|
|
+ */
|
|
|
+ public GamePanel getView() {
|
|
|
+ if (view == null) {
|
|
|
+ view = new GamePanel(this);
|
|
|
}
|
|
|
return view;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns the GameModel, creating if necessary.
|
|
|
+ *
|
|
|
+ * @return the GameModel
|
|
|
+ */
|
|
|
public GameModel getModel() {
|
|
|
- if(gameModel == null) gameModel = new GameModel();
|
|
|
+ if (gameModel == null) {
|
|
|
+ gameModel = new GameModel();
|
|
|
+ }
|
|
|
return gameModel;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Returns the KeyHandler, creating if necessary.
|
|
|
+ *
|
|
|
+ * @return the KeyHandler
|
|
|
+ */
|
|
|
public KeyHandler getKeyHandler() {
|
|
|
- if(keyHandler == null) keyHandler = new KeyHandler(this);
|
|
|
+ if (keyHandler == null) {
|
|
|
+ keyHandler = new KeyHandler(this);
|
|
|
+ }
|
|
|
return keyHandler;
|
|
|
}
|
|
|
|
|
|
- public void loadWorld(){
|
|
|
- if(view == null) this.view = new GamePanel(this);
|
|
|
+ /**
|
|
|
+ * Loads the world from the default worldPath.
|
|
|
+ */
|
|
|
+ public void loadWorld() {
|
|
|
+ if (view == null) {
|
|
|
+ view = new GamePanel(this);
|
|
|
+ }
|
|
|
view.loadMap(worldPath);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Asks the view to generate a new world.
|
|
|
+ */
|
|
|
public void generateNewWorld() {
|
|
|
- view.generateNewWorld();
|
|
|
+ getView().generateNewWorld();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Handles dragging shifts in screen coordinates, converting to world-grid movement.
|
|
|
+ *
|
|
|
+ * @param dx pixel shift in x
|
|
|
+ * @param dy pixel shift in y
|
|
|
+ */
|
|
|
public void handleTileShift(int dx, int dy) {
|
|
|
if (draggingTile == null) {
|
|
|
return;
|
|
|
}
|
|
|
- // Accumulate residual pixel movement:
|
|
|
+ accumulateResidualShift(dx, dy);
|
|
|
+ applyGridShiftIfNeeded();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Accumulates residual pixel shifts before converting to grid movement.
|
|
|
+ *
|
|
|
+ * @param dx pixel delta x
|
|
|
+ * @param dy pixel delta y
|
|
|
+ */
|
|
|
+ private void accumulateResidualShift(int dx, int dy) {
|
|
|
residualShiftX += dx;
|
|
|
residualShiftY += dy;
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * Checks if enough residual has accumulated to shift by whole tiles, and applies if valid.
|
|
|
+ */
|
|
|
+ private void applyGridShiftIfNeeded() {
|
|
|
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
|
|
|
+ return;
|
|
|
}
|
|
|
-
|
|
|
- // Subtract the used pixels, keep leftover:
|
|
|
+ // Remove used pixels
|
|
|
residualShiftX -= gridShiftX * tileSize;
|
|
|
residualShiftY -= gridShiftY * tileSize;
|
|
|
|
|
|
- // Now shift the stored tile model:
|
|
|
+ attemptTilePositionShift(gridShiftX, gridShiftY);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Attempts to shift the dragging tile model by given grid offsets. Reverts residuals if invalid.
|
|
|
+ *
|
|
|
+ * @param gridShiftX number of tiles to shift in x
|
|
|
+ * @param gridShiftY number of tiles to shift in y
|
|
|
+ */
|
|
|
+ private void attemptTilePositionShift(int gridShiftX, int gridShiftY) {
|
|
|
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);
|
|
|
+ // Revert residual since shift is invalid
|
|
|
+ int tileSize = getView().tileSize;
|
|
|
+ residualShiftX += gridShiftX * tileSize;
|
|
|
+ residualShiftY += gridShiftY * tileSize;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
model.setWorldGridX(newX);
|
|
|
model.setWorldGridY(newY);
|
|
|
- //System.out.printf("Tile shifted from (%d, %d) to (%d, %d)%n", oldX, oldY, newX, newY);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Checks if draggingTile can be placed at new grid coordinates without out-of-bounds or collision.
|
|
|
+ *
|
|
|
+ * @param newX target grid X
|
|
|
+ * @param newY target grid Y
|
|
|
+ * @return true if valid position
|
|
|
+ */
|
|
|
private boolean isValidPosition(int newX, int newY) {
|
|
|
- if (draggingTile == null) return false;
|
|
|
-
|
|
|
+ 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) {
|
|
|
+ InteractiveTileView tileView = draggingTile.getView();
|
|
|
+ int width = tileView.getScaleX();
|
|
|
+ int height = tileView.getScaleY();
|
|
|
+
|
|
|
+ // Check 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
|
|
|
+ // Check collisions
|
|
|
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
|
|
|
+ InteractiveTileController other = getTileAt(x, y);
|
|
|
+ if (other != null && other != draggingTile) {
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- // Hilfsmethoden, um von Screen-Koordinaten in Weltkoordinaten umzurechnen
|
|
|
+ /**
|
|
|
+ * Converts a screen X coordinate to world grid X.
|
|
|
+ *
|
|
|
+ * @param screenX screen X in pixels
|
|
|
+ * @return world grid X coordinate
|
|
|
+ */
|
|
|
public int screenToWorldX(int screenX) {
|
|
|
- return (int)((getView().camera.worldX + screenX - getView().camera.screenX) / getView().tileSize);
|
|
|
+ GamePanel gp = getView();
|
|
|
+ return (gp.camera.worldX + screenX - gp.camera.screenX) / gp.tileSize;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Converts a screen Y coordinate to world grid Y.
|
|
|
+ *
|
|
|
+ * @param screenY screen Y in pixels
|
|
|
+ * @return world grid Y coordinate
|
|
|
+ */
|
|
|
public int screenToWorldY(int screenY) {
|
|
|
- return (int)((getView().camera.worldY + screenY - getView().camera.screenY) / getView().tileSize);
|
|
|
+ GamePanel gp = getView();
|
|
|
+ return (gp.camera.worldY + screenY - gp.camera.screenY) / gp.tileSize;
|
|
|
}
|
|
|
|
|
|
- // Methode, um das Tile unter der aktuellen Weltposition zu bekommen
|
|
|
+ /**
|
|
|
+ * Returns the InteractiveTileController at the specified grid coordinates, or null if none.
|
|
|
+ *
|
|
|
+ * @param worldX grid X coordinate
|
|
|
+ * @param worldY grid Y coordinate
|
|
|
+ * @return the tile controller at that position, or null
|
|
|
+ */
|
|
|
public InteractiveTileController getTileAt(int worldX, int worldY) {
|
|
|
+ if (interactiveTileControllers == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
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())) {
|
|
|
+ int tileX = model.getWorldGridX();
|
|
|
+ int tileY = model.getWorldGridY();
|
|
|
+ int width = tile.getView().getScaleX();
|
|
|
+ int height = tile.getView().getScaleY();
|
|
|
+
|
|
|
+ boolean withinX = (worldX >= tileX && worldX < tileX + width);
|
|
|
+ boolean withinY = (worldY >= tileY && worldY < tileY + height);
|
|
|
+ if (withinX && withinY) {
|
|
|
return tile;
|
|
|
}
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- public void setDraggingTile(InteractiveTileController tileAt) {
|
|
|
- draggingTile = tileAt;
|
|
|
+ /**
|
|
|
+ * Sets the tile currently being dragged.
|
|
|
+ *
|
|
|
+ * @param tile the InteractiveTileController being dragged
|
|
|
+ */
|
|
|
+ public void setDraggingTile(InteractiveTileController tile) {
|
|
|
+ this.draggingTile = tile;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Resets any accumulated residual pixel shift (e.g., when drag ends).
|
|
|
+ */
|
|
|
public void resetResidualShift() {
|
|
|
residualShiftX = 0;
|
|
|
residualShiftY = 0;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Loads interactive tiles and entities from the saved GameModel.
|
|
|
+ */
|
|
|
+ public void loadGame() {
|
|
|
+ loadInteractiveTilesFromSave();
|
|
|
+ loadEntitiesFromSave();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Re-initializes interactiveTileControllers from models in gameModel.
|
|
|
+ */
|
|
|
private void loadInteractiveTilesFromSave() {
|
|
|
interactiveTileControllers = new ArrayList<>();
|
|
|
- for (InteractiveTileModel model : gameModel.getInteractiveTileModels()) {
|
|
|
+ for (InteractiveTileModel model : getModel().getInteractiveTileModels()) {
|
|
|
InteractiveTileController controller = InteractiveTileFactory.createTile(this, model);
|
|
|
if (controller != null) {
|
|
|
- addInteractiveTile(controller);
|
|
|
+ addInteractiveTileController(controller);
|
|
|
} else {
|
|
|
System.err.println("Unknown tile type: " + model.getTileType());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Re-initializes entityControllers from models in gameModel.
|
|
|
+ */
|
|
|
private void loadEntitiesFromSave() {
|
|
|
entityControllers = new ArrayList<>();
|
|
|
- for (EntityModel model : gameModel.getEntityModels()) {
|
|
|
+ for (EntityModel model : getModel().getEntityModels()) {
|
|
|
EntityController controller = EntityFactory.createEntity(this, model);
|
|
|
if (controller != null) {
|
|
|
- addEntity(controller);
|
|
|
+ addEntityController(controller);
|
|
|
} else {
|
|
|
System.err.println("Unknown entity type: " + model.getEntityType());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public void loadGame() {
|
|
|
- loadInteractiveTilesFromSave();
|
|
|
- loadEntitiesFromSave();
|
|
|
+ /**
|
|
|
+ * Initializes the Main Menu for changing worlds etc.
|
|
|
+ */
|
|
|
+ public void loadMainMenu() {
|
|
|
+
|
|
|
}
|
|
|
|
|
|
+ public boolean isRunning() {
|
|
|
+ return running;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addToInventory(Item collected) {
|
|
|
+ getModel().getInventory().addToInventory(collected);
|
|
|
+ }
|
|
|
}
|
|
|
+
|