Nuestro juego ya tiene un fondo, un personaje (que podemos cambiar), frutas para sumar puntos y cajas.
A continuación incorporaremos una nueva acción a nuestro héroe, podrá disparar afiladas sierras para abrirse paso.
Comenzaremos definiendo una clase llamada Weapon que implemente la interfaz de Element:
package gsampallo;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class Weapon implements Element {
public int width = 19;
public int height = 19;
private Point position;
public Weapon(Point initialPosition) {
this.position = initialPosition;
loadImages();
}
private BufferedImage imageWeapon;
private void loadImages() {
try {
imageWeapon = ImageIO.read(new File("image/Traps/Saw/On (19x19).png"));
} catch (Exception e) {
System.err.println("No se pudieron cargar imagenes de Box");
System.err.println(e.getMessage());
}
}
Como se implementa la interfaz Element, debemos definir los siguientes métodos:
public int getX() {
return this.position.x;
}
public int getY() {
return this.position.y;
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
private boolean visible = true;
public boolean isVisible(){
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
De paso definimos isVisible() para determinar si es visible o no.
También debemos definir el método updateWeapon() para poder actualizar los parámetros y getImage() para obtener la imagen que será dibujada:
private int imageNumber = 0;
public void updateWeapon(boolean move) {
if(imageNumber < (imageWeapon.getWidth()/width)-1) {
imageNumber++;
} else {
imageNumber=0;
}
position.x = position.x + 3;
visible = visible && (position.x < RunnerOne.FRAME_WIDTH);
}
public BufferedImage getImage() {
int x = imageNumber*width;
return imageWeapon.getSubimage(x, 0, this.width,this.height);
}
En esta ocasión el disparo siempre actualizara su posición; en lugar de disminuir en 1 a position.x, que lo acercaría al limite izquierda de la ventana, sumamos 3 de manera que se desplace hacia la derecha a mayor velocidad.
Al igual que con las frutas y las cajas, utilizaremos un ArrayList para mantener la lista de disparos activos; estos a diferencia de las anteriores serán generados por un evento del jugador: cuando presione la tecla SPACE.
Incorporamos en RunnerOne entonces:
private ArrayList<Weapon> listWeapon;
public RunnerOne() {
/** resto del codigo **/
listWeapon = new ArrayList<Weapon>();
}
Definiremos un método llamado shootWeapons() que será invocado cuando se presione la tecla espacio; de esa manera incorporamos:
public void shootWeapons() {
Weapon weapon = new Weapon(new Point(player.getX(),player.getY()+6));
listWeapon.add(weapon);
}
Toma el punto (x,y+6) como punto de partida para dibujar la sierra en el plano; luego lo incorpora a la lista.
En GameKeys.keyPressed( ) incorporamos:
public class GameKeys extends KeyAdapter {
public void keyPressed(KeyEvent e) {
/** resto del codigo **/
} else if(e.getKeyCode() == KeyEvent.VK_SPACE) {
shootWeapons();
}
}
}
Debemos actualizar el método updateGame() para que recorra la lista de weapons y actualice el estado de cada una:
public void updateGame() {
/** resto del codigo **/
if(!listWeapon.isEmpty()) {
Iterator it = listWeapon.iterator();
while(it.hasNext()) {
Weapon weapon = (Weapon)it.next();
weapon.updateWeapon(moved);
if(!weapon.isVisible()) {
it.remove();
}
}
}
}
También debemos actualizar es paint(Graphics g) para que dibuje los disparos:
public void paint(Graphics g) {
/** resto del codigo **/
if(!listWeapon.isEmpty()) {
Iterator it = listWeapon.iterator();
while(it.hasNext()) {
Weapon weapon = (Weapon)it.next();
if(weapon.isVisible()) {
g.drawImage(weapon.getImage(),weapon.getX(),weapon.getY(),null);
}
}
}
}
Si en este punto ejecutamos el juego, al presionar la tecla espacio se efectuaran los disparos:
Debemos determinar el comportamiento que tendrá la sierra ante los objetos con los que colisione, por el momento solo tenemos dos: cajas (de tres tipos) y las frutas; con las frutas no tendrá ningún efecto; pero las cajas, dependiendo su tipo las destruirá.
Debemos modificar el método updateGame(), en el bloque de código que actualiza los weapons, para que recorra la lista de cajas y las actualice según corresponda, para ello debemos hacer algunos cambios:
public void updateGame() {
/** resto del codigo **/
if(!listWeapon.isEmpty()) {
Iterator it = listWeapon.iterator();
while(it.hasNext()) {
Weapon weapon = (Weapon)it.next();
weapon.updateWeapon(moved);
if(weapon.isVisible()) {
if(!listBox.isEmpty()) {
Iterator<Box> it1 = listBox.iterator();
while(it1.hasNext()) {
Box box = (Box)it1.next();
if(isHorizontalColision(weapon, box, 0)){
box.setBreak();
weapon.setVisible(false);
break;
}
}
}
} else {
it.remove();
}
}
}
}
Recorremos la lista de cajas, si se cumple la condición que que existe una colisión horizontal (por ahora no vamos a complicarnos con el otro eje), entonces indicamos que la caja se rompe, weapon ya no es visible y salimos del bucle.
La ultima caja, la del tipo BOX3, quiero que sea a prueba de disparos; modificaremos el método setBreak() de la clase Box:
public void setBreak() {
isBreak = (this.boxNumber<BOX3);
}
Con este cambio solo se romperán las cajas de tipo BOX1 y BOX2.