Skip to content

NPC Factory

Isaac Arli edited this page Oct 17, 2023 · 26 revisions

Introduction

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 image

UML Diagram: NPC

Base melee mob function createMeleeBaseNPC()

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;

Base range mob function createRangedBaseNPC()

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;

Creating Fireworm createFireworm()

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: Attack Walk Death

Creating Wizard createWizard()

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: Attack2 Run Death

Creating Coat createCoat()

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;
  }

Fullmain

Creating WaterQueen createWaterQueen()

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:

03_surf 08_2_atk 14_death

Creating Skeleton createSkeleton()

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:

Skeleton enemy

Creating Necromancer createNecromancer()

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;
}

Necromancer_creativekind-Sheet

Special Feature Mobs

Creating NightBorne createNightBorne()

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));
  }

NightBorne

Creating WaterSlime createBaseWaterSlime()

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: slime-move-0 slime-move-1 slime-move-2 slime-move-3 slime-die-0 slime-die-1 slime-die-2

Creating Dodging Arcane Archer createDodgingArcaneArcher()

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: spritesheet

Creating DragonKnight createDragonKnight()

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:

dragon_knight_run dragon_knight_attack_1 dragon_knight_death

Creating Deflecting FireWizard createFirewizard()

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: Attack Death Move

Creating Split Rocky createSplitRocky()

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:

fire_split_move5 fire_split_move4 fire_split_move3 fire_split_move1

Clone this wiki locally