From 8a750520ea24bfdb9fcc50b10ac9cfa9324cf972 Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:15:36 +1000 Subject: [PATCH 01/19] modified tower build to deselect after a tower placement --- .../game/components/maingame/UIElementsDisplay.java | 11 ----------- .../com/csse3200/game/input/BuildInputComponent.java | 3 +++ .../com/csse3200/game/services/CurrencyService.java | 5 +++++ .../csse3200/game/input/BuildInputComponentTest.java | 9 ++++++++- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java index b84b24fe3..514d2ae20 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java @@ -2,28 +2,19 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Sound; -import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.math.GridPoint2; -import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.Array; -import com.csse3200.game.entities.Entity; -import com.csse3200.game.entities.factories.TowerFactory; import com.csse3200.game.screens.TowerType; import com.csse3200.game.services.ServiceLocator; -import com.csse3200.game.ui.ButtonFactory; import com.csse3200.game.ui.UIComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashSet; -import java.util.Set; /** * Displays a button to represent the remaining mobs left in the current wave and a button to skip to the next wave. @@ -40,8 +31,6 @@ public class UIElementsDisplay extends UIComponent { }; private Sound click; private Sound hover; -// private TextButton remainingMobsButton = new ButtonFactory().createButton("Mobs left:"); -// private final TextButton timerButton = new ButtonFactory().createButton("Next wave:"); private TextButton remainingMobsButton; private TextButton timerButton; private final int timer = 110; diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 451c99129..7116d8e31 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -113,6 +113,9 @@ public void buildTower(int x, int y) { long soundId = buildSound.play(); buildSound.setVolume(soundId, 0.4f); + + // deselect the tower after building + ServiceLocator.getCurrencyService().setTowerType(null); } else { // play a sound to indicate an invalid action long soundId = errorSound.play(); diff --git a/source/core/src/main/com/csse3200/game/services/CurrencyService.java b/source/core/src/main/com/csse3200/game/services/CurrencyService.java index d76f7b147..4221d7a9c 100644 --- a/source/core/src/main/com/csse3200/game/services/CurrencyService.java +++ b/source/core/src/main/com/csse3200/game/services/CurrencyService.java @@ -49,6 +49,11 @@ public CurrencyDisplay getDisplay() { return display; } + /** + * Sets the tower type to build - triggered by pressing a tower build button in-game + * newTower can be a towertype or a null value to indicate clearing the value? + * @param newTower The towertype to be set for building, null if deselecting + */ public void setTowerType(TowerType newTower) { if (tower == newTower) { tower = null; diff --git a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java index 3cd427659..4d6837a55 100644 --- a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java +++ b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java @@ -1,8 +1,11 @@ //package com.csse3200.game.input; // +//import com.badlogic.gdx.Gdx; +//import com.badlogic.gdx.Graphics; //import com.badlogic.gdx.graphics.g2d.TextureAtlas; //import com.badlogic.gdx.maps.tiled.TiledMap; //import com.badlogic.gdx.math.Vector2; +//import com.csse3200.game.GdxGame; //import com.csse3200.game.components.CameraComponent; //import com.csse3200.game.currency.Currency; //import com.csse3200.game.entities.Entity; @@ -58,6 +61,9 @@ // // @BeforeEach // void setup() { +// Gdx.graphics = mock(Graphics.class); +// when(Gdx.graphics.getDeltaTime()).thenReturn(10f); +// // GameTime gameTime = mock(GameTime.class); // CameraComponent camera = mock(CameraComponent.class); // when(gameTime.getDeltaTime()).thenReturn(0.02f); @@ -69,7 +75,8 @@ // // CurrencyService currencyService = new CurrencyService(); // ResourceService resourceService = new ResourceService(); -// MapService mapService = new MapService(camera); +// MapService mapService = mock(MapService.class); +// when(mapService.getComponent().tileToWorldPosition(0,0)).thenReturn(new Vector2(0,0)); // EntityService entityService = new EntityService(); // // ServiceLocator.registerResourceService(resourceService); From c9ad35f482fbed931e391b97169baa8e54b690e1 Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:43:46 +1000 Subject: [PATCH 02/19] added shortcut key functionality for build menu --- .../maingame/UIElementsDisplay.java | 5 +++ .../game/input/BuildInputComponent.java | 35 +++++++++++++++++++ .../game/screens/TurretSelectionScreen.java | 8 ++++- .../game/services/ServiceLocator.java | 26 ++++++++++---- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java index 514d2ae20..0cd5b3e81 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java @@ -87,6 +87,11 @@ private void addActors() { } } + // Update the centrally located towerTypes list - + logger.info("In UIElementsDisplay, the towers being sent to ServiceLocator are " + towers); + ServiceLocator.setTowerTypes(towers); + + // Create the buttons - TODO This needs overhauling to pretty buttons TextButton tower1 = new TextButton(towers.get(0).getTowerName(), skin); TextButton tower2 = new TextButton(towers.get(1).getTowerName(), skin); TextButton tower3 = new TextButton(towers.get(2).getTowerName(), skin); diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 7116d8e31..8f21e528b 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -1,15 +1,19 @@ package com.csse3200.game.input; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.utils.Array; import com.csse3200.game.areas.ForestGameArea; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.EntityService; import com.csse3200.game.entities.factories.TowerFactory; import com.csse3200.game.screens.TowerType; import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.utils.math.Vector2Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +32,7 @@ public class BuildInputComponent extends InputComponent { }; private Sound buildSound; private Sound errorSound; + private Array towers = new Array<>(); /** * Constructor for the BuildInputComponent @@ -37,6 +42,7 @@ public BuildInputComponent(Camera camera) { this.entityService = ServiceLocator.getEntityService(); this.camera = camera; loadSounds(); + towers.addAll(ServiceLocator.getTowerTypes()); } /** @@ -79,6 +85,35 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { return false; } + /** + * Triggers player events on specific keycodes. + * + * @return whether the input was processed + * @see InputProcessor#keyDown(int) + */ + @Override + public boolean keyDown(int keycode) { + switch (keycode) { + case Input.Keys.NUM_1: + ServiceLocator.getCurrencyService().setTowerType(towers.get(0)); + return true; + case Input.Keys.NUM_2: + ServiceLocator.getCurrencyService().setTowerType(towers.get(1)); + return true; + case Input.Keys.NUM_3: + ServiceLocator.getCurrencyService().setTowerType(towers.get(2)); + return true; + case Input.Keys.NUM_4: + ServiceLocator.getCurrencyService().setTowerType(towers.get(3)); + return true; + case Input.Keys.NUM_5: + ServiceLocator.getCurrencyService().setTowerType(towers.get(4)); + return true; + default: + return false; + } + } + /** * Instantiates and spawns the selected tower at the given x y coordinates on the tile map. Assumes that the given * x and y coordinate is valid and that the TowerType exists in the CurrencyService. diff --git a/source/core/src/main/com/csse3200/game/screens/TurretSelectionScreen.java b/source/core/src/main/com/csse3200/game/screens/TurretSelectionScreen.java index e27598388..fc768374d 100644 --- a/source/core/src/main/com/csse3200/game/screens/TurretSelectionScreen.java +++ b/source/core/src/main/com/csse3200/game/screens/TurretSelectionScreen.java @@ -20,6 +20,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.csse3200.game.GdxGame; import com.csse3200.game.services.ResourceService; @@ -115,7 +116,12 @@ public void clicked(InputEvent event, float x, float y) { @Override public void clicked(InputEvent event, float x, float y) { // Store the selected towers in the ServiceLocator for transferring across screens - ServiceLocator.setTowerTypes(selectedTurrets);; + // (as an Array) + Array towers = new Array<>(); + for (TowerType t : selectedTurrets) { + towers.add(t); + } + ServiceLocator.setTowerTypes(towers);; game.setScreen(GdxGame.ScreenType.MAIN_GAME); } }); 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 8f3c72154..1df468c8f 100644 --- a/source/core/src/main/com/csse3200/game/services/ServiceLocator.java +++ b/source/core/src/main/com/csse3200/game/services/ServiceLocator.java @@ -33,7 +33,7 @@ public class ServiceLocator { private static WaveService waveService; private static MapService mapService; - private static Set towerTypes = new HashSet<>(); + private static Array towerTypes = new Array<>(); public static CurrencyService getCurrencyService() { return currencyService; @@ -120,12 +120,24 @@ public static void registerMapService(MapService source) { mapService = source; } - public static void setTowerTypes(Set selectedTowers) { - towerTypes.clear(); - towerTypes.addAll(selectedTowers); - } - - public static Set getTowerTypes() { + public static void setTowerTypes(Array selectedTowers) { + if (towerTypes.isEmpty()) { + // set default towers + TowerType[] defaultTowers = { + TowerType.TNT, + TowerType.DROID, + TowerType.INCOME, + TowerType.WALL, + TowerType.WEAPON + }; + towerTypes.addAll(defaultTowers); + } else{ + towerTypes.clear(); + towerTypes.addAll(selectedTowers); + } + } + + public static Array getTowerTypes() { return towerTypes; } From 03c09059ee00b0ea7f4b41fa6afa264eb0e05970 Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Tue, 10 Oct 2023 22:40:41 +1000 Subject: [PATCH 03/19] updated buildInputComponent test --- .../maingame/UIElementsDisplay.java | 1 - .../csse3200/game/entities/EntityService.java | 2 +- .../game/input/BuildInputComponent.java | 12 +- .../game/input/BuildInputComponentTest.java | 284 ++++++++---------- 4 files changed, 128 insertions(+), 171 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java index 0cd5b3e81..42bd789ef 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java @@ -88,7 +88,6 @@ private void addActors() { } // Update the centrally located towerTypes list - - logger.info("In UIElementsDisplay, the towers being sent to ServiceLocator are " + towers); ServiceLocator.setTowerTypes(towers); // Create the buttons - TODO This needs overhauling to pretty buttons diff --git a/source/core/src/main/com/csse3200/game/entities/EntityService.java b/source/core/src/main/com/csse3200/game/entities/EntityService.java index f45576fb0..95af09587 100644 --- a/source/core/src/main/com/csse3200/game/entities/EntityService.java +++ b/source/core/src/main/com/csse3200/game/entities/EntityService.java @@ -221,7 +221,7 @@ public boolean entitiesInTile(int x_coord, int y_coord) { try { mp = (TiledMapTileLayer)ServiceLocator.getMapService().getComponent().getMap().getLayers().get(0); } catch (NullPointerException e) { - // MapService is not running + // MapService is not running - consider this occupied (invalid tile) return true; } if (mp.getCell(x_coord, y_coord) != null) { diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 8f21e528b..5c87099d3 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -81,12 +81,15 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { buildTower((int)cursorPosition.x, (int)cursorPosition.y); logger.debug("spawning a tower at {}, {}", cursorPosition.x, cursorPosition.y); return true; + } else { + // TODO: Create a tile indication of invalid placement here?? + return false; } - return false; } /** - * Triggers player events on specific keycodes. + * Configures shortcut keys for building towers. Pressing the shortcut key + * sets the 'tower to build' variable in CurrencyService * * @return whether the input was processed * @see InputProcessor#keyDown(int) @@ -141,6 +144,7 @@ public void buildTower(int x, int y) { // build the selected tower newTower.setPosition(x, y); ServiceLocator.getEntityService().register(newTower); + // Decrement currency and show a popup that reflects the cost of the build ServiceLocator.getCurrencyService().getScrap().modify(-cost); ServiceLocator.getCurrencyService().getDisplay().updateScrapsStats(); @@ -154,7 +158,9 @@ public void buildTower(int x, int y) { } else { // play a sound to indicate an invalid action long soundId = errorSound.play(); - errorSound.setVolume(soundId, 0.5f); + errorSound.setVolume(soundId, 1f); + // TODO: add a visual indication of the build fail, through + // currency display flash } } } diff --git a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java index 4d6837a55..fc48e2e3c 100644 --- a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java +++ b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java @@ -1,166 +1,118 @@ -//package com.csse3200.game.input; -// -//import com.badlogic.gdx.Gdx; -//import com.badlogic.gdx.Graphics; -//import com.badlogic.gdx.graphics.g2d.TextureAtlas; -//import com.badlogic.gdx.maps.tiled.TiledMap; -//import com.badlogic.gdx.math.Vector2; -//import com.csse3200.game.GdxGame; -//import com.csse3200.game.components.CameraComponent; -//import com.csse3200.game.currency.Currency; -//import com.csse3200.game.entities.Entity; -//import com.csse3200.game.entities.EntityService; -//import com.csse3200.game.entities.factories.TowerFactory; -//import com.csse3200.game.extensions.GameExtension; -//import com.csse3200.game.physics.PhysicsService; -//import com.csse3200.game.rendering.DebugRenderer; -//import com.csse3200.game.rendering.RenderService; -//import com.csse3200.game.services.*; -//import org.junit.jupiter.api.AfterEach; -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -// -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.junit.jupiter.api.Assertions.assertFalse; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(GameExtension.class) -//class BuildInputComponentTest { -// -// private BuildInputComponent buildInputComponent; -// private Entity baseTower; -// private Entity weaponTower; -// private Entity wallTower; -// private Entity stunTower; -// private Entity fireTower; -// private Entity tntTower; -// private Entity droidTower; -// private String[] texture = { -// "images/towers/turret_deployed.png", -// "images/towers/turret01.png", -// "images/towers/wall_tower.png", -// "images/towers/fire_tower_atlas.png", -// "images/towers/stun_tower.png", -// "images/towers/DroidTower.png", -// "images/towers/TNTTower.png" -// }; -// private String[] atlas = { -// "images/towers/turret01.atlas", -// "images/towers/stun_tower.atlas", -// "images/towers/fire_tower_atlas.atlas", -// "images/towers/DroidTower.atlas", -// "images/towers/TNTTower.atlas", -// "images/towers/barrier.atlas" -// }; -// private static final String[] sounds = { -// "sounds/towers/gun_shot_trimmed.mp3", -// "sounds/towers/deploy.mp3", -// "sounds/towers/stow.mp3" -// }; -// -// @BeforeEach -// void setup() { -// Gdx.graphics = mock(Graphics.class); -// when(Gdx.graphics.getDeltaTime()).thenReturn(10f); -// -// GameTime gameTime = mock(GameTime.class); -// CameraComponent camera = mock(CameraComponent.class); -// when(gameTime.getDeltaTime()).thenReturn(0.02f); -// ServiceLocator.registerTimeSource(gameTime); -// ServiceLocator.registerPhysicsService(new PhysicsService()); -// RenderService render = new RenderService(); -// render.setDebug(mock(DebugRenderer.class)); -// ServiceLocator.registerRenderService(render); -// -// CurrencyService currencyService = new CurrencyService(); -// ResourceService resourceService = new ResourceService(); -// MapService mapService = mock(MapService.class); -// when(mapService.getComponent().tileToWorldPosition(0,0)).thenReturn(new Vector2(0,0)); -// EntityService entityService = new EntityService(); -// -// ServiceLocator.registerResourceService(resourceService); -// ServiceLocator.registerCurrencyService(currencyService); -// ServiceLocator.registerMapService(mapService); -// ServiceLocator.registerEntityService(entityService); -// -// resourceService.loadTextures(texture); -// resourceService.loadTextureAtlases(atlas); -// resourceService.loadSounds(sounds); -// resourceService.loadAll(); -// -// ServiceLocator.getResourceService() -// .getAsset("images/towers/turret01.atlas", TextureAtlas.class); -// baseTower = TowerFactory.createBaseTower(); -// weaponTower = TowerFactory.createWeaponTower(); -// wallTower = TowerFactory.createWallTower(); -// fireTower = TowerFactory.createFireTower(); -// stunTower = TowerFactory.createFireTower(); -// tntTower = TowerFactory.createTNTTower(); -// droidTower = TowerFactory.createDroidTower(); -// -// buildInputComponent = new BuildInputComponent(camera.getCamera()); -// } -// -// @Test -// void shouldUpdatePriority() { -// int newPriority = 100; -// InputComponent inputComponent = spy(InputComponent.class); -// -// inputComponent.setPriority(newPriority); -// verify(inputComponent).setPriority(newPriority); -// -// int priority = inputComponent.getPriority(); -// verify(inputComponent).getPriority(); -// -// assertEquals(newPriority, priority); -// } -// -// @Test -// void shouldRegisterOnCreate() { -// InputService inputService = spy(InputService.class); -// ServiceLocator.registerInputService(inputService); -// -// InputComponent inputComponent = spy(InputComponent.class); -// inputComponent.create(); -// verify(inputService).register(inputComponent); -// } -// -// @Test -// void shouldHandleTouchDown() { -// BuildInputComponent inputComponent = spy(BuildInputComponent.class); -// assertFalse(inputComponent.touchDown( 5, 6, 7, 8)); -// } -// -// @Test -// void shouldRejectOccupiedTile() { -// Vector2 tile = ServiceLocator.getMapService().getComponent().tileToWorldPosition(0, 0); -// tntTower.setPosition(0,0); -// assertFalse(buildInputComponent.touchDown(0,0, 7,8)); -// } -// -// @Test -// void shouldRejectInvalidTile() { -// -// } -// -// @Test -// void shouldHandleMissingMapService() { -// -// } -// -// @Test -// void shouldHandleMissingCurrencyService() { -// -// } -// -// @Test -// void shouldHandleInvalidTower() { -// -// } -// -// @Test -// void shouldHandleMissingEntityService() { -// -// } -//} +package com.csse3200.game.input; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Graphics; +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.math.Vector2; +import com.csse3200.game.areas.terrain.TerrainComponent; +import com.csse3200.game.components.CameraComponent; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.EntityService; +import com.csse3200.game.entities.factories.TowerFactory; +import com.csse3200.game.extensions.GameExtension; +import com.csse3200.game.physics.PhysicsService; +import com.csse3200.game.rendering.DebugRenderer; +import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.services.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.*; + +@ExtendWith(GameExtension.class) +class BuildInputComponentTest { + + private BuildInputComponent buildInputComponent; + EntityService entityService; + + @BeforeEach + void setup() { + Gdx.graphics = mock(Graphics.class); + when(Gdx.graphics.getDeltaTime()).thenReturn(10f); + + GameTime gameTime = mock(GameTime.class); + CameraComponent camera = mock(CameraComponent.class); + when(camera.getCamera()).thenReturn(mock(Camera.class)); + when(gameTime.getDeltaTime()).thenReturn(0.02f); + ServiceLocator.registerTimeSource(gameTime); + ServiceLocator.registerPhysicsService(new PhysicsService()); + RenderService render = new RenderService(); + render.setDebug(mock(DebugRenderer.class)); + ServiceLocator.registerRenderService(render); + + CurrencyService currencyService = new CurrencyService(); + ResourceService resourceService = new ResourceService(); + MapService mapService = mock(MapService.class); + when(mapService.getComponent()).thenReturn(mock(TerrainComponent.class)); + entityService = mock(EntityService.class); + + ServiceLocator.registerResourceService(resourceService); + ServiceLocator.registerCurrencyService(currencyService); + ServiceLocator.registerMapService(mapService); + ServiceLocator.registerEntityService(entityService); + + buildInputComponent = new BuildInputComponent(camera.getCamera()); + } + + @Test + void shouldUpdatePriority() { + int newPriority = 100; + InputComponent inputComponent = spy(InputComponent.class); + + inputComponent.setPriority(newPriority); + verify(inputComponent).setPriority(newPriority); + + int priority = inputComponent.getPriority(); + verify(inputComponent).getPriority(); + + assertEquals(newPriority, priority); + } + + @Test + void shouldRegisterOnCreate() { + InputService inputService = spy(InputService.class); + ServiceLocator.registerInputService(inputService); + + InputComponent inputComponent = spy(InputComponent.class); + inputComponent.create(); + verify(inputService).register(inputComponent); + } + + @Test + void shouldHandleTouchDown() { + when(entityService.entitiesInTile(5, 5)).thenReturn(false); + assert(buildInputComponent.touchDown( 5, 5, 7, 8)); + } + + @Test + void shouldRejectOccupiedOrInvalidTile() { + // entitiesInTile checks for out of bounds condition as well + when(entityService.entitiesInTile(5, 5)).thenReturn(true); + assertFalse(buildInputComponent.touchDown(5,5, 7,8), + "Attempting to build on an existing tower should return False"); + } + + @Test + void shouldHandleMissingMapService() { + + } + + @Test + void shouldHandleMissingCurrencyService() { + + } + + @Test + void shouldHandleInvalidTower() { + + } + + @Test + void shouldHandleMissingEntityService() { + + } +} From 16b587acd7095f62fa771fe6ae75956d63030b13 Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 13:05:11 +1000 Subject: [PATCH 04/19] Fixed issue with income tower being invulnerable --- .../game/components/tasks/CurrencyTask.java | 40 +++++++++++++++++-- .../tasks/WallTowerDestructionTask.java | 4 +- .../game/entities/factories/TowerFactory.java | 9 ++++- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java b/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java index 1793115c6..dac8bbae3 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java @@ -3,7 +3,9 @@ import com.badlogic.gdx.math.Vector2; import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.ai.tasks.PriorityTask; +import com.csse3200.game.components.CombatStatsComponent; import com.csse3200.game.currency.Scrap; +import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; @@ -22,6 +24,13 @@ public class CurrencyTask extends DefaultTask implements PriorityTask { private final int currencyAmount = scrap.getAmount(); // amount of currency to update private static final String IDLE = "idleStartEco"; private static final String MOVE = "moveStartEco"; + private static final String DEATH = "deathStartEco"; + + public enum STATE { + IDLE, DEATH + } + public STATE towerState = STATE.IDLE; + /** * @param priority Task priority for currency updates. Must be a positive integer. @@ -40,7 +49,8 @@ public CurrencyTask(int priority, int interval) { public void start() { super.start(); owner.getEntity().getEvents().addListener("addIncome",this::changeInterval); - endTime = timeSource.getTime() + (30 * 1000L); + // TODO: GOT RID OF THE 30 TIMES MULTIPLIER + endTime = timeSource.getTime() + (1000L); owner.getEntity().getEvents().trigger(IDLE); } @@ -52,14 +62,38 @@ public void start() { @Override public void update() { if (timeSource.getTime() >= endTime) { - owner.getEntity().getEvents().trigger(MOVE); - updateCurrency(); // update currency + updateTowerState(); logger.info(String.format("Interval: %d", interval)); endTime = timeSource.getTime() + (interval * 1000L); // reset end time } } + /** + * This method acts is the state machine for IncomeTower. Relevant animations are triggered based on relevant state + * of the game. If the tower runs out of health it dies. + */ + public void updateTowerState() { + if (owner.getEntity().getComponent(CombatStatsComponent.class).getHealth() <= 0 && towerState != STATE.DEATH) { + owner.getEntity().getEvents().trigger(DEATH); + towerState = STATE.DEATH; + } + + switch (towerState) { + case IDLE -> { + owner.getEntity().getEvents().trigger(MOVE); + updateCurrency(); // update currency + towerState = STATE.IDLE; + } + case DEATH -> { + if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { + owner.getEntity().setFlagForDelete(true); + } + } + } + } + + /** * Updates the currency based on time intervals. */ diff --git a/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java b/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java index 988ff0071..390c3359d 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java @@ -41,7 +41,7 @@ public class WallTowerDestructionTask extends DefaultTask implements PriorityTas private final RaycastHit hit = new RaycastHit(); public enum STATE { - IDLE, ATTACK, DEATH + IDLE, DEATH } public STATE towerState = STATE.IDLE; @@ -97,7 +97,7 @@ public void updateTowerState() { switch (towerState) { case IDLE -> { owner.getEntity().getEvents().trigger(IDLE); - towerState = STATE.ATTACK; + towerState = STATE.IDLE; } case DEATH -> { if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index a92dbb234..ca8f28b98 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -1,5 +1,6 @@ package com.csse3200.game.entities.factories; +import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Filter; import com.csse3200.game.components.tasks.DroidCombatTask; import com.csse3200.game.components.tasks.TNTTowerCombatTask; @@ -25,6 +26,7 @@ import com.csse3200.game.input.UpgradeUIComponent;import java.util.HashSet; import java.util.Set; + /** * Factory to create a tower entity. * @@ -34,7 +36,6 @@ public class TowerFactory { // Define a set to keep track of occupied lanes private static final Set occupiedLanes = new HashSet<>(); - private static final int COMBAT_TASK_PRIORITY = 2; private static final int WEAPON_TOWER_MAX_RANGE = 40; private static final int TNT_TOWER_MAX_RANGE = 6; @@ -467,6 +468,8 @@ public static Entity createHealTower() { */ public static Entity createBaseTower() { // we're going to add more components later on + + Entity tower = new Entity() .addComponent(new ColliderComponent()) .addComponent(new HitboxComponent().setLayer(PhysicsLayer.TOWER)) // TODO: we might have to change the names of the layers @@ -474,7 +477,9 @@ public static Entity createBaseTower() { .addComponent(new TowerUpgraderComponent()); tower.setLayer(1); // Set priority to 1, which is 1 below scrap (which is 0) - + // Set hitboxes and colliders to one tile + tower.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(1f, 1f), PhysicsComponent.AlignX.CENTER, PhysicsComponent.AlignY.CENTER); + tower.getComponent(ColliderComponent.class).setAsBoxAligned(new Vector2(1f, 1f), PhysicsComponent.AlignX.CENTER, PhysicsComponent.AlignY.CENTER); return tower; } public static Entity createAndPlaceTower(int lane) { From 6215af197dde5aeb4f62a274197d910959fd555c Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:15:42 +1000 Subject: [PATCH 05/19] fixed key shortcut bug that set towers to default --- .../components/gamearea/CurrencyDisplay.java | 11 ++++++ .../game/input/BuildInputComponent.java | 38 +++++++++++++++---- .../game/services/ServiceLocator.java | 18 ++------- .../com/csse3200/game/ui/UIComponent.java | 4 ++ .../game/input/BuildInputComponentTest.java | 37 ++++++++++++++---- 5 files changed, 79 insertions(+), 29 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/gamearea/CurrencyDisplay.java b/source/core/src/main/com/csse3200/game/components/gamearea/CurrencyDisplay.java index a887ed896..a2c348b74 100644 --- a/source/core/src/main/com/csse3200/game/components/gamearea/CurrencyDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/gamearea/CurrencyDisplay.java @@ -2,6 +2,7 @@ import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; @@ -15,6 +16,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.utils.Align; +import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; import com.csse3200.game.ui.UIComponent; import com.badlogic.gdx.scenes.scene2d.actions.Actions; @@ -89,6 +91,15 @@ public void updateScrapsStats() { scrapsTb.getLabel().setText(text); } + /** + * Displays a warning animation of the scraps display if the player tries to + * build something that costs more than the balance + */ + public void scrapBalanceFlash() { + // TODO: IMPLEMENT THIS + scrapsTb.setText("Insufficient!"); + } + /** * Updates the currency (Crystals) value on the UI component */ diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 5c87099d3..11fed6a5e 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -13,7 +13,6 @@ import com.csse3200.game.entities.factories.TowerFactory; import com.csse3200.game.screens.TowerType; import com.csse3200.game.services.ServiceLocator; -import com.csse3200.game.utils.math.Vector2Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +32,7 @@ public class BuildInputComponent extends InputComponent { private Sound buildSound; private Sound errorSound; private Array towers = new Array<>(); + private Array defaultTowers = new Array<>(); /** * Constructor for the BuildInputComponent @@ -43,6 +43,21 @@ public BuildInputComponent(Camera camera) { this.camera = camera; loadSounds(); towers.addAll(ServiceLocator.getTowerTypes()); + +// logger.info("selected towers in buildInputComponent are " + towers); + TowerType[] defaultTowerTypes = { + TowerType.TNT, + TowerType.DROID, + TowerType.INCOME, + TowerType.WALL, + TowerType.WEAPON + }; + defaultTowers.addAll(defaultTowerTypes); + + if (towers.isEmpty()) { + ServiceLocator.setTowerTypes(defaultTowers); + towers = defaultTowers; + } } /** @@ -74,12 +89,12 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { // determine if the tile is unoccupied boolean tileOccupied = entityService.entitiesInTile((int)cursorPosition.x, (int)cursorPosition.y); - logger.debug("Tile is occupied: " + tileOccupied ); +// logger.debug("Tile is occupied: " + tileOccupied ); // check that no entities are occupying the tile if (!tileOccupied) { buildTower((int)cursorPosition.x, (int)cursorPosition.y); - logger.debug("spawning a tower at {}, {}", cursorPosition.x, cursorPosition.y); +// logger.debug("spawning a tower at {}, {}", cursorPosition.x, cursorPosition.y); return true; } else { // TODO: Create a tile indication of invalid placement here?? @@ -95,7 +110,7 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { * @see InputProcessor#keyDown(int) */ @Override - public boolean keyDown(int keycode) { + public boolean keyUp(int keycode) { switch (keycode) { case Input.Keys.NUM_1: ServiceLocator.getCurrencyService().setTowerType(towers.get(0)); @@ -126,6 +141,7 @@ public boolean keyDown(int keycode) { */ public void buildTower(int x, int y) { // fetch the currently set TowerType in the currency service, and its associated build cost. + TowerType tower = ServiceLocator.getCurrencyService().getTower(); if (tower != null) { // fetch the price of the selected tower and attempt to instantiate @@ -159,6 +175,7 @@ public void buildTower(int x, int y) { // play a sound to indicate an invalid action long soundId = errorSound.play(); errorSound.setVolume(soundId, 1f); + ServiceLocator.getCurrencyService().getDisplay().scrapBalanceFlash(); // TODO: add a visual indication of the build fail, through // currency display flash } @@ -169,9 +186,14 @@ public void buildTower(int x, int y) { * Load the sound assets related to in-game tower building activity */ private void loadSounds() { - ServiceLocator.getResourceService().loadSounds(sounds); - ServiceLocator.getResourceService().loadAll(); - buildSound = ServiceLocator.getResourceService().getAsset("sounds/economy/buildSound.ogg", Sound.class); - errorSound = ServiceLocator.getResourceService().getAsset("sounds/ui/Switch/NA_SFUI_Vol1_switch_01.ogg", Sound.class); + try { + ServiceLocator.getResourceService().loadSounds(sounds); + ServiceLocator.getResourceService().loadAll(); + buildSound = ServiceLocator.getResourceService().getAsset("sounds/economy/buildSound.ogg", Sound.class); + errorSound = ServiceLocator.getResourceService().getAsset("sounds/ui/Switch/NA_SFUI_Vol1_switch_01.ogg", Sound.class); + + } catch (NullPointerException e) { + logger.error("BuildInputComponent line 173: Couldn't load sounds for build menu"); + } } } 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 1df468c8f..7c16fc03f 100644 --- a/source/core/src/main/com/csse3200/game/services/ServiceLocator.java +++ b/source/core/src/main/com/csse3200/game/services/ServiceLocator.java @@ -121,20 +121,9 @@ public static void registerMapService(MapService source) { } public static void setTowerTypes(Array selectedTowers) { - if (towerTypes.isEmpty()) { - // set default towers - TowerType[] defaultTowers = { - TowerType.TNT, - TowerType.DROID, - TowerType.INCOME, - TowerType.WALL, - TowerType.WEAPON - }; - towerTypes.addAll(defaultTowers); - } else{ - towerTypes.clear(); - towerTypes.addAll(selectedTowers); - } + + towerTypes.clear(); + towerTypes.addAll(selectedTowers); } public static Array getTowerTypes() { @@ -151,6 +140,7 @@ public static void clear() { gameEndService = null; waveService = null; mapService = null; + towerTypes.clear(); } private ServiceLocator() { diff --git a/source/core/src/main/com/csse3200/game/ui/UIComponent.java b/source/core/src/main/com/csse3200/game/ui/UIComponent.java index 60cfe7009..025282e70 100644 --- a/source/core/src/main/com/csse3200/game/ui/UIComponent.java +++ b/source/core/src/main/com/csse3200/game/ui/UIComponent.java @@ -32,4 +32,8 @@ public int getLayer() { public float getZIndex() { return 1f; } + + public static Skin getSkin() { + return skin; + } } diff --git a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java index fc48e2e3c..61f2d1935 100644 --- a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java +++ b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java @@ -3,17 +3,14 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Graphics; import com.badlogic.gdx.graphics.Camera; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.math.Vector2; import com.csse3200.game.areas.terrain.TerrainComponent; import com.csse3200.game.components.CameraComponent; -import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.EntityService; -import com.csse3200.game.entities.factories.TowerFactory; import com.csse3200.game.extensions.GameExtension; import com.csse3200.game.physics.PhysicsService; import com.csse3200.game.rendering.DebugRenderer; import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.screens.TowerType; import com.csse3200.game.services.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -98,21 +95,47 @@ void shouldRejectOccupiedOrInvalidTile() { @Test void shouldHandleMissingMapService() { - + when(ServiceLocator.getMapService()).thenReturn(null); + assertFalse(buildInputComponent.touchDown(5,5,7,8)); } @Test void shouldHandleMissingCurrencyService() { + when(ServiceLocator.getCurrencyService()).thenReturn(null); + assertFalse(buildInputComponent.touchDown(5,5,7,8)); + } + @Test + void shouldHandleNullTowerName() { + TowerType towerType = mock(TowerType.class); + when(towerType.getTowerName()).thenReturn(null); + ServiceLocator.getCurrencyService().setTowerType(towerType); } @Test - void shouldHandleInvalidTower() { + void shouldHandleNullTowerDesc() { + TowerType towerType = mock(TowerType.class); + when(towerType.getDescription()).thenReturn(null); + ServiceLocator.getCurrencyService().setTowerType(towerType); + } + @Test + void shouldHandleNullTowerCost() { + TowerType towerType = mock(TowerType.class); + when(towerType.getPrice()).thenReturn(null); + ServiceLocator.getCurrencyService().setTowerType(towerType); } @Test - void shouldHandleMissingEntityService() { + void shouldHandleInvalidTowerName() { + TowerType towerType = mock(TowerType.class); + when(towerType.getTowerName()).thenReturn(null); + ServiceLocator.getCurrencyService().setTowerType(towerType); + } + @Test + void shouldHandleMissingEntityService() { + when(ServiceLocator.getEntityService()).thenReturn(null); + assertFalse(buildInputComponent.touchDown(5,5,7,8)); } } From ec25e7e4bf66ea60c28538beaaf0c0ff3175633f Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:35:39 +1000 Subject: [PATCH 06/19] updated buildInputComponent JUnit tests --- .../game/input/BuildInputComponent.java | 36 ++++++++++++++----- .../game/input/BuildInputComponentTest.java | 2 +- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 11fed6a5e..8af5618c8 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -12,6 +12,7 @@ import com.csse3200.game.entities.EntityService; import com.csse3200.game.entities.factories.TowerFactory; import com.csse3200.game.screens.TowerType; +import com.csse3200.game.services.CurrencyService; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -93,9 +94,8 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { // check that no entities are occupying the tile if (!tileOccupied) { - buildTower((int)cursorPosition.x, (int)cursorPosition.y); // logger.debug("spawning a tower at {}, {}", cursorPosition.x, cursorPosition.y); - return true; + return buildTower((int)cursorPosition.x, (int)cursorPosition.y); } else { // TODO: Create a tile indication of invalid placement here?? return false; @@ -139,15 +139,24 @@ public boolean keyUp(int keycode) { * @param x x-coordinate int value * @param y y-coordinate int value */ - public void buildTower(int x, int y) { + public boolean buildTower(int x, int y) { + TowerType tower; + CurrencyService currencyService; // fetch the currently set TowerType in the currency service, and its associated build cost. - - TowerType tower = ServiceLocator.getCurrencyService().getTower(); + try { + currencyService = ServiceLocator.getCurrencyService(); + } catch (NullPointerException e) { + // if the currency service fails or is not running + logger.error("BuildInputComponent line 148: Failed to fetch currency service"); + // Set to default weaponTower + return false; + } + tower = currencyService.getTower(); if (tower != null) { // fetch the price of the selected tower and attempt to instantiate - int cost = Integer.parseInt(ServiceLocator.getCurrencyService().getTower().getPrice()); + int cost = Integer.parseInt(currencyService.getTower().getPrice()); - if (cost <= ServiceLocator.getCurrencyService().getScrap().getAmount()) { + if (cost <= currencyService.getScrap().getAmount()) { Entity newTower = switch (tower) { case WEAPON -> TowerFactory.createWeaponTower(); case INCOME -> TowerFactory.createIncomeTower(); @@ -159,7 +168,15 @@ public void buildTower(int x, int y) { }; // build the selected tower newTower.setPosition(x, y); - ServiceLocator.getEntityService().register(newTower); + EntityService entityService; + try { + entityService = ServiceLocator.getEntityService(); + } catch (NullPointerException e) { + // failed to fetch entityService + logger.error("BuildInputComponent line 173: Failed to fetch EntityService"); + return false; + } + entityService.register(newTower); // Decrement currency and show a popup that reflects the cost of the build ServiceLocator.getCurrencyService().getScrap().modify(-cost); @@ -171,6 +188,7 @@ public void buildTower(int x, int y) { // deselect the tower after building ServiceLocator.getCurrencyService().setTowerType(null); + return true; } else { // play a sound to indicate an invalid action long soundId = errorSound.play(); @@ -178,8 +196,10 @@ public void buildTower(int x, int y) { ServiceLocator.getCurrencyService().getDisplay().scrapBalanceFlash(); // TODO: add a visual indication of the build fail, through // currency display flash + } } + return false; } /** diff --git a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java index 61f2d1935..b67900aa8 100644 --- a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java +++ b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java @@ -82,7 +82,7 @@ void shouldRegisterOnCreate() { @Test void shouldHandleTouchDown() { when(entityService.entitiesInTile(5, 5)).thenReturn(false); - assert(buildInputComponent.touchDown( 5, 5, 7, 8)); + assertFalse(buildInputComponent.touchDown( 5, 5, 7, 8)); } @Test From cc84d3c576e59ce2ba3eefa38b106dcf9be3db9e Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 14:17:53 +1000 Subject: [PATCH 07/19] fixed FireworksTower projectile position and hitbox location --- .../game/components/tasks/FireworksTowerCombatTask.java | 4 ++-- .../com/csse3200/game/entities/factories/TowerFactory.java | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java index ef7c74f89..6dac9ea9d 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java @@ -69,7 +69,7 @@ public void start() { // Set the default state to IDLE state owner.getEntity().getEvents().trigger(IDLE); - endTime = timeSource.getTime() + (INTERVAL * 5000); + endTime = timeSource.getTime() + (INTERVAL * 500); } /** @@ -108,7 +108,7 @@ public void updateTowerState() { Entity newProjectile = ProjectileFactory.createSplitFireWorksFireball(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), 3); newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y + 0.25)); + (float) (owner.getEntity().getPosition().y)); ServiceLocator.getEntityService().register(newProjectile); } else { owner.getEntity().getEvents().trigger(IDLE); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index ca8f28b98..13a349654 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -376,8 +376,6 @@ public static Entity createFireworksTower() { .addComponent(animator) .addComponent(new FireworksTowerAnimationController()); - fireworksTower.setScale(1.5f, 1.5f); - PhysicsUtils.setScaledCollider(fireworksTower, 0.2f, 0.2f); return fireworksTower; } @@ -477,7 +475,8 @@ public static Entity createBaseTower() { .addComponent(new TowerUpgraderComponent()); tower.setLayer(1); // Set priority to 1, which is 1 below scrap (which is 0) - // Set hitboxes and colliders to one tile + + // Set hitbox and collider to a vector of size 1 and align the hitbox and collider to the center of the tower tower.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(1f, 1f), PhysicsComponent.AlignX.CENTER, PhysicsComponent.AlignY.CENTER); tower.getComponent(ColliderComponent.class).setAsBoxAligned(new Vector2(1f, 1f), PhysicsComponent.AlignX.CENTER, PhysicsComponent.AlignY.CENTER); return tower; From d6853874f54c5e30bc6a649d9f97d7cc0329e491 Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 14:27:18 +1000 Subject: [PATCH 08/19] fixed fireworks tower fire rate --- .../game/components/tasks/FireworksTowerCombatTask.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java index 6dac9ea9d..96ff3c921 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java @@ -22,7 +22,7 @@ public class FireworksTowerCombatTask extends DefaultTask implements PriorityTask { // constants // Time interval (in seconds) to scan for enemies - private static final int INTERVAL = 1; + private static final int INTERVAL = 2; // The type of targets this tower will detect private static final short TARGET = PhysicsLayer.NPC; //Following constants are names of events that will be triggered in the state machine @@ -69,7 +69,7 @@ public void start() { // Set the default state to IDLE state owner.getEntity().getEvents().trigger(IDLE); - endTime = timeSource.getTime() + (INTERVAL * 500); + endTime = timeSource.getTime() + (INTERVAL * 1000); } /** From ae64a9d0404c80b697dda193fd4ee0d273b3e0fd Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 14:36:53 +1000 Subject: [PATCH 09/19] Fixed pierce tower hitbox and projectile --- .../csse3200/game/components/tasks/PierceTowerCombatTask.java | 2 +- .../main/com/csse3200/game/entities/factories/TowerFactory.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java index 8d8723f65..8fd0986af 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java @@ -112,7 +112,7 @@ public void updateTowerState() { Entity newProjectile = ProjectileFactory.createPierceFireBall(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f)); newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y + 0.25)); + (float) (owner.getEntity().getPosition().y)); ServiceLocator.getEntityService().register(newProjectile); } } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index 13a349654..b017487cc 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -408,7 +408,6 @@ public static Entity createPierceTower() { .addComponent(aiTaskComponent); pierceTower.setScale(1.5f, 1.5f); - PhysicsUtils.setScaledCollider(pierceTower, 0.5f, 0.5f); return pierceTower; } From ccdf375d7081050023780a132a8b26dacb8d8f90 Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 14:46:19 +1000 Subject: [PATCH 10/19] fixed ricochet hitbox and projectile position --- .../csse3200/game/components/tasks/RicochetTowerCombatTask.java | 2 +- .../main/com/csse3200/game/entities/factories/TowerFactory.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java index d057c1ab0..39d5ded0e 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java @@ -113,7 +113,7 @@ public void updateTowerState() { // NEED TO DO USER TESTING TO FIGURE OUT THE BOUNCE COUNT new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), 3); newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y + 0.25)); + (float) (owner.getEntity().getPosition().y)); ServiceLocator.getEntityService().register(newProjectile); } } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index b017487cc..9421b236c 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -436,7 +436,6 @@ public static Entity createRicochetTower() { // ADD ANIMATION COMPONENTS ricochetTower.setScale(1.5f, 1.5f); - PhysicsUtils.setScaledCollider(ricochetTower, 0.5f, 0.5f); return ricochetTower; } public static Entity createHealTower() { From 3839d779f6905d3c88db53467bf4caef59bac009 Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 15:05:14 +1000 Subject: [PATCH 11/19] changed position of bottom droid projectile so that it is within a lane --- .../game/components/tower/DroidAnimationController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tower/DroidAnimationController.java b/source/core/src/main/com/csse3200/game/components/tower/DroidAnimationController.java index d8307e0e4..19406ff99 100644 --- a/source/core/src/main/com/csse3200/game/components/tower/DroidAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/tower/DroidAnimationController.java @@ -114,9 +114,8 @@ void shootDown() { entity.getPosition().y), new Vector2(2,2), ProjectileEffects.SLOW, false); Projectile.setScale(new Vector2(0.5f,0.5f)); Projectile.setPosition((float) (entity.getPosition().x + 0.2), - (float) (entity.getPosition().y - 0.2)); + (float) (entity.getPosition().y)); ServiceLocator.getEntityService().register(Projectile); - } } From 6a21853cc8c46a8195c2706df5b8348a4f39f83c Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 15:16:45 +1000 Subject: [PATCH 12/19] fixed weapon tower so it could die and projectile was in the lane --- .../game/components/tasks/TowerCombatTask.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java index f1d0eb9ca..e6d891375 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java @@ -4,11 +4,13 @@ import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.ai.tasks.PriorityTask; import com.csse3200.game.areas.ForestGameArea; +import com.csse3200.game.components.CombatStatsComponent; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.ProjectileFactory; import com.csse3200.game.physics.PhysicsEngine; import com.csse3200.game.physics.PhysicsLayer; import com.csse3200.game.physics.raycast.RaycastHit; +import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; @@ -30,6 +32,7 @@ public class TowerCombatTask extends DefaultTask implements PriorityTask { private static final String DEPLOY = "deployStart"; private static final String FIRING = "firingStart"; private static final String IDLE = "idleStart"; + private static final String DEATH = "deathStart"; // class attributes private final int priority; // The active priority this task will have @@ -44,7 +47,7 @@ public class TowerCombatTask extends DefaultTask implements PriorityTask { private static final Logger logger = LoggerFactory.getLogger(ForestGameArea.class); private enum STATE { - IDLE, DEPLOY, FIRING, STOW + IDLE, DEPLOY, FIRING, STOW, DEATH } private STATE towerState = STATE.IDLE; @@ -114,6 +117,11 @@ public void update() { */ public void updateTowerState() { // configure tower state depending on target visibility + if (owner.getEntity().getComponent(CombatStatsComponent.class).getHealth() <= 0 && towerState != STATE.DEATH) { + owner.getEntity().getEvents().trigger(DEATH); + towerState = STATE.DEATH; + return; + } switch (towerState) { case IDLE -> { // targets detected in idle mode - start deployment @@ -144,7 +152,7 @@ public void updateTowerState() { Entity newProjectile = ProjectileFactory.createFireBall(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f)); newProjectile.setScale(1.1f, 0.8f); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.5), (float) (owner.getEntity().getPosition().y + 0.5)); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.5), (float) (owner.getEntity().getPosition().y)); ServiceLocator.getEntityService().register(newProjectile); // * TEMPRORARYYYYYYYY PLS DON'T DELETE THIS @@ -177,6 +185,11 @@ public void updateTowerState() { towerState = STATE.IDLE; } } + case DEATH -> { + if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { + owner.getEntity().setFlagForDelete(true); + } + } } } /** From ca6d3bb56a88212bfaa9693e56da00e2f51ee30c Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 15:38:28 +1000 Subject: [PATCH 13/19] Fixed projectile positions for all towers --- .../game/components/tasks/CurrencyTask.java | 4 ++-- .../components/tasks/DroidCombatTask.java | 2 +- .../components/tasks/FireTowerCombatTask.java | 2 +- .../tasks/FireworksTowerCombatTask.java | 3 ++- .../components/tasks/StunTowerCombatTask.java | 2 +- .../tasks/WallTowerDestructionTask.java | 2 +- .../entities/configs/IncomeTowerConfig.java | 2 +- .../game/entities/factories/TowerFactory.java | 20 ------------------- 8 files changed, 9 insertions(+), 28 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java b/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java index dac8bbae3..8f2ea18cd 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/CurrencyTask.java @@ -49,8 +49,8 @@ public CurrencyTask(int priority, int interval) { public void start() { super.start(); owner.getEntity().getEvents().addListener("addIncome",this::changeInterval); - // TODO: GOT RID OF THE 30 TIMES MULTIPLIER - endTime = timeSource.getTime() + (1000L); + // TODO: changed 30 TIMES MULTIPLIER to 5 times + endTime = timeSource.getTime() + (interval * 1500L); owner.getEntity().getEvents().trigger(IDLE); } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/DroidCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/DroidCombatTask.java index 384549af7..1c597fc2e 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/DroidCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/DroidCombatTask.java @@ -74,7 +74,7 @@ public void start() { // Default to idle mode owner.getEntity().getEvents().trigger(WALK); owner.getEntity().getEvents().addListener("addFireRate",this::changeFireRateInterval); - endTime = timeSource.getTime() + (INTERVAL * 500); + endTime = timeSource.getTime() + (INTERVAL * 1000); } /** diff --git a/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java index abf01bb79..c45234f51 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java @@ -123,7 +123,7 @@ public void updateTowerState() { Entity newProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), ProjectileEffects.BURN, false); newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y + 0.25)); + (float) (owner.getEntity().getPosition().y)); ServiceLocator.getEntityService().register(newProjectile); } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java index 96ff3c921..b99a8f09d 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java @@ -22,7 +22,7 @@ public class FireworksTowerCombatTask extends DefaultTask implements PriorityTask { // constants // Time interval (in seconds) to scan for enemies - private static final int INTERVAL = 2; + private static final int INTERVAL = 1; // The type of targets this tower will detect private static final short TARGET = PhysicsLayer.NPC; //Following constants are names of events that will be triggered in the state machine @@ -103,6 +103,7 @@ public void updateTowerState() { } } case ATTACK -> { + // check if fired last time if not fire if so hold if (isTargetVisible()) { owner.getEntity().getEvents().trigger(ATTACK); Entity newProjectile = ProjectileFactory.createSplitFireWorksFireball(PhysicsLayer.NPC, diff --git a/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java index cce8ec833..ff61e16f0 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java @@ -122,7 +122,7 @@ public void updateTowerState() { new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), ProjectileEffects.STUN, false); newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y + 0.25)); + (float) (owner.getEntity().getPosition().y)); ServiceLocator.getEntityService().register(newProjectile); } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java b/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java index 390c3359d..749647851 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/WallTowerDestructionTask.java @@ -68,7 +68,7 @@ public void start() { // Set the default state to IDLE state owner.getEntity().getEvents().trigger(IDLE); - endTime = timeSource.getTime() + (INTERVAL * 5000); + endTime = timeSource.getTime() + (INTERVAL * 1000); } /** diff --git a/source/core/src/main/com/csse3200/game/entities/configs/IncomeTowerConfig.java b/source/core/src/main/com/csse3200/game/entities/configs/IncomeTowerConfig.java index 9e79376e2..bdcf77c06 100644 --- a/source/core/src/main/com/csse3200/game/entities/configs/IncomeTowerConfig.java +++ b/source/core/src/main/com/csse3200/game/entities/configs/IncomeTowerConfig.java @@ -9,6 +9,6 @@ public class IncomeTowerConfig { public int cost = 1; public float attackRate = 0; - public float incomeRate = 30; + public float incomeRate = 10; } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index 9421b236c..50585a49c 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -345,7 +345,6 @@ public static Entity createStunTower() { .addComponent(new StunTowerAnimationController()); stunTower.setScale(1.5f, 1.5f); - PhysicsUtils.setScaledCollider(stunTower, 0.5f, 0.5f); return stunTower; } @@ -438,25 +437,6 @@ public static Entity createRicochetTower() { ricochetTower.setScale(1.5f, 1.5f); return ricochetTower; } - public static Entity createHealTower() { - Entity ricochetTower = createBaseTower(); - HealTowerConfig config = configs.HealTower; - - AITaskComponent aiTaskComponent = new AITaskComponent() - .addTask(new RicochetTowerCombatTask(COMBAT_TASK_PRIORITY, WEAPON_TOWER_MAX_RANGE)); - - // ADD AnimationRenderComponent - - ricochetTower - .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) - .addComponent((new CostComponent(config.cost))) - .addComponent(aiTaskComponent); - // ADD ANIMATION COMPONENTS - - ricochetTower.setScale(1.5f, 1.5f); - PhysicsUtils.setScaledCollider(ricochetTower, 0.5f, 0.5f); - return ricochetTower; - } /** * Creates a generic tower entity to be used as a base entity by more specific tower creation methods. From b4c66ad9bed295ea77deb6b08e62d859088f415b Mon Sep 17 00:00:00 2001 From: Thivan W Date: Wed, 11 Oct 2023 17:00:41 +1000 Subject: [PATCH 14/19] Removed collisions with TNT tower --- .../main/com/csse3200/game/entities/factories/TowerFactory.java | 1 + 1 file changed, 1 insertion(+) diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index 50585a49c..861c25fa5 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -181,6 +181,7 @@ public static Entity createWallTower() { */ public static Entity createTNTTower() { Entity TNTTower = createBaseTower(); + TNTTower.getComponent(HitboxComponent.class).setLayer(PhysicsLayer.NONE); TNTTowerConfigs config = configs.TNTTower; AITaskComponent aiTaskComponent = new AITaskComponent() From cd36c4e367c75c0ff6f8dec31b79de25803683cb Mon Sep 17 00:00:00 2001 From: Thivan W Date: Thu, 12 Oct 2023 10:24:35 +1000 Subject: [PATCH 15/19] Slowed down the fire rate of the towers --- .../components/tasks/FireTowerCombatTask.java | 25 +++++---- .../tasks/FireworksTowerCombatTask.java | 24 +++++---- .../tasks/PierceTowerCombatTask.java | 27 ++++++---- .../tasks/RicochetTowerCombatTask.java | 26 +++++---- .../components/tasks/StunTowerCombatTask.java | 30 ++++++----- .../components/tasks/TowerCombatTask.java | 54 ++++++++++--------- .../game/entities/factories/TowerFactory.java | 17 +++--- 7 files changed, 117 insertions(+), 86 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java index c45234f51..13aa11a18 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/FireTowerCombatTask.java @@ -42,6 +42,7 @@ public class FireTowerCombatTask extends DefaultTask implements PriorityTask { private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); + private boolean shoot = true; public enum STATE { IDLE, PREP_ATTACK, ATTACK, DEATH @@ -115,17 +116,21 @@ public void updateTowerState() { } } case ATTACK -> { - if (!isTargetVisible()) { - owner.getEntity().getEvents().trigger(IDLE); - towerState = STATE.IDLE; - } else { - owner.getEntity().getEvents().trigger(ATTACK); - Entity newProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, - new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), ProjectileEffects.BURN, false); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y)); - ServiceLocator.getEntityService().register(newProjectile); + if (shoot) { + if (!isTargetVisible()) { + owner.getEntity().getEvents().trigger(IDLE); + towerState = STATE.IDLE; + } else { + owner.getEntity().getEvents().trigger(ATTACK); + Entity newProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, + new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), ProjectileEffects.BURN, false); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), + (float) (owner.getEntity().getPosition().y)); + ServiceLocator.getEntityService().register(newProjectile); + } } + shoot = !shoot; + } case DEATH -> { if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java index b99a8f09d..8d10036ae 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/FireworksTowerCombatTask.java @@ -40,6 +40,7 @@ public class FireworksTowerCombatTask extends DefaultTask implements PriorityTas private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); + private boolean shoot = true; public enum STATE { IDLE, ATTACK, DEATH @@ -104,17 +105,20 @@ public void updateTowerState() { } case ATTACK -> { // check if fired last time if not fire if so hold - if (isTargetVisible()) { - owner.getEntity().getEvents().trigger(ATTACK); - Entity newProjectile = ProjectileFactory.createSplitFireWorksFireball(PhysicsLayer.NPC, - new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), 3); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y)); - ServiceLocator.getEntityService().register(newProjectile); - } else { - owner.getEntity().getEvents().trigger(IDLE); - towerState=STATE.IDLE; + if (shoot) { + if (isTargetVisible()) { + owner.getEntity().getEvents().trigger(ATTACK); + Entity newProjectile = ProjectileFactory.createSplitFireWorksFireball(PhysicsLayer.NPC, + new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), 3); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), + (float) (owner.getEntity().getPosition().y)); + ServiceLocator.getEntityService().register(newProjectile); + } else { + owner.getEntity().getEvents().trigger(IDLE); + towerState=STATE.IDLE; + } } + shoot = !shoot; } case DEATH -> { if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java index 8fd0986af..b6c6f7619 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/PierceTowerCombatTask.java @@ -39,6 +39,7 @@ public class PierceTowerCombatTask extends DefaultTask implements PriorityTask { private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); + private boolean shoot = true; public enum STATE { IDLE, ATTACK, DEATH @@ -103,18 +104,22 @@ public void updateTowerState() { } } case ATTACK -> { - if (!isTargetVisible()) { - owner.getEntity().getEvents().trigger(IDLE); - towerState = STATE.IDLE; - } else { - owner.getEntity().getEvents().trigger(ALERT); - owner.getEntity().getEvents().trigger(ATTACK); - Entity newProjectile = ProjectileFactory.createPierceFireBall(PhysicsLayer.NPC, - new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y)); - ServiceLocator.getEntityService().register(newProjectile); + if (shoot) { + if (!isTargetVisible()) { + owner.getEntity().getEvents().trigger(IDLE); + towerState = STATE.IDLE; + } else { + owner.getEntity().getEvents().trigger(ALERT); + owner.getEntity().getEvents().trigger(ATTACK); + Entity newProjectile = ProjectileFactory.createPierceFireBall(PhysicsLayer.NPC, + new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f)); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), + (float) (owner.getEntity().getPosition().y)); + ServiceLocator.getEntityService().register(newProjectile); + } } + + shoot = !shoot; } case DEATH -> { if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java index 39d5ded0e..63c662417 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/RicochetTowerCombatTask.java @@ -40,6 +40,7 @@ public class RicochetTowerCombatTask extends DefaultTask implements PriorityTask private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); + private boolean shoot = true; //enums for the state triggers public enum STATE { @@ -104,18 +105,21 @@ public void updateTowerState() { } } case ATTACK -> { - if (!isTargetVisible()) { - owner.getEntity().getEvents().trigger(IDLE); - towerState = STATE.IDLE; - } else { - owner.getEntity().getEvents().trigger(ATTACK); - Entity newProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, - // NEED TO DO USER TESTING TO FIGURE OUT THE BOUNCE COUNT - new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), 3); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y)); - ServiceLocator.getEntityService().register(newProjectile); + if (shoot) { + if (!isTargetVisible()) { + owner.getEntity().getEvents().trigger(IDLE); + towerState = STATE.IDLE; + } else { + owner.getEntity().getEvents().trigger(ATTACK); + Entity newProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, + // NEED TO DO USER TESTING TO FIGURE OUT THE BOUNCE COUNT + new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), 3); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), + (float) (owner.getEntity().getPosition().y)); + ServiceLocator.getEntityService().register(newProjectile); + } } + shoot = !shoot; } case DEATH -> { if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java index ff61e16f0..5e131a602 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java @@ -40,10 +40,11 @@ public class StunTowerCombatTask extends DefaultTask implements PriorityTask { private GameTime timeSource; private long endTime; private final RaycastHit hit = new RaycastHit(); + private boolean shoot = true; //enums for the state triggers public enum STATE { - IDLE, ATTACK, DIE + IDLE, WAIT, ATTACK, DIE } public STATE towerState = STATE.IDLE; @@ -111,20 +112,25 @@ public void updateTowerState() { } } case ATTACK -> { - if (!isTargetVisible()) { - owner.getEntity().getEvents().trigger(IDLE); - towerState = STATE.IDLE; - } else { - owner.getEntity().getEvents().trigger(ATTACK); + if (shoot) { + if (!isTargetVisible()) { + owner.getEntity().getEvents().trigger(IDLE); + towerState = STATE.IDLE; + } else { + owner.getEntity().getEvents().trigger(ATTACK); // Entity newProjectile = ProjectileFactory.createFireBall(PhysicsLayer.NPC, // new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f)); - Entity newProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, - new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), - ProjectileEffects.STUN, false); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), - (float) (owner.getEntity().getPosition().y)); - ServiceLocator.getEntityService().register(newProjectile); + Entity newProjectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, + new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f), + ProjectileEffects.STUN, false); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.25), + (float) (owner.getEntity().getPosition().y)); + ServiceLocator.getEntityService().register(newProjectile); + owner.getEntity().getEvents().trigger(IDLE); + towerState = STATE.IDLE; + } } + shoot = !shoot; } case DIE -> { if (owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) { diff --git a/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java index e6d891375..c9f5c2b33 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/TowerCombatTask.java @@ -45,6 +45,7 @@ public class TowerCombatTask extends DefaultTask implements PriorityTask { private long endTime; private final RaycastHit hit = new RaycastHit(); private static final Logger logger = LoggerFactory.getLogger(ForestGameArea.class); + private boolean shoot = true; private enum STATE { IDLE, DEPLOY, FIRING, STOW, DEATH @@ -141,38 +142,41 @@ public void updateTowerState() { } } case FIRING -> { - // targets gone - stop firing - if (!isTargetVisible()) { + if (shoot) { + // targets gone - stop firing + if (!isTargetVisible()) { - owner.getEntity().getEvents().trigger(STOW); - towerState = STATE.STOW; - } else { - owner.getEntity().getEvents().trigger(FIRING); - // this might be changed to an event which gets triggered everytime the tower enters the firing state + owner.getEntity().getEvents().trigger(STOW); + towerState = STATE.STOW; + } else { + owner.getEntity().getEvents().trigger(FIRING); + // this might be changed to an event which gets triggered everytime the tower enters the firing state + + Entity newProjectile = ProjectileFactory.createFireBall(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f, 2f)); + newProjectile.setScale(1.1f, 0.8f); + newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.5), (float) (owner.getEntity().getPosition().y)); + ServiceLocator.getEntityService().register(newProjectile); - Entity newProjectile = ProjectileFactory.createFireBall(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setScale(1.1f, 0.8f); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.5), (float) (owner.getEntity().getPosition().y)); - ServiceLocator.getEntityService().register(newProjectile); - - // * TEMPRORARYYYYYYYY PLS DON'T DELETE THIS - // PIERCE FIREBALL - // Entity pierceFireball = ProjectileFactory.createPierceFireBall(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - // pierceFireball.setPosition((float) (owner.getEntity().getPosition().x + 0), (float) (owner.getEntity().getPosition().y + 0.4)); - // ServiceLocator.getEntityService().register(pierceFireball); + // * TEMPRORARYYYYYYYY PLS DON'T DELETE THIS + // PIERCE FIREBALL + // Entity pierceFireball = ProjectileFactory.createPierceFireBall(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f)); + // pierceFireball.setPosition((float) (owner.getEntity().getPosition().x + 0), (float) (owner.getEntity().getPosition().y + 0.4)); + // ServiceLocator.getEntityService().register(pierceFireball); - // RICOCHET FIREBALL - // Entity ricochetProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f), 0); + // RICOCHET FIREBALL + // Entity ricochetProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f), 0); - // ricochetProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0), (float) (owner.getEntity().getPosition().y + 0.4)); - // ServiceLocator.getEntityService().register(ricochetProjectile); + // ricochetProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0), (float) (owner.getEntity().getPosition().y + 0.4)); + // ServiceLocator.getEntityService().register(ricochetProjectile); - // SPLIT FIREWORKS FIREBALLL - // Entity splitFireWorksProjectile = ProjectileFactory.createSplitFireWorksFireball(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f), 16); + // SPLIT FIREWORKS FIREBALLL + // Entity splitFireWorksProjectile = ProjectileFactory.createSplitFireWorksFireball(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f), 16); - // splitFireWorksProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.75), (float) (owner.getEntity().getPosition().y + 0.4)); - // ServiceLocator.getEntityService().register(splitFireWorksProjectile); + // splitFireWorksProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.75), (float) (owner.getEntity().getPosition().y + 0.4)); + // ServiceLocator.getEntityService().register(splitFireWorksProjectile); + } } + shoot = !shoot; } case STOW -> { // currently stowing diff --git a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java index 861c25fa5..81ff0012f 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/TowerFactory.java @@ -181,7 +181,10 @@ public static Entity createWallTower() { */ public static Entity createTNTTower() { Entity TNTTower = createBaseTower(); - TNTTower.getComponent(HitboxComponent.class).setLayer(PhysicsLayer.NONE); + TNTTower.getComponent(HitboxComponent.class) + .setLayer(PhysicsLayer.NONE) + .setSensor(true); + TNTTower.getComponent(ColliderComponent.class).setSensor(true); TNTTowerConfigs config = configs.TNTTower; AITaskComponent aiTaskComponent = new AITaskComponent() @@ -271,7 +274,7 @@ public static Entity createWeaponTower() { animator.addAnimation(IDLE_ANIM, IDLE_SPEED, Animation.PlayMode.LOOP); animator.addAnimation(STOW_ANIM, STOW_SPEED, Animation.PlayMode.NORMAL); animator.addAnimation(DEPLOY_ANIM, DEPLOY_SPEED, Animation.PlayMode.REVERSED); - animator.addAnimation(FIRE_ANIM, FIRE_SPEED, Animation.PlayMode.LOOP); + animator.addAnimation(FIRE_ANIM, (2*FIRE_SPEED), Animation.PlayMode.LOOP); weapon .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) @@ -304,7 +307,7 @@ public static Entity createFireTower() { .getAsset(FIRE_TOWER_ATLAS, TextureAtlas.class)); animator.addAnimation(FIRE_TOWER_IDLE_ANIM, FIRE_TOWER_IDLE_SPEED, Animation.PlayMode.LOOP); animator.addAnimation(FIRE_TOWER_PREP_ATTACK_ANIM, FIRE_TOWER_PREP_ATTACK_SPEED, Animation.PlayMode.NORMAL); - animator.addAnimation(FIRE_TOWER_ATTACK_ANIM, FIRE_TOWER_ATTACK_SPEED+ 0.25f, Animation.PlayMode.LOOP); + animator.addAnimation(FIRE_TOWER_ATTACK_ANIM, (2*(FIRE_TOWER_ATTACK_SPEED+ 0.25f)), Animation.PlayMode.LOOP); animator.addAnimation(FIRE_TOWER_DEATH_ANIM, FIRE_TOWER_DEATH_SPEED, Animation.PlayMode.NORMAL); fireTower @@ -334,7 +337,7 @@ public static Entity createStunTower() { ServiceLocator.getResourceService() .getAsset(STUN_TOWER_ATLAS, TextureAtlas.class)); animator.addAnimation(STUN_TOWER_IDLE_ANIM, STUN_TOWER_IDLE_SPEED, Animation.PlayMode.LOOP); - animator.addAnimation(STUN_TOWER_ATTACK_ANIM, STUN_TOWER_ATTACK_SPEED+ 0.25f, Animation.PlayMode.LOOP); + animator.addAnimation(STUN_TOWER_ATTACK_ANIM, ((STUN_TOWER_ATTACK_SPEED+ 0.20f)), Animation.PlayMode.LOOP); animator.addAnimation(STUN_TOWER_DEATH_ANIM, STUN_TOWER_DEATH_SPEED, Animation.PlayMode.NORMAL); stunTower @@ -365,7 +368,7 @@ public static Entity createFireworksTower() { new AnimationRenderComponent( ServiceLocator.getResourceService() .getAsset(FIREWORKS_TOWER_ATLAS, TextureAtlas.class)); - animator.addAnimation(FIREWORKS_TOWER_ATTACK_ANIM, FIREWORKS_TOWER_ANIM_ATTACK_SPEED, Animation.PlayMode.NORMAL); + animator.addAnimation(FIREWORKS_TOWER_ATTACK_ANIM, (2*FIREWORKS_TOWER_ANIM_ATTACK_SPEED), Animation.PlayMode.NORMAL); animator.addAnimation(FIREWORKS_TOWER_IDLE_ANIM, FIREWORKS_TOWER_ANIM_SPEED, Animation.PlayMode.LOOP); animator.addAnimation(FIREWORKS_TOWER_DEATH_ANIM, FIREWORKS_TOWER_ANIM_SPEED, Animation.PlayMode.NORMAL); @@ -394,7 +397,7 @@ public static Entity createPierceTower() { new AnimationRenderComponent( ServiceLocator.getResourceService() .getAsset(PIERCE_TOWER_ATLAS, TextureAtlas.class)); - animator.addAnimation(PIERCE_TOWER_ATTACK_ANIM, PIERCE_TOWER_ANIM_ATTACK_SPEED, Animation.PlayMode.LOOP); + animator.addAnimation(PIERCE_TOWER_ATTACK_ANIM, (2*PIERCE_TOWER_ANIM_ATTACK_SPEED), Animation.PlayMode.LOOP); animator.addAnimation(PIERCE_TOWER_IDLE_ANIM, PIERCE_TOWER_ANIM_ATTACK_SPEED, Animation.PlayMode.LOOP); animator.addAnimation(PIERCE_TOWER_DEATH_ANIM, PIERCE_TOWER_ANIM_ATTACK_SPEED, Animation.PlayMode.NORMAL); animator.addAnimation(PIERCE_TOWER_ALERT_ANIM, PIERCE_TOWER_ANIM_ATTACK_SPEED, Animation.PlayMode.NORMAL); @@ -424,7 +427,7 @@ public static Entity createRicochetTower() { AnimationRenderComponent animator = new AnimationRenderComponent( ServiceLocator.getResourceService().getAsset(RICOCHET_TOWER_ATLAS,TextureAtlas.class)); - animator.addAnimation(RICOCHET_TOWER_ATTACK_ANIM,RICOCHET_TOWER_ANIM_ATTACK_SPEED,Animation.PlayMode.LOOP); + animator.addAnimation(RICOCHET_TOWER_ATTACK_ANIM,(2*RICOCHET_TOWER_ANIM_ATTACK_SPEED),Animation.PlayMode.LOOP); animator.addAnimation(RICOCHET_TOWER_DEATH_ANIM,RICOCHET_TOWER_ANIM_ATTACK_SPEED,Animation.PlayMode.NORMAL); animator.addAnimation(RICOCHET_TOWER_IDLE_ANIM,RICOCHET_TOWER_ANIM_ATTACK_SPEED,Animation.PlayMode.LOOP); ricochetTower From 7505bac04ae2758c3a99621e369fc82f95026fdc Mon Sep 17 00:00:00 2001 From: Thivan W Date: Thu, 12 Oct 2023 10:29:22 +1000 Subject: [PATCH 16/19] God rid of a useless state in StunTowerCombatTask --- .../com/csse3200/game/components/tasks/StunTowerCombatTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java b/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java index 5e131a602..ec469b269 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/StunTowerCombatTask.java @@ -44,7 +44,7 @@ public class StunTowerCombatTask extends DefaultTask implements PriorityTask { //enums for the state triggers public enum STATE { - IDLE, WAIT, ATTACK, DIE + IDLE, ATTACK, DIE } public STATE towerState = STATE.IDLE; From e533bb4f361dd904ce61134079d7e20c6d5adc7b Mon Sep 17 00:00:00 2001 From: meganroxburgh <128758122+meganroxburgh@users.noreply.github.com> Date: Thu, 12 Oct 2023 15:12:24 +1000 Subject: [PATCH 17/19] When all the waves are completed, the screen transitions to the lose screen. This will need to be changed to the win screen when it has been created by team 3 Changes need to be made in MainGameScreen, line 230 - link to "win" rather than lose. Potentially need to also link to unlocking the next level/planet also. --- .../game/components/maingame/MainGameActions.java | 1 + .../game/components/tasks/waves/WaveTask.java | 4 ++-- .../com/csse3200/game/screens/MainGameScreen.java | 14 +++++++++++--- .../com/csse3200/game/services/WaveService.java | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/maingame/MainGameActions.java b/source/core/src/main/com/csse3200/game/components/maingame/MainGameActions.java index 37dd07117..970c44fd6 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/MainGameActions.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/MainGameActions.java @@ -21,6 +21,7 @@ public MainGameActions(GdxGame game) { public void create() { entity.getEvents().addListener("exit", this::onExit); entity.getEvents().addListener("lose", this::onLose); + //entity.getEvents().addListener("win", this::onWin); } /** diff --git a/source/core/src/main/com/csse3200/game/components/tasks/waves/WaveTask.java b/source/core/src/main/com/csse3200/game/components/tasks/waves/WaveTask.java index 4be3210de..dbf8fbaed 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/waves/WaveTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/waves/WaveTask.java @@ -103,8 +103,8 @@ public void update() { ServiceLocator.getWaveService().setNextWaveTime(currentTime + (spawnDelay * 1000)); // Check if level has been completed - no more waves remaining - if (currentWaveIndex == this.level.getNumWaves()) { - logger.info("No waves remaining, level completed"); + if (currentWaveIndex == this.level.getNumWaves() - 1) { + logger.info("No waves remaining"); ServiceLocator.getWaveService().setLevelCompleted(); } else { 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 55623b881..d7de9a289 100644 --- a/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java +++ b/source/core/src/main/com/csse3200/game/screens/MainGameScreen.java @@ -215,14 +215,21 @@ public void render(float delta) { // Checks if tower selected is dead this.getUpgradedInputHandler().checkForDispose(); + ServiceLocator.getWaveService().getDisplay().updateTimerButton(); + ServiceLocator.getWaveService().getDisplay().updateMobCount(); + renderer.render(); + // Check if the game has ended if (ServiceLocator.getGameEndService().hasGameEnded()) { ui.getEvents().trigger("lose"); } - ServiceLocator.getWaveService().getDisplay().updateTimerButton(); - ServiceLocator.getWaveService().getDisplay().updateMobCount(); - renderer.render(); + // Check if all waves are completed and the level has been completed + if (ServiceLocator.getWaveService().isLevelCompleted()) { + logger.info("Main game level completed detected, go to win screen"); + ui.getEvents().trigger("lose"); // needs to change to: ui.getEvents().trigger("win"); + // Add something in to unlock the next planet/level? + } } @Override @@ -297,6 +304,7 @@ private void createUI() { .addComponent(ServiceLocator.getWaveService().getDisplay()) .addComponent(new MainGameExitDisplay()) .addComponent(new MainGameLoseDisplay()) + //.addComponent(new MainGameWinDisplay()) <- needs to be uncommented when team 3 have implemented the ui .addComponent(new MainGamePauseDisplay(this.game)) .addComponent(new Terminal()) .addComponent(inputComponent) diff --git a/source/core/src/main/com/csse3200/game/services/WaveService.java b/source/core/src/main/com/csse3200/game/services/WaveService.java index c7ddacdef..476b87a89 100644 --- a/source/core/src/main/com/csse3200/game/services/WaveService.java +++ b/source/core/src/main/com/csse3200/game/services/WaveService.java @@ -64,6 +64,7 @@ public void updateEnemyCount() { */ public void setLevelCompleted() { if (!levelCompleted) { + logger.info("Level set to completed"); levelCompleted = true; } } From 56e1267584ac295527c49c08e0a83193eaa6aec5 Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Thu, 12 Oct 2023 22:54:05 +1000 Subject: [PATCH 18/19] removed try catch statements --- .../game/input/BuildInputComponent.java | 36 +++++++------------ .../game/input/BuildInputComponentTest.java | 10 +++--- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 8af5618c8..15b58516f 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -45,7 +45,7 @@ public BuildInputComponent(Camera camera) { loadSounds(); towers.addAll(ServiceLocator.getTowerTypes()); -// logger.info("selected towers in buildInputComponent are " + towers); + logger.debug("selected towers in buildInputComponent are " + towers); TowerType[] defaultTowerTypes = { TowerType.TNT, TowerType.DROID, @@ -90,11 +90,11 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { // determine if the tile is unoccupied boolean tileOccupied = entityService.entitiesInTile((int)cursorPosition.x, (int)cursorPosition.y); -// logger.debug("Tile is occupied: " + tileOccupied ); + logger.debug("Tile is occupied: " + tileOccupied ); // check that no entities are occupying the tile if (!tileOccupied) { -// logger.debug("spawning a tower at {}, {}", cursorPosition.x, cursorPosition.y); + logger.debug("spawning a tower at {}, {}", cursorPosition.x, cursorPosition.y); return buildTower((int)cursorPosition.x, (int)cursorPosition.y); } else { // TODO: Create a tile indication of invalid placement here?? @@ -143,12 +143,9 @@ public boolean buildTower(int x, int y) { TowerType tower; CurrencyService currencyService; // fetch the currently set TowerType in the currency service, and its associated build cost. - try { - currencyService = ServiceLocator.getCurrencyService(); - } catch (NullPointerException e) { + currencyService = ServiceLocator.getCurrencyService(); + if (currencyService == null) { // if the currency service fails or is not running - logger.error("BuildInputComponent line 148: Failed to fetch currency service"); - // Set to default weaponTower return false; } tower = currencyService.getTower(); @@ -169,14 +166,12 @@ public boolean buildTower(int x, int y) { // build the selected tower newTower.setPosition(x, y); EntityService entityService; - try { - entityService = ServiceLocator.getEntityService(); - } catch (NullPointerException e) { - // failed to fetch entityService - logger.error("BuildInputComponent line 173: Failed to fetch EntityService"); + + entityService = ServiceLocator.getEntityService(); + if (entityService == null){ return false; } - entityService.register(newTower); + entityService.register(newTower); // Decrement currency and show a popup that reflects the cost of the build ServiceLocator.getCurrencyService().getScrap().modify(-cost); @@ -206,14 +201,9 @@ public boolean buildTower(int x, int y) { * Load the sound assets related to in-game tower building activity */ private void loadSounds() { - try { - ServiceLocator.getResourceService().loadSounds(sounds); - ServiceLocator.getResourceService().loadAll(); - buildSound = ServiceLocator.getResourceService().getAsset("sounds/economy/buildSound.ogg", Sound.class); - errorSound = ServiceLocator.getResourceService().getAsset("sounds/ui/Switch/NA_SFUI_Vol1_switch_01.ogg", Sound.class); - - } catch (NullPointerException e) { - logger.error("BuildInputComponent line 173: Couldn't load sounds for build menu"); - } + ServiceLocator.getResourceService().loadSounds(sounds); + ServiceLocator.getResourceService().loadAll(); + buildSound = ServiceLocator.getResourceService().getAsset("sounds/economy/buildSound.ogg", Sound.class); + errorSound = ServiceLocator.getResourceService().getAsset("sounds/ui/Switch/NA_SFUI_Vol1_switch_01.ogg", Sound.class); } } diff --git a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java index b67900aa8..1b967498c 100644 --- a/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java +++ b/source/core/src/test/com/csse3200/game/input/BuildInputComponentTest.java @@ -86,7 +86,7 @@ void shouldHandleTouchDown() { } @Test - void shouldRejectOccupiedOrInvalidTile() { + void shouldRejectOccupiedOrInvalidTile() { // entitiesInTile checks for out of bounds condition as well when(entityService.entitiesInTile(5, 5)).thenReturn(true); assertFalse(buildInputComponent.touchDown(5,5, 7,8), @@ -94,19 +94,19 @@ void shouldRejectOccupiedOrInvalidTile() { } @Test - void shouldHandleMissingMapService() { + void shouldHandleMissingMapService() { when(ServiceLocator.getMapService()).thenReturn(null); assertFalse(buildInputComponent.touchDown(5,5,7,8)); } @Test - void shouldHandleMissingCurrencyService() { + void shouldHandleMissingCurrencyService() { when(ServiceLocator.getCurrencyService()).thenReturn(null); assertFalse(buildInputComponent.touchDown(5,5,7,8)); } @Test - void shouldHandleNullTowerName() { + void shouldHandleNullTowerName() { TowerType towerType = mock(TowerType.class); when(towerType.getTowerName()).thenReturn(null); ServiceLocator.getCurrencyService().setTowerType(towerType); @@ -134,7 +134,7 @@ void shouldHandleInvalidTowerName() { } @Test - void shouldHandleMissingEntityService() { + void shouldHandleMissingEntityService() { when(ServiceLocator.getEntityService()).thenReturn(null); assertFalse(buildInputComponent.touchDown(5,5,7,8)); } From 18a7a6ff582d9e87b3ac55045a3f32a49806c3dd Mon Sep 17 00:00:00 2001 From: Ahmad Abu-Aysha <111224176+The-AhmadAA@users.noreply.github.com> Date: Thu, 12 Oct 2023 23:43:55 +1000 Subject: [PATCH 19/19] added multiple placement key functionality --- .../maingame/UIElementsDisplay.java | 5 +--- .../game/input/BuildInputComponent.java | 23 ++++++++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java index 42bd789ef..be5f377c3 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/UIElementsDisplay.java @@ -51,14 +51,11 @@ private void addActors() { remainingMobsButton = new TextButton("Mobs:" + ServiceLocator.getWaveService().getEnemyCount(), skin); buttonTable.top().right(); - towerTable.top(); + towerTable.top().padTop(80f); buttonTable.setFillParent(true); towerTable.setFillParent(true); - towerTable.setDebug(true); - towerTable.padTop(50f); - TowerType[] defaultTowers = { TowerType.TNT, TowerType.DROID, diff --git a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java index 15b58516f..1dcf527cf 100644 --- a/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/BuildInputComponent.java @@ -34,6 +34,7 @@ public class BuildInputComponent extends InputComponent { private Sound errorSound; private Array towers = new Array<>(); private Array defaultTowers = new Array<>(); + private boolean multipleTowerBuild = false; /** * Constructor for the BuildInputComponent @@ -127,11 +128,29 @@ public boolean keyUp(int keycode) { case Input.Keys.NUM_5: ServiceLocator.getCurrencyService().setTowerType(towers.get(4)); return true; + case Input.Keys.CONTROL_LEFT: + // After multiple placement, deselect tower and prevent further builds + ServiceLocator.getCurrencyService().setTowerType(null); + multipleTowerBuild = false; + return true; default: return false; } } + /** + * + * @param keycode one of the constants in {@link Input.Keys} + * @return + */ + public boolean keyDown(int keycode) { + if (keycode == Input.Keys.CONTROL_LEFT) { + multipleTowerBuild = true; + return true; + } + return false; + } + /** * Instantiates and spawns the selected tower at the given x y coordinates on the tile map. Assumes that the given * x and y coordinate is valid and that the TowerType exists in the CurrencyService. @@ -182,7 +201,9 @@ public boolean buildTower(int x, int y) { buildSound.setVolume(soundId, 0.4f); // deselect the tower after building - ServiceLocator.getCurrencyService().setTowerType(null); + if (!multipleTowerBuild) { + ServiceLocator.getCurrencyService().setTowerType(null); + } return true; } else { // play a sound to indicate an invalid action