Snake, odczytywanie dwoch klawiszy na raz

0

Witam, mam takie problem, że w mojej grze gdy ide w prawo i szybko nacisne w dol i w lewo to waz zawraca jakby w miejscu i najezdza na siebie(co oczywiscie powoduje kolizje i koniec gry). Dalem printy w keylistenerze zeby sprawdzic czy klawisze sie wywoluja jak powinny i dzialaja dobrze, w sytuacji ktora opisalem wykonuje sie najpierw klawisz w dol a nastepnie w lewo, nie wiem czemu program jakby omija te komende w dol. Oto kod:

package projekt;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Plansza extends JPanel{
    
    private int szerokosc, wysokosc;
    private int szybkosc;
    private boolean gora = false, dol = false, lewa = false, prawa = false;
    private Klawisz klawisz;
    private ArrayList<Waz> waz;
    private ArrayList<Bonus> bonus;
    private int x, y;
    private int bx, by;
    private int dlugosc;
    public boolean over;
    private Image snake;
    private Image jablko;
    private Image tlo;
    private Image glowa;
    private int punkty;
    public static JButton powrot = new JButton("Powrot");
    private int wait;
    Timer czas;
    Random los;
    
    
    public Plansza(int szerokosc, int wysokosc, int szybkosc){
        this.szerokosc = szerokosc;
        this.wysokosc = wysokosc;
        this.szybkosc = szybkosc;
        punkty = 0;
        x = 0; y = 0;
        dlugosc = 200;
        over = false;
        
        czas = new Timer();
        Odswiezanie odswiezanie = new Odswiezanie();
        czas.scheduleAtFixedRate(odswiezanie, 100, szybkosc);
        
        setPreferredSize(new Dimension(szerokosc, wysokosc));
        
        klawisz  = new Klawisz();
        
        los = new Random();
        bx = (los.nextInt(szerokosc/20-1)+1)*20;
        by = (los.nextInt(wysokosc/20-1)+1)*20;
        
        waz = new ArrayList();
        bonus = new ArrayList();
        Waz w = new Waz(x,y);
        Bonus b = new Bonus(bx,by);
        
        addKeyListener(klawisz);
        waz.add(w);
        bonus.add(b);
        zaladujObrazki();
        setFocusable(true);
        
        setLayout(null);
        powrot.setBounds(szerokosc/2-40, wysokosc-20, 80, 20);
        
        wait = 0;
    }
    
    private void zaladujObrazki(){
        ImageIcon iis = new ImageIcon("cialo.png");
        snake = iis.getImage();
        ImageIcon iij = new ImageIcon("jablko.png");
        jablko = iij.getImage();
        ImageIcon iit = new ImageIcon("tlo.png");
        tlo = iit.getImage();
        ImageIcon iig = new ImageIcon("glowa.png");
        glowa = iig.getImage();
    }
    
    private void ruch(){
        
        if(prawa){
            x += 20;
        }
        
        if(lewa){
            x-=20;
        }
        
        if(gora){
            y-=20;
        }
        
        if(dol){
            y+=20;
        }
        
        Waz w = new Waz(x,y);
        waz.add(w);
        
        if(waz.size()>dlugosc){
            waz.remove(0);
        }
    }
    private void kolizje(){
        
        for(Bonus b : bonus){
            if(b.getX()==x && b.getY() ==y){
                b.setX((los.nextInt(szerokosc/20-1)+1)*20);
                b.setY((los.nextInt(wysokosc/20-1)+1)*20);
                dlugosc++;
                punkty += 10;
                for(Waz w : waz){
                    if(b.getX() == w.getX() && b.getY() == w.getY()){
                        b.setX((los.nextInt(szerokosc/20-1)+1)*20);
                        b.setY((los.nextInt(wysokosc/20-1)+1)*20);
                    }
                }
            }
        }
        
        if(x == 0 && y == 0){
        }
        else{
            for(int i = 0; i < waz.size()-2; i++){
                if(waz.get(waz.size()-1).getX() == waz.get(i).getX() &&
                   waz.get(waz.size()-1).getY() == waz.get(i).getY()){

                    over = true;
                }
            }
        }
        
        if(x<0 || y<0 || x>szerokosc-20 || y>wysokosc-20){
            over = true;
        }
        
    }
    
    public void paintComponent(Graphics g){
        
        g.clearRect(0, 0, szerokosc, wysokosc);
        g.drawImage(tlo, 0, 0, szerokosc, wysokosc, this);
        
        for(int i = 0; i<waz.size();i++){
            if(i+1 == waz.size()){
                g.drawImage(glowa, waz.get(i).getX(), waz.get(i).getY(),this);
            }
            else g.drawImage(snake, waz.get(i).getX(), waz.get(i).getY(),this);
        }
        
        for(int i = 0; i<bonus.size();i++){
            g.drawImage(jablko, bonus.get(i).getX(), bonus.get(i).getY(), this);
        }
        
        if(over){
            czas.cancel();
            g.clearRect(0, 0, szerokosc, wysokosc);
            g.drawImage(tlo, 0, 0, this);
            g.setColor(Color.BLACK);
            g.setFont(new Font("TimesRoman", Font.BOLD, 70)); 
            g.drawString("Punkty:", 80, 150);
            g.drawString(" "+punkty, 80, 250);
            add(powrot);
        }
    }
    
    private class Odswiezanie extends TimerTask{
        
        @Override
        public void run(){
            ruch();
            kolizje();
            repaint();
            requestFocus();
        }
    }
    
    private class Klawisz implements KeyListener{
        
        @Override
        public void keyPressed(KeyEvent e) {
            int klawisz = e.getKeyCode();
        
            if(klawisz == KeyEvent.VK_UP && !dol){
                gora = true;
                lewa = false;
                prawa = false;
                ImageIcon iig = new ImageIcon("glowapion.png");
                glowa = iig.getImage();
                System.out.println("gora");
            }
        
            if(klawisz == KeyEvent.VK_DOWN && !gora){
                dol = true;
                lewa = false;
                prawa = false;
                ImageIcon iig = new ImageIcon("glowapion.png");
                glowa = iig.getImage();
                System.out.println("dol");
            }
        
            if(klawisz == KeyEvent.VK_LEFT && !prawa){
                lewa = true;
                dol = false;
                gora = false;
                ImageIcon iig = new ImageIcon("glowa.png");
                glowa = iig.getImage();
                System.out.println("lewa");
            }
        
            if(klawisz == KeyEvent.VK_RIGHT && !lewa){
                prawa = true;
                gora = false;
                dol = false;
                ImageIcon iig = new ImageIcon("glowa.png");
                glowa = iig.getImage();
                System.out.println("prawa");
            }
        }

        @Override
        public void keyTyped(KeyEvent e) {
            //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public void keyReleased(KeyEvent e) {
            //To change body of generated methods, choose Tools | Templates.
        }
    
    }
    
    
}



