Skip to content

Commit

Permalink
Merge pull request #129 from UQcsse3200/Team-2--Engineers
Browse files Browse the repository at this point in the history
Team 2  engineers Sprint 2 - Scanner and Engineer Spawning
  • Loading branch information
The-AhmadAA authored Sep 10, 2023
2 parents fa8df71 + e9436c2 commit 0f09aab
Show file tree
Hide file tree
Showing 15 changed files with 599 additions and 125 deletions.
42 changes: 33 additions & 9 deletions source/core/src/main/com/csse3200/game/areas/ForestGameArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.csse3200.game.components.CombatStatsComponent;
import com.csse3200.game.components.ProjectileEffects;
import com.csse3200.game.areas.terrain.TerrainFactory;
import com.csse3200.game.areas.terrain.TerrainFactory.TerrainType;
import com.csse3200.game.components.player.PlayerStatsDisplay;
import com.csse3200.game.entities.Entity;
import com.csse3200.game.entities.factories.*;
import com.csse3200.game.physics.PhysicsLayer;
Expand All @@ -30,6 +32,8 @@
public class ForestGameArea extends GameArea {
private static final Logger logger = LoggerFactory.getLogger(ForestGameArea.class);

// Counts the number of humans left, if this reaches zero, game over.
private int endStateCounter = 2;
private static final int NUM_BUILDINGS = 4;

private static final int NUM_WALLS = 7;
Expand All @@ -40,10 +44,10 @@ public class ForestGameArea extends GameArea {

private static final int NUM_BOSS=4;


private Timer bossSpawnTimer;
private int bossSpawnInterval = 10000; // 1 minute in milliseconds


private static final int NUM_WEAPON_TOWERS = 3;

private static final GridPoint2 PLAYER_SPAWN = new GridPoint2(1, 4);
Expand Down Expand Up @@ -181,6 +185,8 @@ public void create() {
displayUI();
spawnTerrain();

// Set up infrastructure for end game tracking

player = spawnPlayer();
player.getEvents().addListener("spawnWave", this::spawnXenoGrunts);

Expand All @@ -201,9 +207,9 @@ public void create() {
spawnWeaponTower();
spawnTNTTower();
spawnDroidTower();
spawnEngineer();
spawnGapScanners();
spawnIncome();
bossKing1 = spawnBossKing1();
// bossKing1 = spawnBossKing1();
bossKing2 = spawnBossKing2();


Expand Down Expand Up @@ -304,7 +310,7 @@ private void spawnGhosts() {
private Entity spawnBossKing1() {
GridPoint2 minPos = new GridPoint2(0, 0);
GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2);
GridPoint2 randomPos
GridPoint2 randomPos
= new GridPoint2(0, 0);
Entity ghostKing = NPCFactory.createGhostKing(player);
spawnEntityAt(ghostKing, randomPos, true, true);
Expand Down Expand Up @@ -608,12 +614,30 @@ private void spawnIncome() {
spawnEntityAt(towerfactory, randomPos, true, true);
}
}

private void spawnEngineer() {

for (int i = 0; i < terrain.getMapBounds(0).x; i += 3) {
Entity engineer = EngineerFactory.createEngineer();
spawnEntityAt(engineer, new GridPoint2(1, i), true, true);
private void spawnGapScanners() {
for (int i = 0; i < terrain.getMapBounds(0).y; i++) {
Entity scanner = GapScannerFactory.createScanner();
spawnEntityAt(scanner, new GridPoint2(0, i), true, true);
}
}

// private void gameTrackerStart() {
// Entity endGameTracker = new Entity();
//
// endGameTracker
// .addComponent(new CombatStatsComponent(2, 0))
// .addComponent(new PlayerStatsDisplay());
//// .getEvents().addListener("engineerKilled" , this::decrementCounter);
// endGameTracker.create();
// }
//
// private void decrementCounter() {
// this.endStateCounter -= 1;
// logger.info("Engineer killed");
// if (endStateCounter <= 0) {
// // we've reached the end, game over
// this.dispose();
// }
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ public class HumanAnimationController extends Component {
private static final String FIRE_AUTO_SFX = "sounds/engineers/firing_auto.mp3";
private static final String FIRE_SINGLE_SFX = "sounds/engineers/firing_single.mp3";

AnimationRenderComponent animator;
Sound fireAutoSound = ServiceLocator.getResourceService().getAsset(
private AnimationRenderComponent animator;
private final Sound fireAutoSound = ServiceLocator.getResourceService().getAsset(
FIRE_AUTO_SFX, Sound.class);
Sound fireSingleSound = ServiceLocator.getResourceService().getAsset(
private final Sound fireSingleSound = ServiceLocator.getResourceService().getAsset(
FIRE_SINGLE_SFX, Sound.class);

/**
Expand All @@ -56,7 +56,7 @@ public void create() {
entity.getEvents().addListener(PREP, this::animatePrep);
entity.getEvents().addListener(WALK_PREP, this::animatePrepWalk);
entity.getEvents().addListener(FIRING_SINGLE, this::animateSingleFiring);
entity.getEvents().addListener(FIRING_AUTO, this::animateFiring);
entity.getEvents().addListener(FIRING_AUTO, this::animateFiringAuto);
entity.getEvents().addListener(HIT, this::animateHit);
entity.getEvents().addListener(DEATH, this::animateDeath);
}
Expand Down Expand Up @@ -110,7 +110,7 @@ void animateSingleFiring() {
* Callback that starts the shoot animation in auto mode and plays the auto fire sound.
* Currently unused, but intended to be incorporated as engineer functionality expands.
*/
void animateFiring() {
void animateFiringAuto() {
animator.startAnimation(FIRE_AUTO_ANIM);
fireAutoSound.play();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.slf4j.LoggerFactory;

/**
* Move to a given position, finishing when you get close enough. Requires an entity with a
* 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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,46 +13,59 @@
import org.slf4j.LoggerFactory;

/**
* Wander around by moving a random position within a range of the starting position. Wait a little
* bit between movements. Requires an entity with a PhysicsMovementComponent.
* HumanWanderTask is the entry point for the engineer entity's behaviour. Instantiates subtasks HumanWaitTask,
* HumanMovementTask and EngineerCombatTask, and manages transitions between the tasks. Engineer damage and death
* handled in this class.
*/
public class HumanWanderTask extends DefaultTask implements PriorityTask {
private static final Logger logger = LoggerFactory.getLogger(HumanWanderTask.class);
private static final int TOLERANCE = 1;
private static final float STOP_DISTANCE = 0.5f;
private static final int DEFAULT_PRIORITY = 1;
private static final String DEATH_EVENT = "deathStart";
private static final String IDLE_EVENT = "idleRight";

private float maxRange;
private Vector2 wanderRange;
private final float maxRange;
private final float waitTime;
private Vector2 startPos;
private HumanMovementTask movementTask;
private HumanWaitTask waitTask;

private EngineerCombatTask combatTask;
private Task currentTask;

private boolean isDead = false;

/**
* Constructor of HumanWanderTask
*
* @param waitTime How long in seconds to wait between wandering.
* @param maxRange Maximum detection and fighting range of the entity
*/
public HumanWanderTask(float waitTime, float maxRange) {
this.waitTime = waitTime;
this.maxRange = maxRange;
}

/**
* Fetches the priority of this task.
* @return current priority of this task. Priority for this task is a set value and does not change.
*/
@Override
public int getPriority() {
return 1; // Low priority task
return DEFAULT_PRIORITY; // Low priority task
}

/**
* Starts the HumanWanderTask instance and instantiates subtasks (HumanWaitTask, HumanWanderTask, EngineerCombatTask).
*
*/
@Override
public void start() {
super.start();
startPos = owner.getEntity().getPosition();
this.wanderRange = owner.getEntity().getCenterPosition();
this.startPos = owner.getEntity().getCenterPosition();
waitTask = new HumanWaitTask(waitTime);
waitTask.create(owner);

movementTask = new HumanMovementTask(this.wanderRange, 1f);
movementTask = new HumanMovementTask(this.startPos, STOP_DISTANCE);
movementTask.create(owner);
movementTask.start();

Expand All @@ -63,58 +76,92 @@ public void start() {
currentTask = movementTask;
}

/**
* Operates the main logic of the entity in this task. All calls to switch to particular states are determined during
* the update phase.
* The logical flow is:
* - Check if the entity has died since last update
* - Check if the entity has finished dying
* - If not dead
*/
@Override
public void update() {
// Check if engineer has died since last update
if (!isDead && owner.getEntity().getComponent(CombatStatsComponent.class).isDead()) {
owner.getEntity().getEvents().trigger("deathStart");
owner.getEntity().getComponent(ColliderComponent.class).setLayer(PhysicsLayer.NONE);
owner.getEntity().getComponent(HitboxComponent.class).setLayer(PhysicsLayer.NONE);
currentTask.stop();
// Add a time delay here to allow animation to play?
isDead = true;
startDying();
}
// Check if engineer has finished dying

// Check if engineer has finished dying animation
else if (isDead && owner.getEntity().getComponent(AnimationRenderComponent.class).isFinished()) {
owner.getEntity().setFlagForDelete(true);
// TODO: make the appropriate calls to decrement the human count.
}
// otherwise doing engineer things

// otherwise doing engineer things since engineer is alive
else if (!isDead) {
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("idleRight");
owner.getEntity().getEvents().trigger(IDLE_EVENT);

} else if (combatTask.isTargetVisible()) {
if (combatTask.fetchTarget().y < owner.getEntity().getCenterPosition().y + 2 &&
combatTask.fetchTarget().y > owner.getEntity().getCenterPosition().y - 2) {
startCombat();
} else {
startMoving(new Vector2(owner.getEntity().getCenterPosition().x, combatTask.fetchTarget().y));
}
// if the engineer is positioned within the tolerance range of the mob's y position, enter combat state
if (combatTask.fetchTarget().y < owner.getEntity().getCenterPosition().y + TOLERANCE &&
combatTask.fetchTarget().y > owner.getEntity().getCenterPosition().y - TOLERANCE) {
startCombat();

// move into position for targeting mob
} else {
startMoving(new Vector2(owner.getEntity().getCenterPosition().x, combatTask.fetchTarget().y));
}
}
}
currentTask.update();
}
}

/**
* 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)
* and stops the current task.
*/
private void startDying() {
owner.getEntity().getEvents().trigger(DEATH_EVENT);
owner.getEntity().getComponent(ColliderComponent.class).setLayer(PhysicsLayer.NONE);
owner.getEntity().getComponent(HitboxComponent.class).setLayer(PhysicsLayer.NONE);
currentTask.stop();
isDead = true;
}

/**
* Starts the wait task.
*/
private void startWaiting() {
logger.debug("Starting waiting");
swapTask(waitTask);
}

/**
* 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) {
logger.debug("Starting moving");
movementTask.setTarget(destination);
swapTask(movementTask);
}

/**
* Starts the combat task.
*/
private void startCombat() {
logger.debug("Starting Combat");
swapTask(combatTask);
}

/**
* Allows manual switching of tasks, from the current task to the supplied newTask.
* @param newTask the task being switched to.
*/
private void swapTask(Task newTask) {
if (currentTask != null) {
currentTask.stop();
Expand All @@ -123,9 +170,11 @@ private void swapTask(Task newTask) {
currentTask.start();
}

private Vector2 getDirection() {
// float y = startPos.y;
// return new Vector2(0, y);
return this.wanderRange;
/**
* Fetch the start position.
* @return a Vector2 start position
*/
public Vector2 getStartPos() {
return this.startPos;
}
}
Loading

0 comments on commit 0f09aab

Please sign in to comment.