diff --git a/source/core/assets/images/towers/imageedit_9_7173145411.png b/source/core/assets/images/towers/imageedit_9_7173145411.png new file mode 100644 index 000000000..c43b4675b Binary files /dev/null and b/source/core/assets/images/towers/imageedit_9_7173145411.png differ diff --git a/source/core/assets/images/towers/WallTower.png b/source/core/assets/images/towers/wall_tower.png similarity index 100% rename from source/core/assets/images/towers/WallTower.png rename to source/core/assets/images/towers/wall_tower.png diff --git a/source/core/assets/images/turret-select/Weapon-Tower-Clicked.png b/source/core/assets/images/turret-select/Weapon-Tower-Clicked.png new file mode 100644 index 000000000..fbfbedccb Binary files /dev/null and b/source/core/assets/images/turret-select/Weapon-Tower-Clicked.png differ diff --git a/source/core/assets/images/turret-select/Weapon-Tower-Default.png b/source/core/assets/images/turret-select/Weapon-Tower-Default.png new file mode 100644 index 000000000..fff06381b Binary files /dev/null and b/source/core/assets/images/turret-select/Weapon-Tower-Default.png differ diff --git a/source/core/assets/images/turret-select/droid-tower-clicked.png b/source/core/assets/images/turret-select/droid-tower-clicked.png new file mode 100644 index 000000000..4d182496d Binary files /dev/null and b/source/core/assets/images/turret-select/droid-tower-clicked.png differ diff --git a/source/core/assets/images/turret-select/droid-tower-default.png b/source/core/assets/images/turret-select/droid-tower-default.png new file mode 100644 index 000000000..958470e53 Binary files /dev/null and b/source/core/assets/images/turret-select/droid-tower-default.png differ diff --git a/source/core/assets/images/turret-select/fire-tower-clicked.png b/source/core/assets/images/turret-select/fire-tower-clicked.png new file mode 100644 index 000000000..ce1969010 Binary files /dev/null and b/source/core/assets/images/turret-select/fire-tower-clicked.png differ diff --git a/source/core/assets/images/turret-select/fire-tower-default.png b/source/core/assets/images/turret-select/fire-tower-default.png new file mode 100644 index 000000000..318b0f138 Binary files /dev/null and b/source/core/assets/images/turret-select/fire-tower-default.png differ diff --git a/source/core/assets/images/turret-select/imageedit_15_5627113584.png b/source/core/assets/images/turret-select/imageedit_15_5627113584.png new file mode 100644 index 000000000..14412cd66 Binary files /dev/null and b/source/core/assets/images/turret-select/imageedit_15_5627113584.png differ diff --git a/source/core/assets/images/turret-select/imageedit_28_4047785594.png b/source/core/assets/images/turret-select/imageedit_28_4047785594.png new file mode 100644 index 000000000..a7f312043 Binary files /dev/null and b/source/core/assets/images/turret-select/imageedit_28_4047785594.png differ diff --git a/source/core/assets/images/turret-select/imageedit_2_8132799771.png b/source/core/assets/images/turret-select/imageedit_2_8132799771.png new file mode 100644 index 000000000..6fafcf62f Binary files /dev/null and b/source/core/assets/images/turret-select/imageedit_2_8132799771.png differ diff --git a/source/core/assets/images/turret-select/imageedit_4_5616741474.png b/source/core/assets/images/turret-select/imageedit_4_5616741474.png new file mode 100644 index 000000000..f877adaec Binary files /dev/null and b/source/core/assets/images/turret-select/imageedit_4_5616741474.png differ diff --git a/source/core/assets/images/turret-select/mine-tower-clicked.png b/source/core/assets/images/turret-select/mine-tower-clicked.png new file mode 100644 index 000000000..cb8eebc75 Binary files /dev/null and b/source/core/assets/images/turret-select/mine-tower-clicked.png differ diff --git a/source/core/assets/images/turret-select/mine-tower-default.png b/source/core/assets/images/turret-select/mine-tower-default.png new file mode 100644 index 000000000..64bb31cae Binary files /dev/null and b/source/core/assets/images/turret-select/mine-tower-default.png differ diff --git a/source/core/assets/images/turret-select/stun-tower-clicked.png b/source/core/assets/images/turret-select/stun-tower-clicked.png new file mode 100644 index 000000000..d620b84e7 Binary files /dev/null and b/source/core/assets/images/turret-select/stun-tower-clicked.png differ diff --git a/source/core/assets/images/turret-select/stun-tower-default.png b/source/core/assets/images/turret-select/stun-tower-default.png new file mode 100644 index 000000000..5674c9020 Binary files /dev/null and b/source/core/assets/images/turret-select/stun-tower-default.png differ diff --git a/source/core/assets/images/turret-select/tnt-tower-clicked.png b/source/core/assets/images/turret-select/tnt-tower-clicked.png new file mode 100644 index 000000000..9abee203c Binary files /dev/null and b/source/core/assets/images/turret-select/tnt-tower-clicked.png differ diff --git a/source/core/assets/images/turret-select/tnt-tower-default.png b/source/core/assets/images/turret-select/tnt-tower-default.png new file mode 100644 index 000000000..09ee3b6de Binary files /dev/null and b/source/core/assets/images/turret-select/tnt-tower-default.png differ diff --git a/source/core/assets/images/turret-select/wall-tower-clicked.png b/source/core/assets/images/turret-select/wall-tower-clicked.png new file mode 100644 index 000000000..35cf07460 Binary files /dev/null and b/source/core/assets/images/turret-select/wall-tower-clicked.png differ diff --git a/source/core/assets/images/turret-select/wall-tower-default.png b/source/core/assets/images/turret-select/wall-tower-default.png new file mode 100644 index 000000000..bc7ba42f8 Binary files /dev/null and b/source/core/assets/images/turret-select/wall-tower-default.png differ diff --git a/source/core/assets/sounds/turret-select/Modern4.wav b/source/core/assets/sounds/turret-select/Modern4.wav new file mode 100644 index 000000000..98b9386fa Binary files /dev/null and b/source/core/assets/sounds/turret-select/Modern4.wav differ diff --git a/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java b/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java index 14c42b74e..93798e8d4 100644 --- a/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java +++ b/source/core/src/main/com/csse3200/game/ai/tasks/AITaskComponent.java @@ -1,6 +1,7 @@ package com.csse3200.game.ai.tasks; import com.csse3200.game.components.Component; +import com.csse3200.game.components.ComponentType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +36,24 @@ public AITaskComponent addTask(PriorityTask task) { return this; } + /** + * Get a task from the list of tasks. This can be used to get a reference to + * a task to modify it. This is inspired from Entity.getComponent(). + * + * @param task The task to get + * @return A reference to a task with the given class + * @param The type of task to get + */ + public T getTask(Class task) { + for (PriorityTask priorityTask : priorityTasks) { + if (priorityTask.getClass() == task) { + return (T) priorityTask; + } + } + logger.info("Task {} not found", task); + return null; + } + /** * On update, run the current highest priority task. If it's a different one, stop the old one and * start the new one. If the highest priority task has negative priority, no task will be run. diff --git a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java index d960b9777..cbbf427d9 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -89,7 +89,7 @@ public class ForestGameArea extends GameArea { "images/mobs/Hurt.png", "images/mobs/Idle.png", "images/mobs/rangeBossRight.png", - "images/towers/WallTower.png", + "images/towers/wall_tower.png", "images/background/building2.png", "images/iso_grass_3.png", "images/terrain_use.png", @@ -276,13 +276,22 @@ public void create() { // spawnTNTTower(); // spawnIncome(); spawnIncome(); + playMusic(); + spawnXenoGrunts(); + startWaveTimer(); + spawnScrap(); + spawnDeflectXenoGrunt(15, 5); + spawnSplittingXenoGrunt(15, 4); + spawnScrap(); + spawnTNTTower(); + spawnWeaponTower(); + spawnGapScanners(); spawnDroidTower(); } private void displayUI() { Entity ui = new Entity(); - ui.addComponent(new GameAreaDisplay("Box Forest")); ui.addComponent(ServiceLocator.getGameEndService().getDisplay()); ui.addComponent(ServiceLocator.getCurrencyService().getDisplay()); spawnEntity(ui); diff --git a/source/core/src/main/com/csse3200/game/components/gamearea/GameAreaDisplay.java b/source/core/src/main/com/csse3200/game/components/gamearea/GameAreaDisplay.java index 83582470b..47096ea75 100644 --- a/source/core/src/main/com/csse3200/game/components/gamearea/GameAreaDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/gamearea/GameAreaDisplay.java @@ -76,7 +76,7 @@ public void create() { for (int i = 0; i < 2; i++) { // Use "building1" for the first tower and "building2" for the second tower skin.add("default", new Label.LabelStyle(new BitmapFont(), Color.WHITE)); - skin.add("building1", new Texture("images/towers/WallTower.png")); + skin.add("building1", new Texture("images/towers/wall_tower.png")); // Load textures for building1 and building2 towers1[i] = new Image(skin, "building1"); towers1[i].setBounds(Gdx.graphics.getWidth() * 40f / 100f, Gdx.graphics.getHeight() * 80f / 100f, 100, 100); @@ -131,7 +131,7 @@ public void touchUp(InputEvent event, float x, float y, int pointer, int button) for (int i = 0; i < 2; i++) { // Use "building1" for the first tower and "building2" for the second tower skin.add("default", new Label.LabelStyle(new BitmapFont(), Color.WHITE)); - skin.add("building2", new Texture("images/towers/WallTower.png")); + skin.add("building2", new Texture("images/towers/wall_tower.png")); towers2[i] = new Image(skin, "building2"); towers2[i].setBounds(Gdx.graphics.getWidth() * 50f / 100f, Gdx.graphics.getHeight() * 80f / 100f, 100, 100); stage.addActor(towers2[i]); diff --git a/source/core/src/main/com/csse3200/game/components/npc/EngineerMenuComponent.java b/source/core/src/main/com/csse3200/game/components/npc/EngineerMenuComponent.java new file mode 100644 index 000000000..096fb5962 --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/npc/EngineerMenuComponent.java @@ -0,0 +1,150 @@ +package com.csse3200.game.components.npc; + +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +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.csse3200.game.components.player.HumanAnimationController; +import com.csse3200.game.components.tower.TowerUpgraderComponent; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.EntityService; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.input.EngineerInputComponent; +import com.csse3200.game.rendering.AnimationRenderComponent; +import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.ui.UIComponent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EngineerMenuComponent extends UIComponent { + private Logger logger = LoggerFactory.getLogger(EngineerMenuComponent.class); + Table table; + + @Override + public void create() { + super.create(); + } + + @Override + public void draw(SpriteBatch batch) { + // draw is handled by the stage + } + + /** + * Creates a menu for the engineer + * @param x cursor x coordinate + * @param y cursor y coordinate + * @param camera camera of the game + */ + public void createMenu(float x, float y, Camera camera) { + this.table = createTable(x, y, camera); + + // add buttons + TextButton moveButton = createButton("Move"); + TextButton repairButton = createButton("Repair"); + + // add listeners to buttons + AnimationRenderComponent animator = getEntity().getComponent(AnimationRenderComponent.class); + HumanAnimationController controller = getEntity().getComponent(HumanAnimationController.class); + EngineerInputComponent input = ServiceLocator.getInputService().getEngineerInput(); + + moveButton.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + input.setMoveClicked(true); + controller.deselectEngineer(animator.getCurrentAnimation()); + + //logger.info("Move button clicked"); + } + }); + + repairButton.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + controller.deselectEngineer(animator.getCurrentAnimation()); + EntityService entityService = ServiceLocator.getEntityService(); + Array tower = entityService.getEntitiesInLayer(getEntity(), 0.1f, PhysicsLayer.TOWER); + if (tower.size == 0) { + logger.info("No tower to repair"); + return; + } + logger.info("repairing"); + tower.get(0).getComponent(TowerUpgraderComponent.class).repairTower(); + //logger.info("Repair button clicked"); + } + }); + + table.add(moveButton).grow(); + table.row(); + table.add(repairButton).grow(); + table.row(); + stage.addActor(table); + + } + + /** + * Creates a table for the menu + * @param x cursor x coordinate + * @param y cursor y coordinate + * @param camera camera of the game + * @return table for the menu + */ + private Table createTable(float x, float y, Camera camera) { + Table table = new Table(); + table.top(); + table.defaults().pad(0).space(0); + table.setSize(90, 60); // fixed table size + + // convert cursor position to stage coordinates + Vector3 entityCoordinates = new Vector3(x, y, 0); + Vector3 entityScreenCoordinate = camera.project(entityCoordinates); + Vector2 stageCoordinates = stage.screenToStageCoordinates( + new Vector2(entityScreenCoordinate.x, entityScreenCoordinate.y)); + stage.getViewport().unproject(stageCoordinates); + table.setPosition(stageCoordinates.x, stageCoordinates.y); + + // set table background + String imageFilePath = "images/ui/Sprites/UI_Glass_Frame_Standard_01a.png"; + Drawable drawable = new TextureRegionDrawable(new TextureRegion(new Texture(imageFilePath))); + table.setBackground(drawable); + + return table; + } + + /** + * Creates a button for the menu + * @param text text to be displayed on the button + * @return the button + */ + private TextButton createButton(String text) { + String upImageFilePath = "images/ui/Sprites/UI_Glass_Button_Medium_Lock_01a2.png"; + String downImageFilePath = "images/ui/Sprites/UI_Glass_Button_Medium_Press_01a2.png"; + + Drawable upDrawable = new TextureRegionDrawable(new TextureRegion(new Texture(upImageFilePath))); + Drawable downDrawable = new TextureRegionDrawable(new TextureRegion(new Texture(downImageFilePath))); + TextButton button = new TextButton(text, + new TextButton.TextButtonStyle(upDrawable, downDrawable, null, new BitmapFont())); + + button.setTransform(true); + return button; + } + + /** + * Removes the menu from the stage + */ + public void removeMenu() { + table.clear(); + table.remove(); + } + +} diff --git a/source/core/src/main/com/csse3200/game/components/player/HumanAnimationController.java b/source/core/src/main/com/csse3200/game/components/player/HumanAnimationController.java index c6231f29e..bcaf10f1f 100644 --- a/source/core/src/main/com/csse3200/game/components/player/HumanAnimationController.java +++ b/source/core/src/main/com/csse3200/game/components/player/HumanAnimationController.java @@ -2,6 +2,7 @@ import com.badlogic.gdx.audio.Sound; import com.csse3200.game.components.Component; +import com.csse3200.game.components.npc.EngineerMenuComponent; import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.ServiceLocator; @@ -31,6 +32,18 @@ public class HumanAnimationController extends Component { private static final String FIRE_SINGLE_ANIM = "firing_single"; private static final String HIT_ANIM = "hit"; private static final String DEATH_ANIM = "death"; + + private static final String IDLEL_ANIM_OUTLINE = "idle_left_outline"; + private static final String IDLER_ANIM_OUTLINE = "idle_right_outline"; + private static final String WALKL_ANIM_OUTLINE = "walk_left_outline"; + private static final String WALKR_ANIM_OUTLINE = "walk_right_outline"; + private static final String WALK_PREP_ANIM_OUTLINE = "walk_prep_outline"; + private static final String FIRE_AUTO_ANIM_OUTLINE = "firing_auto_outline"; + private static final String FIRE_SINGLE_ANIM_OUTLINE = "firing_single_outline"; + private static final String PREP_ANIM_OUTLINE = "prep_outline"; + private static final String HIT_ANIM_OUTLINE = "hit_outline"; + private static final String DEATH_ANIM_OUTLINE = "death_outline"; + // Sound effects constants private static final String FIRE_AUTO_SFX = "sounds/engineers/firing_auto.mp3"; private static final String FIRE_SINGLE_SFX = "sounds/engineers/firing_single.mp3"; @@ -41,6 +54,9 @@ public class HumanAnimationController extends Component { private final Sound fireSingleSound = ServiceLocator.getResourceService().getAsset( FIRE_SINGLE_SFX, Sound.class); + private boolean clicked = false; + + /** * Instantiates a HumanAnimationController and adds all the event listeners for the * Human entity - Just engineers at this stage. @@ -65,21 +81,33 @@ public void create() { * Callback that starts the idle animation facing left */ void animateIdleLeft() { - animator.startAnimation(IDLEL_ANIM); + if (clicked) { + animator.startAnimation(IDLEL_ANIM_OUTLINE); + } else { + animator.startAnimation(IDLEL_ANIM); + } } /** * Callback that starts the idle animation facing right */ void animateIdleRight() { - animator.startAnimation(IDLER_ANIM); + if (clicked) { + animator.startAnimation(IDLER_ANIM_OUTLINE); + } else { + animator.startAnimation(IDLER_ANIM); + } } /** * Callback that starts the walk animation for left movement */ void animateLeftWalk() { - animator.startAnimation(WALKL_ANIM); + if (clicked) { + animator.startAnimation(WALKL_ANIM_OUTLINE); + } else { + animator.startAnimation(WALKL_ANIM); + } // runSound.play(); } @@ -87,7 +115,11 @@ void animateLeftWalk() { * Callback that starts the walk animation for right movement */ void animateRightWalk() { - animator.startAnimation(WALKR_ANIM); + if (clicked) { + animator.startAnimation(WALKR_ANIM_OUTLINE); + } else { + animator.startAnimation(WALKR_ANIM); + } } /** @@ -95,14 +127,22 @@ void animateRightWalk() { * unused, but intended to be incorporated as engineer functionality expands */ void animatePrepWalk() { - animator.startAnimation(WALK_PREP_ANIM); + if (clicked) { + animator.startAnimation(WALK_PREP_ANIM_OUTLINE); + } else { + animator.startAnimation(WALK_PREP_ANIM); + } } /** * Callback that starts the shoot animation in single fire mode, and plays the single fire sound */ void animateSingleFiring() { - animator.startAnimation(FIRE_SINGLE_ANIM); + if (clicked) { + animator.startAnimation(FIRE_SINGLE_ANIM_OUTLINE); + } else { + animator.startAnimation(FIRE_SINGLE_ANIM); + } fireSingleSound.play(); } @@ -111,7 +151,11 @@ void animateSingleFiring() { * Currently unused, but intended to be incorporated as engineer functionality expands. */ void animateFiringAuto() { - animator.startAnimation(FIRE_AUTO_ANIM); + if (clicked) { + animator.startAnimation(FIRE_AUTO_ANIM_OUTLINE); + } else { + animator.startAnimation(FIRE_AUTO_ANIM); + } fireAutoSound.play(); } @@ -119,20 +163,61 @@ void animateFiringAuto() { * Callback that starts the 'prep' animation, i.e., raising weapon in preparation for firing */ void animatePrep() { - animator.startAnimation(PREP); + if (clicked) { + animator.startAnimation(PREP_ANIM_OUTLINE); + } else { + animator.startAnimation(PREP); + } } /** * Callback that starts the 'hit' animation when engineer is damaged */ void animateHit() { - animator.startAnimation(HIT_ANIM); + if (clicked) { + animator.startAnimation(HIT_ANIM_OUTLINE); + } else { + animator.startAnimation(HIT_ANIM); + } } /** * Callback that starts the 'death' animation when the engineer entity's health reaches zero. */ void animateDeath() { - animator.startAnimation(DEATH_ANIM); + if (clicked) { + animator.startAnimation(DEATH_ANIM_OUTLINE); + } else { + animator.startAnimation(DEATH_ANIM); + } + } + + /** + * @return true if the entity has been clicked/selected, false otherwise + */ + public boolean isClicked() { + return clicked; + } + + /** + * Sets the clicked state of the entity + * @param clicked true if the entity has been clicked/selected, false otherwise + */ + public void setClicked(boolean clicked) { + this.clicked = clicked; + } + + /** + * Deseelects the engineer entity by starting the appropriate animation without an outline + * and removes the engineer menu from the stage + * @param currentAnimation the current animation of the entity + */ + public void deselectEngineer(String currentAnimation) { + AnimationRenderComponent animator = this.entity.getComponent(AnimationRenderComponent.class); + EngineerMenuComponent menu = this.entity.getComponent(EngineerMenuComponent.class); + + animator.startAnimation(currentAnimation.substring(0, currentAnimation.lastIndexOf('_'))); + menu.removeMenu(); + setClicked(false); } } \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/components/tasks/human/HumanMovementTask.java b/source/core/src/main/com/csse3200/game/components/tasks/human/HumanMovementTask.java index fa589460f..933ffacc1 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/human/HumanMovementTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/human/HumanMovementTask.java @@ -2,6 +2,7 @@ import com.badlogic.gdx.math.Vector2; import com.csse3200.game.ai.tasks.DefaultTask; +import com.csse3200.game.ai.tasks.PriorityTask; import com.csse3200.game.physics.components.PhysicsMovementComponent; import com.csse3200.game.services.GameTime; import com.csse3200.game.services.ServiceLocator; @@ -10,7 +11,7 @@ * Move a human entity to a given position, finishing when you get close enough. Requires an entity with a * PhysicsMovementComponent. */ -public class HumanMovementTask extends DefaultTask { +public class HumanMovementTask extends DefaultTask implements PriorityTask { private final GameTime gameTime; private Vector2 target; private float stopDistance = 0.01f; @@ -18,6 +19,8 @@ public class HumanMovementTask extends DefaultTask { private Vector2 lastPos; private PhysicsMovementComponent movementComponent; + private int priority = 1000; // default priority + public HumanMovementTask(Vector2 target) { this.target = target; this.gameTime = ServiceLocator.getTimeSource(); @@ -85,4 +88,9 @@ private void checkIfStuck() { private boolean didMove() { return owner.getEntity().getPosition().dst2(lastPos) > 0.001f; } + + @Override + public int getPriority() { + return priority; + } } diff --git a/source/core/src/main/com/csse3200/game/components/tasks/human/HumanWanderTask.java b/source/core/src/main/com/csse3200/game/components/tasks/human/HumanWanderTask.java index 528348b8a..499ce2937 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/human/HumanWanderTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/human/HumanWanderTask.java @@ -31,6 +31,8 @@ public class HumanWanderTask extends DefaultTask implements PriorityTask { private Task currentTask; private boolean isDead = false; + private boolean isSelected = false; + private boolean hasDied = false; /** @@ -105,35 +107,35 @@ public void update() { // otherwise doing engineer things since engineer is alive else if (!isDead){ doEngineerThings(); - currentTask.update(); } } private void doEngineerThings() { - if (currentTask.getStatus() != Status.ACTIVE) { - - // if the engineer is in move state and update has been called, engineer has arrived at destination - if (currentTask == movementTask) { - startWaiting(); - owner.getEntity().getEvents().trigger(IDLE_EVENT); - - } else if (combatTask.isTargetVisible()) { - float engY = owner.getEntity().getCenterPosition().y; - float targetY = combatTask.fetchTarget().y; - // if the engineer is positioned within the tolerance range of the mob's y position, enter combat state - if (engY < targetY + TOLERANCE && - engY > targetY - TOLERANCE) { - startCombat(); - - // move into position for targeting mob - } else { - Vector2 newPos = new Vector2(owner.getEntity().getPosition().x, combatTask.fetchTarget().y); - startMoving(newPos); - } + if (currentTask.getStatus() == Status.ACTIVE) { + return; + } + + // if the engineer is in move state and update has been called, engineer has arrived at destination + if (currentTask == movementTask) { + startWaiting(); + owner.getEntity().getEvents().trigger(IDLE_EVENT); + } else if (combatTask.isTargetVisible()) { + float engY = owner.getEntity().getCenterPosition().y; + float targetY = combatTask.fetchTarget().y; + // if the engineer is positioned within the tolerance range of the mob's y position, enter combat state + if (engY < targetY + TOLERANCE && + engY > targetY - TOLERANCE) { + startCombat(); + + // move into position for targeting mob + } else if (!this.isSelected()) { + Vector2 newPos = new Vector2(owner.getEntity().getPosition().x, combatTask.fetchTarget().y); + startMoving(newPos); } } } + /** * Handle the dying phase of the entity. Triggers an event to play the appropriate media, * sets HitBox and Collider components to ignore contact (stops the body being pushed around) @@ -150,7 +152,7 @@ private void startDying() { /** * Starts the wait task. */ - private void startWaiting() { + public void startWaiting() { swapTask(waitTask); } @@ -158,7 +160,7 @@ private void startWaiting() { * Starts the movement task, to a particular destination * @param destination the Vector2 position to which the entity needs to move */ - private void startMoving(Vector2 destination) { + public void startMoving(Vector2 destination) { movementTask.setTarget(destination); swapTask(movementTask); } @@ -166,7 +168,7 @@ private void startMoving(Vector2 destination) { /** * Starts the combat task. */ - private void startCombat() { + public void startCombat() { swapTask(combatTask); } @@ -181,4 +183,12 @@ private void swapTask(Task newTask) { currentTask = newTask; currentTask.start(); } + + private boolean isSelected() { + return isSelected; + } + + public void setSelected(boolean isSelected) { + this.isSelected = isSelected; + } } diff --git a/source/core/src/main/com/csse3200/game/components/tower/TowerUpgraderComponent.java b/source/core/src/main/com/csse3200/game/components/tower/TowerUpgraderComponent.java index f4e2a3aaf..e83210b48 100644 --- a/source/core/src/main/com/csse3200/game/components/tower/TowerUpgraderComponent.java +++ b/source/core/src/main/com/csse3200/game/components/tower/TowerUpgraderComponent.java @@ -62,7 +62,7 @@ void upgradeTowerMaxHealth(int increase) { /** * Restores the tower's health to its maximum health. */ - void repairTower() { + public void repairTower() { int maxHealth = getEntity().getComponent(CombatStatsComponent.class).getMaxHealth(); getEntity().getComponent(CombatStatsComponent.class).setHealth(maxHealth); } 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 7adb4fc8e..3511d598b 100644 --- a/source/core/src/main/com/csse3200/game/entities/EntityService.java +++ b/source/core/src/main/com/csse3200/game/entities/EntityService.java @@ -173,4 +173,17 @@ private boolean entityContainsPosition(Entity entity, float x, float y) { return (x >= entityX && x <= entityX + entityWidth && y >= entityY && y <= entityY + entityHeight); } + public Entity getEntityAtPositionLayer(float x, float y, short layer) { + for (int i = 0; i < entities.size; i++) { + Entity entity = entities.get(i); + if (entityContainsPosition(entity, x, y)) { + HitboxComponent hitBox = entity.getComponent(HitboxComponent.class); + if (hitBox != null && PhysicsLayer.contains(layer, hitBox.getLayer())) { + return entity; + } + } + } + return null; + } + } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java index 836b6b359..e9feaf2aa 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/EngineerFactory.java @@ -5,6 +5,7 @@ import com.csse3200.game.ai.tasks.AITaskComponent; import com.csse3200.game.components.CombatStatsComponent; import com.csse3200.game.components.TouchAttackComponent; +import com.csse3200.game.components.npc.EngineerMenuComponent; import com.csse3200.game.components.player.HumanAnimationController; import com.csse3200.game.components.tasks.human.HumanWanderTask; import com.csse3200.game.entities.Entity; @@ -57,6 +58,7 @@ public static Entity createEngineer() { .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) .addComponent(animator) .addComponent(new HumanAnimationController()) + .addComponent(new EngineerMenuComponent()) .addComponent(aiComponent); engineer.getComponent(AITaskComponent.class).addTask(new HumanWanderTask(COMBAT_TASK_PRIORITY, ENGINEER_RANGE)); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java index d77ff1d1d..95dd20596 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/PlayerFactory.java @@ -50,8 +50,8 @@ public static Entity createPlayer() { .addComponent(new CombatStatsComponent(1000, 5000)) .addComponent(new InventoryComponent(stats.gold)) .addComponent(inputComponent) - .addComponent(aiComponent) - .addComponent(new PlayerStatsDisplay()); + .addComponent(aiComponent); + //.addComponent(new PlayerStatsDisplay()); PhysicsUtils.setScaledCollider(player, 0.6f, 0.3f); player.getComponent(ColliderComponent.class).setDensity(1.5f); 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 e7e2e6512..0bf5ace38 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 @@ -38,7 +38,8 @@ public class TowerFactory { private static final int TNT_TOWER_MAX_RANGE = 6; private static final int TNT_TOWER_RANGE = 6; private static final int TNT_KNOCK_BACK_FORCE = 10; - private static final String WALL_IMAGE = "images/towers/WallTower.png"; + private static final String WALL_IMAGE = "images/towers/wall_tower.png"; + private static final String RESOURCE_TOWER = "images/towers/mine_tower.png"; private static final String TURRET_ATLAS = "images/towers/turret01.atlas"; private static final String FIRE_TOWER_ATLAS = "images/towers/fire_tower_atlas.atlas"; private static final String STUN_TOWER_ATLAS = "images/towers/stun_tower.atlas"; diff --git a/source/core/src/main/com/csse3200/game/input/EngineerInputComponent.java b/source/core/src/main/com/csse3200/game/input/EngineerInputComponent.java index c92ceb4bc..4b2388878 100644 --- a/source/core/src/main/com/csse3200/game/input/EngineerInputComponent.java +++ b/source/core/src/main/com/csse3200/game/input/EngineerInputComponent.java @@ -1,12 +1,21 @@ package com.csse3200.game.input; import com.badlogic.gdx.Game; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; +import com.csse3200.game.ai.tasks.AITaskComponent; +import com.csse3200.game.ai.tasks.PriorityTask; +import com.csse3200.game.ai.tasks.Task; +import com.csse3200.game.components.npc.EngineerMenuComponent; import com.csse3200.game.components.player.HumanAnimationController; +import com.csse3200.game.components.tasks.human.HumanMovementTask; +import com.csse3200.game.components.tasks.human.HumanWanderTask; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.EntityService; import com.csse3200.game.entities.factories.EngineerFactory; +import com.csse3200.game.physics.PhysicsLayer; import com.csse3200.game.rendering.AnimationRenderComponent; import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; @@ -19,6 +28,9 @@ public class EngineerInputComponent extends InputComponent { private Camera camera; private EntityService entityService; + private Entity selectedEngineer = null; + private boolean moveClicked = false; + public EngineerInputComponent(Game game, Camera camera) { this.game = game; this.camera = camera; @@ -29,26 +41,91 @@ public boolean touchDown(int screenX, int screenY, int pointer, int button) { Vector3 worldCoordinates = new Vector3((float) screenX , (float) screenY, 0); camera.unproject(worldCoordinates); Vector2 cursorPosition = new Vector2(worldCoordinates.x, worldCoordinates.y); - Entity engineer = entityService.getEntityAtPosition(cursorPosition.x, cursorPosition.y); + camera.project(worldCoordinates); + Entity engineer = entityService.getEntityAtPositionLayer(cursorPosition.x, cursorPosition.y, PhysicsLayer.ENGINEER); //logger.info("Clicked entity: " + engineer); // Case when engineer is not clicked if (engineer == null || engineer.getComponent(HumanAnimationController.class) == null) { - return false; + if (selectedEngineer != null && moveClicked) { + moveEngineer(cursorPosition); + selectedEngineer = null; + moveClicked = false; + return true; + } else { + return false; + } } - // Case when engineer is clicked AnimationRenderComponent animator = engineer.getComponent(AnimationRenderComponent.class); String currentAnimation = animator.getCurrentAnimation(); + HumanAnimationController controller = engineer.getComponent(HumanAnimationController.class); + EngineerMenuComponent menu = engineer.getComponent(EngineerMenuComponent.class); - // outline image if it is not already outlined and vice versa - if (currentAnimation.contains("_outline")) { - animator.startAnimation(currentAnimation.substring(0, currentAnimation.lastIndexOf('_'))); + if (engineer.equals(selectedEngineer)) { + // Deselect the engineer by clicking on itself + this.getWanderTask().setSelected(false); + selectedEngineer = null; + moveClicked = false; + if (currentAnimation.contains("_outline")) { + controller.deselectEngineer(currentAnimation); + //logger.info("Engineer deselected"); + } } else { - animator.startAnimation(currentAnimation + "_outline"); + this.selectedEngineer = engineer; + this.getWanderTask().setSelected(true); + moveClicked = false; + logger.info("Engineer size: {}", engineer.getScale()); + + // outline image if it is not already outlined and vice versa + if (!currentAnimation.contains("_outline")) { + animator.startAnimation(currentAnimation + "_outline"); + menu.createMenu(cursorPosition.x, cursorPosition.y, camera); + controller.setClicked(true); + } } + return true; + } + @Override + public boolean keyDown(int keycode) { + if (selectedEngineer == null) { + return false; + } + + + if (Gdx.input.isKeyPressed(Input.Keys.P)) { + manualShoot(); + } return true; } + private void manualShoot() { + HumanWanderTask wander = this.getWanderTask(); + wander.startWaiting(); + wander.startCombat(); + } + + private HumanWanderTask getWanderTask() { + AITaskComponent movementTask = selectedEngineer.getComponent(AITaskComponent.class); + return movementTask.getTask(HumanWanderTask.class); + } + + private void moveEngineer(Vector2 cursorPosition) { + if (selectedEngineer == null) { + logger.info("Trying to move an engineer that is not selected"); + } + + HumanWanderTask wander = this.getWanderTask(); + wander.startWaiting(); + Vector2 enggpos = selectedEngineer.getPosition(); + Vector2 offset = new Vector2(cursorPosition.x > enggpos.x ? 0.17f : -0.6f , cursorPosition.y > enggpos.y ? 0.0f : -0.5f); + Vector2 dest = cursorPosition.add(offset); + wander.startMoving(dest); + } + + public void setMoveClicked(boolean moveClicked) { + this.moveClicked = moveClicked; + } + } diff --git a/source/core/src/main/com/csse3200/game/input/InputService.java b/source/core/src/main/com/csse3200/game/input/InputService.java index 6c2e8d2ae..bb9a8dbe0 100644 --- a/source/core/src/main/com/csse3200/game/input/InputService.java +++ b/source/core/src/main/com/csse3200/game/input/InputService.java @@ -27,11 +27,13 @@ public class InputService implements InputProcessor, GestureDetector.GestureList private final List inputHandlers = new ArrayList<>(); private final InputFactory inputFactory; + private EngineerInputComponent engineerInputComponent; public InputService() { this(InputFactory.createFromInputType(inputType)); } + public InputService(InputFactory inputFactory) { this.inputFactory = inputFactory; Gdx.input.setInputProcessor(this); @@ -46,6 +48,10 @@ public InputFactory getInputFactory() { return inputFactory; } + public EngineerInputComponent getEngineerInput() { + return engineerInputComponent; + } + /** * Register an input handler based on its priority and reorder inputHandlers. * @@ -53,6 +59,9 @@ public InputFactory getInputFactory() { */ public void register(InputComponent inputHandler) { logger.debug("Registering input handler {}", inputHandler); + if (inputHandler instanceof EngineerInputComponent) { + engineerInputComponent = (EngineerInputComponent) inputHandler; + } inputHandlers.add(inputHandler); inputHandlers.sort(comparator); } diff --git a/source/core/src/main/com/csse3200/game/screens/TowerType.java b/source/core/src/main/com/csse3200/game/screens/TowerType.java index 1dd3eadf5..a6f79dbdf 100644 --- a/source/core/src/main/com/csse3200/game/screens/TowerType.java +++ b/source/core/src/main/com/csse3200/game/screens/TowerType.java @@ -1,35 +1,48 @@ package com.csse3200.game.screens; public enum TowerType { - WEAPON("images/towers/turret_deployed.png", "Weapon Tower", - "The Weapon Tower is a simple and basic turret that fires rapid shots at enemies dealing damage over time."), - TNT("images/towers/turret_deployed.png", "TNT Tower", - "The TNT Tower launches explosive projectiles, dealing area damage to groups of enemies."), - DROID("images/towers/turret_deployed.png", "Droid Tower", - "Droid Towers deploy robotic helpers that assist in combat and provide support to nearby turrets."), - WALL("images/towers/turret_deployed.png", "Wall Tower", - "The Wall Tower creates barriers to block enemy paths, slowing down their progress."), - FIRE("images/towers/turret_deployed.png", "Fire Tower", - "The Fire Tower emits flames, causing damage over time to enemies caught in its fiery radius."), - STUN("images/towers/turret_deployed.png", "Stun Tower", - "The Stun Tower releases electric shocks that temporarily immobilize and damage enemies."), - INCOME("images/towers/turret_deployed.png", "Income Tower", - "The Income Tower generates additional in-game currency over time."); - - private final String imagePath; + WEAPON("Weapon Tower", "The Weapon Tower is a simple and basic turret that fires rapid shots at enemies dealing damage over time.", + 0, "0", "images/turret-select/Weapon-Tower-Default.png", "images/turret-select/Weapon-Tower-Clicked.png"), + TNT("TNT Tower", "The TNT Tower launches explosive projectiles, dealing area damage to groups of enemies.", + 1, "0", "images/turret-select/tnt-tower-default.png", "images/turret-select/tnt-tower-clicked.png"), + DROID("Droid Tower", "Droid Towers deploy robotic helpers that assist in combat and provide support to nearby turrets.", + 2, "0", "images/turret-select/droid-tower-default.png", "images/turret-select/droid-tower-clicked.png"), + WALL("Wall Tower", "The Wall Tower creates barriers to block enemy paths, slowing down their progress.", + 3, "100", "images/turret-select/wall-tower-default.png", "images/turret-select/wall-tower-clicked.png"), + FIRE("Fire Tower", "The Fire Tower emits flames, causing damage over time to enemies caught in its fiery radius.", + 4, "0", "images/turret-select/fire-tower-default.png", "images/turret-select/fire-tower-clicked.png"), + STUN("Stun Tower", "The Stun Tower releases electric shocks that temporarily immobilize and damage enemies.", + 5, "1000", "images/turret-select/stun-tower-default.png", "images/turret-select/stun-tower-clicked.png"), + INCOME("Income Tower", "The Income Tower generates additional in-game currency over time.", + 5, "0", "images/turret-select/mine-tower-default.png", "images/turret-select/mine-tower-clicked.png"); + private final String towerName; private final String description; + private final int id; + private final String cost; + private final String defaultImage; + private final String clickedImage; + - TowerType(String imagePath, String towerName, String description) { - this.imagePath = imagePath; + TowerType(String towerName, String description, int id, String cost, String defaultImage, String clickedImage) { this.towerName = towerName; this.description = description; + this.id = id; + this.cost = cost; + this.defaultImage = defaultImage; + this.clickedImage = clickedImage; } - public String getImagePath() { return imagePath; } + public int getID() { return id; } public String getTowerName() { return towerName; } public String getDescription() { return description; } + public String getPrice() { return cost; } + + public String getDefaultImage() {return defaultImage;} + + public String getClickedImage() {return clickedImage;} + } 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 d120d8854..a679dd30c 100644 --- a/source/core/src/main/com/csse3200/game/screens/TurretSelectionScreen.java +++ b/source/core/src/main/com/csse3200/game/screens/TurretSelectionScreen.java @@ -2,22 +2,33 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Label; 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.ClickListener; +import com.badlogic.gdx.scenes.scene2d.utils.Drawable; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.csse3200.game.GdxGame; import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.csse3200.game.services.ResourceService; +import com.csse3200.game.services.ServiceLocator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.Text; import java.util.*; @@ -26,18 +37,23 @@ public class TurretSelectionScreen extends ScreenAdapter { private static final int MAX_SELECTED_TURRETS = 5; private Stage stage; + private Label descText; private List turretList; private TextButton confirmButton; + private String turretDescriptionText; private GdxGame game; private SpriteBatch batch; + private String turretDescription; + private String turretName; + TextButton turretDescriptionLabel; private Sprite introSprite; private Label message; - private Label turretsPicked; private Table table; + private TextButton descriptionLabel; private static final String TEXTURE = "planets/background.png"; private Set selectedTurrets = new HashSet<>(); @@ -60,12 +76,15 @@ public TurretSelectionScreen(GdxGame game) { turretList.addAll(Arrays.asList(TowerType.values())); // Restrictions can be added to the arrays i.e. map == "Forest" && level == 1 using for loop - Skin skin = new Skin(Gdx.files.internal("flat-earth/skin/flat-earth-ui.json")); message = new Label("Select your turrets", skin); - turretsPicked = new Label("Turrets picked: ", skin); - confirmButton = new TextButton("Continue", skin); + confirmButton = createButton("images/turret-select/imageedit_4_5616741474.png", + "images/ui/Sprites/UI_Glass_Button_Large_Press_01a1.png", "Continue", "", ""); + Drawable pressDrawable = new TextureRegionDrawable(new TextureRegion( + new Texture("images/ui/Sprites/UI_Glass_Button_Large_Press_01a1.png"))); + confirmButton.getStyle().down = pressDrawable; + confirmButton.pad(0,0,6,0); confirmButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { @@ -73,9 +92,20 @@ public void clicked(InputEvent event, float x, float y) { } }); + turretDescriptionLabel = createButton("images/turret-select/imageedit_28_4047785594.png", + "images/turret-select/imageedit_28_4047785594.png", "", "", turretDescriptionText); + + BitmapFont font = new BitmapFont(); + Label.LabelStyle labelStyle = new Label.LabelStyle(); + labelStyle.font = font; // Set your desired BitmapFont + descText = new Label(turretDescriptionText, labelStyle); + descText.setWrap(true); + descText.setWidth(190f); + + turretName = ""; + // Centered the message and turrets label table.add(message).center().colspan(4).row(); - table.add(turretsPicked).center().colspan(4).row(); int towersPerRow = 4; // Set the number of towers to display per row int numRows = (int) Math.ceil((double)turretList.size() / towersPerRow); // Calculate the number of rows @@ -92,23 +122,19 @@ public void clicked(InputEvent event, float x, float y) { Table turretTable = new Table(); turretTable.center(); // Center the contents of the nested table - // Load the turret image - Texture turretTexture = new Texture(Gdx.files.internal(turret.getImagePath())); - Image turretImage = new Image(turretTexture); + descriptionLabel = createButton("images/turret-select/imageedit_15_5627113584.png", + "images/turret-select/imageedit_15_5627113584.png", "Description: ", turretName, ""); - // Add the image to the nested table - turretTable.add(turretImage).pad(10).row(); + //turretDescriptionText = createButton("images/turret-select/imageedit_20_9050213399.png", + // "images/turret-select/imageedit_20_9050213399.png", ) - // Create a label for the turret description - Label turretDescriptionLabel = new Label(turret.getDescription(), skin); - turretDescriptionLabel.setWrap(true); // Wrap text if it's too long - // Add the description label to the nested table - turretTable.add(turretDescriptionLabel).center().width(200).pad(10).row(); // Adjust width if needed + TextButton button = createButton(turret.getDefaultImage(), + turret.getClickedImage(), turret.getPrice(), turret.getTowerName(), turret.getDescription()); + + button.pad(103, 15, 0, 0); + button.addListener(new ClickListener() { - // Create a TextButton for the turret name - TextButton turretButton = new TextButton(turret.getTowerName(), skin); - turretButton.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { logger.info(String.valueOf(selectedTurrets.size())); @@ -122,20 +148,17 @@ public void clicked(InputEvent event, float x, float y) { selectedTurrets.remove(turret); // You can also change the button appearance to indicate unselection logger.info(selectedTurrets.toString()); - turretsPicked.setText("Turrets picked: " + selectedTurrets.toString()); } else if (selectedTurrets.size() == MAX_SELECTED_TURRETS) { // Turret is not selected, but the max number of turrets has been reached message.setText("You can only select up to 5 turrets."); } else if (selectedTurrets.size() < MAX_SELECTED_TURRETS) { // Turret is not selected, select it selectedTurrets.add(turret); - turretsPicked.setText("Turrets picked: " + selectedTurrets.toString()); logger.info(selectedTurrets.toString()); } else { // Turret is not selected, select it selectedTurrets.add(turret); - turretsPicked.setText("Turrets picked: " + selectedTurrets.toString()); //logger.info(selectedTurrets.toString()); // You can change the button appearance to indicate selection @@ -143,8 +166,8 @@ public void clicked(InputEvent event, float x, float y) { } }); - // Add the turret name button to the nested table - turretTable.add(turretButton).center(); + // Add the image to the nested table + turretTable.add(button).pad(10).row(); // Add the nested table to the main table table.add(turretTable).pad(10).center(); @@ -161,6 +184,21 @@ public void clicked(InputEvent event, float x, float y) { // Centered the "continue" button table.add(confirmButton).center().colspan(4).padBottom(20).row(); + descriptionLabel.setPosition(Gdx.graphics.getWidth() - descriptionLabel.getWidth(), Gdx.graphics.getHeight() - descriptionLabel.getHeight()); + float turretDescriptionLabelX = Gdx.graphics.getWidth() - turretDescriptionLabel.getWidth() - 11; + float turretDescriptionLabelY = Gdx.graphics.getHeight() - descriptionLabel.getHeight() - turretDescriptionLabel.getHeight() - 7; // Adjusted vertical position + +// Set the position for turretDescriptionLabel + turretDescriptionLabel.setPosition(turretDescriptionLabelX, turretDescriptionLabelY); + descText.setPosition(turretDescriptionLabelX + 18, turretDescriptionLabelY + 70); + +// Add the actors to the stage + stage.addActor(turretDescriptionLabel); + stage.addActor(descriptionLabel); + stage.addActor(descText); + + + // Center the table within the stage table.center(); stage.addActor(table); @@ -172,16 +210,84 @@ public void clicked(InputEvent event, float x, float y) { public void render(float delta) { Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + batch.begin(); introSprite.draw(batch); batch.end(); - stage.draw(); + + stage.act(); // Update the stage + stage.draw(); // Draw the stage } public List getTurretList() { return turretList; } + private TextButton createButton(String defaultImageFilePath, String alternateImageFilePath, String cost, + String towerName, String turretDesc) { + Drawable defaultDrawable = new TextureRegionDrawable(new TextureRegion(new Texture(defaultImageFilePath))); + Drawable alternateDrawable = new TextureRegionDrawable(new TextureRegion(new Texture(alternateImageFilePath))); + + TextButton.TextButtonStyle buttonStyle = new TextButton.TextButtonStyle(); + buttonStyle.font = new BitmapFont(); // Set your desired font + buttonStyle.up = defaultDrawable; // Default state + + // Create button + TextButton tb = new TextButton(cost, buttonStyle); + + final boolean[] isDefaultImage = {true}; // Keep track of the image state + + tb.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + super.clicked(event, x, y); + + // Toggle the image + if (isDefaultImage[0]) { + tb.getStyle().up = alternateDrawable; + } else { + tb.getStyle().up = defaultDrawable; + } + + // Update the image state + isDefaultImage[0] = !isDefaultImage[0]; + } + }); + + // Add a hover listener to update turretName when hovered over + tb.addListener(new InputListener() { + @Override + public void enter(InputEvent event, float x, float y, int pointer, com.badlogic.gdx.scenes.scene2d.Actor fromActor) { + super.enter(event, x, y, pointer, fromActor); + turretDescription = towerName; // Update turretDescription when hovering over the button + turretDescriptionText = turretDesc; + updateDescriptionLabel(); + updateDescriptionText(); + } + + @Override + public void exit(InputEvent event, float x, float y, int pointer, com.badlogic.gdx.scenes.scene2d.Actor toActor) { + super.exit(event, x, y, pointer, toActor); + turretDescription = ""; // Reset turretDescription when exiting the button + turretDescriptionText = ""; + updateDescriptionLabel(); + updateDescriptionText(); + } + }); + + tb.setDisabled(true); + + return tb; + } + + private void updateDescriptionLabel() { + descriptionLabel.setText("Description: " + turretDescription); + } + + private void updateDescriptionText() { + descText.setText(turretDescriptionText); + } + @Override public void dispose() { stage.dispose();