java game - slick - collisions

Programovacie jazyky, rady, poradňa...
mikehudak
Amateur
Amateur
Príspevky: 30
Registrovaný: 22 mar 2009, 17:15
Kontaktovať používateľa:

java game - slick - collisions

Príspevok od používateľa mikehudak »

Ahoj, mam vyrieseny pohyb a chcel by som vyriesit kolizie.

Vytvoril som mapu, kde tazdy stvorec (tile) ma parameter blocked = true;

Ako mam implementovat kolizie, ak narazim na stenu tak by som sa nemal dalej pohybovat. Taktiez ak pridem na okraj mapy tak by som nemal pokracovat dalej.


projekt v netBeans:
https://www.box.com/s/9nicp0n067de632kcpj3

Kód: Vybrať všetko

package javagame;

za vase prispevky dakujem

import org.newdawn.slick.Animation;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.tiled.TiledMap;

public class Play extends BasicGameState {

    Animation movingUp, movingDown, movingLeft, movingRight;
    Animation player;
    int[] duration = {200, 200, 200};
    float playerX = 0;
    float playerY = 0;
    float cameraX;
    float cameraY;
    float screenWidth;
    float screenHeight;
    private TiledMap map = null;
    private static final float SPEED = 0.1f;

    private boolean[][] blocked;

    public Play(int state, int x, int y) {
        playerX = (float) x;
        playerY = (float) y;
    }

    private boolean blocked(float x, float y) {
        return blocked[(int) x][(int) y];
    }

    @Override
    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {

        map = new TiledMap("map/map.tmx");

        // build a collision map based on tile properties in the TileD map 
        blocked = new boolean[map.getWidth()][map.getHeight()];
        for (int x = 0; x < map.getWidth(); x++) {
            for (int y = 0; y < map.getHeight(); y++) {
                int tileID = map.getTileId(x, y, 0);
                String value = map.getTileProperty(tileID, "blocked", "false");
                if ("true".equals(value)) {
                    blocked[x][y] = true;
                }
            }
        }

        Image[] walkUp = {
            new Image("graphics/player/up0.png"),
            new Image("graphics/player/up1.png"),
            new Image("graphics/player/up2.png")
        };

        Image[] walkDown = {
            new Image("graphics/player/down0.png"),
            new Image("graphics/player/down1.png"),
            new Image("graphics/player/down2.png")
        };
        Image[] walkLeft = {
            new Image("graphics/player/left0.png"),
            new Image("graphics/player/left1.png"),
            new Image("graphics/player/left2.png")
        };
        Image[] walkRight = {
            new Image("graphics/player/right0.png"),
            new Image("graphics/player/right1.png"),
            new Image("graphics/player/right2.png")
        };

        movingUp = new Animation(walkUp, duration, false);
        movingDown = new Animation(walkDown, duration, false);
        movingLeft = new Animation(walkLeft, duration, false);
        movingRight = new Animation(walkRight, duration, false);

        player = movingDown;

    }

    @Override
    public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {

        screenWidth = gc.getWidth();
        screenHeight = gc.getHeight();

        cameraX = (screenWidth / 2) - (playerX / 2);
        cameraY = (screenHeight / 2) - (playerY / 2);

        map.render((int) playerX, (int) playerY);

        player.draw(cameraX, cameraY);

        g.drawString("X: " + playerX + "\nY: " + playerY, 520, 20);
        g.resetTransform();

    }

    @Override
    public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
        Input input = gc.getInput();

        if (input.isKeyDown(Input.KEY_UP) || input.isKeyDown(Input.KEY_W)) {
            player = movingUp;
            playerY += delta * SPEED;
            player.update(delta);
        } else if (input.isKeyDown(Input.KEY_DOWN) || input.isKeyDown(Input.KEY_S)) {
            player = movingDown;
            playerY -= delta * SPEED;
            player.update(delta);
        } else if (input.isKeyDown(Input.KEY_LEFT) || input.isKeyDown(Input.KEY_A)) {
            player = movingLeft;
            playerX += delta * SPEED;
            player.update(delta);
        } else if (input.isKeyDown(Input.KEY_RIGHT) || input.isKeyDown(Input.KEY_D)) {
            player = movingRight;
            playerX -= delta * SPEED;
            player.update(delta);
        }

    }

}

