Skip to content

Commit

Permalink
Created an event for shooting projectiles in DroidAnimationController…
Browse files Browse the repository at this point in the history
… rather than calling it manually in the combat task
  • Loading branch information
Mohamad11Dab committed Sep 10, 2023
1 parent 49a23d4 commit 1b26c61
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ public class TNTTowerCombatTask extends DefaultTask implements PriorityTask {
private static final int INTERVAL = 1; // time interval to scan for enemies in seconds
private static final short TARGET = PhysicsLayer.NPC; // The type of targets that the tower will detect
// the following four constants are the event names that will be triggered in the state machine
private static final String DIG = "digStart";
private static final String EXPLOSION = "explodeStart";
private static final String DEFAULT = "defaultStart";
private static final String DAMAGE = "TNTDamageStart";
public static final String DIG = "digStart";
public static final String EXPLOSION = "explodeStart";
public static final String DEFAULT = "defaultStart";
public static final String DAMAGE = "TNTDamageStart";


// class attributes
Expand All @@ -37,9 +37,9 @@ public class TNTTowerCombatTask extends DefaultTask implements PriorityTask {
private final GameTime timeSource;
private long endTime;
private final RaycastHit hit = new RaycastHit();
private boolean readToDelete = false;
public boolean readToDelete = false;

private enum STATE {
public enum STATE {
IDLE, EXPLODE, REMOVE
}
private STATE towerState = STATE.IDLE;
Expand Down Expand Up @@ -135,6 +135,15 @@ public int getPriority() {
}
}

/**
* Returns the current state of the tower.
*
* @return the current state of the tower.
*/
public STATE getState() {
return this.towerState;
}

/**
* Fetches the active priority of the Task if a target is visible.
* @return (int) active priority if a target is visible, -1 otherwise
Expand All @@ -157,7 +166,7 @@ private int getInactivePriority() {
* Uses a raycast to determine whether there are any targets in detection range
* @return true if a target is visible, false otherwise
*/
private boolean isTargetVisible() {
public boolean isTargetVisible() {
// If there is an obstacle in the path to the max range point, mobs visible.
return physics.raycast(towerPosition, maxRangePosition, TARGET, hit);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package com.csse3200.game.components.tower;

import com.badlogic.gdx.math.Vector2;
import com.csse3200.game.components.Component;
import com.csse3200.game.components.ProjectileEffects;
import com.csse3200.game.entities.Entity;
import com.csse3200.game.entities.factories.ProjectileFactory;
import com.csse3200.game.physics.PhysicsLayer;
import com.csse3200.game.rendering.AnimationRenderComponent;
import com.csse3200.game.services.ServiceLocator;

/**
* This class listens to events relevant to DroidTower entity's state and plays the animation when one
Expand All @@ -25,6 +31,8 @@ public void create() {
entity.getEvents().addListener("attackUpStart",this::animateAttackUp);
entity.getEvents().addListener("attackDownStart",this::animateAttackDown);
entity.getEvents().addListener("deathStart",this::animateDeath);
entity.getEvents().addListener("ShootUp",this::shootUp);
entity.getEvents().addListener("ShootDown",this::shootDown);

}

Expand Down Expand Up @@ -83,4 +91,32 @@ void animateDeath() {
*/
void animateDefault() { animator.startAnimation("idle");}


//TODO: For the time being, these items will be positioned here. Next, we should create a component that enables an entity to fire projectiles.

/**
* Fires a projectile upwards from the entity's current position.
*/
void shootUp() {
Entity Projectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(100,
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.5));
ServiceLocator.getEntityService().register(Projectile);
}

/**
* Fires a projectile downwards from the entity's current position.
*/
void shootDown() {
Entity Projectile = ProjectileFactory.createEffectProjectile(PhysicsLayer.NPC, new Vector2(100,
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));
ServiceLocator.getEntityService().register(Projectile);

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.csse3200.game.components.tasks;

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import com.badlogic.gdx.math.Vector2;
import com.csse3200.game.ai.tasks.AITaskComponent;
import com.csse3200.game.entities.Entity;
import com.csse3200.game.entities.factories.TowerFactory;
import com.csse3200.game.events.EventHandler;
import com.csse3200.game.events.listeners.EventListener0;
import com.csse3200.game.physics.PhysicsEngine;
import com.csse3200.game.physics.PhysicsLayer;
import com.csse3200.game.physics.PhysicsService;
import com.csse3200.game.physics.components.ColliderComponent;
import com.csse3200.game.physics.components.HitboxComponent;
import com.csse3200.game.physics.components.PhysicsComponent;
import com.csse3200.game.physics.raycast.RaycastHit;
import com.csse3200.game.services.GameTime;
import com.csse3200.game.services.ServiceLocator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class TNTTowerCombatTaskTest {



Entity entity;

TNTTowerCombatTask tntTowerCombatTask;

@BeforeEach
void setUp() {
GameTime gameTime = mock(GameTime.class);

ServiceLocator.registerTimeSource(gameTime);
ServiceLocator.registerPhysicsService(new PhysicsService());

tntTowerCombatTask = new TNTTowerCombatTask(2,4);
}

@Test
public void testStartTriggersDefaultEvent() {

Entity entity = createTNT();

EventListener0 defaultStartListener = mock(EventListener0.class);
entity.getEvents().addListener(TNTTowerCombatTask.DEFAULT, defaultStartListener);

tntTowerCombatTask.start();

verify(defaultStartListener).handle();
}

@Test
public void testUpdateTowerStateIdleMode() {

Entity entity = createTNT();
entity.setPosition(10,10);

Entity Target = createNPC();
Target.setPosition(12,10);

EventListener0 defaultStartListener = mock(EventListener0.class);
// still in idle
assertEquals(TNTTowerCombatTask.STATE.IDLE, tntTowerCombatTask.getState());
entity.getEvents().addListener(TNTTowerCombatTask.DIG, defaultStartListener);

ServiceLocator.getPhysicsService().getPhysics().update();
entity.update();
assertTrue(tntTowerCombatTask.isTargetVisible());

tntTowerCombatTask.updateTowerState();

verify(defaultStartListener).handle();
// ready to explode
assertEquals(TNTTowerCombatTask.STATE.EXPLODE, tntTowerCombatTask.getState());
}

@Test
public void testGetPriority() {
// Arrange
tntTowerCombatTask.readToDelete = false;

// Act
int priority = tntTowerCombatTask.getPriority();

// Assert

assertEquals(2, priority);
}

Entity createTNT() {
AITaskComponent aiTaskComponent = new AITaskComponent().addTask(tntTowerCombatTask);
Entity entity = new Entity().addComponent(aiTaskComponent).
addComponent(new PhysicsComponent())
.addComponent(new HitboxComponent())
.addComponent(new ColliderComponent());
entity.create();
return entity;

}

Entity createNPC() {
Entity Target = new Entity().addComponent(new HitboxComponent().setLayer(PhysicsLayer.NPC))
.addComponent(new ColliderComponent())
.addComponent(new PhysicsComponent());

Target.create();
return Target;
}


}

0 comments on commit 1b26c61

Please sign in to comment.