TileManager.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. package view.tile;
  2. import controller.tiles.interactive.InteractiveTileController;
  3. import model.Tile;
  4. import model.tiles.BackgroundTile;
  5. import model.tiles.InteractiveTileModel;
  6. import util.WorldGenerator;
  7. import view.GamePanel;
  8. import view.sound.SoundManager;
  9. import view.tile.interactive.InteractiveTileView;
  10. import view.util.RenderingManager;
  11. import java.awt.*;
  12. import java.io.*;
  13. public class TileManager implements RenderingManager {
  14. private GamePanel gamePanel;
  15. private Tile[] tile;
  16. private int[][] mapTileNum;
  17. private int mapTileOverflow = 1;
  18. private InteractiveTileController draggingTile;
  19. private int originalGridX, originalGridY;
  20. public TileManager(GamePanel gp){
  21. this.gamePanel = gp;
  22. tile = new Tile[10];
  23. mapTileNum = new int[GamePanel.maxWorldCol][GamePanel.maxWorldRow];
  24. getTileImage();
  25. }
  26. public int getTileSize(){
  27. return gamePanel.tileSize;
  28. }
  29. public void addInteractiveTile(InteractiveTileController tile) {
  30. gamePanel.gameController.interactiveTileControllers.add(tile);
  31. }
  32. public void loadMap(String filePath){
  33. try{
  34. InputStream is = getClass().getResourceAsStream(filePath);
  35. BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
  36. int col = 0;
  37. int row = 0;
  38. while(col < gamePanel.maxWorldCol && row < gamePanel.maxWorldRow){
  39. String line = br.readLine();
  40. while(col < gamePanel.maxWorldRow){
  41. String numbers[] = line.split(" ");
  42. int num = Integer.parseInt(numbers[col]);
  43. mapTileNum[col][row] = num;
  44. col++;
  45. }
  46. if(col == gamePanel.maxWorldCol) {
  47. col = 0;
  48. row++;
  49. }
  50. }
  51. br.close();
  52. }catch (Exception e){
  53. System.out.println("Couldn't find world path... Creating new World...");
  54. gamePanel.generateNewWorld();
  55. }
  56. }
  57. public void draw(Graphics2D g2){
  58. int worldCol = 0;
  59. int worldRow = 0;
  60. while (worldCol< gamePanel.maxWorldCol && worldRow < gamePanel.maxWorldRow){
  61. int tileNum = mapTileNum[worldCol][worldRow];
  62. int worldX = worldCol * gamePanel.tileSize;
  63. int worldY = worldRow * gamePanel.tileSize;
  64. double screenX = worldX - gamePanel.camera.worldX + gamePanel.camera.screenX;
  65. double screenY = worldY - gamePanel.camera.worldY + gamePanel.camera.screenY;
  66. if(worldX + gamePanel.tileSize*mapTileOverflow > gamePanel.camera.worldX - gamePanel.camera.screenX &&
  67. worldX - gamePanel.tileSize*mapTileOverflow < gamePanel.camera.worldX + gamePanel.camera.screenX &&
  68. worldY + gamePanel.tileSize*mapTileOverflow > gamePanel.camera.worldY - gamePanel.camera.screenY &&
  69. worldY - gamePanel.tileSize*mapTileOverflow < gamePanel.camera.worldY + gamePanel.camera.screenY ) {
  70. g2.drawImage(tile[tileNum].image, (int) screenX, (int) screenY, gamePanel.tileSize, gamePanel.tileSize, null);
  71. }
  72. worldCol++;
  73. if(worldCol == gamePanel.maxWorldCol){
  74. worldCol = 0;
  75. worldRow++;
  76. }
  77. }
  78. drawAllTiles(g2);
  79. }
  80. /**
  81. * Entry point for dragging movement: called from GameMouseListener.mouseDragged when right mouse button.
  82. * dx, dy are screen pixel deltas.
  83. */
  84. public void handleTileShift(int dx, int dy) {
  85. if (draggingTile == null) {
  86. return;
  87. }
  88. // Smooth pixel-based move: update view's screen coordinates by delta
  89. InteractiveTileView view = draggingTile.getView();
  90. view.setScreenCoordinates(view.getScreenX() + dx, view.getScreenY() + dy);
  91. }
  92. /**
  93. * Drawing loop: update view coords from model for non-dragged tiles; draw all.
  94. */
  95. public void drawAllTiles(Graphics2D g2) {
  96. // Optionally draw non-dragged first, then dragged to render on top
  97. for (InteractiveTileController tile : gamePanel.gameController.interactiveTileControllers) {
  98. if (!isTileDragged(tile)) {
  99. InteractiveTileModel model = tile.getModel();
  100. int sx = worldColToScreenX(model.getWorldGridX());
  101. int sy = worldRowToScreenY(model.getWorldGridY());
  102. tile.getView().setScreenCoordinates(sx, sy);
  103. tile.drawTile(g2);
  104. }
  105. }
  106. if (getDraggedTile() != null) {
  107. // Draw dragged tile on top
  108. getDraggedTile().drawTile(g2);
  109. }
  110. }
  111. public int worldColToScreenX(int worldCol) {
  112. double worldX = worldCol * gamePanel.tileSize; // Reactively use tileSize
  113. return (int) (worldX - gamePanel.camera.worldX + gamePanel.camera.screenX);
  114. }
  115. public int worldRowToScreenY(int worldRow) {
  116. double worldY = worldRow * gamePanel.tileSize; // Reactively use tileSize
  117. return (int) (worldY - gamePanel.camera.worldY + gamePanel.camera.screenY);
  118. }
  119. public void getTileImage(){
  120. try{
  121. setupTile(0, "grass");
  122. setupTile(1, "wall");
  123. setupTile(2, "water");
  124. setupTile(3, "earth");
  125. setupTile(4, "tree");
  126. setupTile(5, "sand");
  127. }catch (IOException e){
  128. e.printStackTrace();
  129. }
  130. }
  131. private void setupTile(int index, String path) throws IOException {
  132. tile[index] = new BackgroundTile();
  133. tile[index].setImage("/tiles/background/" + path + ".png");
  134. }
  135. private void setupInteractiveTile( int index, String path) throws IOException {
  136. tile[index] = new BackgroundTile();
  137. tile[index].setImage("/tiles/" + path + ".png");
  138. }
  139. public void generateNewWorld() {
  140. String filePath = WorldGenerator.generateNewWorld(GamePanel.maxWorldCol, GamePanel.maxWorldRow, (int) Math.floor(Math.random()*100000));
  141. loadMap(filePath);
  142. }
  143. @Override
  144. public void drawPopup(Graphics2D g2) {
  145. for (InteractiveTileController tile : gamePanel.gameController.interactiveTileControllers) {
  146. tile.drawPopup(g2);
  147. }
  148. }
  149. @Override
  150. public void resize(int newTileSize) {
  151. for (InteractiveTileController tile : gamePanel.gameController.interactiveTileControllers) {
  152. tile.resize(newTileSize);
  153. }
  154. }
  155. public void handleTileRelease() {
  156. SoundManager.getInstance().stopLoopSound(SoundManager.SOUNDS.MOVING_BUSH);
  157. if (draggingTile == null) {
  158. return;
  159. }
  160. InteractiveTileView view = draggingTile.getView();
  161. InteractiveTileModel model = draggingTile.getModel();
  162. int tileSize = gamePanel.tileSize;
  163. int widthTiles = view.getScaleX();
  164. int heightTiles = view.getScaleY();
  165. // Compute the screen coordinates of the tile's top-left
  166. int dropScreenX = view.getScreenX();
  167. int dropScreenY = view.getScreenY();
  168. // Compute the center pixel position of the tile
  169. int centerScreenX = dropScreenX + (widthTiles * tileSize) / 2;
  170. int centerScreenY = dropScreenY + (heightTiles * tileSize) / 2;
  171. // Convert center to world grid coordinate (floor)
  172. int centerGridX = screenToWorldX(centerScreenX);
  173. int centerGridY = screenToWorldY(centerScreenY);
  174. // Compute top-left grid position so that tile center aligns to centerGrid
  175. int targetGridX = centerGridX - (widthTiles / 2);
  176. int targetGridY = centerGridY - (heightTiles / 2);
  177. if (isValidPosition(targetGridX, targetGridY)) {
  178. model.setWorldGridX(targetGridX);
  179. model.setWorldGridY(targetGridY);
  180. } else {
  181. // Revert to original grid position
  182. model.setWorldGridX(originalGridX);
  183. model.setWorldGridY(originalGridY);
  184. }
  185. // After updating model, reset view’s screen coords to the snapped grid position
  186. int snappedScreenX = worldColToScreenX(model.getWorldGridX());
  187. int snappedScreenY = worldRowToScreenY(model.getWorldGridY());
  188. view.setScreenCoordinates(snappedScreenX, snappedScreenY);
  189. // Clear dragging state
  190. draggingTile = null;
  191. }
  192. /**
  193. * Checks if draggingTile can be placed at new grid coordinates without out-of-bounds or collision.
  194. *
  195. * @param newX target grid X
  196. * @param newY target grid Y
  197. * @return true if valid position
  198. */
  199. private boolean isValidPosition(int newX, int newY) {
  200. if (draggingTile == null) {
  201. return false;
  202. }
  203. InteractiveTileModel model = draggingTile.getModel();
  204. InteractiveTileView tileView = draggingTile.getView();
  205. int width = tileView.getScaleX();
  206. int height = tileView.getScaleY();
  207. // Check world bounds
  208. if (newX < 0 || newY < 0
  209. || newX + width > GamePanel.maxWorldCol
  210. || newY + height > GamePanel.maxWorldRow) {
  211. return false;
  212. }
  213. // Check collisions
  214. for (int x = newX; x < newX + width; x++) {
  215. for (int y = newY; y < newY + height; y++) {
  216. InteractiveTileController other = getTileAt(x, y);
  217. if (other != null && other != draggingTile) {
  218. return false;
  219. }
  220. }
  221. }
  222. return true;
  223. }
  224. /**
  225. * Returns the InteractiveTileController at the specified grid coordinates, or null if none.
  226. *
  227. * @param worldX grid X coordinate
  228. * @param worldY grid Y coordinate
  229. * @return the tile controller at that position, or null
  230. */
  231. public InteractiveTileController getTileAt(int worldX, int worldY) {
  232. if (gamePanel.gameController.interactiveTileControllers == null) {
  233. return null;
  234. }
  235. for (InteractiveTileController tile : gamePanel.gameController.interactiveTileControllers) {
  236. InteractiveTileModel model = tile.getModel();
  237. int tileX = model.getWorldGridX();
  238. int tileY = model.getWorldGridY();
  239. int width = tile.getView().getScaleX();
  240. int height = tile.getView().getScaleY();
  241. boolean withinX = (worldX >= tileX && worldX < tileX + width);
  242. boolean withinY = (worldY >= tileY && worldY < tileY + height);
  243. if (withinX && withinY) {
  244. return tile;
  245. }
  246. }
  247. return null;
  248. }
  249. // screenToWorldX/Y assumed unchanged
  250. public int screenToWorldX(int screenX) {
  251. return (gamePanel.camera.worldX + screenX - gamePanel.camera.screenX) / gamePanel.tileSize;
  252. }
  253. public int screenToWorldY(int screenY) {
  254. return (gamePanel.camera.worldY + screenY - gamePanel.camera.screenY) / gamePanel.tileSize;
  255. }
  256. /**
  257. *
  258. */
  259. public boolean isTileDragged(InteractiveTileController controller){
  260. return draggingTile == controller;
  261. }
  262. public InteractiveTileController getDraggedTile() {
  263. return draggingTile;
  264. }
  265. public void setDraggingTile(InteractiveTileController tile) {
  266. draggingTile = tile;
  267. if (draggingTile != null) {
  268. InteractiveTileModel model = draggingTile.getModel();
  269. originalGridX = model.getWorldGridX();
  270. originalGridY = model.getWorldGridY();
  271. // Optionally, ensure view's screen coords are set initially
  272. InteractiveTileView view = draggingTile.getView();
  273. int sx = worldColToScreenX(originalGridX);
  274. int sy = worldRowToScreenY(originalGridY);
  275. view.setScreenCoordinates(sx, sy);
  276. }
  277. }
  278. }