riso90
Novice
Novice
Príspevky: 4
Registrovaný: 08 feb 2010, 21:06

Re: java game - slick - collisions

Príspevok od používateľa riso90 »

Čavko tu máš jednoduchý príklad ako implementovať kolízie pomocou java.awt.Rectangle a jeho metódy intersects.
Kolízia sa kontroluje v metóde run():

Kód: Vybrať všetko

import java.awt.Rectangle;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Riso-Desktop
 */
public class Okno extends javax.swing.JFrame implements Runnable{

    /**
     * Creates new form Okno
     */
    
    Thread t;
    Rectangle cerveny = new Rectangle();
    Rectangle zeleny = new Rectangle();
    boolean bezi = false;
    public Okno() {
        initComponents();
        jLabel3.setVisible(false);
        cerveny.setBounds(jLabel1.getBounds());
        zeleny.setBounds(jLabel2.getBounds());
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jButton1 = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setMinimumSize(new java.awt.Dimension(450, 300));
        getContentPane().setLayout(null);

        jLabel1.setBackground(new java.awt.Color(255, 255, 255));
        jLabel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(255, 0, 0), 4));
        getContentPane().add(jLabel1);
        jLabel1.setBounds(20, 130, 80, 60);

        jLabel2.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 255, 0), 4));
        getContentPane().add(jLabel2);
        jLabel2.setBounds(230, 120, 100, 90);

        jButton1.setText("Start");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        getContentPane().add(jButton1);
        jButton1.setBounds(320, 10, 57, 23);

        jLabel3.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
        jLabel3.setText("Kolizia");
        getContentPane().add(jLabel3);
        jLabel3.setBounds(140, 20, 80, 30);

        pack();
    }// </editor-fold>

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:
        if(!bezi){
            t  = new Thread(this);
            jButton1.setText("Stop");
            t.start();
            bezi = true;
        }else{
            jButton1.setText("Start");
            bezi = false;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Okno.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Okno.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Okno.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Okno.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Okno().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    // End of variables declaration

    @Override
    public void run() {
        int smer1=1;
        int smer2=-1;
        while(bezi){
            if(jLabel1.getX()<0)smer1=1;
            if(jLabel1.getX()>350)smer1=-1;
            if(jLabel2.getX()<0)smer2=1;
            if(jLabel2.getX()>350)smer2=-1;
            
            jLabel1.setLocation(jLabel1.getX()+smer1, jLabel1.getY());
            jLabel2.setLocation(jLabel2.getX()+smer2, jLabel2.getY());
            cerveny.setBounds(jLabel1.getBounds());
            zeleny.setBounds(jLabel2.getBounds());
            
            //kontrola kolízie
            if(cerveny.intersects(zeleny)){
                jLabel3.setVisible(true);
            }else{
                jLabel3.setVisible(false);
            }
            try {
                t.sleep(10);
            } catch (InterruptedException ex) {
                Logger.getLogger(Okno.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
    }
}
mikehudak
Amateur
Amateur
Príspevky: 30
Registrovaný: 22 mar 2009, 17:15
Kontaktovať používateľa:

Re: java game - slick - collisions

Príspevok od používateľa mikehudak »

mna skor zaujima pouzitie tvojej metody v mojom priklade. Ja uz koliznu mapu mam vytvorenu, len neviem ako zabranit hracovi pohyb cez koliznu mapu (aby cez steny a objekty s vlastnostou blocked = true;)
riso90
Novice
Novice
Príspevky: 4
Registrovaný: 08 feb 2010, 21:06

Re: java game - slick - collisions

Príspevok od používateľa riso90 »

V metóde update zisti na ktorom políčku sa nachádza postavička a na ktoré políčko sa chystá vstúpiť...ak ďalší krok znamená prechod do iného poľa zisti či nemá v poli blocked hodnotu true. Alebo namiesto poľa boolean-ov si vytvor pole rectanglov a testuj, či sa nepreseknú s rectanglom na postavičke - toto nedoporúčam pri veľkom množstve štvorcov na mape.
mikehudak
Amateur
Amateur
Príspevky: 30
Registrovaný: 22 mar 2009, 17:15
Kontaktovať používateľa:

Re: java game - slick - collisions

Príspevok od používateľa mikehudak »

ved to ze mapa ma stvorce(tiles) o velkosti 32x32 px. A mapa moze mat 1000 x 1000 stvorcov, to by som musel kazdy stvorec testovat. Namiesto toho mam pole booleanov, kde viem ze je vlastnost blocked. Chcem sa uberat inym smerom ako mi odporucas.
BX
Addict
Addict
Používateľov profilový obrázok
Príspevky: 4572
Registrovaný: 10 jan 2008, 15:30

Re: java game - slick - collisions

Príspevok od používateľa BX »

Aj by som chcel poradiť, ale nechce sa mi študovať ten kód. Mohol by si slovami opísať, čo a ako robíš?
Chceš kolízie nad "hladkým" pohybom (po pixeloch), alebo sa pohybuješ v štvorcovej mape? (pohyby doprava, doľava, hore, dolu o stále rovnaký kus)
Trocha to rozpíš :)
mikehudak
Amateur
Amateur
Príspevky: 30
Registrovaný: 22 mar 2009, 17:15
Kontaktovať používateľa:

Re: java game - slick - collisions

Príspevok od používateľa mikehudak »

Aj by som chcel poradiť, ale nechce sa mi študovať ten kód. Mohol by si slovami opísať, čo a ako robíš?
Chceš kolízie nad "hladkým" pohybom (po pixeloch), alebo sa pohybuješ v štvorcovej mape? (pohyby doprava, doľava, hore, dolu o stále rovnaký kus)
Trocha to rozpíš

Hrac pohybuje obrazkom (animaciou) 4 smermi (bez diagonalov) po pixeloch (volny pohyb) = nie je to "snap to grid" pohyb.
Pod hracom sa posuva po mape (Scroller), ktoru som vytvoril map.tmx (tiled map).
Mapa ma koordinaty hraca, a hrac je posunuty do stredu okna aplikacie. Tym vznika scroller, ze hrac je staticky v strede obrazovky a pohybuje sa po mape (mapa sa posuva, nie hrac).

Mapa je tvorena stvorcami (tiles). V mape som si kazdy stvorec, ktory sa sprava ako stena oznacil vlastnostou blocked = true;
Vytvoril som pole stvorcov, ktore maju tuto vlastnost.

Chcel by som aby ked sa hrac dostane do kolizie so stvorcom(tile), ktory ma tu vlastnost, tak aby sa nemohol dostat dalej.
Taktiez, ak sa hrac dostane na okraj mapy tak aby z nej "nevypadol", t.j. aby nemohol ist za hranicu mapy.

Kód: Vybrať všetko

if (input.isKeyDown(Input.KEY_UP) || input.isKeyDown(Input.KEY_W)) {
            player = movingUp;
            playerY += delta * SPEED;
            player.update(delta);
}
Ak je stlaceny klaves HORE alebo W tak:

spusti sa animacia(hrac chodiaci smerom hore)

Kód: Vybrať všetko

            player = movingUp;
Hrac sa posunie hore (pripocita sa k Y-osi)

Kód: Vybrať všetko

            playerY += delta * SPEED;
aktualizuje sa pozicia hraca na mape

Kód: Vybrať všetko

            player.update(delta);
- v tomto kroku by sa pravdepodobne malo robit osetrenie kolizie, ak je kolizia, tak sa neaktualizuje pozicia hraca (stoji)
BX
Addict
Addict
Používateľov profilový obrázok
Príspevky: 4572
Registrovaný: 10 jan 2008, 15:30

Re: java game - slick - collisions

Príspevok od používateľa BX »

Fúha, tak to nebude úplne triviálne.

V prvom rade by som určite mapu netvoril štvoracmi s block/non-block vlastnosťou. To musí byť pri veľkej mape hromada (zbytočných) dát.
Urob si pole obdĺžnikov, ktoré predstavujú prekážku. Tie umiestni na svoju pozíciu v mape - to by znamenalo, že musíš vždy hýbať aj nimi, ale to sa dá zoptimalizovať len na prípad viditeľnej časti obrazovky.
Toto pole ideálne naplň zdola nahor v smere mapy (dôvod neskôr). Teraz ti stačí kontrolovať kolíziu panáka a relevantných prekážok. Relevantných preto, že si schopný zistiť, ktoré prekážky sú na obrazovke. Pre tie mimo nej samozrejme kolízie počítať nemusíš. Tu je výhoda to indexovanie zdola nahor, pretože ak môžeš ísť len hore, prekážku, ktorú si raz prešiel už druhý krát potrebovať určite nebudeš. Tak môžeš veľmi rýchlo znížiť počet tých relevantných.
Ak môžeš ísť aj dozadu, môžeš využiť to isté, len to bude chcieť trochu viac réžie okolo - postrážiť si, ktorú prekážku znovu beriem do úvahy.
Takisto takto zjednodušíš výber tých relevantných, pretože idú za sebou. Stačí ti teda nájsť tú najspodnejšiu a najvrchnejšiu na obrazovke a tie relevantné budú všetky medzi nimi (včetne nich)

No a teda čo ak zistím, že s nejakou prekážkou kolidujem?

Kód: Vybrať všetko

if (input.isKeyDown(Input.KEY_UP) || input.isKeyDown(Input.KEY_W))
{
            if ( NOT player.is_in_collision_up(pole_prekazok) ) )
            {
                 player = movingUp;
                 playerY += delta * SPEED;
                 player.update(delta);
            }
}
Blbé je, že musíš kontrolovať, kde kolízia nastala. V tomto prípade by stačila funkcia pre každú kolíziu (vľavo, vpravo, hore, (dolu?)) a ak v kolízií som, pohyb jednoducho nevykonať.

To pole prekážok by mal byť ideálne nejaký objekt, ktorý si vie postrážiť jednotlivé prekážky a určiť, ktoré sú relevantné, a ktoré nie.
Implementácia už je na tebe. Píšem len taký prvotný nápad, ak v ňom vidíš problém, kľudne napíš.
mikehudak
Amateur
Amateur
Príspevky: 30
Registrovaný: 22 mar 2009, 17:15
Kontaktovať používateľa:

Re: java game - slick - collisions

Príspevok od používateľa mikehudak »

mne ide o to, co mam robit v tej

Kód: Vybrať všetko

player.is_in_collision_up(pole_prekazok)
metode.
BX
Addict
Addict
Používateľov profilový obrázok
Príspevky: 4572
Registrovaný: 10 jan 2008, 15:30

Re: java game - slick - collisions

Príspevok od používateľa BX »

Kolízia dvoch obdĺňikov v rovine je triviálna.
Ak máme súradnicu ľavej, pravej, hornej a dolnej strany, tak pre dva obdĺžniky stačí podmienka (pre kolíziu s hornou stranou)

Kód: Vybrať všetko

If r1.Top < r2.Top And r2.Top < r1.Bottom Then
    isVerticalCollision = True
End If
podobne pre každú ďalšiu. Nakresli si to a uvidíš to tam.
Napísať odpoveď