Skip to content

Commit

Permalink
Merge pull request #136 from UQcsse3200/Team-4---General-Mobs
Browse files Browse the repository at this point in the history
Team 4   general mobs
  • Loading branch information
meganroxburgh authored Sep 11, 2023
2 parents 456a6d7 + 4a23ae5 commit 65faa31
Show file tree
Hide file tree
Showing 18 changed files with 382 additions and 97 deletions.
File renamed without changes
File renamed without changes.
22 changes: 12 additions & 10 deletions source/core/src/main/com/csse3200/game/areas/ForestGameArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ public class ForestGameArea extends GameArea {
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);

private static final GridPoint2 PLAYER_SPAWN = new GridPoint2(0, 0);
// Temporary spawn point for testing
private static final float WALL_WIDTH = 0.1f;

Expand Down Expand Up @@ -124,18 +122,16 @@ public class ForestGameArea extends GameArea {
"images/ghostKing.atlas",
"images/towers/turret.atlas",
"images/towers/turret01.atlas",
"images/mobs/xenoGrunt.atlas",
"images/towers/fire_tower_atlas.atlas",
"images/towers/stun_tower.atlas",
"images/mobs/xenoGruntRunning.atlas",
"images/mobs/robot.atlas",
"images/mobs/rangeBossRight.atlas",
"images/towers/DroidTower.atlas",
"images/xenoGrunt.atlas",
"images/mobs/robot.atlas",
"images/mobs/rangeBossRight.atlas",
"images/towers/TNTTower.atlas",
"images/projectiles/basic_projectile.atlas",

"images/projectiles/mobProjectile.atlas",
"images/projectiles/engineer_projectile.atlas",
"images/projectiles/mobKing_projectile.atlas",
Expand Down Expand Up @@ -379,14 +375,14 @@ private void spawnProjectile(Vector2 position, short targetLayer, int space, in


private void spawnXenoGrunts() {
GridPoint2 minPos = terrain.getMapBounds(0).sub(1, 5);
GridPoint2 maxPos = terrain.getMapBounds(0).sub(1, 25);
int[] pickedLanes = new Random().ints(1, 7)
.distinct().limit(5).toArray();
for (int i = 0; i < NUM_GRUNTS; i++) {
GridPoint2 randomPos = RandomUtils.random(maxPos, minPos);
GridPoint2 randomPos = new GridPoint2(19, pickedLanes[i]);
System.out.println(randomPos);
Entity xenoGrunt = NPCFactory.createXenoGrunt(player);
xenoGrunt.setScale(1.5f, 1.5f);
spawnEntityAt(xenoGrunt, randomPos, true, true);
spawnEntityAt(xenoGrunt, randomPos, true, false);
}
}

Expand Down Expand Up @@ -620,6 +616,12 @@ private void spawnGapScanners() {
Entity scanner = GapScannerFactory.createScanner();
spawnEntityAt(scanner, new GridPoint2(0, i), true, true);
}
// GridPoint2 minPos = new GridPoint2(0, 0);
// GridPoint2 maxPos = new GridPoint2(5, terrain.getMapBounds(0).sub(2, 2).y);
// GridPoint2 randomPos = RandomUtils.random(minPos, maxPos);
//
// Entity engineer = EngineerFactory.createEngineer();
// spawnEntityAt(engineer, randomPos, true, true);
}

// private void gameTrackerStart() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.csse3200.game.entities.Entity;
import com.csse3200.game.entities.Weapon;
import com.csse3200.game.physics.BodyUserData;
import com.csse3200.game.physics.PhysicsLayer;
import com.csse3200.game.physics.components.HitboxComponent;
Expand Down Expand Up @@ -64,7 +65,7 @@ public void create() {
hitboxComponent = entity.getComponent(HitboxComponent.class);
}

private void onCollisionStart(Fixture me, Fixture other) {
public void onCollisionStart(Fixture me, Fixture other) {
if (hitboxComponent.getFixture() != me) {
// Not triggered by hitbox, ignore
return;
Expand Down Expand Up @@ -105,9 +106,22 @@ public void setDisposeOnHit(boolean disposeOnHit) {
this.disposeOnHit = disposeOnHit;
}


public void setKnockBack(float knockback) {
this.knockbackForce = knockback;
}
public Weapon chooseWeapon(Fixture other) {
Entity target = ((BodyUserData) other.getBody().getUserData()).entity;
Weapon weapon = null;
if (target.getComponent(CombatStatsComponent.class) != null) {
weapon = combatStats.getWeapon(target);
}
return weapon;
}

private void onCollisionEnd(Fixture me, Fixture other) {
// Nothing to do on collision end
}
// private void onCollisionEnd(Fixture me, Fixture other) {
// // Nothing to do on collision end
// }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.csse3200.game.components.npc;

import com.badlogic.gdx.graphics.g2d.Animation;
import com.csse3200.game.components.Component;
import com.csse3200.game.rendering.AnimationRenderComponent;

import java.util.Objects;

/**
* This class listens to events relevant to a ghost entity's state and plays the animation when one
* of the events is triggered.
Expand All @@ -14,34 +17,48 @@ public class XenoAnimationController extends Component {
public void create() {
super.create();
animator = this.entity.getComponent(AnimationRenderComponent.class);
entity.getEvents().addListener("wanderStart", this::animateWander);
entity.getEvents().addListener("chaseStart", this::animateChase);
entity.getEvents().addListener("wanderStart", this::animateRun);
entity.getEvents().addListener("runHurt", this::animateHurt);
entity.getEvents().addListener("meleeStart", this::animateMelee1);
entity.getEvents().addListener("meleeStart", this::animateMelee2);
entity.getEvents().addListener("shootStart", this::animateShoot);
entity.getEvents().addListener("dieStart", this::animateDie);
entity.getEvents().addListener("stop", this::stopAnimation);
}

void animateWander() {
animator.startAnimation("xeno_run");
void animateRun() {
if (!Objects.equals(animator.getCurrentAnimation(), "xeno_shoot")) {
animator.stopAnimation();
animator.startAnimation("xeno_run");
}
}

void animateChase() {
animator.startAnimation("xeno_run");
void animateHurt() {
animator.stopAnimation();
animator.startAnimation("xeno_hurt");
}

void animateShoot() {
animator.stopAnimation();
animator.startAnimation("xeno_shoot");
}

void animateMelee1() {
animator.stopAnimation();
animator.startAnimation("xeno_melee_1");
}

void animateMelee2() {
animator.stopAnimation();
animator.startAnimation("xeno_melee_2");
}

void animateDie() {
animator.stopAnimation();
animator.startAnimation("xeno_die");
}

void stopAnimation() {
animator.stopAnimation();
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package com.csse3200.game.components.tasks;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.csse3200.game.ai.tasks.DefaultTask;
import com.csse3200.game.ai.tasks.PriorityTask;
import com.csse3200.game.components.CombatStatsComponent;
import com.csse3200.game.components.TouchAttackComponent;
import com.csse3200.game.entities.Entity;
import com.badlogic.gdx.math.Vector2;
import com.csse3200.game.entities.Melee;
import com.csse3200.game.entities.Weapon;
import com.csse3200.game.entities.factories.ProjectileFactory;
import com.csse3200.game.physics.PhysicsEngine;
import com.csse3200.game.physics.PhysicsLayer;
import com.csse3200.game.physics.components.HitboxComponent;
import com.csse3200.game.physics.components.PhysicsMovementComponent;
import com.csse3200.game.physics.raycast.RaycastHit;
import com.csse3200.game.services.ServiceLocator;
import com.csse3200.game.rendering.AnimationRenderComponent;
import com.csse3200.game.services.GameTime;
import com.csse3200.game.entities.factories.ProjectileFactory;
import com.csse3200.game.services.ServiceLocator;


/**
Expand All @@ -22,11 +27,13 @@ public class MobAttackTask extends DefaultTask implements PriorityTask {
private static final short TARGET = PhysicsLayer.HUMANS; // mobs detecting for towers
// ^ fix this

private static final String STOW = "stowStart";
private static final String STOW = "wanderStart";
private static final String DEPLOY = "deployStart";
private static final String FIRING = "firingStart";
private static final String FIRING = "shootStart";
private static final String IDLE = "idleStart";

private Fixture target;

private final int priority;
private final float maxRange;
private Vector2 mobPosition = new Vector2(10f,10f);
Expand Down Expand Up @@ -67,7 +74,7 @@ public void start() {
startTime = timeSource.getTime();
this.mobPosition = owner.getEntity().getCenterPosition();
this.maxRangePosition.set(0, mobPosition.y);
owner.getEntity().getEvents().trigger(IDLE);
//owner.getEntity().getEvents().trigger(IDLE);
endTime = timeSource.getTime() + (INTERVAL * 500);
owner.getEntity().getEvents().trigger("shootStart");
}
Expand All @@ -90,14 +97,6 @@ public void update() {
* triggers the appropriate events corresponding to the STATE enum.
*/
public void updateMobState() {
// TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class);
CombatStatsComponent statsComp = owner.getEntity().getComponent(CombatStatsComponent.class);
// if (statsComp != null) {
// System.out.println("is the target visible " + isTargetVisible());
// }
if (!isTargetVisible()) {
System.out.println("target is not visible for " + owner.getEntity().getId());
}
switch (mobState) {

case IDLE -> {
Expand All @@ -110,7 +109,8 @@ public void updateMobState() {

case DEPLOY -> {
// currently deploying,
if (isTargetVisible()) {
if (isTargetVisible() || this.meleeOrProjectile() != null) {
owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(false);
owner.getEntity().getEvents().trigger(FIRING);
mobState = STATE.FIRING;
} else {
Expand All @@ -120,19 +120,29 @@ public void updateMobState() {
}

case FIRING -> {
// targets gone - stop firing
if (!isTargetVisible()) {
// targets gone or cannot be attacked - stop firing
if (!isTargetVisible() || this.meleeOrProjectile() == null) {
owner.getEntity().getEvents().trigger(STOW);
mobState = STATE.STOW;
} else {
owner.getEntity().getEvents().trigger(FIRING);
Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f));
newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y + 0.1));
newProjectile.setScale(-0.7f, 0.7f);
ServiceLocator.getEntityService().register(newProjectile);
mobState = STATE.STOW;
owner.getEntity().getEvents().trigger("shootStart");
if (this.meleeOrProjectile() instanceof Melee) {
System.out.println("Melee attack");
TouchAttackComponent attackComp = owner.getEntity().getComponent(TouchAttackComponent.class);
HitboxComponent hitboxComp = owner.getEntity().getComponent(HitboxComponent.class);
attackComp.onCollisionStart(hitboxComp.getFixture(), target);
} else {
Entity newProjectile = ProjectileFactory.createMobBall(PhysicsLayer.HUMANS, new Vector2(0, owner.getEntity().getPosition().y), new Vector2(2f,2f));
newProjectile.setPosition((float) (owner.getEntity().getPosition().x), (float) (owner.getEntity().getPosition().y));
// newProjectile.setScale(-1f, 0.5f);
ServiceLocator.getEntityService().register(newProjectile);

// System.out.printf("ANIMATION: " + owner.getEntity().getComponent(AnimationRenderComponent.class).getCurrentAnimation() + "\n");
owner.getEntity().getEvents().trigger(FIRING);
mobState = STATE.STOW;
}
}
owner.getEntity().getComponent(PhysicsMovementComponent.class).setEnabled(true);

}

case STOW -> {
Expand All @@ -153,8 +163,12 @@ public void updateMobState() {
*/
@Override
public void stop() {
super.stop();
owner.getEntity().getEvents().trigger(STOW);
if (mobState == STATE.FIRING || mobState == STATE.DEPLOY) {
this.updateMobState();
} else {
super.stop();
owner.getEntity().getEvents().trigger(STOW);
}
}

/**
Expand All @@ -163,26 +177,20 @@ public void stop() {
*/
@Override
public int getPriority() {
// return -1;
if (status == Status.ACTIVE) {
return getActivePriority();
}
return getInactivePriority();
// return isTargetVisible() ? getActivePriority() : getInactivePriority();
}

/**
* Fetches the active priority of the Task if a target is visible.
* @return (int) active priority if a target is visible, -1 otherwise
*/
private int getActivePriority() {
if ((startTime + delay) < timeSource.getTime()) {
// if (isTargetVisible() && (startTime + delay) > timeSource.getTime()) {
// System.out.println("ready to fire while active");
if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) {
return priority;
}
// System.out.println("not ready to fire while active");
// return !isTargetVisible() ? -1 : priority;
return -1;
}

Expand All @@ -191,22 +199,46 @@ private int getActivePriority() {
* @return (int) -1 if a target is not visible, active priority otherwise
*/
private int getInactivePriority() {
// return isTargetVisible() ? priority : 0;
if ((startTime + delay) < timeSource.getTime()) {
// if (isTargetVisible() && (startTime + delay) > timeSource.getTime()) {
// System.out.println("ready to fire while inactive");
if ((startTime + delay) < timeSource.getTime() && isTargetVisible() && this.meleeOrProjectile() != null) {
return priority;
}
return -1;
// System.out.println("not ready to fire while inactive");
// return isTargetVisible() ? priority : -1;
}

/**
* 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() {
return physics.raycast(mobPosition, maxRangePosition, TARGET, hit);
Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f);
return physics.raycast(owner.getEntity().getPosition(), newVector, TARGET, hit);
}

/**
* Uses a custom raycast method to find the closest target to the mob. Based on the distance to the
* target, the mob will choose a weapon to attack with.
*
* If the object does not have a CombatStatsComponent (which handles dealing damage etc), then
* the function will return null. If it returns null when the mob is in state FIRING or DEPLOY, it will not fire
* and will STOW.
*
* returns the Weapon (Melee or Projectile) the mob will use to attack the target. null if immune target or no target
* */
private Weapon meleeOrProjectile() {
// Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f);
// Fixture hitraycast = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET);
setTarget();
TouchAttackComponent comp = owner.getEntity().getComponent(TouchAttackComponent.class);
Weapon chosenWeapon = null;
if (comp != null) {
chosenWeapon = comp.chooseWeapon(target);
}

return chosenWeapon;
}

private void setTarget() {
Vector2 newVector = new Vector2(owner.getEntity().getPosition().x - 10f, owner.getEntity().getPosition().y - 2f);
target = physics.raycastGetHit(owner.getEntity().getPosition(), newVector, TARGET);
}
}
Loading

0 comments on commit 65faa31

Please sign in to comment.