Presentation and first question about arraylist and inheritance

Hello, how are you, I’m new here.

I would like to learn how to use processing correctly so I can create my own games and become a good programmer.

At the moment I have not programmed any games, I am trying to create a small base so that each object inherits from it and it is easier to create games.

I have two databases, one with arraylist and the other with hashmap but I don’t know if I am doing it correctly and that is why I have registered in this forum to be able to learn everything I can.

I’m going to show the code I have to see if I’m on the right track or if something needs to be changed. I already asked this in the processing forum but the answer was not very clear.

The code that I am going to show has a parent class that is responsible for managing a list where the objects will be added and a method to execute the draw method and another to delete objects.

The player class shows a ship that moves and can fire bullets by pressing the z button and the bullet class moves up and is eliminated when leaving the screen.

//prueba de veracidad

void settings(){
  size(640,480);
  noSmooth();
}

void setup(){
  frameRate(60);
  background(85,106,206);
  new Jugador();
}

void draw(){
  background(85,106,206);
  Padre.draw_all();
}
//clase disparo-----------------------------------
class Disparo extends Padre{
  private float x,y,velocidad;
  private PImage grafico = loadImage("disparo.png");
  
  public Disparo(float x,float y){
    super();
    imageMode(CENTER);
    this.x = x;
    this.y = y;
    this.velocidad = 5;
  }
  
  public void draw(){
    mover();
    eliminar();
    image(grafico,x,y);
  }
  
  private void mover(){
    y -= velocidad;
  }
  
  private void eliminar(){
    if(y < 64){
      live = false;
      kill();
    }
  }
  
} //fin clase disparo---------------------------------
//clase jugador--------------------------------------
class Jugador extends Padre{
  private float x,y,velocidad;
  private PImage grafico = loadImage("jugador.png");
  private int contador; 
  
  public Jugador(){
    super();
    imageMode(CENTER);
    this.x = 320;
    this.y = 400;
    this.velocidad = 5;
    this.contador = 0;
  }
  
  public void draw(){
    mover();
    disparar();
    image(grafico,x,y);
  }
  
  private void mover(){
    if(keyPressed && key == CODED && keyCode == LEFT){
      x -= velocidad;
    }else if(keyPressed && key == CODED && keyCode == RIGHT){
      x += velocidad;
    }
    
    if(keyPressed && key == CODED && keyCode == UP){
      y -= velocidad;
    }else if(keyPressed && key == CODED && keyCode == DOWN){
      y += velocidad;
    }
  }
  
  private void disparar(){
    contador++;
    if(keyPressed && key == 'z' && contador > 5){
      new Disparo(x,y); 
      contador = 0;
    }
  }

} //fin clase jugador------------------------------------
//clase padre-----------------------------------
static class Padre{
  private static ArrayList<Padre> lista = new ArrayList<Padre>();
  public boolean live = true;
  
  public Padre(){
    lista.add(this);
  }
  
  public void draw(){
  }
  
   public static void draw_all(){
    for(int indice = lista.size()-1;indice >= 0;indice--){
      Padre padre = lista.get(indice);
      padre.draw();
    }
  }
  
  public void kill(){
    for(int indice = lista.size()-1;indice >= 0;indice--){
      Padre padre = lista.get(indice);
      if(padre.live == false){
        lista.remove(indice);
      }
    }
  }

} //fin clase padre------------------------------

Does your code work, or do you get an error?

My first thought is that I’m not sure what you’re getting from having everything extend from the Padre class, and it feels a little unwieldy to maintain a static list of instances inside the class.

But if it works and it makes sense to you, that’s what matters the most!

The code works and you can check it by changing the graphics to squares or circles.

The classes inherit from the parent class to be able to use the draw method and later I would add new methods and some variables to use in the classes that inherit from it.

It doesn’t really make sense to me, I just asked in a forum on bliztmax about how to create an abstraction layer and better organize my code and they showed me this way to do it.

Since I want to learn how to do things correctly, I have entered this forum to see if they can teach me or help me.

That’s the fascinating (and sometimes) frustrating thing about code: there isn’t really one “correct” way to do any particular thing. There are a ton of different ways to do everything, and choosing an approach is often more subjective than you might expect.