1

Może spróbuj dodawać eventy do BlockingQueue i zdejmować eventy gracza w evencie timera? Jak robiłem snake client-servet to zrobiłem to w ten sposób. U Ciebie wygląda to tak, że zanim uruchomi się kolejny event timera, Ty zdążysz kliknąć w dół i lewo co w rezultacie oznacza, że wąż z kierunku prawo zaczyna przesuwać się w lewo, dlatego masz kolizję.

0

A mozesz mi dac wskazowki jak to zaimplementowac? Nie oczekuje gotowego kodu, ale nigdy wczesniej tego nie uzywalem :)

1

Aplikacja co prawda client-server ale zawsze coś pomoże:

/**
 * Timer odlicza czas pomiędzy kolejnymi ruchami węża.
 */
@Component
public class Timer implements Runnable {
    /**
     * Kolejka blokująca w której timer umieszcza eventy.
     */
    private final BlockingQueue<GameEvent> blockingQueue;

    @Value("${Timer.exception}")
    private String timerErrorText;

    /**
     * Tworzy Timer.
     *
     * @param blockingQueue klejka blokująca zawierająca eventy od gracza
     */
    public Timer(final BlockingQueue<GameEvent> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    /**
     * Usypia wątek po czym umieszcza TimerEvent w kolejce blokującej.
     */
    @Override
    public void run() {
        try {
            while (true) {
                Thread.sleep(100);
                blockingQueue.add(new TimerEvent());
            }
        } catch (Exception e) {
            System.out.println(timerErrorText);
            e.printStackTrace();
        }
    }
}
/**
 * Klasa odpowiedzialna za komunikację z serwerem.
 */
public class ClientNetwork {
    /**
     * Widok klienta.
     */
    final private View view;
    /**
     * Socket z którym komunikuje się klient.
     */
    private Socket clientSocket;
    /**
     * Strumeń obiektów wyjściowych do serwera.
     */
    private ObjectOutputStream objectOutputStream;

