How would I make ellipses move from an image to a moving square?

@Chrisir, How would I make bullets shoot automatically from a tower to an enemy to kill it?

Code so far:

Wave w;

PImage map, 
  enemy1, enemy1dead, 
  enemy2, enemy2dead, 
  enemy3, enemy3dead, 
  enemy4, enemy4dead;


PImage[] towerSprites;

final int cellSize = 60;

ArrayList<Tower> allTowers = new ArrayList<Tower>();
ArrayList<Projectile> projectiles = new ArrayList();

int cols = 15;
int rows = 8;

int time;

Map[][] grid = new Map[cols][rows];

// -----------------------------------------------------------------------

void setup() {

  size(900, 600);

  w = new Wave();

  time = millis() + 500;

  enemy1 = loadImage("enemy1.png");
  enemy2 = loadImage("enemy2.png");
  enemy3 = loadImage("enemy3.png");
  enemy4 = loadImage("enemy4.png");

  enemy1dead = loadImage("enemy1dead.png");
  enemy2dead = loadImage("enemy2dead.png");
  enemy3dead = loadImage("enemy3dead.png");
  enemy4dead = loadImage("enemy4dead.png");

  map = loadImage("map.png");
  map.resize(900, 600);

  towerSprites = new PImage[] {
    loadImage("tower1.png"), 
    loadImage("tower2.png"), 
    loadImage("tower3.png"), 
    loadImage("tower4.png"), 
    loadImage("tower5.png")
  };

  // important function: 
  makeGrid() ;
}

//-----------------------------------------------------------

