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 f597631f4..3a7147167 100644 --- a/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java +++ b/source/core/src/main/com/csse3200/game/areas/ForestGameArea.java @@ -169,6 +169,9 @@ public void create() { // Types of projectile spawnEffectProjectile(new Vector2(0, 10), PhysicsLayer.HUMANS, towardsMobs, new Vector2(2f, 2f), ProjectileEffects.BURN, true); + spawnPierceFireBall(new Vector2(2, 3), PhysicsLayer.NPC, towardsMobs, new Vector2(2f, 2f)); + spawnRicochetFireball(new Vector2(2, 4), PhysicsLayer.NPC, towardsMobs, new Vector2(2f, 2f)); + spawnSplitFireWorksFireBall(new Vector2(2, 5), PhysicsLayer.NPC, towardsMobs, new Vector2(2f, 2f), 12); // spawnProjectileTest(new Vector2(0, 8), PhysicsLayer.NPC, towardsMobs, new Vector2(2f, 2f)); spawnXenoGrunts(); @@ -199,23 +202,29 @@ private void spawnTerrain() { Vector2 worldBounds = new Vector2(tileBounds.x * tileSize, tileBounds.y * tileSize); // Left + // ! THIS ONE DOESNT WORK. GRIDPOINTS2UTIL.ZERO is (0, 4), not (0, 0) + // spawnEntityAt( + // ObstacleFactory.createWall(WALL_WIDTH, worldBounds.y), GridPoint2Utils.ZERO, false, false); spawnEntityAt( - ObstacleFactory.createWall(WALL_WIDTH, worldBounds.y), GridPoint2Utils.ZERO, false, false); + ObstacleFactory.createWall(WALL_WIDTH, worldBounds.y), new GridPoint2(1, 0), false, false); // Right spawnEntityAt( ObstacleFactory.createWall(WALL_WIDTH, worldBounds.y), - new GridPoint2(tileBounds.x, 0), + new GridPoint2(tileBounds.x , 0), false, false); // Top spawnEntityAt( - ObstacleFactory.createWall(worldBounds.x, WALL_WIDTH), - new GridPoint2(0, tileBounds.y), + ObstacleFactory.createWall(worldBounds.x, WALL_WIDTH * 7), + new GridPoint2(0, tileBounds.y - 1), false, false); // Bottom + // spawnEntityAt( + // ObstacleFactory.createWall(worldBounds.x, WALL_WIDTH), GridPoint2Utils.ZERO, false, false); + // * TMPORARY spawnEntityAt( - ObstacleFactory.createWall(worldBounds.x, WALL_WIDTH), GridPoint2Utils.ZERO, false, false); + ObstacleFactory.createWall(worldBounds.x, WALL_WIDTH * 7), new GridPoint2(0, 0), false, false); } private void spawnBuilding1() { GridPoint2 minPos = new GridPoint2(0, 0); @@ -422,6 +431,55 @@ private void spawnEffectProjectile(Vector2 position, short targetLayer, int dire spawnEntity(Projectile); } + /** + * Spawns a pierce fireball. + * Pierce fireball can go through targetlayers without disappearing but damage + * will still be applied. + * + * @param position The position of the Entity that's shooting the projectile. + * @param targetLayer The enemy layer of the "shooter". + * @param direction The direction the projectile should head towards. + * @param speed The speed of the projectiles. + */ + private void spawnPierceFireBall(Vector2 position, short targetLayer, int direction, Vector2 speed) { + Entity projectile = ProjectileFactory.createPierceFireBall(targetLayer, new Vector2(direction, position.y), speed); + projectile.setPosition(position); + spawnEntity(projectile); + } + + /** + * Spawns a ricochet fireball + * Ricochet fireballs bounce off targets with a specified maximum count of 3 + * Possible extensions: Make the bounce count flexible with a param. + * + * @param position The position of the Entity that's shooting the projectile. + * @param targetLayer The enemy layer of the "shooter". + * @param direction The direction the projectile should head towards. + * @param speed The speed of the projectiles. + */ + private void spawnRicochetFireball(Vector2 position, short targetLayer, int direction, Vector2 speed) { + // Bounce count set to 0. + Entity projectile = ProjectileFactory.createRicochetFireball(targetLayer, new Vector2(direction, position.y), speed, 0); + projectile.setPosition(position); + spawnEntity(projectile); + } + + /** + * Spawns a split firework fireball. + * Splits into mini projectiles that spreads out after collision. + * + * @param position The position of the Entity that's shooting the projectile. + * @param targetLayer The enemy layer of the "shooter". + * @param direction The direction the projectile should head towards. + * @param speed The speed of the projectiles. + * @param amount The amount of projectiles appearing after collision. + */ + private void spawnSplitFireWorksFireBall(Vector2 position, short targetLayer, int direction, Vector2 speed, int amount) { + Entity projectile = ProjectileFactory.createSplitFireWorksFireball(targetLayer, new Vector2(direction, position.y), speed, amount); + projectile.setPosition(position); + spawnEntity(projectile); + } + private void spawnWeaponTower() { GridPoint2 minPos = new GridPoint2(0, 0); GridPoint2 maxPos = terrain.getMapBounds(0).sub(2, 2); diff --git a/source/core/src/main/com/csse3200/game/components/DeleteOnMapEdgeComponent.java b/source/core/src/main/com/csse3200/game/components/DeleteOnMapEdgeComponent.java new file mode 100644 index 000000000..4359c118d --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/DeleteOnMapEdgeComponent.java @@ -0,0 +1,34 @@ +package com.csse3200.game.components; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.physics.BodyUserData; +import com.csse3200.game.physics.PhysicsLayer; + +/** + * Entities with this component will self destruct after hitting the grid edge + * upon collision. + */ +public class DeleteOnMapEdgeComponent extends Component { + + @Override + public void create() { + entity.getEvents().addListener("collisionEnd", this::onCollisionEnd); + } + + private void onCollisionEnd(Fixture me, Fixture other) { + Entity selfEntity = ((BodyUserData) me.getBody().getUserData()).entity; + + // * Should change the PhysicLayer to WALL / BOUNDARIES when established + if (!PhysicsLayer.contains(PhysicsLayer.WALL, other.getFilterData().categoryBits)) + return; + + Vector2 position = selfEntity.getPosition(); + + if (position.x <= 1 || position.x >= 18 || position.y < 0 || position.y >= 6.5) { + System.out.println("DELETION POSITION: " + position); + selfEntity.setFlagForDelete(true); + } + } +} diff --git a/source/core/src/main/com/csse3200/game/components/RicochetComponent.java b/source/core/src/main/com/csse3200/game/components/RicochetComponent.java index f2732375e..4203dfa6a 100644 --- a/source/core/src/main/com/csse3200/game/components/RicochetComponent.java +++ b/source/core/src/main/com/csse3200/game/components/RicochetComponent.java @@ -1,29 +1,35 @@ package com.csse3200.game.components; - import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.Fixture; -import com.csse3200.game.ai.tasks.AITaskComponent; -import com.csse3200.game.components.tasks.TrajectTask; import com.csse3200.game.entities.Entity; import com.csse3200.game.entities.factories.ProjectileFactory; import com.csse3200.game.physics.BodyUserData; import com.csse3200.game.physics.PhysicsLayer; import com.csse3200.game.physics.components.HitboxComponent; -import com.csse3200.game.physics.components.PhysicsComponent; import com.csse3200.game.services.ServiceLocator; /** * Ricochet based on target layers. - * Basically a bouncing effect that continues to bounce off entities - * Possible extensions: Have a limitied amount of bounce until self-destruct. + * A bouncing effect that continues to bounce off desired entities. */ public class RicochetComponent extends Component { private short targetLayer; private HitboxComponent hitBoxComponent; + private int bounceCount; + private static int MAX_BOUNCE_Y_DIRECTION = 250; + private static int MIN_BOUNCE_Y_DIRECTION = -250; - public RicochetComponent(short targetLayer) { + /** + * Initialise a RicochetComponent that spawns another projectile upon collision. + * Projectile has a chance to head upwards or downwards and upon spawning, + * it will be slighlty up or down in respect to original disappearance. + * @param targetLayer Target layer upon collision + * @param bounceCount Keeps track of the bounce count upon initial collision + * Stops self-spawning when bounce count is greater or equal than two. + */ + public RicochetComponent(short targetLayer, int bounceCount) { this.targetLayer = targetLayer; + this.bounceCount = bounceCount; } @Override @@ -31,26 +37,45 @@ public void create() { entity.getEvents().addListener("collisionEnd", this::onCollisionEnd); hitBoxComponent = entity.getComponent(HitboxComponent.class); } - + /** - * After collision ends, make another fireball that spawns just before the original one. This assumes - * that the original fireball is already deleted. Set TouchAttackComponent disposeOnHit to true. + * After collision ends, make another fireball that spawns just before the + * original one. This assumes + * that the original fireball is already deleted. Set TouchAttackComponent + * disposeOnHit to true. + * * @param me * @param other */ private void onCollisionEnd(Fixture me, Fixture other) { - if(hitBoxComponent.getFixture() != me) return; - - if(!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) return; - + if (hitBoxComponent.getFixture() != me + || !PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits) + || bounceCount >= 3) // BounceCount base case of 3 + return; + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; - Entity newProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, new Vector2(100, projectile.getPosition().y + getRandomNumFrom(-250, 250)), new Vector2(2f, 2f)); - newProjectile.setPosition((float) (projectile.getPosition().x -1.5), (float) (projectile.getPosition().y)); + // Projectile heads upwards or downwards. + int randomDirection = getRandomNumFrom(MIN_BOUNCE_Y_DIRECTION, MAX_BOUNCE_Y_DIRECTION); + + // Spawning of the projectile to be above (+ve) or below (-ve) upon + // collision + int up_or_down = randomDirection <= 0 ? -1 : 1; + + float newXPosition = (float) (projectile.getPosition().x - 0.75); + float newYPosition = (float) (projectile.getPosition().y + (0.65 * up_or_down)); + + // Prevent spawn of new projectile if it goes out of boundaries. + if (newYPosition >= 8 || newYPosition <= 1 || newXPosition >= 17 || newXPosition <= 1) + return; + + // * RIGHT NOW TARGET IS NPC, SUBJECT TO CHANGE + Entity newProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, + new Vector2(100, projectile.getPosition().y + randomDirection), new Vector2(2f, 2f), ++bounceCount); // Increment bounceCount + + newProjectile.setPosition(newXPosition, newYPosition); + newProjectile.setScale(0.75f, 0.75f); - // projectile.getComponent(AITaskComponent.class).addTask(new TrajectTask(new Vector2(100, projectile.getPosition().y + 50))); - - ServiceLocator.getEntityService().register(newProjectile); } diff --git a/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java b/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java new file mode 100644 index 000000000..a48f6595a --- /dev/null +++ b/source/core/src/main/com/csse3200/game/components/SplitFireworksComponent.java @@ -0,0 +1,71 @@ +package com.csse3200.game.components; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Fixture; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.factories.ProjectileFactory; +import com.csse3200.game.physics.BodyUserData; +import com.csse3200.game.physics.PhysicsLayer; +import com.csse3200.game.physics.components.HitboxComponent; +import com.csse3200.game.services.ServiceLocator; + +/** + * A component that splits the projectile into multiple mini projectiles. + * Assumes projectile has a disposesOnHit functionality. + */ +public class SplitFireworksComponent extends Component { + private short targetLayer; + private HitboxComponent hitboxComponent; + private int amount; + private static int TOTAL_RANGE = 450; + + /** + * Initialises a component that splits the projectile into multiple fireballs + * upon collision on a specified target layer. + * The spawned projectiles will be spawned just before original projectile + * and spread out in multiple direction set by a certain range. + * Assumes amount of split projectiles is greater or equal than 2. + * + * @param targetLayer Target layer upon collision. + * @param amount Amount of projectiles that is split after collision event. + */ + public SplitFireworksComponent(short targetLayer, int amount) { + this.targetLayer = targetLayer; + this.amount = amount; + } + + @Override + public void create() { + entity.getEvents().addListener("collisionEnd", this::onCollisionEnd); + hitboxComponent = entity.getComponent(HitboxComponent.class); + } + + private void onCollisionEnd(Fixture me, Fixture other) { + if (hitboxComponent.getFixture() != me + || !PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits) + || amount < 2) // Amount of split projectiles must be >= 2 + return; + + Entity projectile = ((BodyUserData) me.getBody().getUserData()).entity; + + for (int i = 0; i < amount; i++) { + int newDirection = (i * TOTAL_RANGE) / (amount - 1); + + // Boundaries + float newXPosition = (float) (projectile.getPosition().x + 1.75); + if (newXPosition >= 18 || newXPosition <= 1) + return; + + // * RIGHT NOW TARGET IS NPC, SUBJECT TO CHANGE + // Speed is a bit faster than normal but can change. + Entity newProjectile = ProjectileFactory.createFireBall(PhysicsLayer.NPC, + new Vector2(100, projectile.getPosition().y + (newDirection - (TOTAL_RANGE/2))), new Vector2(3f, 3f)); + + newProjectile.setPosition(newXPosition, (float) projectile.getPosition().y); + + newProjectile.setScale(0.5f, 0.5f); + + ServiceLocator.getEntityService().register(newProjectile); + } + } +} diff --git a/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java b/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java index c42945db3..b84e55b7d 100644 --- a/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java +++ b/source/core/src/main/com/csse3200/game/components/TouchAttackComponent.java @@ -11,6 +11,7 @@ /** * When this entity touches a valid enemy's hitbox, deal damage to them and apply a knockback. + * Has an optional disposeOnHit property that disposes projectile upon collision. * *
Requires CombatStatsComponent, HitboxComponent on this entity. * diff --git a/source/core/src/main/com/csse3200/game/components/tasks/RangeBossMovementTask.java b/source/core/src/main/com/csse3200/game/components/tasks/RangeBossMovementTask.java index 15db419ea..87f51b1a3 100644 --- a/source/core/src/main/com/csse3200/game/components/tasks/RangeBossMovementTask.java +++ b/source/core/src/main/com/csse3200/game/components/tasks/RangeBossMovementTask.java @@ -4,6 +4,10 @@ import com.csse3200.game.ai.tasks.DefaultTask; import com.csse3200.game.ai.tasks.PriorityTask; import com.csse3200.game.ai.tasks.Task; +import com.csse3200.game.entities.Entity; +import com.csse3200.game.entities.factories.ProjectileFactory; +import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.physics.PhysicsLayer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,7 +19,7 @@ public class RangeBossMovementTask extends DefaultTask implements PriorityTask { private static final Logger logger = LoggerFactory.getLogger(RangeBossMovementTask.class); private final float waitTime; - private Vector2 startPos; + private Vector2 currentPos; private MovementTask movementTask; private WaitTask waitTask; private Task currentTask; @@ -36,11 +40,11 @@ public int getPriority() { @Override public void start() { super.start(); - startPos = owner.getEntity().getPosition(); + currentPos = owner.getEntity().getPosition(); waitTask = new WaitTask(waitTime); waitTask.create(owner); - movementTask = new MovementTask(startPos.sub(2,0)); + movementTask = new MovementTask(currentPos.sub(2,0)); movementTask.create(owner); movementTask.start(); @@ -54,6 +58,11 @@ public void start() { public void update() { if (currentTask.getStatus() != Status.ACTIVE) { if (currentTask == movementTask) { + Entity newProjectile = ProjectileFactory.createFireBall(PhysicsLayer.OBSTACLE, new Vector2(0, currentPos.y + 0.75f), new Vector2(2f,2f)); + + newProjectile.scaleHeight(-0.4f); + newProjectile.setPosition((float) (currentPos.x), (float) (currentPos.y+0.75f)); + ServiceLocator.getEntityService().register(newProjectile); startWaiting(); } else { startMoving(); @@ -69,7 +78,7 @@ private void startWaiting() { private void startMoving() { logger.debug("Starting moving"); - movementTask.setTarget(startPos.sub(2,0)); + movementTask.setTarget(currentPos.sub(2,0)); swapTask(movementTask); } @@ -81,4 +90,4 @@ private void swapTask(Task newTask) { currentTask.start(); } -} \ No newline at end of file +} 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 752a67859..566e04568 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 @@ -113,12 +113,26 @@ public void updateTowerState() { 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)); - - // * TEMPORARYYYYYYY - // Entity newProjectile = ProjectileFactory.createRicochetFireball(PhysicsLayer.NPC, new Vector2(100, owner.getEntity().getPosition().y), new Vector2(2f,2f)); - newProjectile.setPosition((float) (owner.getEntity().getPosition().x + 0.75), (float) (owner.getEntity().getPosition().y + 0.4)); 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); + + // 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); + + // 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); } } case STOW -> { diff --git a/source/core/src/main/com/csse3200/game/entities/Entity.java b/source/core/src/main/com/csse3200/game/entities/Entity.java index c26ba6f00..138c8ed61 100644 --- a/source/core/src/main/com/csse3200/game/entities/Entity.java +++ b/source/core/src/main/com/csse3200/game/entities/Entity.java @@ -251,13 +251,20 @@ public void update() { if (!enabled) { return; } - for (Component component : createdComponents) { - component.triggerUpdate(); - } - if (isFlaggedForDelete) { - dispose(); - return; - } + + // ! ITERATOR CAUSES PROBLEMS + // for (Component component : createdComponents) { + // component.triggerUpdate(); + // } + + for (int i = 0; i < createdComponents.size; i++) { + createdComponents.get(i).triggerUpdate(); + } + + // if (isFlaggedForDelete) { + // dispose(); + // return; + // } } /** diff --git a/source/core/src/main/com/csse3200/game/entities/factories/BossKingFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/BossKingFactory.java index b4260b2be..99077b50f 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/BossKingFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/BossKingFactory.java @@ -61,8 +61,8 @@ public static Entity createBossKing1(Entity target) { .addComponent(new BossAnimationController()); bossKing1.getComponent(AnimationRenderComponent.class).scaleEntity(); - bossKing1.scaleHeight(0.5f); - bossKing1.scaleWidth(0.5f); + bossKing1.setScale(-1f,1f); + return bossKing1; } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/ObstacleFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/ObstacleFactory.java index c271ea2d6..0fef2bc2e 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/ObstacleFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/ObstacleFactory.java @@ -70,7 +70,7 @@ public static Entity createWall(float width, float height) { Entity wall = new Entity() .addComponent(new PhysicsComponent().setBodyType(BodyType.StaticBody)) // * TMEPORARRYY WALLL - .addComponent(new ColliderComponent().setLayer(PhysicsLayer.OBSTACLE)); + .addComponent(new ColliderComponent().setLayer(PhysicsLayer.WALL)); wall.setScale(width, height); return wall; } diff --git a/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java index 522fb61e7..0ac4646e2 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/ProjectileFactory.java @@ -6,9 +6,11 @@ import com.csse3200.game.components.ProjectileEffects; import com.csse3200.game.components.TouchAttackComponent; import com.csse3200.game.components.RicochetComponent; +import com.csse3200.game.components.SplitFireworksComponent; import com.csse3200.game.components.tasks.TrajectTask; import com.csse3200.game.ai.tasks.AITaskComponent; import com.csse3200.game.components.CombatStatsComponent; +import com.csse3200.game.components.DeleteOnMapEdgeComponent; import com.csse3200.game.entities.configs.BaseEntityConfig; import com.csse3200.game.entities.configs.NPCConfigs; import com.csse3200.game.files.FileLoader; @@ -84,10 +86,21 @@ public static Entity createPierceFireBall(short targetLayer, Vector2 destination * Create a ricochet fireball. * Ricochet fireball bounces off specified targets while applying intended effects i.e. damage */ - public static Entity createRicochetFireball(short targetLayer, Vector2 destination, Vector2 speed) { + public static Entity createRicochetFireball(short targetLayer, Vector2 destination, Vector2 speed, int bounceCount) { Entity fireBall = createFireBall(targetLayer, destination, speed); - fireBall.addComponent(new RicochetComponent(targetLayer)); + fireBall + .addComponent(new RicochetComponent(targetLayer, bounceCount)); + + setColliderSize(fireBall, (float) 0.1, (float) 0.1); + + return fireBall; + } + public static Entity createSplitFireWorksFireball(short targetLayer, Vector2 destination, Vector2 speed, int amount) { + Entity fireBall = createFireBall(targetLayer, destination, speed); + fireBall + .addComponent(new SplitFireworksComponent(targetLayer, amount)); + return fireBall; } @@ -112,6 +125,8 @@ public static Entity createFireBall(short targetLayer, Vector2 destination, Vect projectile .addComponent(animator) .addComponent(new ProjectileAnimationController()); + // * TEMPORARY + // .addComponent(new DeleteOnMapEdgeComponent()); // .addComponent(new SelfDestructOnHitComponent(PhysicsLayer.OBSTACLE)); return projectile; @@ -163,6 +178,8 @@ public static Entity createMobBall(short targetLayer, Vector2 destination, Vecto projectile .addComponent(animator) .addComponent(new MobProjectileAnimationController()); + // * TEMPORARY + // .addComponent(new DeleteOnMapEdgeComponent()); projectile .getComponent(AnimationRenderComponent.class).scaleEntity(); @@ -225,7 +242,9 @@ public static Entity createBaseProjectile(short targetLayer, Vector2 // specified target. // Original knockback value: 1.5f .addComponent(new TouchAttackComponent(targetLayer, 1.5f, true)) - .addComponent(new CombatStatsComponent(config.health, config.baseAttack)); + .addComponent(new CombatStatsComponent(config.health, config.baseAttack)) + // *TEMPORARY + .addComponent(new DeleteOnMapEdgeComponent()); projectile .getComponent(PhysicsMovementComponent.class).setSpeed(speed); diff --git a/source/core/src/main/com/csse3200/game/physics/PhysicsEngine.java b/source/core/src/main/com/csse3200/game/physics/PhysicsEngine.java index 882ad4935..bb7258f4c 100644 --- a/source/core/src/main/com/csse3200/game/physics/PhysicsEngine.java +++ b/source/core/src/main/com/csse3200/game/physics/PhysicsEngine.java @@ -45,7 +45,7 @@ public PhysicsEngine(World world, GameTime timeSource) { public void update() { // Check for deleted bodies and joints - // checkAndDeleteBodies(); + checkAndDeleteBodies(); // Updating physics isn't as easy as triggering an update every frame. Each frame could take a // different amount of time to run, but physics simulations are only stable if computed at a @@ -90,19 +90,17 @@ public void checkAndDeleteBodies() { world.getBodies(bodies); - // Check for bodies to be deleted - for (Body body : bodies) { - // check for null values - if (body.getUserData() != null) { - Entity entity = ((BodyUserData) body.getUserData()).entity; - // If the entity is flagged for deletion, destroy the body before world.step() is called - if (entity.getFlagForDelete()) { - logger.debug("Destroying physics body {}", body); - ProjectileDestructors.destroyProjectile(entity); - - // Make sure not to delete the body twice - entity.setFlagForDelete(false); - } + // ! CANNOT USE ITERATOR HERE + // ! If you do: "ERROR: #ITERATOR CAN'T BE NESTED" + for(int i = 0; i < bodies.size; i++) { + if(bodies.get(i) != null + && bodies.get(i).getUserData() != null + && (BodyUserData) bodies.get(i).getUserData() != null) { + Entity entity = ((BodyUserData) bodies.get(i).getUserData()).entity; + + if(entity.getFlagForDelete()) { + entity.dispose(); + } } } } diff --git a/source/core/src/main/com/csse3200/game/physics/PhysicsLayer.java b/source/core/src/main/com/csse3200/game/physics/PhysicsLayer.java index 73c5904aa..c72e1e137 100644 --- a/source/core/src/main/com/csse3200/game/physics/PhysicsLayer.java +++ b/source/core/src/main/com/csse3200/game/physics/PhysicsLayer.java @@ -10,6 +10,8 @@ public class PhysicsLayer { public static final short NPC = (1 << 3); public static final short PROJECTILE = (1 << 4); public static final short TOWER = (1 << 5); + // * TEMPORARY WALL BOUNDARIES? + public static final short WALL = (1 << 6); public static final short HUMANS = (1 << 1) | (1 << 5); public static final short ALL = ~0;