package asteroides;
//Importamos librerias
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import javax.swing.JOptionPane;
/**
* Clase del juego que contiene el canvas, y keylistener para las teclas del teclado
* OBJETIVO; Copiar la versión del juego Asteroid: http://www.juegomaniac.com/jugar.php?id=51&ancho=740&alto=510
* ESPACIO: DISPARA
* ARRIBA: ACELERA
* IRQUIERDA: GIRA IRQUIERDA
* DERECHA: GIRA DERECHA
* SHIFT: DESAPARECE DE LA POSICIÓN Y APARECE EN OTRA POSICIÓN ALEATORIA
*/
//Tamaño de la ventana del juego
double ancho;
double alto;
//Variables de tiempo
long refrescar;
long inicio;
long fin;
//Variables de jugador
int vidas;
long puntos;
//Nave
Nave nave;
//Booleans para saber si hay colisión
boolean colisionNave;
//ArrayList de disparos
ArrayList<Disparo> disparos;
//Variables del disparo
final double tiempoDisparo = 10;
double tiempoFinalDisparo;
//ArrayList de los asteroid
//Número de asteroides con los que se inicia el juego
int numeroAsteroides = 4;
//ArrayList de asteroides eliminados
ArrayList<Asteroid> asteroidEliminado;
ArrayList<Enemigo> ovni;
//Threads para arranque (tiempo para iniciar), espera (tiempo para actualizar), naveFuera (tiempo que la nave desaparece, cuando choca o se mueve a otro sitio)
//Dimension de la ventana
//Booleans para el paint, y mostrar nave o no (por colisión)
boolean repintar = false;
boolean mostrarNave = false;
boolean ovn = false;
int contador;
int vidaOvni = 1;
long contSalirOvni;
/**
* Constructor de la clase.
*/
public EspacioCanvas () {
//Configuraciones de la ventana
setIgnoreRepaint (false);
resize (740, 510);
dim = getSize ();
ancho = dim.width;
alto = dim.height;
//Tiempo de actualización
refrescar = 25;
//Cogemos las acciones del teclado
addKeyListener(this);
setFocusable(true);
//Creamos una nave nueva en el centro
nave = new Nave(ancho/2, alto/2, 30, 0.10, 0.5, 0.90);
//Boolean relacionado con la nave, falsos
colisionNave = false;
//Número de vidas
vidas = 3;
//Declaramos los arrayList
asteroides = new ArrayList<Asteroid>();
asteroidEliminado
= new ArrayList <Asteroid
>(); disparos = new ArrayList<Disparo>();
}
/**
* Get de las vidas de la nave - jugador
* @return
*/
public int getVidas() {
return vidas;
}
/**
* Método de dibujar, mediante bufferstrategy se guardan los elementos y se van actualizando según las acciones
* @param g
*/
@Override
//Si el boolean es cierto, sigue
if (repintar)
return;
repintar = true;
//Creamos una dimensión nueva con la anterior
dNueva = getSize();
//Cogemos el bufferstrategy
BufferStrategy buffer = getBufferStrategy();
//Le pasamos al graphics el dibujo
Graphics imagen
= buffer.
getDrawGraphics(); //Y la clase le pasamos el resultado
super.paint(imagen);
//Le ponemos fondo negro
setBackground
(Color.
BLACK); //Pinta relleno de todo el juego
g2d.fillRect(0, 0, (int) ancho, (int) alto);
//Cogemos el color blanco
g2d.
setColor(Color.
WHITE); //Dibujamos un string dónde se muestra la puntuación
g2d.drawString(""+puntos, 30, 30);
//Recorremos el array de los asteroides y los pintamos
for (int cont = 0; cont < asteroides.size(); cont ++) {
asteroides.get(cont).pintar(g2d);
}
//Recorremos el array de los asteroides eliminados, cuando son disparados
for (int cont = 0; cont < asteroidEliminado.size() ; cont ++) {
asteroidEliminado.get(cont).pintarExplosion(g2d);
}
//Pintamos disparos cuando se realizan
for (int cont = 0; cont < disparos.size(); cont ++) {
disparos.get(cont).pintar(g2d);
}
//Si se debe mostrar el ovni, se muestra
if (ovn) {
for (int cont = 0; cont < ovni.size(); cont ++) {
ovni.get(cont).pintar(g2d);
}
}
//Si el boolean de mostrar la nave esta activado, la dibujamos
if (mostrarNave) {
nave.pintar(g2d);
}
//Si la nave ha chocado
while (colisionNave) {
colocarNave();
}
//Posición
g2d.translate(40, 45);
//Tamaño
g2d.scale(0.50, 0.50);
//Recorremos las vidas
for (int cont = 0; cont < this.getVidas(); cont ++) {
//Mostramos los dibujos en pequeño de la nave para las vidas
g2d.
setColor(Color.
white); int [] posicionInicialHorizontal = {-8, 0, -6, 6, 8, 0};
int [] posicionInicialVertical = {10, -10, 6, 6, 10, -10};
g2d.drawPolygon(posicionInicialHorizontal, posicionInicialVertical, posicionInicialHorizontal.length);
g2d.translate(30, 0);
}
//Si graphics es diferentre de null
if (imagen != null) {
imagen.dispose();
}
//Cerramos el buffer
buffer.show();
Toolkit.
getDefaultToolkit().
sync(); //False el repintar
repintar = false;
}
@Override
paint(g);
}
public void colocarNave () {
//Restamos vidas
vidas--;
//Colocamos la nave al centro
nave.setHorizontal(ancho / 2);
nave.setVertical(alto / 2);
//Volvemos a mostrar la nave
mostrarNave = true;
colisionNave = false;
}
@Override
/**
* Método que para cuando se pulsan las teclas
* @param e
*/
@Override
//Cogemos el código de la tecla presionada para saber que acción hace
int tecla = e.getKeyCode();
//Si la tecla es el espacio, dispara
nave.disparo = true;
if (tiempoFinalDisparo <= 0) {
disparos.add(nave.disparo());
tiempoFinalDisparo = tiempoDisparo;
}
}
//Si la tecla es la de arriba, aumenta velocidad
nave.acelerador = true;
}
//Si es la de derecha, va a la derecha
nave.derecha = true;
}
//Si es la de la irquierda, va a la irquierda
nave.irzquierda = true;
}
//Si se pulsa la tecla shift, la nave desaparece de donde esta y aparece en otra posición
mostrarNave = false;
double h
= (Math.
random() * ancho
) + 1; double v
= (Math.
random() * alto
) + 1; nave.setHorizontal(h);
nave.setVertical(v);
mostrarNave = true;
}
}
/**
* Método que se activa cuando las teclas se sueltam
* @param e
*/
@Override
//Cogemos el código
int tecla = e.getKeyCode();
//Y desactivamos la opción de cada tecla
nave.disparo = false;
}
nave.acelerador = false;
}
nave.derecha = false;
}
nave.irzquierda = false;
}
}
/**
* Método para añadir más asteroides al juego según se van pasando pantallas.
*/
public synchronized void masAsteroides() {
//Damos el valor del numero de asteroides
int numAsteroides = numeroAsteroides;
//Tamaño del asteroide
int tamaño;
//Recorremos hasta encotrar el número de asteorides necesarios, según el nivel
for (int cont = 0; cont < numeroAsteroides; cont ++) {
//Escogemos posiciones aleatorias
double asteroidHorizontal
= (Math.
random() * ancho
) + 1; double asteroidVertical
= (Math.
random() * alto
) + 1; //Escogemos una velocidad aleatoria de cada posición
double velocidadHorizontal
= Math.
random() + 1; double velocidadVertical
= Math.
random() + 1; //Escogemos la dirección
double direccionHorizontal
= (Math.
random() * 2); double direccionVertical
= (Math.
random() * 2); //Si la dirección es igual a 1
if (direccionHorizontal == 1) {
//A la velocidad le damos la vuelta
velocidadHorizontal *= (-1);
}
if (direccionVertical == 1) {
velocidadVertical *= (-1);
}
tamaño = 2;
//Añadimos el nuevo asteroide con los datos obtenidos
Asteroid ast = new Asteroid(asteroidHorizontal, asteroidVertical, 0, .1, velocidadHorizontal, velocidadVertical, tamaño);
asteroides.add(ast);
//Restamos el número por poner
numAsteroides --;
//Cogemos el centro del asteroide y la nave
Point2D asteroidCenter
= asteroides.
get(cont
).
getCentro(); Point2D naveCenter
= nave.
getCentro(); //Calculamos la distancia
double distancia = asteroidCenter.distance(naveCenter);
///Si la distancia entre el asteroide y la nave es menor de 80, no se crea
if (distancia <= 80) {
asteroides.remove(cont);
cont --;
numAsteroides ++;
}
}
}
/**
* Método que comprueba las acciones y colisiones relacionadas con los Asteroid y el ovni.
*/
public synchronized void compruebaAccionesColisiones() {
accionesAsteroid ();
accionesOvni ();
}
/**
* Método que determina las acciones del asteroid en función de su movimiento y choques
* COLISIÓN CON LA NAVE
* COLISIÓN CON LOS DISPAROS DE LA NAVE
* COLISIÓN CON LOS DISPAROS DEL OVNI.
*/
public synchronized void accionesAsteroid(){
//Recorremos los asteroides y los ponemos en movimiento
for (int contA = 0; contA < asteroides.size(); contA ++) {
// asteroides.get(contA).start();
// asteroides.get(contA).mover(ancho, alto);
try {
//Comprueba si chocan con la nave
if (asteroides.get(contA).colisionNave(nave)) {
//Los añadimos a los eliminados y explotamos
asteroidEliminado.add(asteroides.get(contA).explota());
//Los dividimos
divisionAsteroides(contA);
//si a la nave se le acaban las vidas
if (vidas <= 0 && !colisionNave) {
colisionNave = true;
mostrarNave = false;
}
//Si aún le quedan vidas
if (vidas > 0) {
colisionNave = true;
mostrarNave = false;
nave.setHorizontal(ancho/2);
nave.setVertical(alto/2);
nave.getRotAngulo();
}
//Restamos vida a la nave
vidas --;
}
//Comprueban si chocan con un disparo de la nave
for (int contD = 0; contD < disparos.size(); contD ++) {
if (asteroides.get(contA).colisionDisparo(disparos.get(contD))) {
disparos.get(contD).limite = 0;
//Se le quita tiempo de vida
asteroides.get(contA).vidaAsteroide --;
if (asteroides.get(contA).vidaAsteroide > 0) {
Asteroid a = asteroides.get(contA);
//Según el radio del asteroid se da una puntuación o otra
if (a.getRadioAsteroid() >= 60) {
//Añadiomos los asteroides en el array
for (int contAE = 0; contAE < 3; contAE++) {
asteroidEliminado.add(a.explota());
}
//Los dividimos el dos
divisionAsteroides(contA);
//Sumamos los puntos correspondientes
puntos += 20;
}
else if (a.getRadioAsteroid() >= 30) {
for (int contAE = 0; contAE < 3; contAE++) {
asteroidEliminado.add(a.explota());
}
divisionAsteroides(contA);
puntos += 50;
}
else {
for (int contAE = 0; contAE < 3; contAE++) {
asteroidEliminado.add(a.explota());
}
//Llegado a este punto, se eliminan
asteroides.remove(contA);
puntos += 100;
}
}
//Vamos eliminando los disparos
disparos.remove(contD);
}
}
//Comprueba si choca con los disparos del ovni, recorre los arraylist de ovni y el de disparos
for (int contO = 0; contO < ovni.size(); contO ++) {
for (int contD = 0; contD < ovni.get(contO).disparosOvni.size(); contD++ ) {
if (asteroides.get(contA).colisionDisparo(ovni.get(contO).disparosOvni.get(contD))) {
asteroides.get(contA).vidaAsteroide --;
ovni.get(contO).disparosOvni.get(contD).limite = 0;
if (asteroides.get(contA).vidaAsteroide > 0) {
Asteroid a = asteroides.get(contA);
asteroidEliminado.add(a.explota());
divisionAsteroides(contA);
asteroides.remove(contA);
}
if (asteroides.get(contA).vidaAsteroide <= 0) {
asteroides.remove(contA);
}
}
}
ovni.get(contO).disparosOvni.remove(this);
}
}
}
}
/**
* Acciones que se realizan en función del movimiento y choques del ovni
* COLISIÓN CON LOS DISPAROS DE LA NAVE
* COLISIÓN CON LOS ASTEROID
* COLISIÓN CON LA NAVE
* COLISIÓN DE LA NAVE CON LOS DISPAROS DEL OVNI.
*/
public synchronized void accionesOvni() {
//Determinamos de forma aleatoria, cuando sale
int aleatorio
= (int) (Math.
random() * 1000); if (contSalirOvni > 700) {
//Si el número aleatorio es menor que el número de asteroides, sale
if (aleatorio < asteroides.size()) {
ovn = true;
}
//Le añadimos un ovni, si no hay ninguno
if (ovn && ovni.size() < 1) {
ovni.
add(new Enemigo
(-10,
Math.
random() * alto
)); }
}
try {
//Recorremos y los vamos moviendo
for (int contO = 0; contO < ovni.size(); contO ++) {
ovni.get(contO).start();
// ovni.get(contO).mover(ancho, alto);
//Si el ovni se queda si vida, no sale
if (vidaOvni == 0) {
ovn = false;
}
//Busca otro numero aleatorio, si es menor a número de asteroides, se le da vida.
if (aleatorio < asteroides.size()) {
vidaOvni = 1;
}
//Comrpueba si le da un disparo de la nave
for (int contD = 0; contD < disparos.size(); contD ++) {
if (ovni.get(contO).colisionDisparo(disparos.get(contD))) {
//Se le quita la vida al ovni
ovni.get(contO).vida --;
vidaOvni --;
disparos.get(contD).limite = 0;
//Y puntuación
puntos += 120;
}
}
//Recorremos los asteroides para comprobar si se choca con alguno
for (int contA = 0; contA < asteroides.size(); contA ++) {
if (ovni.get(contO).colisionAsteroid(asteroides.get(contA))) {
ovni.get(contO).vida --;
vidaOvni --;
asteroidEliminado.add(asteroides.get(contA).explota());
divisionAsteroides(contA);
asteroides.remove(contA);
}
}
//Comprueba si colisiona con la nave
if (ovni.get(contO).colisionNave(nave)) {
//Si la nave aún tiene vida
if(vidas > 0 && !colisionNave){
nave.setHorizontal(ancho/2);
nave.setVertical(alto/2);
colisionNave = true;
mostrarNave = false;
}
ovni.get(contO).vida --;
vidaOvni --;
//Si no tiene vidas
if (vidas <= 0) {
mostrarNave = false;
colisionNave = true;
}
vidas --;
}
//Comprueba si la nave es colisionada con un disparo del ovni
if (nave.colisionDisparo(ovni.get(contO).disparosOvni) && !colisionNave) { //pregunta si lan ave colisiona con los disparos del ovni
//Si la nave no tiene vidas
if (nave.vida <= 0) {
mostrarNave = false;
colisionNave = true;
}
//Si le quedan
if (nave.vida > 0) {
mostrarNave = false;
nave.setHorizontal(ancho/2);
nave.setVertical(alto/2);
nave.getRotAngulo();
colisionNave = true;
}
vidas --;
}
ovni.get(contO).disparosOvni.remove(this);
}
}
//Recorremos el array list y si no tiene vidas ni el ovni o la nave, se eliminan.
for (int cont = 0; cont < ovni.size(); cont ++) {
if (ovni.get(cont).vida <= 0 || nave.vida <= 0) {
ovni.remove(cont);
}
}
}
/**
* Método de la division de los asteroides.
* @param num
*/
public synchronized void divisionAsteroides (int num) {
//Seleccionamos el asteroide que se ha disparado
Asteroid a = asteroides.get(num);
//Cogemos las posiciones
double asteroideHorizontal = a.getHorizontal();
double asteroideVertical = a.getVertical();
//Y dividimos el tamaño original en dos
int tamaño = (a.getTamaño() / 2);
//Recorremos los dos asteorides nuevos para determinar velocidad y dirección
for (int cont = 0; cont < 2; cont++) {
double velocidadHorizontal
= Math.
random() + 1; double velocidadVertical
= Math.
random() + 1; double direccionHorizontal
= (Math.
random() * 2); double direccionVertical
= (Math.
random() * 2); //Si la dirección es igual 1, giramos la velocidad
if (direccionHorizontal == 1) {
velocidadHorizontal *= (-1);
}
if (direccionVertical == 1) {
velocidadVertical *= (-1);
}
//Añadimos los nuevos asteroides
asteroides.add(new Asteroid(asteroideHorizontal, asteroideVertical, 0, .1, velocidadHorizontal, velocidadVertical, tamaño));
}
//Eliminamos el asteoride del array
asteroides.remove(num);
}
/**
* Método de inicio - FALLAN LOS THREAD.
*/
public void start () {
if (arranque == null) {
arranque.start();
}
while (true) {
for (int contO = 0; contO < asteroides.size(); contO ++) {
asteroides.get(contO).start();
}
for (int contO = 0; contO < disparos.size(); contO ++) {
disparos.get(contO).start();
}
}
}
/**
* Método de arranque.
*/
@Override
public void run() {
//Esperamos tres segundos antes de mostrar los elementos
try {
arranque.sleep(3000);
}
//Mientras sea cierto
while (true) {
//Mostramos la nave
mostrarNave = true;
//Ponemos los asteroides
masAsteroides();
//Mientras las vidas sean mayores que cero
while (vidas >= 0) {
//Iniciamos un contador de tiempo
inicio
= System.
currentTimeMillis(); //Damos movimiento a nave, asteroides y disparos
nave.mover(ancho, alto);
for (int cont = 0; cont < asteroidEliminado.size(); cont ++) {
asteroidEliminado.get(cont).moverExplosion();
if (asteroidEliminado.get(cont).getVidaAsteroide() <= 0) {
asteroidEliminado.remove(cont);
}
}
for (int cont = 0; cont < disparos.size(); cont++) {
disparos.get(cont).mover(ancho, alto);
if (!disparos.get(cont).getActivado()) {
disparos.remove(cont);
}
}
//Restamos tiempo de disparo
tiempoFinalDisparo --;
//Comprobamos las colisones
compruebaAccionesColisiones();
//Repintamos
repaint();
//Si terminamos los asteroides y con el ovni aumentamos los asteroides.
if (asteroides.isEmpty() && !ovn) {
//Aumentamos el número de asteroides
numeroAsteroides ++;
//Añadimos asteroides
masAsteroides();
//Damos true a que puede salir
ovn = true;
contSalirOvni = 0;
}
//Hacer
try {
//Asignamos un nuevo contador de tiempo al final
fin
= System.
currentTimeMillis(); //Si la diferencia de refrescar entre la diferencia de fin e inicio es mayor a 0
if (refrescar - (fin - inicio) > 0) {
//Tiempo de espera es refrescar menos la diferencia
Thread.
sleep(refrescar
- (fin
- inicio
)); }
}
contSalirOvni ++;
}
stop();
}
}
/**
* Método de finalización del juego.
*/
public void stop () {
if (arranque != null) {
arranque = null;
}
}
}