Ranged Enemy Projectiles - UQdeco2800/2022-studio-1 GitHub Wiki

Link back to main page

Spawning of Projectile

The current implementation to spawn a ranged enemy projectile can be found in the shoottask.java and the projectileFactory.java classes. Firstly the creation of a ranged enemy has been changed to include a new AI task, shooting. This is similar to previous tasks but has additional implementation.

private static Enemy createBaseRangeNPC(Entity target, Entity crystal) {
    //Vector2 RangeHitbox = new Vector2(2f, 1f);
    AITaskComponent aiComponent =
            new AITaskComponent()
                    .addTask(new WanderTask(new Vector2(3f, 3f), 2f))
                    .addTask(new RangedMovementTask(crystal, 10, 2f, 50f, 60f))
                    .addTask(new RangedMovementTask(target, 20, 2f, 50f, 60f))
                    .addTask(new MeleeAvoidObstacleTask(target))
                    .addTask(new ShootTask(target, 30, 50f, 60f))
                    .addTask(new ShootTask(crystal, 30, 50f, 60f));
    Enemy enemy =
            (Enemy) new Enemy()
                    .addComponent(new PhysicsComponent())
                    .addComponent(new PhysicsMovementComponent())
                    .addComponent(new ColliderComponent())
                    .addComponent(new HitboxComponent().setLayer(PhysicsLayer.RangeNPC))
                    .addComponent(new TouchAttackComponent(PhysicsLayer.RangeNPC))
                    .addComponent(aiComponent);

    PhysicsUtils.setScaledCollider(enemy, 0.9f, 0.4f);
    return enemy;
  }

The Shoot task includes a time check to periodically check if it is time to create a new projecitle entity, This task has a range similar to the movement tasks to ensure that the enemy does not constantly spawn projectiles.

Shoot Task

public ShootTask(Entity target, int priority, float viewDistance, float maxChaseDistance) {
        this.target = target;
        this.priority = priority;
        this.maxChaseDistance = maxChaseDistance;
        this.GameTime = ServiceLocator.getTimeSource();
        this.viewDistance = viewDistance;
        physics = ServiceLocator.getPhysicsService().getPhysics();
        debugRenderer = ServiceLocator.getRenderService().getDebug();
    }

    @Override
    public void start() {
        super.start();
        System.out.println("start shooting");
        taskEnd = GameTime.getTime() + (int)(1 * SECOND);
        System.out.println(taskEnd);
    }

    @Override
    public void update() {
        Entity entity = this.owner.getEntity();
        System.out.println(taskEnd);
        System.out.println(GameTime.getTime());
        if (GameTime.getTime() >= taskEnd) {
            System.out.println("shoots");
            ProjectileFactory.createProjectile(entity, target);
            taskEnd = GameTime.getTime() + (int)(SECOND);
        }
        System.out.println(entity.getPosition());
        System.out.println("1");
        System.out.println(target.getPosition());
        System.out.println("2");
    }

The below code is the projectileFactory code. Every time the shooting task updates and the current time has passed the update threshold, a new projectile is made. This involves calculating the target of the projectile and creating an entity that will act as the projectile and setting movement characteristics to the entity.

public static Entity createProjectile(Entity shooter, Entity target) {
        Vector2 targetNew = target.getPosition();
        return makeProjectile(targetNew, shooter);
    }

    private static Entity makeProjectile(Vector2 destination, Entity source) {
        Entity projectile = new Entity()
                .addComponent(new TextureRenderComponent("images/Eel_Bright_SW.png"))
                .addComponent(new PhysicsComponent())
                .addComponent(new PhysicsMovementComponent())
                .addComponent(new ColliderComponent())
                .addComponent(new HitboxComponent().setLayer(PhysicsLayer.NPC))
                .addComponent(new CombatStatsComponent(1,5))
                .addComponent(new EntityClassification(EntityClassification.NPCClassification.ENEMY))
                .addComponent(new TouchAttackComponent(PhysicsLayer.PLAYER, 0.2f));

        projectile.getComponent(PhysicsMovementComponent.class).setTarget(destination);
        projectile.getComponent(PhysicsMovementComponent.class).setMoving(true);
        projectile.getComponent(ColliderComponent.class).setSensor(true);

        projectile.setPosition(source.getPosition());
        PhysicsUtils.setScaledCollider(projectile, 2f, 2f);

        ServiceLocator.getEntityService().registerNamed("Enemy@" + projectile.getId(), projectile);
        return projectile;
    }