I wrote a little bit about this here:

In the end, I think the most important thing you can do is make sure your code is easy for you to understand it. I wouldn’t add a ton of abstraction just for the sake of adding it, but if it makes it easier for you to think about your code, then that’s great!

Very interesting article. :slightly_smiling_face:

If you feel like it, I would like you to take my code and adapt it to how you would do it, it is to learn something new since I am always trying to learn new things.

Sure, I can try refactoring it a bit. But keep in mind that just because I might do something differently, doesn’t mean it’s better than what you’re already doing!

Can you post the image files disparo.png and jugador.png that you use in your code so I can run it?

disparo
jugador

Here’s my attempt at refactoring your code to be closer to how I would personally approach it:

Jugador jugador;
ArrayList<Disparo> disparos;

PImage jugadorGrafico;
PImage disparoGrafico;

void setup() {

  jugadorGrafico = loadImage("jugador.png");
  disparoGrafico = loadImage("disparo.png");

  size(640, 480);
  noSmooth();
  imageMode(CENTER);

  jugador = new Jugador();
  disparos = new ArrayList<Disparo>();
}

void draw() {
  background(85, 106, 206);

  jugador.draw();

  for (Disparo disparo : disparos) {
    disparo.draw();
  }

  killOldDisparos();
}

void killOldDisparos() {
  for (int indice = disparos.size()-1; indice >= 0; indice--) {
    Disparo disparo = disparos.get(indice);
    if (!disparo.live) {
      disparos.remove(indice);
    }
  }
}


class Jugador {
  private float x, y, velocidad;
  private int contador;

  public Jugador() {
    super();
    
    this.x = 320;
    this.y = 400;
    this.velocidad = 5;
    this.contador = 0;
  }

  public void draw() {
    mover();
    disparar();
    image(jugadorGrafico, x, y);
  }

  private void mover() {
    if (keyPressed && key == CODED && keyCode == LEFT) {
      x -= velocidad;
    } else if (keyPressed && key == CODED && keyCode == RIGHT) {
      x += velocidad;
    }

    if (keyPressed && key == CODED && keyCode == UP) {
      y -= velocidad;
    } else if (keyPressed && key == CODED && keyCode == DOWN) {
      y += velocidad;
    }
  }

  private void disparar() {
    contador++;
    if (keyPressed && key == 'z' && contador > 5) {
      disparos.add(new Disparo(x, y));
      contador = 0;
    }
  }
}


class Disparo {
  public boolean live = true;
  private float x, y, velocidad;

  public Disparo(float x, float y) {
    this.x = x;
    this.y = y;
    this.velocidad = 5;
  }

  public void draw() {
    mover();
    eliminar();
    image(disparoGrafico, x, y);
  }

  private void mover() {
    y -= velocidad;
  }

  private void eliminar() {
    if (y < 64) {
      live = false;
    }
  }
}

The main change I made was to get rid of the Padre class. In theory, inheritance can be useful, especially if you have many classes with hierarchical behavior. But in your case, your Jugador player class and your Disparo shot class only have a couple of things in common, so I’d probably keep them separate in my logic. Without the Padre class, my version is a little more explicit about what code deals with the player and what code deals with the shots.

I also made a couple minor tweaks like moving the image loading into setup(), that way you aren’t loading the same image file every time you fire a shot.

If it were my code, I would probably go a step further and move the key press handling code to be at the sketch level rather than being inside the Jugador class.

This is how I would personally approach it, but your way also works fine, so if that’s how it fits in your brain, that’s great! Your approach would probably pay off in a more complicated codebase, for example if you started adding multiple types of game objects that all had the same core logic. I’d probably still keep the player separate from that list though.

Let me know if that makes sense!

1 Like

Thank you very much for the help and for taking the trouble to refactor my code, code that has given me some ideas to improve mine. :slightly_smiling_face: :+1:

I think that if I use keypressed in the setup I would have separate code from the player class and that could be problematic if my code was very large, that’s why I prefer to keep the code of each object in its own class to make it easier to search and understand .

I’m going to start programming my first game and I will surely have some questions in the process, when the time comes I will create another thread to continue with more questions.

1 Like