From 50b7c186f8a921efac205fcf556816c21c635503 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Tue, 26 Sep 2023 22:52:17 +1000 Subject: [PATCH 01/13] Added colorTile --- .../game/areas/terrain/TerrainComponent.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java index 4e9f2f8ed..100f53ebf 100644 --- a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java +++ b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java @@ -1,13 +1,22 @@ package com.csse3200.game.areas.terrain; import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMapRenderer; +import com.badlogic.gdx.maps.tiled.TiledMapTile; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; +import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile; import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.Action; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.csse3200.game.rendering.RenderComponent; +import com.csse3200.game.services.ServiceLocator; /** * Render a tiled terrain for a given tiled map and orientation. A terrain is a map of tiles that @@ -21,6 +30,7 @@ public class TerrainComponent extends RenderComponent { private final OrthographicCamera camera; private final TerrainOrientation orientation; private final float tileSize; + private Texture blueTexture; public TerrainComponent( OrthographicCamera camera, @@ -33,6 +43,14 @@ public TerrainComponent( this.orientation = orientation; this.tileSize = tileSize; this.tiledMapRenderer = renderer; + Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); + pixmap.setColor(0, 0, 1, 1); // Set to blue color (R=0, G=0, B=1, Alpha=1) + pixmap.fill(); + blueTexture = new Texture(pixmap); + +// Remember to dispose of the Pixmap once you're done with it to free up memory + pixmap.dispose(); + } public Vector2 tileToWorldPosition(GridPoint2 tilePos) { @@ -89,6 +107,30 @@ public int getLayer() { return TERRAIN_LAYER; } + public void colorTile(int x,int y) { + TiledMapTileLayer tile = (TiledMapTileLayer) tiledMap.getLayers().get(0); + TiledMapTile originalTile = tile.getCell(x,y).getTile(); + StaticTiledMapTile blueTile = new StaticTiledMapTile(new TextureRegion(blueTexture)); +// tile.getCell(x,y).setTile(); + tile.getCell((int) x, (int) y).setTile(blueTile); + + // Create an actor to handle the fade-in and fade-out effect + Actor fadeActor = new Actor(); + fadeActor.addAction(Actions.sequence( + Actions.fadeIn(1f), + Actions.fadeOut(1f), + new Action() { + @Override + public boolean act(float delta) { + tile.getCell(x, y).setTile(originalTile); + return true; + } + } + )); + // Add this actor to the stage to process the actions + ServiceLocator.getRenderService().getStage().addActor(fadeActor); + } + public enum TerrainOrientation { ORTHOGONAL, ISOMETRIC, From b9bd13b268990afe433859722d8642c52b2f1750 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Fri, 29 Sep 2023 16:04:55 +1000 Subject: [PATCH 02/13] Added some Images --- .../assets/images/GrassTile/grass_tile_1.png | Bin 0 -> 5558 bytes .../assets/images/GrassTile/grass_tile_2.png | Bin 0 -> 5558 bytes .../assets/images/GrassTile/grass_tile_3.png | Bin 0 -> 5561 bytes .../assets/images/GrassTile/grass_tile_4.png | Bin 0 -> 5560 bytes .../assets/images/GrassTile/grass_tile_5.png | Bin 0 -> 5559 bytes .../assets/images/GrassTile/grass_tile_6.png | Bin 0 -> 5559 bytes .../assets/images/GrassTile/grass_tile_7.png | Bin 0 -> 5557 bytes source/core/assets/images/grass_2.png | Bin 62732 -> 5560 bytes source/core/assets/images/highlight_tile.png | Bin 0 -> 8435 bytes 9 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 source/core/assets/images/GrassTile/grass_tile_1.png create mode 100644 source/core/assets/images/GrassTile/grass_tile_2.png create mode 100644 source/core/assets/images/GrassTile/grass_tile_3.png create mode 100644 source/core/assets/images/GrassTile/grass_tile_4.png create mode 100644 source/core/assets/images/GrassTile/grass_tile_5.png create mode 100644 source/core/assets/images/GrassTile/grass_tile_6.png create mode 100644 source/core/assets/images/GrassTile/grass_tile_7.png create mode 100644 source/core/assets/images/highlight_tile.png diff --git a/source/core/assets/images/GrassTile/grass_tile_1.png b/source/core/assets/images/GrassTile/grass_tile_1.png new file mode 100644 index 0000000000000000000000000000000000000000..770193053913337b9dbcdd7e24b1745ab4f731cd GIT binary patch literal 5558 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 Hu0mjf_tVC+ literal 0 HcmV?d00001 diff --git a/source/core/assets/images/GrassTile/grass_tile_4.png b/source/core/assets/images/GrassTile/grass_tile_4.png new file mode 100644 index 0000000000000000000000000000000000000000..846fbc18452752189efc10c0880c1b82ebfd326d GIT binary patch literal 5560 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 DOJd9D literal 0 HcmV?d00001 diff --git a/source/core/assets/images/grass_2.png b/source/core/assets/images/grass_2.png index 81dbc6ef70fac96d23a906bc0c4fed2eff753dcf..bc1ab9447c18656d8c5a6e4ef41a8f0b15bb44f3 100644 GIT binary patch literal 5560 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

C{id7bzJ#o%74nrb|ptg%b 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 dv@43_BP$WSzgz1QLF%0D=-#`DzHa;C{{dB=*1!M& diff --git a/source/core/assets/images/highlight_tile.png b/source/core/assets/images/highlight_tile.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6883788d43c8057bd904373cd4f930f5ea2db6 GIT binary patch literal 8435 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 Tw;zvV-vDiOJ+&GY`-uMlzaLJF literal 0 HcmV?d00001 From e0c0cd0429a2166bb6f3d7292b04e94380dd4170 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Fri, 29 Sep 2023 16:18:09 +1000 Subject: [PATCH 03/13] Fixed a bug in TerrainFactory where all Cells were filled with the same TerrainTile --- .../com/csse3200/game/areas/ForestGameArea.java | 15 +++++++++++++-- .../game/areas/terrain/TerrainFactory.java | 16 +++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index 3ed44061f..8340eab9d 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.Vector2; +import com.csse3200.game.areas.terrain.TerrainComponent; import com.csse3200.game.components.ProjectileEffects; import com.csse3200.game.areas.terrain.TerrainFactory; import com.csse3200.game.areas.terrain.TerrainFactory.TerrainType; @@ -114,7 +115,15 @@ public class ForestGameArea extends GameArea { "images/mobboss/demon.png", "images/mobboss/demon2.png", "images/mobs/fire_worm.png", - "images/mobboss/patrick.png" + "images/mobboss/patrick.png", + "images/GrassTile/grass_tile_1.png", + "images/GrassTile/grass_tile_2.png", + "images/GrassTile/grass_tile_3.png", + "images/GrassTile/grass_tile_4.png", + "images/GrassTile/grass_tile_5.png", + "images/GrassTile/grass_tile_6.png", + "images/GrassTile/grass_tile_7.png", + "images/highlight_tile.png" }; private static final String[] forestTextureAtlases = { "images/economy/econ-tower.atlas", @@ -281,7 +290,9 @@ private void displayUI() { private void spawnTerrain() { terrain = terrainFactory.createTerrain(TerrainType.ALL_DEMO); - spawnEntity(new Entity().addComponent(terrain)); + // TODO: We might need a MapService + Entity entity = new Entity().addComponent(terrain); + spawnEntity(entity); // Terrain walls float tileSize = terrain.getTileSize(); diff --git a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainFactory.java b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainFactory.java index d6377e4a1..dfbd4f782 100644 --- a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainFactory.java +++ b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainFactory.java @@ -1,6 +1,7 @@ package com.csse3200.game.areas.terrain; import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.maps.tiled.TiledMap; @@ -8,6 +9,7 @@ import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell; import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; +import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile; import com.badlogic.gdx.math.GridPoint2; import com.csse3200.game.components.CameraComponent; import com.csse3200.game.services.ResourceService; @@ -81,7 +83,7 @@ private TerrainComponent createTerrain(float tileWorldSize, TextureRegion terrai * @return A TiledMapRenderer instance suitable for the given map and scale. */ - private TiledMapRenderer createRenderer(TiledMap tiledMap, float tileScale) { + public TiledMapRenderer createRenderer(TiledMap tiledMap, float tileScale) { switch (orientation) { case ORTHOGONAL: return new OrthogonalTiledMapRenderer(tiledMap, tileScale); @@ -100,9 +102,8 @@ private TiledMapRenderer createRenderer(TiledMap tiledMap, float tileScale) { private TiledMap createTiles(GridPoint2 tileSize, TextureRegion terrain) { TiledMap tiledMap = new TiledMap(); - TerrainTile Tile = new TerrainTile(terrain); - TiledMapTileLayer Layer = new TiledMapTileLayer(20, 8, tileSize.x, tileSize.y); - fillInvisibleTiles(Layer, new GridPoint2(20, 8), Tile); + TiledMapTileLayer Layer = new TiledMapTileLayer(20, 6, tileSize.x, tileSize.y); + fillInvisibleTiles(Layer, new GridPoint2(20, 6), terrain); tiledMap.getLayers().add(Layer); return tiledMap; @@ -114,11 +115,12 @@ private TiledMap createTiles(GridPoint2 tileSize, TextureRegion terrain) { * * @param layer The tile layer to fill. * @param mapSize The size of the map in tiles. - * @param tile The tile used to fill the layer. + * @param terrain The tile used to fill the layer. */ - private void fillInvisibleTiles(TiledMapTileLayer layer, GridPoint2 mapSize, TerrainTile tile) { + private void fillInvisibleTiles(TiledMapTileLayer layer, GridPoint2 mapSize, TextureRegion terrain) { for (int x = 0; x < mapSize.x; x++) { - for (int y = 2; y < mapSize.y; y++) { + for (int y = 0; y < mapSize.y; y++) { + TerrainTile tile = new TerrainTile(terrain); Cell cell = new Cell(); cell.setTile(tile); layer.setCell(x, y, cell); From a5166a5429bd67e95f8d29ceaf9e202236c11996 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Fri, 29 Sep 2023 16:19:03 +1000 Subject: [PATCH 04/13] Implemented the tile highlighting functionality --- .../game/areas/terrain/TerrainComponent.java | 112 ++++++++++++------ 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java index 100f53ebf..f83b8ef69 100644 --- a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java +++ b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java @@ -1,28 +1,29 @@ package com.csse3200.game.areas.terrain; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Pixmap; -import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.*; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMapRenderer; import com.badlogic.gdx.maps.tiled.TiledMapTile; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; -import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile; import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.scenes.scene2d.Action; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.actions.Actions; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.utils.Timer; import com.csse3200.game.rendering.RenderComponent; +import com.csse3200.game.services.ResourceService; import com.csse3200.game.services.ServiceLocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Render a tiled terrain for a given tiled map and orientation. A terrain is a map of tiles that * shows the 'ground' in the game. Enabling/disabling this component will show/hide the terrain. */ public class TerrainComponent extends RenderComponent { + private static final Logger logger = LoggerFactory.getLogger(TerrainComponent.class); private static final int TERRAIN_LAYER = 0; private final TiledMap tiledMap; @@ -30,7 +31,11 @@ public class TerrainComponent extends RenderComponent { private final OrthographicCamera camera; private final TerrainOrientation orientation; private final float tileSize; - private Texture blueTexture; + private TiledMapTileLayer.Cell lastHoveredCell = null; + private TiledMapTile originalTile = null; + private TextureRegion originalRegion = null; + + public TerrainComponent( OrthographicCamera camera, @@ -43,13 +48,6 @@ public TerrainComponent( this.orientation = orientation; this.tileSize = tileSize; this.tiledMapRenderer = renderer; - Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); - pixmap.setColor(0, 0, 1, 1); // Set to blue color (R=0, G=0, B=1, Alpha=1) - pixmap.fill(); - blueTexture = new Texture(pixmap); - -// Remember to dispose of the Pixmap once you're done with it to free up memory - pixmap.dispose(); } @@ -88,6 +86,7 @@ public TiledMap getMap() { @Override public void draw(SpriteBatch batch) { tiledMapRenderer.setView(camera); + hoverHighlight(); tiledMapRenderer.render(); } @@ -107,28 +106,67 @@ public int getLayer() { return TERRAIN_LAYER; } - public void colorTile(int x,int y) { - TiledMapTileLayer tile = (TiledMapTileLayer) tiledMap.getLayers().get(0); - TiledMapTile originalTile = tile.getCell(x,y).getTile(); - StaticTiledMapTile blueTile = new StaticTiledMapTile(new TextureRegion(blueTexture)); -// tile.getCell(x,y).setTile(); - tile.getCell((int) x, (int) y).setTile(blueTile); - - // Create an actor to handle the fade-in and fade-out effect - Actor fadeActor = new Actor(); - fadeActor.addAction(Actions.sequence( - Actions.fadeIn(1f), - Actions.fadeOut(1f), - new Action() { - @Override - public boolean act(float delta) { - tile.getCell(x, y).setTile(originalTile); - return true; - } - } - )); - // Add this actor to the stage to process the actions - ServiceLocator.getRenderService().getStage().addActor(fadeActor); + // TODO : This is just a visual effect that we might not need in the end but just keeping it here for now + public void colorTile(final int x, final int y) { + final TiledMapTileLayer tileLayer = (TiledMapTileLayer) tiledMap.getLayers().get(0); + final TiledMapTile originalTile = tileLayer.getCell(x, y).getTile(); + + ResourceService resourceService = ServiceLocator.getResourceService(); + + // Load all the tiles into an array + final TerrainTile[] terrainTiles = new TerrainTile[7]; + for (int i = 0; i < 7; i++) { + Texture texture = resourceService.getAsset("images/GrassTile/grass_tile_" + (i + 1) + ".png", Texture.class); + terrainTiles[i] = new TerrainTile(new TextureRegion(texture)); + } + + final float interval = 0.2f; // Switch every 0.2 seconds + final float duration = 1.4f; // 7 images * 0.2 seconds each + + Timer.schedule(new Timer.Task() { + float timeElapsed = 0.0f; + + @Override + public void run() { + timeElapsed += interval; + + if (timeElapsed >= duration) { + tileLayer.getCell(x, y).setTile(originalTile); // Reset to original tile after the total duration + this.cancel(); // End the timer task + } else { + int index = (int) (timeElapsed / interval); + tileLayer.getCell(x, y).setTile(terrainTiles[index]); + } + } + }, 0, interval, (int) (duration / interval) - 1); // Scheduling the task + } + + public void hoverHighlight() { + Vector3 mousePos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + camera.unproject(mousePos); + + + int tileX = (int) (mousePos.x / tileSize); + int tileY = (int) (mousePos.y / tileSize); + + final TiledMapTileLayer tileLayer = (TiledMapTileLayer) tiledMap.getLayers().get(0); + TiledMapTileLayer.Cell currentCell = tileLayer.getCell(tileX, tileY); + + + if (lastHoveredCell != null && lastHoveredCell != currentCell && originalRegion != null) { + lastHoveredCell.getTile().setTextureRegion(originalRegion); + } + + + if (currentCell != null && currentCell != lastHoveredCell) { + originalRegion = currentCell.getTile().getTextureRegion(); + + ResourceService resourceService = ServiceLocator.getResourceService(); + Texture texture = resourceService.getAsset("images/highlight_tile.png", Texture.class); + currentCell.getTile().setTextureRegion(new TextureRegion(texture)); + } + + lastHoveredCell = currentCell; } public enum TerrainOrientation { From 699ce0039361809bafbe84ce1542ba7677b76d29 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Fri, 29 Sep 2023 16:19:35 +1000 Subject: [PATCH 05/13] Wrote some Junit tests --- .../areas/terrain/TerrainComponentTest.java | 47 ++++++++++++++ .../areas/terrain/TerrainFactoryTest.java | 63 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 source/core/src/test/com/csse3200/game/areas/terrain/TerrainFactoryTest.java diff --git a/source/core/src/test/com/csse3200/game/areas/terrain/TerrainComponentTest.java b/source/core/src/test/com/csse3200/game/areas/terrain/TerrainComponentTest.java index 6761b39b9..72961fb8d 100644 --- a/source/core/src/test/com/csse3200/game/areas/terrain/TerrainComponentTest.java +++ b/source/core/src/test/com/csse3200/game/areas/terrain/TerrainComponentTest.java @@ -3,12 +3,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.maps.MapLayers; import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMapRenderer; +import com.badlogic.gdx.maps.tiled.TiledMapTile; +import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; import com.badlogic.gdx.math.Vector2; import com.csse3200.game.areas.terrain.TerrainComponent.TerrainOrientation; import com.csse3200.game.extensions.GameExtension; +import static org.mockito.Mockito.*; + +import com.csse3200.game.services.ResourceService; +import com.csse3200.game.services.ServiceLocator; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -35,6 +46,42 @@ void shouldConvertPositionHexagonal() { TerrainComponent component = makeComponent(TerrainOrientation.HEXAGONAL, 3f); } + @Test + void shouldHighlightTileOnHover1() { + + TerrainComponent component = makeComponent(TerrainOrientation.ORTHOGONAL, 1f); + + // Mock Gdx input to return specific mouse position + Gdx.input = mock(Input.class); + when(Gdx.input.getX()).thenReturn(2); + when(Gdx.input.getY()).thenReturn(4); + + + MapLayers mockLayers = mock(MapLayers.class); + when(component.getMap().getLayers()).thenReturn(mockLayers); + + TiledMapTileLayer mockTileLayer = mock(TiledMapTileLayer.class); + when(mockLayers.get(0)).thenReturn(mockTileLayer); + + TiledMapTileLayer.Cell mockCell = mock(TiledMapTileLayer.Cell.class); + when(mockTileLayer.getCell(2, 4)).thenReturn(mockCell); + + TiledMapTile mockTile = mock(TiledMapTile.class); + when(mockCell.getTile()).thenReturn(mockTile); + + + Texture mockTexture = mock(Texture.class); + ServiceLocator.registerResourceService(mock(ResourceService.class)); + when(ServiceLocator.getResourceService().getAsset("images/highlight_tile.png", Texture.class)) + .thenReturn(mockTexture); + + + component.hoverHighlight(); + + // Verify that the tile's texture region was changed + verify(mockTile).setTextureRegion(any(TextureRegion.class)); + } + private static TerrainComponent makeComponent(TerrainOrientation orientation, float tileSize) { OrthographicCamera camera = mock(OrthographicCamera.class); TiledMap map = mock(TiledMap.class); diff --git a/source/core/src/test/com/csse3200/game/areas/terrain/TerrainFactoryTest.java b/source/core/src/test/com/csse3200/game/areas/terrain/TerrainFactoryTest.java new file mode 100644 index 000000000..c70237fd5 --- /dev/null +++ b/source/core/src/test/com/csse3200/game/areas/terrain/TerrainFactoryTest.java @@ -0,0 +1,63 @@ +package com.csse3200.game.areas.terrain; + +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.maps.tiled.TiledMap; +import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; +import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; +import com.csse3200.game.components.CameraComponent; +import com.csse3200.game.services.ResourceService; +import com.csse3200.game.services.ServiceLocator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +public class TerrainFactoryTest { + + private TerrainFactory terrainFactory; + private CameraComponent mockedCameraComponent; + private OrthogonalTiledMapRenderer mockedRenderer; + private ResourceService mockResourceService; + private Texture mockTexture; + + @BeforeEach + public void setUp() { + // Create mocks + mockedCameraComponent = mock(CameraComponent.class); + mockedRenderer = mock(OrthogonalTiledMapRenderer.class); + mockResourceService = mock(ResourceService.class); + mockTexture = mock(Texture.class); + + + ServiceLocator.registerResourceService(mockResourceService); + + + OrthographicCamera mockedCamera = mock(OrthographicCamera.class); + when(mockedCameraComponent.getCamera()).thenReturn(mockedCamera); + + + terrainFactory = spy(new TerrainFactory(mockedCameraComponent)); + + + // When createRenderer is called on terrainFactory return the mockedRenderer + doReturn(mockedRenderer).when(terrainFactory).createRenderer(any(TiledMap.class), anyFloat()); + } + + @Test + public void testCreateTerrainGeneral() { + // Given the texture is taken from the ResourceService + when(mockResourceService.getAsset("images/terrain_use.png", Texture.class)).thenReturn(mockTexture); + + + TerrainComponent terrainComponent = terrainFactory.createTerrain(TerrainFactory.TerrainType.ALL_DEMO); + TiledMapTileLayer layer = (TiledMapTileLayer) terrainComponent.getMap().getLayers().get(0); + + // the terrainComponent should not be null + assertNotNull(terrainComponent, "TerrainComponent should not be null"); + assertEquals(6,layer.getHeight()); // 6 lanes + assertEquals(20,layer.getWidth()); // 20 tiles per lane + + } +} From a9c5805113f6b850f16fcdc01182b60d3adcad3d Mon Sep 17 00:00:00 2001 From: Mohamad Date: Fri, 29 Sep 2023 16:30:12 +1000 Subject: [PATCH 06/13] Added JavaDoc comment --- .../game/areas/terrain/TerrainComponent.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java index f83b8ef69..3b56b4ab5 100644 --- a/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java +++ b/source/core/src/main/com/csse3200/game/areas/terrain/TerrainComponent.java @@ -141,6 +141,25 @@ public void run() { }, 0, interval, (int) (duration / interval) - 1); // Scheduling the task } + /** + * Highlights the tile under the mouse cursor by changing its texture region. + * + *

When hovering over a tile on the terrain, this method performs the following: + *

    + *
  1. Unprojects the mouse's screen position to the world position using the camera.
  2. + *
  3. Calculates the tile's coordinates based on the world position and tile size.
  4. + *
  5. If there was a previously highlighted tile, it restores its original texture region.
  6. + *
  7. If the current tile under the mouse is different from the last hovered tile, it updates + * the tile's texture region to a highlight texture.
  8. + *
  9. Updates the reference to the last hovered tile.
  10. + *
+ *

+ * + * @see TiledMapTileLayer + * @see TiledMapTileLayer.Cell + * @see TextureRegion + */ + public void hoverHighlight() { Vector3 mousePos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); camera.unproject(mousePos); From 1b28d477292e245e4298453cb77378335400a3fc Mon Sep 17 00:00:00 2001 From: Mohamad Date: Sat, 30 Sep 2023 15:51:51 +1000 Subject: [PATCH 07/13] Did some changes --- .../main/com/csse3200/game/areas/ForestGameArea.java | 12 ++++++------ .../game/components/tower/TNTDamageComponent.java | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index 8340eab9d..b03689e32 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -596,8 +596,8 @@ private void spawnWaterSlime() { // } private void spawnWeaponTower() { - GridPoint2 minPos = new GridPoint2(0, 2); - GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); + GridPoint2 minPos = new GridPoint2(0, 0); + GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 1); for (int i = 0; i < NUM_WEAPON_TOWERS + 10; i++) { GridPoint2 randomPos1 = RandomUtils.random(minPos, maxPos); @@ -625,8 +625,8 @@ private void spawnDroidTowerAt(int x, int y) { } private void spawnTNTTower() { - GridPoint2 minPos = new GridPoint2(0, 2); - GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); + GridPoint2 minPos = new GridPoint2(0, 0); + GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 1); for (int i = 0; i < NUM_WEAPON_TOWERS; i++) { GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); @@ -637,8 +637,8 @@ private void spawnTNTTower() { } private void spawnDroidTower() { - GridPoint2 minPos = new GridPoint2(0, 2); - GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); + GridPoint2 minPos = new GridPoint2(0, 0); + GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 1); for (int i = 0; i < NUM_WEAPON_TOWERS; i++) { GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); diff --git a/source/core/src/main/com/csse3200/game/components/tower/TNTDamageComponent.java b/source/core/src/main/com/csse3200/game/components/tower/TNTDamageComponent.java index 775653651..e7ba86ef6 100644 --- a/source/core/src/main/com/csse3200/game/components/tower/TNTDamageComponent.java +++ b/source/core/src/main/com/csse3200/game/components/tower/TNTDamageComponent.java @@ -124,6 +124,7 @@ private void applyDamage(Fixture me, Fixture other) { Body targetBody = physicsComponent.getBody(); Vector2 direction = target.getCenterPosition().sub(entity.getCenterPosition()).nor(); + direction.y = 0; Vector2 impulse = direction.scl(knockbackForce); targetBody.applyLinearImpulse(impulse, targetBody.getWorldCenter(), true); } From 0ee86dceb7e09911a55cafa2f906129631cd419f Mon Sep 17 00:00:00 2001 From: Mohamad Date: Sun, 1 Oct 2023 16:25:17 +1000 Subject: [PATCH 08/13] Removed unnecessary commented out code and fixed bound issue --- .../components/tasks/waves/LevelWaves.java | 2 +- .../game/screens/DesertGameScreen.java | 196 ------------------ .../csse3200/game/screens/IceGameScreen.java | 196 ------------------ .../csse3200/game/screens/LavaGameScreen.java | 196 ------------------ .../game/screens/LevelSelectScreen.java | 27 --- 5 files changed, 1 insertion(+), 616 deletions(-) delete mode 100644 source/core/src/main/com/csse3200/game/screens/DesertGameScreen.java delete mode 100644 source/core/src/main/com/csse3200/game/screens/IceGameScreen.java delete mode 100644 source/core/src/main/com/csse3200/game/screens/LavaGameScreen.java diff --git a/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java b/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java index 0c59b6c59..7ab167d9c 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java @@ -65,7 +65,7 @@ public WaveClass getWave(int index) { public void spawnWave() { if (gameTime.getTime() >= startTime + spawnDelay * 1000) { do { - currentRandom = rand.nextInt(1, 7); + currentRandom = rand.nextInt(0, ServiceLocator.getMapService().getHeight() + 1); } while (currentRandom == previousRandom); ServiceLocator.getWaveService().setNextLane(currentRandom); GridPoint2 randomPos = new GridPoint2(19, currentRandom); diff --git a/source/core/src/main/com/csse3200/game/screens/DesertGameScreen.java b/source/core/src/main/com/csse3200/game/screens/DesertGameScreen.java deleted file mode 100644 index 649190860..000000000 --- a/source/core/src/main/com/csse3200/game/screens/DesertGameScreen.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.csse3200.game.screens; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.ScreenAdapter; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.utils.viewport.ScreenViewport; -import com.badlogic.gdx.utils.viewport.Viewport; -import com.csse3200.game.GdxGame; -import com.csse3200.game.areas.ForestGameArea; -import com.csse3200.game.areas.terrain.TerrainFactory; -import com.csse3200.game.components.gamearea.PerformanceDisplay; -import com.csse3200.game.components.maingame.MainGameActions; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.EntityService; -import com.csse3200.game.entities.factories.RenderFactory; -import com.csse3200.game.input.DropInputComponent; -import com.csse3200.game.input.InputComponent; -import com.csse3200.game.input.InputDecorator; -import com.csse3200.game.input.InputService; -import com.csse3200.game.physics.PhysicsEngine; -import com.csse3200.game.physics.PhysicsService; -import com.csse3200.game.rendering.RenderService; -import com.csse3200.game.rendering.Renderer; -import com.csse3200.game.services.*; -import com.csse3200.game.ui.terminal.Terminal; -import com.csse3200.game.ui.terminal.TerminalDisplay; -import com.csse3200.game.components.maingame.MainGameExitDisplay; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DesertGameScreen extends ScreenAdapter { - private static final Logger logger = LoggerFactory.getLogger(DesertGameScreen.class); - private static final String[] mainGameTextures = {"images/heart.png"}; - private static final Vector2 CAMERA_POSITION = new Vector2(10f, 5.64f); - - private final GdxGame game; - private final Renderer renderer; - private final PhysicsEngine physicsEngine; - - private final Stage stage; - static int screenWidth = Gdx.graphics.getWidth(); - static int screenHeight = Gdx.graphics.getHeight(); - - private Entity ui; - - - public static int viewportWidth = screenWidth; - public static int viewportHeight= screenHeight; - - - - private OrthographicCamera camera; - private SpriteBatch batch; - - private Texture backgroundTexture; - - public DesertGameScreen(GdxGame game) { - this.game = game; - camera = new OrthographicCamera(); - camera.setToOrtho(false, viewportWidth, viewportHeight); - camera.position.set((float) (viewportWidth / 2), (float) (viewportHeight / 2), 0); - - batch = new SpriteBatch(); - - Viewport viewport = new ScreenViewport(camera); - stage = new Stage(viewport, new SpriteBatch()); - - - - logger.debug("Initialising main game screen services"); - ServiceLocator.registerTimeSource(new GameTime()); - - PhysicsService physicsService = new PhysicsService(); - ServiceLocator.registerPhysicsService(physicsService); - physicsEngine = physicsService.getPhysics(); - - ServiceLocator.registerInputService(new InputService()); - ServiceLocator.registerResourceService(new ResourceService()); - - ServiceLocator.registerCurrencyService(new CurrencyService()); - - ServiceLocator.registerEntityService(new EntityService()); - ServiceLocator.registerRenderService(new RenderService()); - ServiceLocator.registerGameEndService(new GameEndService()); - - renderer = RenderFactory.createRenderer(); - renderer.getCamera().getEntity().setPosition(CAMERA_POSITION); - renderer.getDebug().renderPhysicsWorld(physicsEngine.getWorld()); - InputComponent inputHandler = new DropInputComponent(renderer.getCamera().getCamera()); - ServiceLocator.getInputService().register(inputHandler); - - ServiceLocator.getCurrencyService().getDisplay().setCamera(renderer.getCamera().getCamera()); - - loadAssets(); - createUI(); - - logger.debug("Initialising main game screen entities"); - TerrainFactory terrainFactory = new TerrainFactory(renderer.getCamera()); - ForestGameArea forestGameArea = new ForestGameArea(terrainFactory); - forestGameArea.create(); - } - - @Override - public void render(float delta) { - physicsEngine.update(); - ServiceLocator.getEntityService().update(); - - // Check if the game has ended - if (ServiceLocator.getGameEndService().hasGameEnded()) { - ui.getEvents().trigger("lose"); - } - - batch.setProjectionMatrix(camera.combined); - batch.begin(); - batch.draw(backgroundTexture, 0, 0, viewportWidth, viewportHeight); - batch.end(); - - - renderer.render(); - stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); - stage.draw(); - } - - - - - @Override - public void resize(int width, int height) { - renderer.resize(width, height); - logger.trace("Resized renderer: ({} x {})", width, height); - } - - @Override - public void pause() { - logger.info("Game paused"); - } - - @Override - public void resume() { - logger.info("Game resumed"); - } - - @Override - public void dispose() { - logger.debug("Disposing main game screen"); - - renderer.dispose(); - unloadAssets(); - - ServiceLocator.getEntityService().dispose(); - ServiceLocator.getRenderService().dispose(); - ServiceLocator.getResourceService().dispose(); - - ServiceLocator.clear(); - } - - private void loadAssets() { - logger.debug("Loading assets"); - ResourceService resourceService = ServiceLocator.getResourceService(); - resourceService.loadTextures(mainGameTextures); - backgroundTexture = new Texture("images/Dusty_MoonBG.png"); // Load the background image - ServiceLocator.getResourceService().loadAll(); - } - - private void unloadAssets() { - logger.debug("Unloading assets"); - ResourceService resourceService = ServiceLocator.getResourceService(); - resourceService.unloadAssets(mainGameTextures); - } - - /** - * Creates the main game's ui including components for rendering ui elements to the screen and - * capturing and handling ui input. - */ - private void createUI() { - logger.debug("Creating ui"); - Stage stage = ServiceLocator.getRenderService().getStage(); - InputComponent inputComponent = - ServiceLocator.getInputService().getInputFactory().createForTerminal(); - - Entity ui = new Entity(); - ui.addComponent(new InputDecorator(stage, 10)) - .addComponent(new PerformanceDisplay()) - .addComponent(new MainGameActions(this.game)) - .addComponent(new MainGameExitDisplay()) - .addComponent(new Terminal()) - .addComponent(inputComponent) - .addComponent(new TerminalDisplay()); - - ServiceLocator.getEntityService().register(ui); - } -} \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/screens/IceGameScreen.java b/source/core/src/main/com/csse3200/game/screens/IceGameScreen.java deleted file mode 100644 index e35c88b85..000000000 --- a/source/core/src/main/com/csse3200/game/screens/IceGameScreen.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.csse3200.game.screens; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.ScreenAdapter; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.utils.viewport.ScreenViewport; -import com.badlogic.gdx.utils.viewport.Viewport; -import com.csse3200.game.GdxGame; -import com.csse3200.game.areas.ForestGameArea; -import com.csse3200.game.areas.terrain.TerrainFactory; -import com.csse3200.game.components.gamearea.PerformanceDisplay; -import com.csse3200.game.components.maingame.MainGameActions; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.EntityService; -import com.csse3200.game.entities.factories.RenderFactory; -import com.csse3200.game.input.DropInputComponent; -import com.csse3200.game.input.InputComponent; -import com.csse3200.game.input.InputDecorator; -import com.csse3200.game.input.InputService; -import com.csse3200.game.physics.PhysicsEngine; -import com.csse3200.game.physics.PhysicsService; -import com.csse3200.game.rendering.RenderService; -import com.csse3200.game.rendering.Renderer; -import com.csse3200.game.services.*; -import com.csse3200.game.ui.terminal.Terminal; -import com.csse3200.game.ui.terminal.TerminalDisplay; -import com.csse3200.game.components.maingame.MainGameExitDisplay; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class IceGameScreen extends ScreenAdapter { - private static final Logger logger = LoggerFactory.getLogger(IceGameScreen.class); - private static final String[] mainGameTextures = {"images/heart.png"}; - private static final Vector2 CAMERA_POSITION = new Vector2(10f, 5.64f); - - private final GdxGame game; - private final Renderer renderer; - private final PhysicsEngine physicsEngine; - - private final Stage stage; - static int screenWidth = Gdx.graphics.getWidth(); - static int screenHeight = Gdx.graphics.getHeight(); - - private Entity ui; - - - public static int viewportWidth = screenWidth; - public static int viewportHeight= screenHeight; - - - - private OrthographicCamera camera; - private SpriteBatch batch; - - private Texture backgroundTexture; - - public IceGameScreen(GdxGame game) { - this.game = game; - camera = new OrthographicCamera(); - camera.setToOrtho(false, viewportWidth, viewportHeight); - camera.position.set((float) (viewportWidth / 2), (float) (viewportHeight / 2), 0); - - batch = new SpriteBatch(); - - Viewport viewport = new ScreenViewport(camera); - stage = new Stage(viewport, new SpriteBatch()); - - - - logger.debug("Initialising main game screen services"); - ServiceLocator.registerTimeSource(new GameTime()); - - PhysicsService physicsService = new PhysicsService(); - ServiceLocator.registerPhysicsService(physicsService); - physicsEngine = physicsService.getPhysics(); - - ServiceLocator.registerInputService(new InputService()); - ServiceLocator.registerResourceService(new ResourceService()); - - ServiceLocator.registerCurrencyService(new CurrencyService()); - - ServiceLocator.registerEntityService(new EntityService()); - ServiceLocator.registerRenderService(new RenderService()); - ServiceLocator.registerGameEndService(new GameEndService()); - - renderer = RenderFactory.createRenderer(); - renderer.getCamera().getEntity().setPosition(CAMERA_POSITION); - renderer.getDebug().renderPhysicsWorld(physicsEngine.getWorld()); - InputComponent inputHandler = new DropInputComponent(renderer.getCamera().getCamera()); - ServiceLocator.getInputService().register(inputHandler); - - ServiceLocator.getCurrencyService().getDisplay().setCamera(renderer.getCamera().getCamera()); - - loadAssets(); - createUI(); - - logger.debug("Initialising main game screen entities"); - TerrainFactory terrainFactory = new TerrainFactory(renderer.getCamera()); - ForestGameArea forestGameArea = new ForestGameArea(terrainFactory); - forestGameArea.create(); - } - - @Override - public void render(float delta) { - physicsEngine.update(); - ServiceLocator.getEntityService().update(); - - // Check if the game has ended - if (ServiceLocator.getGameEndService().hasGameEnded()) { - ui.getEvents().trigger("lose"); - } - - batch.setProjectionMatrix(camera.combined); - batch.begin(); - batch.draw(backgroundTexture, 0, 0, viewportWidth, viewportHeight); - batch.end(); - - - renderer.render(); - stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); - stage.draw(); - } - - - - - @Override - public void resize(int width, int height) { - renderer.resize(width, height); - logger.trace("Resized renderer: ({} x {})", width, height); - } - - @Override - public void pause() { - logger.info("Game paused"); - } - - @Override - public void resume() { - logger.info("Game resumed"); - } - - @Override - public void dispose() { - logger.debug("Disposing main game screen"); - - renderer.dispose(); - unloadAssets(); - - ServiceLocator.getEntityService().dispose(); - ServiceLocator.getRenderService().dispose(); - ServiceLocator.getResourceService().dispose(); - - ServiceLocator.clear(); - } - - private void loadAssets() { - logger.debug("Loading assets"); - ResourceService resourceService = ServiceLocator.getResourceService(); - resourceService.loadTextures(mainGameTextures); - backgroundTexture = new Texture("images/Dusty_MoonBG.png"); // Load the background image - ServiceLocator.getResourceService().loadAll(); - } - - private void unloadAssets() { - logger.debug("Unloading assets"); - ResourceService resourceService = ServiceLocator.getResourceService(); - resourceService.unloadAssets(mainGameTextures); - } - - /** - * Creates the main game's ui including components for rendering ui elements to the screen and - * capturing and handling ui input. - */ - private void createUI() { - logger.debug("Creating ui"); - Stage stage = ServiceLocator.getRenderService().getStage(); - InputComponent inputComponent = - ServiceLocator.getInputService().getInputFactory().createForTerminal(); - - Entity ui = new Entity(); - ui.addComponent(new InputDecorator(stage, 10)) - .addComponent(new PerformanceDisplay()) - .addComponent(new MainGameActions(this.game)) - .addComponent(new MainGameExitDisplay()) - .addComponent(new Terminal()) - .addComponent(inputComponent) - .addComponent(new TerminalDisplay()); - - ServiceLocator.getEntityService().register(ui); - } -} \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/screens/LavaGameScreen.java b/source/core/src/main/com/csse3200/game/screens/LavaGameScreen.java deleted file mode 100644 index a0ec8d06f..000000000 --- a/source/core/src/main/com/csse3200/game/screens/LavaGameScreen.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.csse3200.game.screens; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.ScreenAdapter; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.utils.viewport.ScreenViewport; -import com.badlogic.gdx.utils.viewport.Viewport; -import com.csse3200.game.GdxGame; -import com.csse3200.game.areas.ForestGameArea; -import com.csse3200.game.areas.terrain.TerrainFactory; -import com.csse3200.game.components.gamearea.PerformanceDisplay; -import com.csse3200.game.components.maingame.MainGameActions; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.EntityService; -import com.csse3200.game.entities.factories.RenderFactory; -import com.csse3200.game.input.DropInputComponent; -import com.csse3200.game.input.InputComponent; -import com.csse3200.game.input.InputDecorator; -import com.csse3200.game.input.InputService; -import com.csse3200.game.physics.PhysicsEngine; -import com.csse3200.game.physics.PhysicsService; -import com.csse3200.game.rendering.RenderService; -import com.csse3200.game.rendering.Renderer; -import com.csse3200.game.services.*; -import com.csse3200.game.ui.terminal.Terminal; -import com.csse3200.game.ui.terminal.TerminalDisplay; -import com.csse3200.game.components.maingame.MainGameExitDisplay; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LavaGameScreen extends ScreenAdapter { - private static final Logger logger = LoggerFactory.getLogger(LavaGameScreen.class); - private static final String[] mainGameTextures = {"images/heart.png"}; - private static final Vector2 CAMERA_POSITION = new Vector2(10f, 5.64f); - - private final GdxGame game; - private final Renderer renderer; - private final PhysicsEngine physicsEngine; - - private final Stage stage; - static int screenWidth = Gdx.graphics.getWidth(); - static int screenHeight = Gdx.graphics.getHeight(); - - private Entity ui; - - - public static int viewportWidth = screenWidth; - public static int viewportHeight= screenHeight; - - - - private OrthographicCamera camera; - private SpriteBatch batch; - - private Texture backgroundTexture; - - public LavaGameScreen(GdxGame game) { - this.game = game; - camera = new OrthographicCamera(); - camera.setToOrtho(false, viewportWidth, viewportHeight); - camera.position.set((float) (viewportWidth / 2), (float) (viewportHeight / 2), 0); - - batch = new SpriteBatch(); - - Viewport viewport = new ScreenViewport(camera); - stage = new Stage(viewport, new SpriteBatch()); - - - - logger.debug("Initialising main game screen services"); - ServiceLocator.registerTimeSource(new GameTime()); - - PhysicsService physicsService = new PhysicsService(); - ServiceLocator.registerPhysicsService(physicsService); - physicsEngine = physicsService.getPhysics(); - - ServiceLocator.registerInputService(new InputService()); - ServiceLocator.registerResourceService(new ResourceService()); - - ServiceLocator.registerCurrencyService(new CurrencyService()); - - ServiceLocator.registerEntityService(new EntityService()); - ServiceLocator.registerRenderService(new RenderService()); - ServiceLocator.registerGameEndService(new GameEndService()); - - renderer = RenderFactory.createRenderer(); - renderer.getCamera().getEntity().setPosition(CAMERA_POSITION); - renderer.getDebug().renderPhysicsWorld(physicsEngine.getWorld()); - InputComponent inputHandler = new DropInputComponent(renderer.getCamera().getCamera()); - ServiceLocator.getInputService().register(inputHandler); - - ServiceLocator.getCurrencyService().getDisplay().setCamera(renderer.getCamera().getCamera()); - - loadAssets(); - createUI(); - - logger.debug("Initialising main game screen entities"); - TerrainFactory terrainFactory = new TerrainFactory(renderer.getCamera()); - ForestGameArea forestGameArea = new ForestGameArea(terrainFactory); - forestGameArea.create(); - } - - @Override - public void render(float delta) { - physicsEngine.update(); - ServiceLocator.getEntityService().update(); - - // Check if the game has ended - if (ServiceLocator.getGameEndService().hasGameEnded()) { - ui.getEvents().trigger("lose"); - } - - batch.setProjectionMatrix(camera.combined); - batch.begin(); - batch.draw(backgroundTexture, 0, 0, viewportWidth, viewportHeight); - batch.end(); - - - renderer.render(); - stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); - stage.draw(); - } - - - - - @Override - public void resize(int width, int height) { - renderer.resize(width, height); - logger.trace("Resized renderer: ({} x {})", width, height); - } - - @Override - public void pause() { - logger.info("Game paused"); - } - - @Override - public void resume() { - logger.info("Game resumed"); - } - - @Override - public void dispose() { - logger.debug("Disposing main game screen"); - - renderer.dispose(); - unloadAssets(); - - ServiceLocator.getEntityService().dispose(); - ServiceLocator.getRenderService().dispose(); - ServiceLocator.getResourceService().dispose(); - - ServiceLocator.clear(); - } - - private void loadAssets() { - logger.debug("Loading assets"); - ResourceService resourceService = ServiceLocator.getResourceService(); - resourceService.loadTextures(mainGameTextures); - backgroundTexture = new Texture("images/Dusty_MoonBG.png"); // Load the background image - ServiceLocator.getResourceService().loadAll(); - } - - private void unloadAssets() { - logger.debug("Unloading assets"); - ResourceService resourceService = ServiceLocator.getResourceService(); - resourceService.unloadAssets(mainGameTextures); - } - - /** - * Creates the main game's ui including components for rendering ui elements to the screen and - * capturing and handling ui input. - */ - private void createUI() { - logger.debug("Creating ui"); - Stage stage = ServiceLocator.getRenderService().getStage(); - InputComponent inputComponent = - ServiceLocator.getInputService().getInputFactory().createForTerminal(); - - Entity ui = new Entity(); - ui.addComponent(new InputDecorator(stage, 10)) - .addComponent(new PerformanceDisplay()) - .addComponent(new MainGameActions(this.game)) - .addComponent(new MainGameExitDisplay()) - .addComponent(new Terminal()) - .addComponent(inputComponent) - .addComponent(new TerminalDisplay()); - - ServiceLocator.getEntityService().register(ui); - } -} \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/screens/LevelSelectScreen.java b/source/core/src/main/com/csse3200/game/screens/LevelSelectScreen.java index 93a78401c..bf2de6a5c 100644 --- a/source/core/src/main/com/csse3200/game/screens/LevelSelectScreen.java +++ b/source/core/src/main/com/csse3200/game/screens/LevelSelectScreen.java @@ -104,38 +104,11 @@ private void spawnPlanetBorders() { logger.info("Loading level {}", planet[4]); GameLevelData.setSelectedLevel(planet[4]); game.setScreen(new TurretSelectionScreen(game)); -// if (planet[4] == 0) { -// handleDesertPlanetClick(); -// game.setScreen(new TurretSelectionScreen(game)); -// } else if (planet[4] == 1) { -// handleIcePlanetClick(); -// game.setScreen(new TurretSelectionScreen(game)); -// } else if (planet[4] == 2) { -// handleLavaPlanetClick(); -// game.setScreen(new TurretSelectionScreen(game)); -// } } } } } - private void handleDesertPlanetClick() { - // Implement logic for when the desert planet is clicked - logger.info("Desert planet clicked."); - game.setScreen(new DesertGameScreen(game)); // Load the DesertGameScreen - } - - private void handleIcePlanetClick() { - // Implement logic for when the ice planet is clicked - logger.info("Ice planet clicked."); - game.setScreen(new IceGameScreen(game)); // Load the IceGameScreen - } - - private void handleLavaPlanetClick() { - // Implement logic for when the lava planet is clicked - logger.info("Lava planet clicked."); - game.setScreen(new LavaGameScreen(game)); // Load the LavaGameScreen - } // TODO: Make it display information about the planet @Override From 98712f18bab079d0949674270087023986043665 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Sun, 1 Oct 2023 16:27:09 +1000 Subject: [PATCH 09/13] Added MapService --- .../csse3200/game/services/MapService.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 source/core/src/main/com/csse3200/game/services/MapService.java diff --git a/source/core/src/main/com/csse3200/game/services/MapService.java b/source/core/src/main/com/csse3200/game/services/MapService.java new file mode 100644 index 000000000..e677c9586 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/services/MapService.java @@ -0,0 +1,76 @@ +package com.csse3200.game.services; + +import com.csse3200.game.areas.terrain.TerrainComponent; +import com.csse3200.game.areas.terrain.TerrainFactory; +import com.csse3200.game.components.CameraComponent; +import com.csse3200.game.entities.Entity; + +/** + * Provides services related to map functionalities such as tiles and lanes in genral. + */ +public class MapService { + + private Entity entity; + private final TerrainFactory terrainFactory; + + /** + * Constructs a new MapService instance based on the provided camera. + * + * @param camera The camera component used for the terrain creation. + */ + public MapService(CameraComponent camera) { + this.terrainFactory = new TerrainFactory(camera); + this.entity = new Entity().addComponent(terrainFactory.createTerrain(TerrainFactory.TerrainType.ALL_DEMO)); + } + + /** + * Constructs a new MapService instance using the given entity and terrain factory. + * + * @param entity The entity associated with this service. + * @param terrainFactory The terrain factory used for creating terrains. + */ + public MapService(Entity entity, TerrainFactory terrainFactory) { + this.entity = entity; + this.terrainFactory = terrainFactory; + } + + /** + * Returns the associated entity. + * + * @return The entity related to this map service. + */ + public Entity getEntity() { + + return this.entity; + } + + /** + * Retrieves the terrain component from the entity. + * + * @return The terrain component of the associated entity. + */ + public TerrainComponent getComponent() { + + return entity.getComponent(TerrainComponent.class); + } + + /** + * Returns the height of the Grid. + * + * @return Height of the Grid. + */ + public int getHeight() { + + return entity.getComponent(TerrainComponent.class).getMapBounds(0).y; + } + + /** + * Returns the width of the Grid. + * + * @return Width of the Grid. + */ + public int getWidth() { + + return entity.getComponent(TerrainComponent.class).getMapBounds(0).x; + } +} From 4d77feb2d0b012ad7dd7bbb4eb7ece7ce6495913 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Sun, 1 Oct 2023 16:28:29 +1000 Subject: [PATCH 10/13] Activated MapService by adding it to the ServiceLocator and other main game files --- .../csse3200/game/areas/ForestGameArea.java | 114 +++--------------- .../csse3200/game/screens/MainGameScreen.java | 9 +- .../game/services/ServiceLocator.java | 10 ++ 3 files changed, 29 insertions(+), 104 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index 3b3117f52..7a961a29e 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -93,7 +93,6 @@ public class ForestGameArea extends GameArea { "images/towers/wallTower.png", "images/background/building2.png", "images/iso_grass_3.png", - "images/terrain_use.png", "images/Dusty_MoonBG.png", "images/economy/scrap.png", "images/economy/crystal.png", @@ -182,7 +181,7 @@ public class ForestGameArea extends GameArea { private static final String backgroundMusic = "sounds/background/Sci-Fi1.ogg"; private static final String[] forestMusic = {backgroundMusic}; - private final TerrainFactory terrainFactory; +// private final TerrainFactory terrainFactory; private Entity player; private Entity waves; @@ -196,12 +195,10 @@ public class ForestGameArea extends GameArea { /** * Initialise this ForestGameArea to use the provided TerrainFactory. * - * @param terrainFactory TerrainFactory used to create the terrain for the GameArea. * @requires terrainFactory != null */ - public ForestGameArea(TerrainFactory terrainFactory) { + public ForestGameArea() { super(); - this.terrainFactory = terrainFactory; } /** @@ -273,18 +270,13 @@ public void create() { logger.info("Lol"); // Set up infrastructure for end game tracking - player = spawnPlayer(); +// player = spawnPlayer(); waves = WaveFactory.createWaves(); spawnEntity(waves); waves.getEvents().addListener("spawnWave", this::spawnMob); playMusic(); - //spawnXenoGrunts(); - //startWaveTimer(); - spawnScrap(); - //spawnDeflectXenoGrunt(15, 5); - //spawnSplittingXenoGrunt(15, 4); spawnScrap(); spawnTNTTower(); spawnWeaponTower(); @@ -303,10 +295,8 @@ private void displayUI() { private void spawnTerrain() { - terrain = terrainFactory.createTerrain(TerrainType.ALL_DEMO); - // TODO: We might need a MapService - Entity entity = new Entity().addComponent(terrain); - spawnEntity(entity); + terrain = ServiceLocator.getMapService().getComponent(); + spawnEntity(ServiceLocator.getMapService().getEntity()); // Terrain walls float tileSize = terrain.getTileSize(); @@ -339,47 +329,6 @@ private void spawnTerrain() { false); } - -// private void spawnBuilding1() { -// GridPoint2 minPos = new GridPoint2(0, 0); -// GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); -// -// for (int i = 0; i < NUM_BUILDINGS; i++) { -// GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); -// Entity building1 = ObstacleFactory.createBuilding1(); -// spawnEntityAt(building1, randomPos, true, false); -// } -// } -// private void spawnBuilding2() { -// GridPoint2 minPos = new GridPoint2(0, 0); -// GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); -// -// for (int i = 0; i < NUM_BUILDINGS; i++) { -// GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); -// Entity building2 = ObstacleFactory.createBuilding2(); -// spawnEntityAt(building2, randomPos, true, false); -// } -// } - - -// private void spawnMountains() { -// ArrayList fixedPositions = new ArrayList<>(); //Generating ArrayList -// -// fixedPositions.add(new GridPoint2(5, 8)); -// fixedPositions.add(new GridPoint2(12, 4)); -// fixedPositions.add(new GridPoint2(20, 10)); -// fixedPositions.add(new GridPoint2(33, 17)); -// -// for (GridPoint2 fixedPos : fixedPositions) { -// Entity tree = ObstacleFactory.createMountain(); -// spawnEntityAt(tree, fixedPos, true, false); -// } -// for (int i = 0; i < NUM_BUILDINGS; i++) { -// GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); -// Entity building1 = ObstacleFactory.createBuilding1(); -// spawnEntityAt(building1, randomPos, true, false); -// } -// } private void spawnBuilding2() { GridPoint2 minPos = new GridPoint2(0, 0); @@ -405,28 +354,6 @@ private Entity spawnPlayer(GridPoint2 position) { return newPlayer; } -// private void spawnGhosts() { -// GridPoint2 minPos = new GridPoint2(0, 0); -// GridPoint2 maxPos = terrain.getMapBounds(0).sub(0, 2); -// -// for (int i = 0; i < NUM_GHOSTS; i++) { -// int fixedX = terrain.getMapBounds(0).x - 1; // Rightmost x-coordinate -// int randomY = MathUtils.random(0, maxPos.y); -// GridPoint2 randomPos = new GridPoint2(fixedX, randomY); -// Entity ghost = createGhost(player); -// spawnEntityAt(ghost, randomPos, true, true); -// } -// } - -// private Entity spawnMobBoss1() { -// GridPoint2 minPos = new GridPoint2(0, 0); -// GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); -// GridPoint2 randomPos -// = new GridPoint2(0, 0); -// Entity ghostKing = NPCFactory.createGhostKing(player); -// spawnEntityAt(ghostKing, randomPos, true, true); -// return ghostKing; -// } private void spawnDemonBoss() { Entity demon = MobBossFactory.createDemonBoss(); @@ -548,7 +475,7 @@ private void spawnDeflectXenoGrunt(int x, int y) { } private void spawnFireWorm() { - int[] pickedLanes = random.ints(1, 7) + int[] pickedLanes = random.ints(1, ServiceLocator.getMapService().getHeight() + 1) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -559,7 +486,7 @@ private void spawnFireWorm() { } private void spawnSkeleton() { - int[] pickedLanes = new Random().ints(1, 7) + int[] pickedLanes = new Random().ints(1, ServiceLocator.getMapService().getHeight() + 1) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -570,7 +497,7 @@ private void spawnSkeleton() { } private void spawnDragonKnight() { - int[] pickedLanes = random.ints(1, 7) + int[] pickedLanes = random.ints(1, ServiceLocator.getMapService().getHeight() + 1) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -581,7 +508,7 @@ private void spawnDragonKnight() { } private void spawnWizard() { - int[] pickedLanes = new Random().ints(1, 7) + int[] pickedLanes = new Random().ints(1, ServiceLocator.getMapService().getHeight() + 1) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -592,7 +519,7 @@ private void spawnWizard() { } private void spawnWaterQueen() { - int[] pickedLanes = new Random().ints(1, 7) + int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() + 1) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -603,7 +530,7 @@ private void spawnWaterQueen() { } private void spawnWaterSlime() { - int[] pickedLanes = new Random().ints(1, 7) + int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() + 1) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -613,21 +540,10 @@ private void spawnWaterSlime() { } } -// private Entity spawnGhostKing() { -// GridPoint2 minPos = new GridPoint2(0, 0); -// GridPoint2 maxPos = terrain.getMapBounds(0).sub(0, 0); -// GridPoint2 randomPos -// = RandomUtils.random(minPos, maxPos); -// // = new GridPoint2(26, 26); -// Entity ghostKing = NPCFactory.createGhostKing(player); -// spawnEntityAt(ghostKing, randomPos, true, true); -// return ghostKing; -// -// } private void spawnWeaponTower() { GridPoint2 minPos = new GridPoint2(0, 0); - GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 1); + GridPoint2 maxPos = terrain.getMapBounds(0).sub(5, 1); for (int i = 0; i < NUM_WEAPON_TOWERS + 10; i++) { GridPoint2 randomPos1 = RandomUtils.random(minPos, maxPos); @@ -656,7 +572,7 @@ private void spawnDroidTowerAt(int x, int y) { private void spawnTNTTower() { GridPoint2 minPos = new GridPoint2(0, 0); - GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 1); + GridPoint2 maxPos = terrain.getMapBounds(0).sub(5, 1); for (int i = 0; i < NUM_WEAPON_TOWERS; i++) { GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); @@ -668,12 +584,12 @@ private void spawnTNTTower() { private void spawnDroidTower() { GridPoint2 minPos = new GridPoint2(0, 0); - GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 1); + GridPoint2 maxPos = terrain.getMapBounds(0).sub(5, 1); for (int i = 0; i < NUM_WEAPON_TOWERS; i++) { GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); Entity weaponTower = TowerFactory.createDroidTower(); - spawnEntityAt(weaponTower, randomPos, true, true); + spawnEntityAt(weaponTower, randomPos, true, false); } } diff --git a/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java b/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java index 0ca778809..526e3ecc8 100644 --- a/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java +++ b/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java @@ -41,7 +41,7 @@ */ public class MainGameScreen extends ScreenAdapter { private static final Logger logger = LoggerFactory.getLogger(MainGameScreen.class); - private static final String[] mainGameTextures = {"images/heart.png","images/ice_bg.png","images/lava_bg.png","images/desert_bg.png"}; + private static final String[] mainGameTextures = {"images/heart.png","images/ice_bg.png","images/lava_bg.png","images/desert_bg.png","images/terrain_use.png"}; private static final Vector2 CAMERA_POSITION = new Vector2(10f, 5.64f); private final GdxGame game; @@ -97,15 +97,14 @@ public MainGameScreen(GdxGame game) { renderer.getDebug().renderPhysicsWorld(physicsEngine.getWorld()); InputComponent inputHandler = new DropInputComponent(renderer.getCamera().getCamera()); ServiceLocator.getInputService().register(inputHandler); - ServiceLocator.getCurrencyService().getDisplay().setCamera(renderer.getCamera().getCamera()); loadAssets(); createUI(); - + ServiceLocator.registerMapService(new MapService(renderer.getCamera())); logger.debug("Initialising main game screen entities"); - TerrainFactory terrainFactory = new TerrainFactory(renderer.getCamera()); - ForestGameArea forestGameArea = new ForestGameArea(terrainFactory); +// TerrainFactory terrainFactory = new TerrainFactory(renderer.getCamera()); + ForestGameArea forestGameArea = new ForestGameArea(); forestGameArea.create(); } diff --git a/source/core/src/main/com/csse3200/game/services/ServiceLocator.java b/source/core/src/main/com/csse3200/game/services/ServiceLocator.java index 12d53a83f..449b7f11a 100644 --- a/source/core/src/main/com/csse3200/game/services/ServiceLocator.java +++ b/source/core/src/main/com/csse3200/game/services/ServiceLocator.java @@ -26,6 +26,7 @@ public class ServiceLocator { private static ResourceService resourceService; private static GameEndService gameEndService; private static WaveService waveService; + private static MapService mapService; public static CurrencyService getCurrencyService() { return currencyService; @@ -61,6 +62,8 @@ public static GameEndService getGameEndService() { public static WaveService getWaveService() { return waveService; } + public static MapService getMapService() { return mapService; } + public static void registerCurrencyService(CurrencyService service) { logger.debug("Registering currency service {}", service); currencyService = service; @@ -105,6 +108,11 @@ public static void registerWaveService(WaveService source) { waveService = source; } + public static void registerMapService(MapService source) { + logger.debug("Registering wave service {}", source); + mapService = source; + } + public static void clear() { entityService = null; renderService = null; @@ -113,6 +121,8 @@ public static void clear() { inputService = null; resourceService = null; gameEndService = null; + waveService = null; + mapService = null; } private ServiceLocator() { From f56833eb8ffdf6db7ed42af11f3f4adef1986fbb Mon Sep 17 00:00:00 2001 From: Mohamad Date: Sun, 1 Oct 2023 16:29:06 +1000 Subject: [PATCH 11/13] Added Junit tests for MapService --- .../game/services/MapServiceTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 source/core/src/test/com/csse3200/game/services/MapServiceTest.java diff --git a/source/core/src/test/com/csse3200/game/services/MapServiceTest.java b/source/core/src/test/com/csse3200/game/services/MapServiceTest.java new file mode 100644 index 000000000..bf1173095 --- /dev/null +++ b/source/core/src/test/com/csse3200/game/services/MapServiceTest.java @@ -0,0 +1,58 @@ +package com.csse3200.game.services; + +import com.badlogic.gdx.math.GridPoint2; +import com.csse3200.game.areas.terrain.TerrainComponent; +import com.csse3200.game.areas.terrain.TerrainFactory; + +import com.csse3200.game.entities.Entity; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import static org.mockito.Mockito.*; + +public class MapServiceTest { + + private TerrainFactory mockTerrainFactory; + private TerrainComponent mockTerrainComponent; + private Entity mockEntity; + + + @BeforeEach + public void setUp() { + mockTerrainFactory = mock(TerrainFactory.class); + mockTerrainComponent = mock(TerrainComponent.class); + mockEntity = mock(Entity.class); + + + when(mockTerrainFactory.createTerrain(TerrainFactory.TerrainType.ALL_DEMO)).thenReturn(mockTerrainComponent); + when(mockEntity.getComponent(TerrainComponent.class)).thenReturn(mockTerrainComponent); + + } + + @Test + public void testConstructor() { + MapService mapService = new MapService(mockEntity, mockTerrainFactory); + + assertEquals(mockTerrainComponent, mapService.getComponent()); + + } + + @Test + public void testGetHeight() { + when(mockTerrainComponent.getMapBounds(0)).thenReturn(new GridPoint2(5,2)); // Example Point class to represent x and y + MapService mapService = new MapService(mockEntity, mockTerrainFactory); + + assertEquals(2, mapService.getHeight()); + } + + @Test + public void testGetWidth() { + when(mockTerrainComponent.getMapBounds(0)).thenReturn(new GridPoint2(5, 10)); // Example Point class to represent x and y + MapService mapService = new MapService(mockEntity, mockTerrainFactory); + + assertEquals(5, mapService.getWidth()); + } + +} From 50ab0d7d63237fe01213eda0dc9a9dd47b3128a5 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Mon, 2 Oct 2023 02:26:26 +1000 Subject: [PATCH 12/13] fixed spawnAt bounderies --- .../csse3200/game/areas/ForestGameArea.java | 18 +++++++++--------- .../components/tasks/waves/LevelWaves.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index 99ef6b1f7..da8a32674 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -527,7 +527,7 @@ private void spawnDeflectWizard(int x, int y) { private void spawnFireWorm() { - int[] pickedLanes = rand.ints(0, ServiceLocator.getMapService().getHeight() + 1) + int[] pickedLanes = rand.ints(0, ServiceLocator.getMapService().getHeight() ) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { @@ -540,7 +540,7 @@ private void spawnFireWorm() { private void spawnSkeleton() { - int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() + 1) + int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() ) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]); @@ -552,7 +552,7 @@ private void spawnSkeleton() { private void spawnDragonKnight() { - int[] pickedLanes = rand.ints(0, ServiceLocator.getMapService().getHeight() + 1) + int[] pickedLanes = rand.ints(0, ServiceLocator.getMapService().getHeight() ) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { @@ -565,7 +565,7 @@ private void spawnDragonKnight() { private void spawnWizard() { - int[] pickedLanes = rand.ints(0, ServiceLocator.getMapService().getHeight() + 1) + int[] pickedLanes = rand.ints(0, ServiceLocator.getMapService().getHeight() ) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { @@ -578,7 +578,7 @@ private void spawnWizard() { private void spawnWaterQueen() { - int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() + 1) + int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() ) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { @@ -591,7 +591,7 @@ private void spawnWaterQueen() { private void spawnWaterSlime() { - int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() + 1) + int[] pickedLanes = new Random().ints(0, ServiceLocator.getMapService().getHeight() ) .distinct().limit(5).toArray(); for (int i = 0; i < NUM_GRUNTS; i++) { @@ -705,7 +705,7 @@ private void spawnWeaponTower() { GridPoint2 minPos = new GridPoint2(0, 0); GridPoint2 maxPos = terrain.getMapBounds(0).sub(5, 1); - for (int i = 0; i < NUM_WEAPON_TOWERS + 10 ; i++) { + for (int i = 0; i < NUM_WEAPON_TOWERS + 7 ; i++) { GridPoint2 randomPos1 = RandomUtils.random(minPos, maxPos); GridPoint2 randomPos2 = RandomUtils.random(minPos, maxPos); Entity wallTower = TowerFactory.createWallTower(); @@ -734,7 +734,7 @@ private void spawnTNTTower() { GridPoint2 minPos = new GridPoint2(0, 0); GridPoint2 maxPos = terrain.getMapBounds(0).sub(5, 1); - for (int i = 0; i < NUM_WEAPON_TOWERS + 15; i++) { + for (int i = 0; i < NUM_WEAPON_TOWERS + 5; i++) { GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); Entity weaponTower = TowerFactory.createTNTTower(); spawnEntityAt(weaponTower, randomPos, true, true); @@ -746,7 +746,7 @@ private void spawnDroidTower() { GridPoint2 minPos = new GridPoint2(0, 0); GridPoint2 maxPos = terrain.getMapBounds(0).sub(5, 1); - for (int i = 0; i < NUM_WEAPON_TOWERS + 15; i++) { + for (int i = 0; i < NUM_WEAPON_TOWERS + 5; i++) { GridPoint2 randomPos = RandomUtils.random(minPos, maxPos); Entity weaponTower = TowerFactory.createDroidTower(); spawnEntityAt(weaponTower, randomPos, true, false); diff --git a/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java b/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java index 7ab167d9c..54010fb54 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/waves/LevelWaves.java @@ -65,7 +65,7 @@ public WaveClass getWave(int index) { public void spawnWave() { if (gameTime.getTime() >= startTime + spawnDelay * 1000) { do { - currentRandom = rand.nextInt(0, ServiceLocator.getMapService().getHeight() + 1); + currentRandom = rand.nextInt(0, ServiceLocator.getMapService().getHeight()); } while (currentRandom == previousRandom); ServiceLocator.getWaveService().setNextLane(currentRandom); GridPoint2 randomPos = new GridPoint2(19, currentRandom); From 3eacec13c2df68cd7a40669a539847eaf142c2f5 Mon Sep 17 00:00:00 2001 From: Mohamad Date: Mon, 2 Oct 2023 12:39:20 +1000 Subject: [PATCH 13/13] commented out spawning weapon towers --- .../core/src/main/com/csse3200/game/areas/ForestGameArea.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index da8a32674..358f615bd 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -312,7 +312,7 @@ public void create() { playMusic(); spawnScrap(); spawnTNTTower(); - spawnWeaponTower(); + //spawnWeaponTower(); spawnGapScanners(); spawnDroidTower();