void makeGrid() {

  // gridData is local  
  int[][] gridData = 
    {
    //0 1  2  3  4  5  6  7  8  9  10 11 12 13 14
    {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1}, //0
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //1
    {0, 1, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //2
    {0, 0, 2, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0}, //3
    {0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2}, //4
    {2, 2, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0}, //5
    {0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0}, //6
    {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //7
  };


  for (int x = 0; x < cols; x++) {
    for (int y = 0; y < rows; y++) {
      int type = gridData[y][x]; 
      grid[x][y]=new Map(x * cellSize, y *  cellSize, type);
    }
  }
}

void draw() {

  // background(0);
  image(map, 0, 0);

  fill(255);
  rect(0, 481, 900, 120);

  //println ((int)mouseX/60, (int)mouseY/60);
  //println(mouseX, mouseY);

  w.updateWave();

  for (int x = 0; x<cols; x++) {
    for (int y = 0; y<rows; y++) {

      //  grid[x][y].gridAvailabilityCheck();
      grid[x][y].outlineMe();
      grid[x][y].outlineMe2();
      //   grid[x][y].buildable();
      // grid[x][y].buildOn(t);
      // grid[x][y].mousePressed();
    }
  }//for

  for (int i = 0; i < allTowers.size(); i ++) {
    if (allTowers.get(i)!=null)
      allTowers.get(i).drawMe();
  }

  for (int j = 0; j < w.enemyWave.size(); j ++)
  {
    for (int i =  0; i < projectiles.size(); i ++) 
    {
      Enemy e = w.enemyWave.get(j);

      Projectile p = projectiles.get(i);

      p.step();

      if (p.px >= 900 || p.px <= 0 || p.py >= 600 || p.py <= 0) {
        projectiles.remove(i);
      }

      if (dist(p.px, p.py, e.pos.x, e.pos.y) < 1) {
        projectiles.remove(i);
        w.enemyWave.remove(j);
      }
    }
  }

  if (millis() > time) {
    time = millis() + 50;
    projectiles.add( new Projectile());
  }
}


// ----------------------------------------------------------

void mousePressed() {
  for (int x = 0; x < cols; x++) {
    for (int y = 0; y < rows; y++) {
      grid[x][y].mousePressed();
    }
  }
}
//

class Enemy {

  PVector pos;
  float size;
  int health;
  float speed;

  int index = 0;

  boolean alive;

  Enemy(float x, float y) {
    pos = new PVector(x, y); 
    size = 25;
    health = 100;
    speed = 1;
    alive = true;
  }

  void move(float targetX, float targetY) {

    if (targetX - pos.x > 0)
      pos.x += speed;
    else if (targetX - pos.x < 0)
      pos.x -= speed;
    else if (targetY - pos.y > 0)
      pos.y += speed;
    else if (targetY - pos.y < 0)
      pos.y -= speed;

    image(enemy1, pos.x - 15, pos.y - 15, size, size);
  }
  //
} // class
//

class Map {

  // ONE CELL in the grid 

  boolean occupant = false;
  float x, y; 
  int type;

  // constructor 
  Map( float xTemp, float yTemp, 
    int typeTemp) {
    x = xTemp;
    y = yTemp;
    type = typeTemp;
  } // constructor 

  void outlineMe() {
    if (over()) {
      noFill();

      if (type == 0)
        stroke(#00FF00); // green
      else stroke(255, 0, 0); // red

      // noStroke(); 
      rect(x, y, 
        cellSize, cellSize);
    }
  }

  void outlineMe2() {

    noFill();
    stroke(#00FF00); // green 
    // noStroke(); 
    // rect(x, y,  cellSize, cellSize);
    fill(0, 0, 255);
    text(type, x+cellSize/2, y+cellSize/2);
  }

  boolean buildable() {
    if (!occupant && type==0)
      return true;
    else
      return false;
  }

  void buildOn(Tower t) {
    if (over()&&buildable()) {
      occupant = true;
      allTowers.add(t);
    }
  }

  void mousePressed() {
    if (over()&&buildable()) {
      buildOn(new Tower(x + cellSize/2, y + cellSize/2, 0));
    }
  }//method

  boolean over() {
    return (mouseX > x && 
      mouseX < x + cellSize && 
      mouseY > y &&
      mouseY < y + cellSize);
  }//method
  //
}//class 
//

class Projectile {

  Tower t;

  float px, py, vx, vy;

  Projectile() {

    px = mouseX;
    py = mouseY;

    for (int i = 0; i < w.enemyWave.size(); i ++)
    {
      Enemy e = w.enemyWave.get(i);

      float a = atan2(e.pos.y-height/2, e.pos.x-width/2);

      vx = 10 * cos(a);
      vy = 10 * sin(a);
    }
  }

  void step() {
    px += vx;
    py += vy;

    ellipse(px, py, 10, 10);
  }
}
//

class Tower {

  float cellX;
  float cellY;

  int spriteIndex;

  Tower(float x, float y, int sprite) {
    cellX = x;
    cellY = y;
    spriteIndex = sprite;
  }

  void drawMe() {
    if (towerSprites[spriteIndex]!=null) {
      // image is OK
      image(towerSprites[spriteIndex], 
        cellX - 20, cellY - 25, 
        cellSize - 15, cellSize - 10);
    } else {
      // image is not OK, we show some text 
      println("image is not OK, we show some text");
      fill(255, 1, 1); // red
      ellipse(cellX, cellY, 11, 11 );
      text(spriteIndex, 
        cellX, cellY );
    }
  }
}//class

class Wave {

  PVector[] targetArray;

  ArrayList<Enemy> enemyWave = new ArrayList();

  Wave() {
    createWave();

    targetArray = new PVector[6];
    targetArray[0] = new PVector(150, 150);
    targetArray[1] = new PVector(330, 150);
    targetArray[2] = new PVector(330, 390);
    targetArray[3] = new PVector(570, 390);
    targetArray[4] = new PVector(570, 270);
    targetArray[5] = new PVector(901, 270);

    //  setIsThereFalse();
  } 

  void createWave() {
    for (int i = 5; i >= 0; i--) {
      Enemy e = new Enemy(i * 40 - 200, 330);
      enemyWave.add(e);
    }
  }

  void setIsThereFalse() {
    for (int i = 0; i < 6; i ++) {
      // isThere[i] = false;
    }
  }

  void updateWave() {

    // we loop backward 
    for (int i = enemyWave.size()-1; i>=0; i--)
    {
      Enemy e = enemyWave.get(i);

      // we move to current target step by step 
      e.move(targetArray[e.index].x, targetArray[e.index].y);

      // when we reached target
      if (dist(e.pos.x, e.pos.y, targetArray[e.index].x, targetArray[e.index].y) < 1) {
        // init next target 
        e.index++;
      } // if   

      // if last target, we kill enemy
      if (dist(e.pos.x, -1, 901, -1) < 2) {
        enemyWave.remove(i);
      }
    }//for

   /* for (int i = 0; i < w.enemyWave.size(); i ++)
    {
      Enemy e = w.enemyWave.get(i);

      pushMatrix();
      fill(255);
      translate(width/2, height/2);
      float a = atan2(e.pos.y-height/2, e.pos.x-width/2);
      rotate(a);
      rect(0, 0, 50, 10);
      popMatrix();
    }//for */
  }//method
  //
} // class Wave
//
Tagged:

Answers

  • Here's some automatic shooting:

    int time;
    
    class Shot {
      float px,py,vx,vy;
      Shot(){
        px=mouseX;
        py=mouseY;
        float a = random(TWO_PI);
        vx=5*cos(a);
        vy=5*sin(a);
      }
      void step(){
        px+=vx;
        py+=vy;
        ellipse(px,py,10,10);
      }
    }
    
    ArrayList<Shot> shots = new ArrayList();
    
    void setup(){
      size(200,200);
      time = millis() + 500;
    }
    
    void draw(){
      background(128);
      for( Shot s : shots) s.step();
      if( millis() > time ){
        time = millis() + 500;
        shots.add( new Shot() );
      }
    }
    

    Just set the velocity of the projectiles so that it follows the line from the tower to what you want to shoot. Assuming your enemy target is not moving too fast, it should hit...

  • @TfGuy44, I did that, check my code.

  • You lost me. The code you have posted is like, 400 lines long. Does it have automatic shooting or not? Do you understand how to use a timer to determine if it is time to do another automatic shot, as my example demonstrates?

  • @TfGuy44, Yes I do, but I want it to shoot from any tower I place.

  • Yes.

    You can’t assume people will do that for you.

    Instead understand the principle of what TfGuy postef for you. Change the code to change its behavior and really work with it so you fully understand it.

    Then don’t copy it but apply the ideas to your own sketch. Only that way you will learn.

  • @Chrisir @TfGuy44, I understand all of that, I have the code done, I just don't know how to make it so when I place a tower, it can shoot the first enemy and kill it.

  • You have a turret already that’s aiming at on the wave of enemies

    You need to merge this turret into the tower class so it’s using the tower‘s position

  • You get bits and pieces from the forum but you don’t take your time to think it through

  • I take too much of my time thinking it through, but I never really get the right answer.

  • @Chrisir, how would I make the px, and py from the Projectile class become the tower's position?

  • So the bullets shoot from the tower

  • That’s easy!!

    Make the projectiles be fired from the tower.

    On firing copy the tower position into the new projectile

  • edited December 8

    So the bullets shoot from the tower...

    Make it so that your class Tower has its own List of Projectile objects. *-:)

  • Hmmmm. You could do it that way, but it might complicate the bullets themselves dealing damage to enemies. I would just dump all the bullets into one ArrayList:

    class Bullet {
      PVector p, v;
      Bullet( float ipx, float ipy ) {
        p = new PVector( ipx, ipy, 0 );
        float a = atan2(mouseY-ipy, mouseX-ipx );// random( TWO_PI );
        v = new PVector( 5*cos(a), 5*sin(a), 0 );
      }
      boolean draw() {
        p.add( v );
        fill( 255 );
        noStroke();
        ellipse( p.x, p.y, 10, 10 );
        return( !on_screen() );
      }
      boolean on_screen() {
        return( p.x > -20 && p.x < width + 20 && p.y > -20 && p.y < height + 20 );
      }
    }
    
    class Tower {
      float px, py;
      int time;
      Tower( float ipx, float ipy ) {
        px = ipx;
        py = ipy;
        new_time();
        time += random(500); // Mix it up a bit.
      }
      void new_time() {
        time = millis() + 500;
      }
      void draw() {
        fill( 0, 0, 255 );
        stroke( 0 );
        triangle( px, py, px+5, py+10, px-5, py+10 );
        if ( millis() > time ) {
          new_time();
          bullets.add( new Bullet( px, py ) ); // Create new bullet at this tower's position.
        }
      }  
    }
    
    ArrayList<Bullet> bullets = new ArrayList();
    
    Tower t0 = new Tower( 100, 100 );
    Tower t1 = new Tower( 100, 300 );
    Tower t2 = new Tower( 300, 300 );
    Tower t3 = new Tower( 300, 100 );
    
    void setup() {
      size( 400, 400 );
    }
    
    void draw() {
      background( 0 );
      for ( int i = bullets.size() - 1; i >= 0; i-- ) if ( bullets.get(i).draw() ) bullets.remove(i);
      t0.draw();
      t1.draw();
      t2.draw();
      t3.draw();
      stroke( 255, 0, 0 );
      noFill();
      ellipse( mouseX, mouseY, 20, 20 );
      ellipse( mouseX, mouseY, 40, 40 );
      line( mouseX - 30, mouseY, mouseX + 30, mouseY );
      line( mouseX, mouseY - 30, mouseX, mouseY + 30 );
    }
    
    void mousePressed() {
      //bullets.add( new Bullet() );
    }
    

    But that's just me.

  • @TfGuy44, I see what you are saying but I don't want the towers already placed, I want it so when you click on an open cell a tower is made and then shoots at the enemies to kill them.

  • edited December 10

    Potterhouse : Yes, you have to combine TfGuys code with yours. TfGuy was only talking about the bullets, not about the tower placement.

  • edited December 10

    These are your goals

    (No, this is not homework, he is doing it as an exercise)

    These are the goals for this game:

    • Create a Map class that displays a map image. Your map class should contain a list of turrets, handle mouse input and the placement of the turrets.

    • Create an Enemy class that will move according to a target.

    • Create a Wave class that contains an arraylist of Enemies and updates their health and movement according to the map’s path. This class will also remove any dead enemies from the list.

    • Create a Turret class that can be placed in any open spot on the map and will rotate to and fire upon any enemy within range.

    • Create a projectile class that is shot in the direction of an enemy close by. It is removed if it collides with an enemy or goes beyond the boundaries of the screen. It will decrease the health points of the enemy shot.

    • Create multiple (instances of) waves of enemies.

    It might help you to draw a plan of the dependencies :

    • 2D arrays of class Map (which is in fact a Cell of the grid, rename it)

    • Cell should contain class turret (because each cell can have a turret and there are no turrets outside a cell. The turrets depend from the cell)

    • Don't have a separate ArrayList for the turrets, it's enough to store them in the class Cell

    • ArrayList with projectiles can be independent and be filled by all turrets as TfGu suggested

    • Map class is missing: it shows the image etc. - but not important right now

    Make a plan

    Without a concept, a plan you are lost.

    So make a plan. Your class list above is a first step but you need to make each step more precise.

    Now. In the moment you go through all cells to display them each cell can tell its turret / tower to do its action. (Remember that the projectiles are in a separate ArrayList as shown by TfGuy.) What is the action of a turret? Turn into the right direction and fire (which means to add a new bullet to the common ArrayList of all turrets):

      if ( millis() > time ) {
          new_time();
          bullets.add( new Bullet( px, py ) ); // Create new bullet at this tower's position.
        }
      }  
    

    This belongs into the turret class. And the variables like time as well.

    Now for the direction of the shooting: each turret locks on a target (enemy) and rotates to follow it (see code by gotoloop). And shoots like above. Now when the turret doesn't have a target you loop over all enemy waves and enemies therein to see which enemy is not shot at. The first enemy that is not shot at becomes the turrets target. So the class Enemy needs a boolean IamBeingShotAtRightNow=false; which you set to true when a turret locks onto it. When the enemy is dead or reached target, or is removed the turret needs to register that and search a new target. The turret needs a variable boolean lockedOnTarget=false; - set it to true when the turret found an enemy.

    When the turret doesn't find an enemy that is not shot at it can just shot on any random enemy or do nothing.

    Also, you could say each bullet can fly only 70 pixels, then they die. That means the range of the weapon is only 70 pixels. That would make the targeting of the turrets more interesting since the enemies must be in range of the turret. When a enemy leaves the range and is not dead, lockedOnTarget=false; for the turret and IamBeingShotAtRightNow=false; for the enemy.

    The enemy needs a health counter and if its get hit, health points are removed from the health, if(health<=0) he dies.

    Chrisir

  • (No, this is not homework, he is doing it as an exercise)

    it appears that YOU are doing it as an exercise.

  • Answer ✓

    That's a true remark.... ;-)

  • @Koogs, Chrisir is correct.

  • So how do you like the new version I sent you via email?

  • //version via e mail//

    same thing as the code I just sent you...

    ??

    man, first you can select a tower from the 5 towers below now!

    there is a green frame around a selected tower! i can't believe you haven't made a class for this. instead you have written multiple similar values as numbers in the code which is very bad. what are you learning from all this when you haven't made a class?!

    second: you can drag towers now from field to field. haven't you seen this??

    do you read my code at all?

    chrisir ;-)

Sign In or Register to comment.