Problems with hashmap

Hello, I’m going to comment on the code that I’m going to show and then ask the question.

I have a file called parent which has a hashmap and two classes to manage that hashmap.

Then I have a player class and I shoot, the player moves with the keys and while pressing “z” the shot is launched.

The shot moves up and is eliminated when leaving the screen and when it is eliminated the ship will automatically move to the right, the latter is just a test.

The problem is that by pressing “z” only one shot is created and it remains stuck in the position of the ship, when I release it it will move up and be deleted. When I have done it with arralist it creates many shots that move up but with hashmap this does not happen and I don’t know where I have the error.

//prueba de veracidad
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;

private Contenedor contenedor1;

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

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

void draw(){
  background(85,106,206);
  contenedor1.Update();
  contenedor1.Draw();
}
//clase disparo-----------------------------------
public class Disparo extends Padre{
  private PImage grafico = loadImage("disparo.png");
  private Padre jugador;
  
  public Disparo(float x,float y){
    this.id = String.valueOf((int)random(1000));
    this.agregar(this.id,this);
    this.jugador = obtener_id("jugador");
    imageMode(CENTER);
    this.x = x;
    this.y = y;
    this.velocidad = 5;
  }
  
  @Override
  public void Update(){
    mover();
    destruir();
  }
  
  @Override
  public void Draw(){
    image(grafico,x,y);
  }
  
  private void mover(){
    y -= velocidad;
  }
  
  private void destruir(){
    if(y < 64){
      jugador.x += 10;
      eliminar(this.id);
    }
  }
  
} //fin clase disparo---------------------------------
//clase jugador--------------------------------------
public class Jugador extends Padre{
  private PImage grafico = loadImage("jugador.png");
  private int contador; 
  
  public Jugador(){
    this.id = "jugador";
    this.agregar(this.id,this);
    imageMode(CENTER);
    this.x = 320;
    this.y = 400;
    this.velocidad = 5;
    this.contador = 0;
  }
  
  @Override
  public void Update(){
    mover();
    disparar();
  }
  
  @Override
  public void Draw(){
    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------------------------------------
//private HashMap<String, Padre> mapa = new HashMap<String, Padre>();
private ConcurrentHashMap<String, Padre> mapa = new ConcurrentHashMap<String, Padre>();

//clase padre--------------------------------------------
private abstract class Padre {
  public float x, y, velocidad;
  public String id; 
  
  public abstract void Update();
  public abstract void Draw();
  
  public void agregar(String identificador, Padre objeto) {
    mapa.put(identificador, objeto);
  }

  public void eliminar(String identificador) {
    for (Map.Entry<String, Padre> indice : mapa.entrySet()) {
      if (indice.getKey().equals(identificador)) {
        mapa.remove(indice.getKey());
      }
    }
  }

  public Padre obtener_id(String identificador) {
    return mapa.get(identificador);
  }
} //fin clase padre---------------------------------------

//clase contenedor-----------------------------------------
public class Contenedor {

  public void Update() {
    for (Map.Entry<String, Padre> indice : mapa.entrySet()) {
      Padre padre = indice.getValue();
      padre.Update();
    }
  }

  public void Draw() {
    for (Map.Entry<String, Padre> indice : mapa.entrySet()) {
      Padre padre = indice.getValue();
      padre.Draw();
    }
  }
} //fin claser contenedor-----------------------------

Your code has two issues:

1st - The reason why the shots are not working correctly, creating only a single shot each time you press the “z” key, is because you are assigning the same ID to all your objects of the Disparo class in the line this.id = "disparo";. Since you are using a Map/HashMap as a data structure for all your entities, you need to create a unique ID for each object, and that will solve this issue. Try, for example, setting the ID of the Disparo class as follows: this.id = String.valueOf((int) random(1000));. This ensures that all your shots have a different ID.

2nd - When the previous issue is resolved, you will encounter the following problem: concurrency. Since you need to iterate over your map constantly to update, draw, add shots, and remove shots, you need to ensure that you are not modifying your map concurrently. There are several ways to do this, but undoubtedly the simplest and most effective way would be to use a ConcurrentHashMap instead of a Map. So just import the library:

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

And then change your variable “mapa” to:
ConcurrentMap<String, Padre> map = new ConcurrentHashMap<>();
This will help prevent concurrent modification issues when dealing with the map.

I hope this will help you :+1:

2 Likes

Thank you very much for the help, now it works much better. But a problem has arisen, now when you press z there are shots that come out above the ship and other shots come out from below.

I think the problem is this: this.id = String.valueOf((int)random(1000));
How do you solve this problem?.