Search code examples
javascriptanimationrotationp5.jspath-finding

Enemy detection and turret animation/control in a JavaScript p5.js game


I'm making a tower defense game using JavaScript and p5.js library. My enemy follows a path and their location is always stored in a list. I have a base and a gun, the gun rotates around the base(as 1 unit) and is supposed to point towards the nearest enemy. I have a function that will allow me to make the gun point towards the enemy pointEnemy however, I'm not able to get the correct condition to make it point towards the nearest enemy in it's range. I need the correct argument for enemyx & enemyy. I'm currently spawning 100 enemies and they keep moving, their location is stored in globalenemy1position. Any help is appreciated, thank you.


Required Code


Some important variables

var numberOfEnemy1 = 100
let classenemy1 = new Enemy1(numberOfEnemy1);
var globalenemy1position = [];   
var isFireTowerPressed = false;
var FireTowerPos = [];    // Position of all FireTowers => [x,y]
var FireTowerRange = 300;
var FireTowerAngle = 0;

My Enemy Class

class Enemy1
{
    constructor(number_of_enemies)
    {
        this.number_of_enemies = number_of_enemies;
        this.enemy_position = [];
        this.enemy1speed = 4;

    }
    enemy1_spawn()
    {
        let randomx = random(-300, -100);
        for(var i=0; i<this.number_of_enemies; i++)
        {
            var positionx = randomx;
            var positiony = 100;

            this.enemy_position.push([positionx + (-i*50), positiony]);
            globalenemy1position.push([positionx + (-i*50), positiony]);
            image(enemy1, this.enemy_position[i][0], this.enemy_position[i][1]);
        }

    }

    enemy1_move()
    {
        for(var i = 0; i < this.enemy_position.length; i++)
        {
            image(enemy1, this.enemy_position[i][0], this.enemy_position[i][1]);

            if (this.enemy_position[i][0] >= 200 && this.enemy_position[i][1] <= 450 && this.enemy_position[i][0] < 599)
            {
                this.enemy_position[i][1] += this.enemy1speed;
                globalenemy1position[i][1] += this.enemy1speed;
            }   

            else if (this.enemy_position[i][1] >= 100 && this.enemy_position[i][0] >= 600)
            {
                this.enemy_position[i][1] -= this.enemy1speed;
                globalenemy1position[i][1] -= this.enemy1speed;
            }

            else if (this.enemy_position[i][0] >= 750)
            {
                this.enemy_position[i][0] = 750;
                lives --;
                this.enemy_position.shift();
                globalenemy1position.shift();
            }   

            else
            {
                this.enemy_position[i][0] += this.enemy1speed;
                globalenemy1position[i][0] += this.enemy1speed;
            }

        }
    }
}

Draw Function - Redraws Every Frame

function draw() 
{

    background(60, 238, 161);
    [...]
    classenemy1.enemy1_move();
    rect(750, 70, 50, 100);
    ShowLives();
    if (isFireTowerPressed == true) 
    {
        image(firetowerbaseImg, mouseX - 28, mouseY - 28);
        noFill();
        stroke(0,0,0);
        strokeWeight(1);
        circle(mouseX, mouseY, 300);
    }
    for (var i = 0; i < FireTowerPos.length; i++) 
    {
        image(firetowerbaseImg, FireTowerPos[i][0], FireTowerPos[i][1]);

        if (globalenemy1position.length >= 1)
        {
            var gunx = FireTowerPos[i][0] +28;
            var guny = FireTowerPos[i][1]+25;
            var gunrange = FireTowerPos[i][3];

            for (j=0; j<globalenemy1position.length; j++)
            {

                // Need help with this statement here
                pointEnemy(globalenemy1position[j][0], globalenemy1position[j][1], gunx, guny, FireTowerPos[i][2], FireTowerPos[i][3]);
                
            }
        }
        else
        {
            image(firetowerturretImg, FireTowerPos[i][0], FireTowerPos[i][1]-20);
        }
    }
}

Function to make the gun point towards Enemy - I need the proper value for enemyx & enemyy

function pointEnemy(enemyx, enemyy, gunx, guny, gunangle, gunrange)
{
    const isWithinRange = dist(enemyx, enemyy, gunx, guny) < gunrange;
    if(isWithinRange)
    {
        gunangle = atan2(enemyy - guny, enemyx - gunx) + radians(90);
    }
        push();
        translate(gunx, guny);
        // rect(-25, -20, 50, 40) // Draw the gun base
        // ellipse(0, 0, gun.range*2) // display the gun range
        rotate(gunangle);
        image(firetowerturretImg, -28, -45); // Set the offset of the gun sprite and draw the gun
        pop();
}

Here is a picture to help visualise the problem

As you can see, currently I'm just iterating through all the enemies and giving their location, so it's basically pointing to every enemy nearby. Visualise Problem


Updates


1

I tried the approach given by @user3386109 , but wasn't able to implement it, also if possible I want the turret/gun to point towards the enemy till it leaves the range and not always point towards the closest enemy. It should start off with the closest and then keep pointing towards it till it leaves or the enemy dies(position removed from the list), whichever comes first. The function should then restart again and continue the process.


Solution

  • This process is the complete aiming for the tower. Add this to draw and it searches for enemies.

    for (var i = 0; i < FireTowerPos.length; i++) 
    {
        // image(firetowerbaseImg, FireTowerPos[i][0], FireTowerPos[i][1]);
        // pointEnemy(mouseX, mouseY, FireTowerPos[i][0] +28, FireTowerPos[i][1]+25, FireTowerPos[i][2], FireTowerPos[i][3]);
        image(firetowerbaseImg, FireTowerPos[i][0], FireTowerPos[i][1]);
    
        var enemiesInRange = [];
        let firetowerx = FireTowerPos[i][0];
        let firetowery = FireTowerPos[i][1];
        for (var j = 0; j < globalenemy1position.length; j++) 
        {
            var checkDist = dist(globalenemy1position[j][0], globalenemy1position[j][1], firetowerx, firetowery);
            let thisenemyx = globalenemy1position[j][0];
            let thisenemyy = globalenemy1position[j][1];
    
            if (checkDist < FireTowerRange) 
            {
                enemiesInRange.push([thisenemyx, thisenemyy]);
                pointEnemy(enemiesInRange[0][0], enemiesInRange[0][1], FireTowerPos[i][0] +28, FireTowerPos[i][1]+25, FireTowerPos[i][2], FireTowerPos[i][3]);
    
            }
            else
            {
                enemiesInRange.shift();
            }
        }
    }