-
Notifications
You must be signed in to change notification settings - Fork 4
NPC Factory
The NPC Factory is responsible for creating the different mobs on the different planets. This includes the Fireworm, Necromancer, Skeleton, Wizard, Coat & Water Queen. Special Feature Mobs include WaterSlime, Night Borne, ArcaneArcher, DragonKnight, FireWizard & Wizard.
Here is the life cycle of an Arcane Archer visualised with a sequence diagram
UML Diagram:
The function createMeleeBaseNPC()
is responsible to assigning the base components for melee mobs within the game. The components added are: PhysicsComponent()
, PhysicsMovementComponent()
, ColliderComponent()
, HitboxComponent()
, TouchAttackComponent()
and aiComponent
.
AITaskComponent aiComponent =
new AITaskComponent()
.addTask(new MobWanderTask(new Vector2(2f, 2f), 2f))
.addTask(new MobMeleeAttackTask(2, 2f));
Entity npc =
new Entity()
.addComponent(new PhysicsComponent())
.addComponent(new PhysicsMovementComponent())
.addComponent(new ColliderComponent())
.addComponent(new HitboxComponent().setLayer(PhysicsLayer.XENO))
.addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS))
.addComponent(aiComponent);
PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f);
return npc;
The function createMeleeBaseNPC()
is responsible to assigning the base components for melee mobs within the game. The components added are: PhysicsComponent()
, PhysicsMovementComponent()
, ColliderComponent()
, HitboxComponent()
, TouchAttackComponent()
and aiComponent
.
AITaskComponent aiComponent =
new AITaskComponent()
.addTask(new MobWanderTask(new Vector2(2f, 2f), 2f))
.addTask(new MobRangedAttackTask(2, 2f));
Entity npc =
new Entity()
.addComponent(new PhysicsComponent())
.addComponent(new PhysicsMovementComponent())
.addComponent(new ColliderComponent())
.addComponent(new HitboxComponent().setLayer(PhysicsLayer.XENO))
.addComponent(new TouchAttackComponent(PhysicsLayer.HUMANS))
.addComponent(aiComponent);
PhysicsUtils.setScaledCollider(npc, 0.3f, 0.5f);
return npc;
This function will build upon the createRangedBaseNPC()
function and adds the specific animation and projectiles. Fireworm is able to shoot projectiles towards the towers.
Entity fireWorm = createRangedBaseNPC();
BaseEnemyConfig config = configs.xenoGrunt;
ArrayList<Melee> melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick));
// tester projectiles
ArrayList<ProjectileConfig> projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall));
ArrayList<Currency> drops = new ArrayList<>();
fireWorm
.addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles))
.addComponent(animator)
.addComponent(new FireWormAnimationController());
Animations for Fireworm:
This function will build upon the createRangedBaseNPC()
function and adds the specific animation and projectiles. Wizards are able to deflect projectiles using createDeflectingWizard
.
Entity wizard = createRangedBaseNPC();
BaseEnemyConfig config = configs.xenoGrunt;
ArrayList<Melee> melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick));
// tester projectiles
ArrayList<ProjectileConfig> projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall));
ArrayList<Currency> drops = new ArrayList<>();
wizard
.addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles))
.addComponent(animator)
.addComponent(new WizardAnimationController());
public static Entity createDeflectWizard() {
Entity deflectWizard = createWizard();
deflectWizard.addComponent(new DeflectingComponent(
PhysicsLayer.PROJECTILE, PhysicsLayer.TOWER, 10));
return deflectWizard;
}
Animations for Wizard:
This function will build upon the createMeleeBaseNPC()
function and adds the specific animation
public static Entity createCoat(int health) {
Entity coat = createBaseNPC();
ArrayList<Currency> drops = new ArrayList<>();
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/mobs/coat.atlas", TextureAtlas.class));
animator.addAnimation("coat_run", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("coat_attack", 0.1f);
animator.addAnimation("coat_death", 0.1f);
animator.addAnimation("default", 0.1f);
AITaskComponent aiTaskComponent = new AITaskComponent()
.addTask(new MobTask(MobType.COAT));
coat
.addComponent(new CombatStatsComponent(health, 0, drops))
.addComponent(animator)
.addComponent(new CoatAnimationController())
.addComponent(aiTaskComponent);
coat.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM);
coat.getComponent(AnimationRenderComponent.class).scaleEntity();
return coat;
}
This function will build upon the createRangedBaseNPC()
function and adds the specific animation and projectiles. Water Queens are able to shoot towards the towers.
Entity WaterQueen = createRangedBaseNPC();
BaseEnemyConfig config = configs.xenoGrunt;
ArrayList<Melee> melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick));
// tester projectiles
ArrayList<ProjectileConfig> projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall));
ArrayList<Currency> drops = new ArrayList<>();
WaterQueen
.addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles))
.addComponent(animator)
.addComponent(new WaterQueenAnimationController());
Animations for Water Queen:
This function will build upon the createMeleeBaseNPC()
function and adds the specific animation and projectiles. Skeletons are able to do close range attack damage.
Entity skeleton = createMeleeBaseNPC();
BaseEnemyConfig config = configs.xenoGrunt;
ArrayList<Melee> melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick));
// tester projectiles
ArrayList<ProjectileConfig> projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall));
ArrayList<Currency> drops = new ArrayList<>();
skeleton
.addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles))
.addComponent(animator)
.addComponent(new SkeletonAnimationController());
Animations for Skeletons:
This function will build upon the createBaseNPC()
function and add the specific animation and projectiles.
public static Entity createNecromancer(int health) {
Entity necromancer = createBaseNPC();
ArrayList<Currency> drops = new ArrayList<>();
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/mobs/necromancer.atlas", TextureAtlas.class));
animator.addAnimation("necromancer_walk", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("necromancer_attack", 0.1f);
animator.addAnimation("necromancer_death", 0.1f);
animator.addAnimation(DEFAULT, 0.1f);
AITaskComponent aiTaskComponent = new AITaskComponent()
.addTask(new MobTask(MobType.NECROMANCER));
necromancer
.addComponent(new CombatStatsComponent(health, 0, drops))
.addComponent(animator)
.addComponent(new NecromancerAnimationController())
.addComponent(aiTaskComponent);
necromancer.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM);
necromancer.getComponent(AnimationRenderComponent.class).scaleEntity();
return necromancer;
}
This function will build upon the createBaseNPC()
function and adds the specific animation and projectiles. NightBornes are able to split into multiple night bornes using createSplittingNightBorne
.
public static Entity createNightBorne(int health) {
Entity nightBorne = createBaseNPC();
ArrayList<Currency> drops = new ArrayList<>();
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/mobs/night_borne.atlas", TextureAtlas.class));
animator.addAnimation("night_borne_run", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("night_borne_attack", 0.1f);
animator.addAnimation("night_borne_death", 0.1f);
animator.addAnimation(DEFAULT, 0.1f);
AITaskComponent aiTaskComponent = new AITaskComponent()
.addTask(new MobTask(MobType.NIGHT_BORNE));
nightBorne
.addComponent(new CombatStatsComponent(health, 0, drops))
.addComponent(animator)
.addComponent(new NightBorneAnimationController())
.addComponent(aiTaskComponent);
nightBorne.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM);
nightBorne.getComponent(AnimationRenderComponent.class).scaleEntity();
return nightBorne;
}
public static Entity createSplittingNightBorne(int health) {
return createNightBorne(health).addComponent(new SplitMoblings(MobType.NIGHT_BORNE, 7, 0.5f));
}
This function will build upon the createMeleeBaseNPC()
function and adds the specific animation and projectiles. Water slimes are able to split once dead using createSplittingWaterSlimes()
.
Entity waterSlime = createMeleeBaseNPC();
BaseEnemyConfig config = configs.xenoGrunt;
ArrayList<Melee> melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick));
// tester projectiles
ArrayList<ProjectileConfig> projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall));
ArrayList<Currency> drops = new ArrayList<>();
waterSlime
.addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles))
.addComponent(animator)
.addComponent(new WaterSlimeAnimationController());
public static Entity createSplittingWaterSlime() {
Entity splitWaterSlime = createBaseWaterSlime()
.addComponent(new SplitMoblings(7, 0.5f));
return splitWaterSlime;
}
Animations for Water Slime:
Arcane Archer is able to dodge incoming projectiles by moving up or down the map.
public static Entity createArcaneArcher(int health) {
Entity coat = createBaseNPC();
ArrayList<Currency> drops = new ArrayList<>();
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/mobs/arcane_archer.atlas", TextureAtlas.class));
animator.addAnimation("arcane_archer_run", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("arcane_archer_attack", 0.1f);
animator.addAnimation("arcane_archer_death", 0.1f);
animator.addAnimation("arcane_archer_dodge", 0.1f);
animator.addAnimation("default", 0.1f);
AITaskComponent aiTaskComponent = new AITaskComponent()
.addTask(new MobTask(MobType.ARCANE_ARCHER));
coat
.addComponent(new CombatStatsComponent(health, 0, drops))
.addComponent(animator)
.addComponent(new ArcaneArcherAnimationController())
.addComponent(aiTaskComponent);
coat.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM);
coat.getComponent(AnimationRenderComponent.class).scaleEntity();
return coat;
}
public static Entity createDodgingArcaneArcher(int health) {
Entity dodgeKnight = createArcaneArcher(health);
dodgeKnight.addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f));
// dodgeKnight.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector2(2f, 2f), 2f, 5));
dodgeKnight.getComponent(AITaskComponent.class).
addTask(new MobDodgeTask(MobType.DRAGON_KNIGHT, 5));
PhysicsUtils.setScaledCollider(dodgeKnight, 0.3f, 0.7f);
dodgeKnight.setScale(0.3f, 0.7f);
return dodgeKnight;
}
Animation for Arcane Archer:
This function will build upon the createMeleeBaseNPC()
function and adds the specific animation. DragonKnight is able to dodge projectiles using createDodgingDragonKnight()
.
Entity dragonKnight = createMeleeBaseNPC();
BaseEnemyConfig config = configs.xenoGrunt;
ArrayList<Melee> melee = new ArrayList<>(Arrays.asList(PredefinedWeapons.sword, PredefinedWeapons.kick));
// tester projectiles
ArrayList<ProjectileConfig> projectiles = new ArrayList<>(Arrays.asList(PredefinedWeapons.fireBall, PredefinedWeapons.frostBall));
ArrayList<Currency> drops = new ArrayList<>();
dragonKnight
.addComponent(new CombatStatsComponent(config.fullHeath, config.baseAttack, drops, melee, projectiles))
.addComponent(animator)
.addComponent(new DragonKnightAnimationController());
public static Entity createDodgingDragonKnight() {
Entity fireWorm = createDragonKnight();
fireWorm.addComponent(new DodgingComponent(PhysicsLayer.PROJECTILE, 0.25f));
fireWorm.getComponent(AITaskComponent.class).addTask(new MobDodgeTask(new Vector2(2f, 2f), 2f, 5));
return fireWorm;
}
Animations for DragonKnight:
Deflecting FireWizard is one of the special feature mobs of the fire planet.
public static Entity createFirewizard(int health) {
Entity Firewizard = createBaseNPC();
ArrayList<Currency> drops = new ArrayList<>();
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/mobs/firewizard.atlas", TextureAtlas.class));
animator.addAnimation("firewizard_move", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("firewizard_attack", 0.1f);
animator.addAnimation("firewizard_death", 0.1f);
animator.addAnimation("default", 0.1f);
AITaskComponent aiTaskComponent = new AITaskComponent()
.addTask(new MobTask(MobType.FIREWIZARD));
Firewizard
.addComponent(new CombatStatsComponent(health, 0, drops))
.addComponent(animator)
.addComponent(new FirewizardAnimationController())
.addComponent(aiTaskComponent);
Firewizard.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM);
Firewizard.getComponent(AnimationRenderComponent.class).scaleEntity();
return Firewizard;
}
public static Entity createDeflectFireWizard(int health) {
Entity deflectWizard = createFirewizard(health);
deflectWizard.addComponent(new DeflectingComponent(
PhysicsLayer.PROJECTILE, PhysicsLayer.TOWER, 10));
return deflectWizard;
}
Animation for FireWizard:
Split Rocky is one of the special feature mobs of the fire planet.
public static Entity createRocky(int health) {
Entity coat = createBaseNPC();
ArrayList<Currency> drops = new ArrayList<>();
AnimationRenderComponent animator =
new AnimationRenderComponent(
ServiceLocator.getResourceService().getAsset("images/mobs/rocky.atlas", TextureAtlas.class));
animator.addAnimation("rocky_move", 0.1f, Animation.PlayMode.LOOP);
animator.addAnimation("rocky_attack", 0.1f);
animator.addAnimation("night_borne_death", 0.1f);
animator.addAnimation("default", 0.1f);
AITaskComponent aiTaskComponent = new AITaskComponent()
.addTask(new MobTask(MobType.NIGHT_BORNE));
coat
.addComponent(new CombatStatsComponent(health, 0, drops))
.addComponent(animator)
.addComponent(new RockyAnimationController())
.addComponent(aiTaskComponent);
coat.getComponent(HitboxComponent.class).setAsBoxAligned(new Vector2(.3f, .5f), PhysicsComponent.AlignX.RIGHT, PhysicsComponent.AlignY.BOTTOM);
coat.getComponent(AnimationRenderComponent.class).scaleEntity();
return coat;
}
public static Entity createSplittingRocky(int health) {
Entity splitRocky = createRocky(health)
.addComponent(new SplitMoblings(MobType.ROCKY, 7, 0.5f));
return splitRocky;
}
Animations for Rocky: