El Blog de Murphy

18 Septiembre 2008

juego en java 2D – 10mo dia

Archivado en: Java 2D — Etiquetas:, , , — Julio Cesar Cachay Pérez @ 6:55 pm

Capitulo Final

Y llegamos al capitulo final de este tutorial, con las optimizaciones que se le hace a las imagenes, el raton y los FPS, tratare de explicar que es lo que hace

SpriteCache.java

public BufferedImage createCompatible(int width, int height, int transparency) {
    GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();//gc va a ser = a las caracteristicas del monitor
    BufferedImage compatible = gc.createCompatibleImage(width,height,transparency);//le indicamos tamaño y transparencia
    return compatible;
}

public BufferedImage getSprite(String name) {
    BufferedImage loaded = (BufferedImage)getResource("imagenes",name);
    BufferedImage compatible = createCompatible(loaded.getWidth(),loaded.getHeight(),Transparency.BITMASK); //Crea una imagen que soporta pixels transparentes
    Graphics g = compatible.getGraphics();
    g.drawImage(loaded,0,0,this);
    return compatible;
}

La sgte optimizacion trata del background, en pocas palabras crearemos 2 background, uno arriba del otro y los iremos desplazando cada vez

invaders.java

backgroundTile = spriteCache.getSprite("oceano.gif");
background = spriteCache.createCompatible(Stage.WIDTH, Stage.HEIGHT + backgroundTile.getHeight(), Transparency.OPAQUE);//creamos una imagen con el alto d pantalla + el alto de oceano.gif y que no soporte transparencia
Graphics2D g = (Graphics2D)background.getGraphics();
g.setPaint( new TexturePaint( backgroundTile, new Rectangle(0,0,backgroundTile.getWidth(),backgroundTile.getHeight())));//creamos el background normal
g.fillRect(0,0,background.getWidth(),background.getHeight());
backgroundY = backgroundTile.getHeight();

g.drawImage( background,0,0,Stage.WIDTH,Stage.HEIGHT,0,backgroundY,Stage.WIDTH,backgroundY+Stage.HEIGHT,this);
//Esto es un poco complicado si ven al api me entendera como funciona, pero mas o menos quedaria asi (0,0,600,400,0,256,400,856)
do {
    Thread.yield();// que espere hasta que currentTimeMillis()-startTime< 17
} while (System.currentTimeMillis()-startTime< 17);

The End ;D

Ahora prosigamos con el libro que nos ayudara mejorar en mucho este codigo

juego en java 2D – 8vo y 9no dia

Archivado en: Java 2D — Etiquetas:, , , — Julio Cesar Cachay Pérez @ 12:10 am

Capitulo 24

Hasta este punto nuestro juego parecía más un juego de tiro al pato más que un Space Invaders… jajajaja xD

Comenzamos, se daran cuanta que laser.java es casi identico a bullet.java por lo tanto nada que decir

monster.java

protected static final double FIRING_FREQUENCY = 0.01;//variable para la frecuencia con q el monstruo va a disparar

if (Math.random()<FIRING_FREQUENCY)//si sale un numero menor a 0.01
    fire();//dispara

public void fire() {//como en player
    Laser m = new Laser(stage);
    m.setX(x+getWidth()/2);
    m.setY(y + getHeight());
    stage.addActor(m);
}

player.java

if (a instanceof Laser ) {//igual que con monster
    a.remove();
    addShields(-10);
}

Capitulo 25

un capitulo interesante despues de bastante… aunque ni tanto… =P

primero que nada explicar que lo unico que se va hacer es varios cuadrados, que llenen la pantalla y luego esos cuadrados los vamos a mover un poco cada cierto tiempo, y modificaremos, otra vez, invaders.java

ocean = spriteCache.getSprite("oceano.gif");
g.setPaint(new TexturePaint(ocean, new Rectangle(0,t,ocean.getWidth(),ocean.getHeight())));//la clase texturepaint, lo que hace es pintar la imagen arriba a la izquierda y luego repetirla al largo y ancho de la pantalla

Capitulo 26

Nada nuevo, ni interesante, aunque cabe resaltar que para darle mas inteligencia la juego, aunque ni tanta, pero si mas dificultad debria el mosntruo mejorar la velocidad y ademas por lo menos deberia aprecer en el mismo lugar para eso tendriamos que hacer esto:

spawn(y,vx);// le paso la altura y la velocidad

public void spawn(int a, int b) {
    Monster m = new Monster(stage);
    m.setX( (int)(Math.random()*Stage.WIDTH) );
    m.setY(a);//recibimos la misma altura
    m.setVx(b+4);// aumentamos la velocidad
    stage.addActor(m);
}

cabe decor que se hacen demasiado rapidos y aumenta la dificultad, pero despues d eun momento son tan rapidos que ia no se peuden ver, pero bueno asi vamos mejorando =P

Capitulo 27

En juegos por ejemplo como F.E.A.R el sonido es vital, bueno aca se toca ese tema, pero kiero hacer enfasis en algo, al comienzo de este blog, dije que url no se utilizaba, la verdad es que luego de investigar me di cuenta que si, se utiliza para llamar una imagen, pero la verdad es que no pude arreglar ese error y en vista de eso, les voya pasar el codigo de como arrgle ese error

ResourceCache.java

public abstract class ResourceCache {
protected HashMap resources;

public ResourceCache() {
    resources = new HashMap();
}

protected Object loadResource(String nombre) {
//        URL url=null;
//        url = this.getClass().getResource(name);
//        return loadResource(url);
    File file=null;
    file = new File(nombre);
    return loadResource(file);
}

protected Object getResource(String name) {
    Object res = resources.get(name);
    if (res == null) {
        res = loadResource("imagenes/"+name);
        resources.put(name,res);
    }
    return res;
}

protected abstract Object loadResource(File file);

SpriteCache.java

public class SpriteCache extends ResourceCache {