    public ClientNetwork(final View view) {
        this.view = view;
    }

    /**
     * Nawiązanie połączenia z serwerem.
     *
     * @param IpNumber numer IP serwera
     * @param isLocal  czy połączenie jest lokalne
     */
    public void conectToServer(final String IpNumber, boolean isLocal) {
        try {
            if (!isRMIConnection(isLocal)) throw new Exception();
            clientSocket = new Socket(IpNumber, 5555);
            objectOutputStream = new ObjectOutputStream(
                    clientSocket.getOutputStream());
            Thread t = new Thread(new InputReader(clientSocket));
            t.start();

        } catch (Exception e) {
            view.showInfoMessage(new InfoMessage("RMI zgłasza błąd podłączenia do serwera"));
        }
    }

    private boolean isRMIConnection(boolean isLocal) {
        if (isLocal) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ignored) {}
                if (RmiClientConnection.isConnectionToServer()) {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    /**
     * Wysyła informacje o zdarzeniu do serwera.
     *
     * @param playerEvent
     */
    public void sendEvent(final PlayerEvent playerEvent) {
        if (objectOutputStream == null) {
            view.showInfoMessage(new InfoMessage("Brak połączenia z serwerem"));
            return;
        }
        try {
            objectOutputStream.writeObject(playerEvent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Nasłuchiwacz obiektów z serwera.
     */
    private class InputReader implements Runnable {
        /**
         * Strumień danych wejściowych z serwera.
         */
        private ObjectInputStream objectInputStream;
        /**
         * Mapa akcji podejmowanych zgodnie z nadchodzącymi obiektami message.
         */
        private final HashMap<Class<? extends GameMessage>, GameAction> actions;

        public InputReader(final Socket socket) {
            actions = new HashMap<Class<? extends GameMessage>, ClientNetwork.InputReader.GameAction>();
            try {
                objectInputStream = new ObjectInputStream(socket.getInputStream());
            } catch (Exception e) {
                e.printStackTrace();
            }
            actions.put(BoardMessage.class, new FakeAction());
            actions.put(InfoMessage.class, new InformationAction());
            actions.put(ScoreMessage.class, new ActScore());
        }

        /**
         * Obsluga nadchodzących informacji z serwera.
         */
        @Override
        public void run() {
            while (true) {
                try {
                    GameMessage gameMessage = (GameMessage) objectInputStream.readObject();
                    actions.get(gameMessage.getClass()).perform(gameMessage);
                } catch (IOException e) {
                    view.showInfoMessage(new InfoMessage("Utracono polaczenie z serwerem"));
                    break;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            try {
                objectOutputStream.close();
                objectInputStream.close();
                objectInputStream = null;
                objectOutputStream = null;
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        /**
         * Abstrakcyjna klasa odpowiedzialna za wykonywanie akcji.
         */
        private abstract class GameAction {
            abstract void perform(GameMessage gameMessage);
        }

        /**
         * Aktualizacja wyników graczy.
         */
        private class ActScore extends GameAction {
            @Override
            void perform(final GameMessage gameMessage) {
                view.actScores((ScoreMessage) gameMessage);
            }
        }

        /**
         * Uaktualnienie widoku głównej planszy.
         */
        private class FakeAction extends GameAction {
            @Override
            void perform(final GameMessage gameMessage) {
                view.updateBoard(gameMessage);
            }
        }

        /**
         * Wyświetlenie okna z informacją.
         */
        private class InformationAction extends GameAction {
            @Override
            void perform(final GameMessage gameMessage) {
                view.showInfoMessage((InfoMessage) gameMessage);
            }
        }
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1