Hola.
No estoy familiarizado con el patrón Observer. De todos modos, se considera obsoleto desde Java 9, por lo que, aunque se pueda usar, no se "debería" hacerlo.
Por otra parte, me ha parecido interesante el juego que propones, así que he intentado hacerlo, a ver como se me ocurría a mí resolverlo, porque no había hecho nada similar antes.
Quiero compartir por aquí mi código por si te sirve para tomar ideas u otros enfoques.
No está terminado, se dibujan "tanques" y se disparan proyectiles, pero falta detectar cuando un proyectil colisiona contra un tanque enemigo.
Para crear los tanques y los proyectiles he usado la clase Polygon para dibujarlos. Nada del otro mundo, son gráficos tipo consola Atari 2600 ja ja
Esta es la clase Tanque, que como digo, hereda de Polygon.
Para construir el polígono se le pasan dos arrays de enteros, uno son las coordenadas X y el otro son las coordenadas Y que situan los puntos/vertices que conformarán el polígono. Además de los dos arrays, se le pasa otro entero indicando la cantidad de vertices que tendrá el polígono.
Solo tiene un método, que se encarga de hacer una transformación, en este caso, una rotación de 180 grados.
Así puedo usar el mismo polígono para el jugador como para los enemigos. No tengo que recalcular yo las posiciones de los vértices para dibujar la figura invertida, con ese código, lo calcula el sistema.
Y ya está, esta clase no tiene más. Básicamente es un polígono que luego podremos dibujar en pantalla. Nada más.
Ahora muestro la clase Bala. También es un polígono, más sencillo de dibujar, pues es un rombo de 4 vértices.
Pero tiene dos peculiaridades.
Una es que, a diferencia del Tanque, primero lo inicializo con vértices en posiciones 0. Esto se debe a que lo primero que tengo que indicarle al polígono son sus vértices invocando la instrucción
super(). Estos vértices no solo determinan su forma, si no también su posición.
Pero yo al instanciar una Bala, no se de antemano cuál será su posición (depende de la posición del tanque del jugador al disparar), tengo que calcularla, pero no me deja hacer cálculos previos a la invocación del
super(). Nada más empezar tengo que darle unas coordenadas, las que sean.
Así que eso hago, le doy unas coordenadas con valor 0, indicando eso sí que serán 4 vértices.
Luego calculo las coordenadas correctas según la posición x e y del tanque del jugador, y entonces paso a actualizar los vértices del polígono con las coordenadas correctas.
Esto no me pasaba con el Tanque, porque si sé de antemano donde va a estar cada uno en el escenario. Así que TODOS los construyo a partir de la posición 0,0 de la pantalla, y luego son trasladados a sus lugares correspondientes. Esto lo veremos luego.
Otra peculiaridad es que uso unas variables para alterar el color de la Bala durante el juego. Uso tres int para representar los canales RGB del color y lo que hago es que varío el color verde (canal G) entre unos límites determinados.
Así cada vez que se redibuja la bala en pantalla el color va cambiando entre unos tonos rojos y amarillos.
Esto no es importante, es algo estético, y por experimentar cosas.
Quedan dos clases más por ver.
La siguiente la he llamado CampoBatalla y es un JPanel donde va a transcurrir la "acción".
Tiene dos atributos, un Vector con los tanques enemigos, y un Tanque que será el jugador.
Mediante métodos, construyo 6 enemigos usando un bucle, donde los roto 180 grados y los traslado a una determinada distancia dejando un espacio entre ellos.
Trasladar es facilísimo usando el método
translate() que ofrece la clase Polygon. Solo le indicamos el desplazamiento que queremos en los ejes Y, X, y el solo se encarga de recalcular la posición de cada vértice.
También construyo el tanque del jugador y los traslado a la parte baja del escenario.
Hay dos métodos llamados
getTanqueX() y
getTanqueY(), se encargan de informar de la posición del tanque del jugador, que nos servirá luego para determinar donde ha de aparece la Bala cuando dispare. Estos valores, ya los retorno con una pequeña variación para que la Bala parezca que salga del cañón.
Los dos siguientes métodos son
moverIzq() y
moverDer().
Lo que hacen es trasladar el Tanque 5 pixeles a un lado o a otro, según la tecla que pulse el jugador. Antes de mover, compruebo si estoy cerca de los límites de la ventana, para evitar que el Tanque se salga y desaparezca.
Después de trasladar el Tanque, pido repintar el escenario con la nueva posición, pero fíjate que solo repinto el cuadrante inferior por donde se desplaza el tanque.
Evito repintar toda la ventana, porque si hay Balas en pantalla (he puesto que se muevan lentos) empiezan a parpadear si movemos el Tanque.
Así que solo repinto la parte necesaria.
El último método es el que "pinta" los Tanques en pantalla.
Por útlimo, la clase principal con el método main().
Es un JFrame que va a contener el CampoBatalla (que es un JPanel).
Incorpora un KeyListener para detectar la pulsación de las flechas izquierda y derecha para mover el tanque. Espacio para disparar.
Lo interesante aquí, es ¿en que consiste disparar?
Para disparar he creado una clase interna que hereda de la clase Thread.
Es decir, cada vez que se dispara, el programa crea un hilo de ejecución paralelo.
Este hilo se encarga de ir desplazando la Bala disparada.
Usando Thread, pueden haber varias Balas en pantalla, cada una moviéndose y cambiando de color, de forma independiente del programa principal. Así podemos seguir moviendo el Tanque y disparando más Balas sin problema.
Y eso es todo por ahora.
Seguramente no es la mejor forma de hacer un juego, pero funciona.
Solo falta hacer que se detecte la colisión entre bala y enemigo. Y que desaparezcan bala y enemigo.
Ahora mismo las balas no desaparecen y el enemigo se borra un poco, pero porque la bala va borrando allá por donde pasa.
A ver si en los próximos días lo completo.
Espero que te sirva de algo, y pregunta cualquier cosa que no entiendas.
Un saludo.