    public BufferedImage getSprite(String nombre) {
        return (BufferedImage)getResource(nombre);

    }
    @Override
    protected Object loadResource(File url) {
        try {
            return ImageIO.read(url);
        } catch (Exception e) {
            System.out.println("No se pudo cargar la imagen de "+url.getAbsolutePath());
            System.out.println("El error fue : "+e.getClass().getName()+" "+e.getMessage());
            System.exit(0);
            return null;
        }
    }
}

Luego de esto viene soundcache.java, desde mi perspectiva esta clase no deberia usar esas liberiras que llama, pero primero voy a usar su forma y al final voy a  mejorarlo

soundcache.java

URI archivo;
@Override
protected Object loadResource(File file) {
    archivo = file.toURI();
    try {
        return Applet.newAudioClip(archivo.toURL());
    } catch (MalformedURLException ex) {
        Logger.getLogger(SoundCache.class.getName()).log(Level.SEVERE, null, ex);
        return null;
    }
}

y con las demas funciones claro esta

El resto de cambios son implementaciones de las funciones, osea nada interesante

Antes de mejorar el codigo del capitulo 27, veamos como mejoran su codigo

Capitulo 28

En este capitulo lo que hace es crear una mejora para su sonido, bueno me imagino que en ese tiempo su computadora seria muy lenta porque en la mia no hay ningun problema aunque el FPS cuando disparo sube, pero no se siente, es que con las maquinas de ahora ¿que puede ser lento?… y los que hacen juegos en C creen que java no tiene futuro en juegos xD, tendriamos que preguntarles a los de assembler que decian lo mismo de ellos…

public void playSound(final String name) {
    new Thread(
    new Runnable() {
        public void run() {
            getAudioClip(name).play();
        }
    }
    ).start();
}

Lo unico que hace es crear un nuevo hilo para hacerlo parecer como si corriera en parealelo, la verdad esto no crei que sea lo mas prudente, si se dan cuenta en su administrador de tareas, java aumenta unos kilobytes significa que esta usando mas memoria, obvio que en este juego no se va a sentir pero imaginenese que avancen las fases y montemos mas sonidos, vamos a usar mas memoria del cpu y el juego se va tornar lento, es por eso que io creo que debriamos cambiar de codigo, primero voy darle el directorio a usar y despuesvoy  cmabiar el codigo de audio

ResourceCache.java

protected Object getResource(String carpeta, String name) {
Object res = resources.get(name);
    if (res == null) {
        res = loadResource(carpeta+"/"+name); // ahora va a recibir la carpeta
        resources.put(name,res);
    }
return res;
}

SoundCache.java

//bueno antes de comenzar con soundcache otra cuestion, ahora usamos file en vez de url entonces soundcache quedaria asi

// quizas el mayor cambio este aqui, donde he cogiod un codigo "prestado" de javacup :P , lo adapte lo mejor que me parecio, cuando lo ejecuten se daran cuenta que el juego deja de hacerse lento y sin necesidad de poner otros hilos

public class SoundCache extends ResourceCache{
    private static Hashtable<String, Clip> sonidos=new Hashtable<String, Clip>();
    @Override
        protected Object loadResource(File file) {
            AudioInputStream audioInputStream;
            try {
                audioInputStream = AudioSystem.getAudioInputStream(file);
                AudioFormat format = audioInputStream.getFormat();
                DataLine.Info info = new DataLine.Info(Clip.class, format);
                Clip m_clip;
                m_clip = (Clip) AudioSystem.getLine(info);
                m_clip.open(audioInputStream);
                sonidos.put(file.getName(), m_clip);
            } catch (UnsupportedAudioFileException ex) {
                Logger.getLogger(SoundCache.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(SoundCache.class.getName()).log(Level.SEVERE, null, ex);
            } catch (LineUnavailableException ex) {
                Logger.getLogger(SoundCache.class.getName()).log(Level.SEVERE, null, ex);
        }
return null;
}
public AudioClip getAudioClip(String name) {
    return (AudioClip)getResource("sonidos",name);
}
public void playSound(String sNombre) {
    try
    {
        if (!sonidos.containsKey(sNombre))
            getAudioClip(sNombre);
        if (sonidos.containsKey(sNombre)){
            Clip m_clip=sonidos.get(sNombre);
            m_clip.setFramePosition(0);
            m_clip.start();
        }
    }
    catch (Exception e)
    {
    //e.printStackTrace();
    }
}
public void loopSound(String sNombre) {
    try
    {
        if (!sonidos.containsKey(sNombre))
            getAudioClip(sNombre);
        if (sonidos.containsKey(sNombre)){
            Clip m_clip=sonidos.get(sNombre);
            m_clip.setFramePosition(0);
            m_clip.loop(m_clip.LOOP_CONTINUOUSLY);
        }
    }
    catch (Exception e)
    {
    //e.printStackTrace();
    }
}}

En resumen mejore el sonido y  el codigo para que no solo pueda buscarse de un solo directorio, sino que la imagenes y los sonidos puedan estar en diferentes directorios

Alaoz

15 Septiembre 2008

juego en java 2D – 7mo dia

Archivado en: Java 2D — Etiquetas:, , , — Julio Cesar Cachay Pérez @ 10:35 am

Capitulo 21

Rapidamente, no hay mucho que comentar en este capitulo, la vida son cuadrados que van uno encima del otro, y evitar el rebote solo se ponen variables exactas como x=0

Player.java

public static final int MAX_SHIELDS = 200;//La vida

Stage.java

public static final int PLAY_HEIGHT = 400; //solo se peude jugar entre 0/400

Invaders.java

g.fillRect(280,Stage.PLAY_HEIGHT,Player.MAX_SHIELDS,30);//posicion x=280,y=400, el largo deacuerdo al numero de shields(200), el grosor de 30

g.fillRect(280+Player.MAX_SHIELDS-player.getShields(),Stage.PLAY_HEIGHT,player.getShields(),30);//repinta por encima con azul pero el largo varia de acuerdo a los shields de player

for (int i = 0; i < player.getClusterBombs();i++) {//pinta segun alla bombas especiales

Solo las lineas de codigo que merecen ser comentadas he colocado

Capitulo 22

Este capitulo no tiene nada que colocar aca, pero me permitire colocar una opinion que tengo, para mi las muertes, los puntajes, osea toda la carnecita del juego debe ir en una clase diferente a invaders sino la clase se convierte en codigo spaguetti, y es imposible ver que pasa hay, chequen lo inmenso que es esa clase ahora, ademas perdemos reusabilidad, lo que va a significar a la larga mas lineas de codigo

Capitulo 23

Bueno en este capitulo no hay mucho de que hablar tampoco solo que viene mas codigo a invaders, y asi seguimos con la mazamorra xD bueno lo unico que agregar es que elllos no pusieron estas lineas de codigo

Stage.java

public void gameOver();

Player.java

public void addShields(int i) {
    shields += i;
    if (shields > MAX_SHIELDS) shields = MAX_SHIELDS;// no puede haber mas vida que la original
}

13 Septiembre 2008

juego en java 2D – 6to dia

Archivado en: Java 2D — Etiquetas:, , , — Julio Cesar Cachay Pérez @ 11:23 am

Capitulo 18

Este capitulo no hace mas que agregar mas funciones controladas por el usuario, no agrega casi nada nuevo a no ser porque ahora la clase Actor maneja un poco la funcionalidad de Bullet, igual de lo mas rescatable es el remove.

public void addActor(Actor a);// nueva funcion para agregar un actor

protected boolean markedForRemoval;//booleano que cambia a true si se tiene que borrar

public void addActor(Actor a) {
    actors.add(a);//funciona igual que en la funcion initworld
}

for (int i = 0; i < actors.size(); i++) {
    Actor m = (Actor)actors.get(i);
    if (m.isMarkedForRemoval()) {
        actors.remove(i);// borra de la lista de actores
    } else {
        m.act();
    }
}

public void fire() {
    Bullet b = new Bullet(stage);//nueva instancia de bullet
    b.setX(x);// recoge X de actor (posicion horizontal)
    b.setY(y - b.getHeight());//Lo hace aparecer en la punta de la nave
    stage.addActor(b);//agrega el actor
}

La clase bullet no aporta nada interesante

Capitulo 19

Arrancamos con bomb.java

switch (heading) {//como el misil pero mas complicado
    case UP_LEFT : vx = -BOMB_SPEED; vy = -BOMB_SPEED; sprite="bombUL.gif";break;
    case UP : vx = 0; vy = -BOMB_SPEED; sprite="bombU.gif";break;
    case UP_RIGHT: vx = BOMB_SPEED; vy = -BOMB_SPEED; sprite="bombUR.gif";break;
    case LEFT : vx = -BOMB_SPEED; vy = 0; sprite = "bombL.gif";break;
    case RIGHT : vx = BOMB_SPEED; vy = 0; sprite = "bombR.gif";break;
    case DOWN_LEFT : vx = -BOMB_SPEED; vy = BOMB_SPEED; sprite="bombDL.gif";break;
    case DOWN : vx = 0; vy = BOMB_SPEED; sprite = "bombD.gif";break;
    case DOWN_RIGHT : vx = BOMB_SPEED; vy = BOMB_SPEED; sprite = "bombDR.gif";break;
}

Player.java

private int clusterBombs; //nro de bombas

clusterBombs = 5; // no deberia estar aqui

clusterBombs--;//quita una bomba
stage.addActor( new Bomb(stage, Bomb.UP_LEFT, x,y));// le dice a invaders que agregue un actor mas al array

Quiero detenerme aca un momento para tratar de entender algunas cosas que me han quedado un poco difusas. Primero como funciona la posicion, ejemplo:

En la imagen que les acabo de poner mas o menos retrata donde esta la bomba UL, con respecto a la nave, para llegar a esa posicion el constructor de bomb recibe 4 valores

Stage stage, int heading, int x, int y

los importantes son X y Y porque son mandados por la clase Player, pero ni siquera viene de ellos, sino que los hereda de la clase Actor, bueno segun la figura, la nave esta en la posicion 290,180 bueno pues, bomb recibe estas variables y hace lo sgte

case UP_LEFT : vx = -BOMB_SPEED; vy = -BOMB_SPEED; sprite=”bombUL.gif”;break;

ahora vx=-5 y vy=-5, hasta ahora no pasa nada, porque las varaibles a cambiar son X y Y pero hay encontramos a la funcion act(), lo que pasa es que cada que creamos un nuevo objeto Bomb, updateworld() de invaders.java ejecuta la funcion de act() y en act existe una suma de X – vx , igual para Y, ahora tenemos la nueva posicion de la bomba, seguimos agregando bombas y al terminar invaders pasa a utilizar la funcion de pintado paintWorld(), pero como sigue siendo visible las funciones se vuelven a ejecutar y asi la bomba sera puesta en una nueva posicion y otra vez pintada, acaba todo cuando act recibe varibles que salen fuera del tamaño de la pantalla (en el caso de la bomba)

Capitulo 20

Este capitulo ya tien que ver con la matanza, por ahora solo la muerte de nuestros enemigos

Actor.java

public Rectangle getBounds() {
    return new Rectangle(x,y,width,height);//crea un nuevo rectangulo con el lugar y las dimensiones del actor(por fin las usamos)
}

Monster.java

public void collision(Actor a) {
    if (a instanceof Bullet || a instanceof Bomb)//su muerte, si a es un objeto de tipo bullet o bomb
        remove();
}

invader.java

public void checkCollisions() {
    Rectangle playerBounds = player.getBounds();//recibimos el rectangulo hecho con la info de player (su herencia)
    // se podria haber implementado un mejor algoritmo de busqueda y comparacion
    for (int i = 0; i < actors.size(); i++) {
        Actor a1 = (Actor)actors.get(i);
        Rectangle r1 = a1.getBounds();
        if (r1.intersects(playerBounds)) {//si el player choca con otro actor
            player.collision(a1);//no hace nada...
            a1.collision(player);//y el actor... tampoco xD
        }
        for (int j = i+1; j < actors.size(); j++) {//ahora a preguntar entre actores
            Actor a2 = (Actor)actors.get(j);
            Rectangle r2 = a2.getBounds();
            if (r1.intersects(r2)) {// si el actor de arriba se intersecta con otro actor
                a1.collision(a2);//reacciona el actor de arriba
                a2.collision(a1);//reaccionan el otro actor
            }
        }
    }
}

Bueno hasta ahi lo mas interesante, falta poco para terminar el cursillo ^_^

10 Septiembre 2008

juego en java 2D – 5to dia

Archivado en: Java 2D — Etiquetas:, , , — Julio Cesar Cachay Pérez @ 4:05 am

Capitulo 15

Y llegaron las matematicas, hacer un juego no solo requiere de conocimientos de programacion y diseño, las matematicas entran de lleno y de cuando en vez tendremos que calcular angulos o, como en este caso, no serviremos de algunas funciones matematicas para hacer el efecto de vida del monstrito, ahora aqui se habla del maximo comun divisor y esas cosas.

public void act() {
    t++;
    if (t % frameSpeed == 0){
    t=0; currentFrame = (currentFrame + 1) % spriteNames.length;
    //cuando inicia  currentframe = 0, le suma 1 y lo divide
    //con 2(spriteNames.length) y saca el residuo que es 1
    //luego suma 2 y el residuo es 0, luego a 3 y el residuo es 1
    // y asi sucesivamente, spriteNames.length nos garantiza que
    //el residuo jamas va a ser mayor al numero de elementos en el array }
}

frame speed es declarado en Monster como 35, aca luego se va sumando t hasta llegar a 35 (o a un multiplo) y cuando lo hace pone t = o y reinicia el conteo

Capitulo 16

En este capitulo no hay absoltutamente nada nuevo, agregar un jugador es como agregar un monstruo

Capitulo 17

Aunque este cpaitulo es muy interesante yo pondria el manejo del jugador en un clase aparte, pero bueno…

public class Invaders extends Canvas implements Stage , KeyListener{ //interface para obtener los metodos referentes al teclado

    addKeyListener(this);//Es el que "escucha" los eventos de tecla

public void keyPressed(KeyEvent e) {
    player.keyPressed(e);//player hereda estas funciones y recibe el evento de tecla
}

public void keyReleased(KeyEvent e) {
    player.keyReleased(e);
}

protected static final int PLAYER_SPEED = 4;//no cambia siempre tendra una nueva posicion en 4 y -4

protected void updateSpeed() {
//se modifican vx y vy y con esto cambian las variables de la funcion act
    vx=0;vy=0;
    if (down) vy = PLAYER_SPEED;
    if (up) vy = -PLAYER_SPEED;
    if (left) vx = -PLAYER_SPEED;
    if (right) vx = PLAYER_SPEED;
}

Y listo con esto nuestro avion deberia ir arriba, abajo, izquierda, derecha usando las teclas de direccion

Por hoy es todo, hablaos

Entradas más antiguas »

Blog de WordPress.com.