Cześć ostatnio postanowiłem dla wprawy napisać grę snake i ogólnie wszystko działa tylko natknąłem się na dwie kwestie, które nie wiem jak rozwiązać. Mianowicie pierwsza sprawa to w momencie gdy wąż posiada 2 człony i zje jabłko, obraz jest na nowo rysowany począwszy od tych dwóch członów. Dzieje się tak zawsze nawet gdy ma on długość powiedzmy 10 elementów w momencie zjedzenia kolejnego jabłka pojawiają się 2 człony i po chwili kolejne, aż do 11. Czy ktoś mógłby powiedzieć co poprawić w kodzie aby to nie występowało i cała długość węża była widoczna cały czas?
Druga sprawa to obsługa klawiatury otóż gdy np. wąż porusza się w prawą stronę i szybko wcisnę strzałkę do góry oraz w lewo wykrywa gra się kończy bo wykrywa kolizję głowy z członem. Co powinienem poprawić aby wprowadzić jakieś opóźnienie przy wykrywaniu kolejnej akcji klawisza albo żeby dopiero po zmianie kierunku poruszania na ekranie była wykrywana kolizja. Poniżej zamieszczam kod.
Klasa z całą logiką gry.


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JButton;

import javax.swing.JPanel;
import javax.swing.Timer;
import static snakev4.Snakev4.managerOkien;

public class Gra extends JPanel implements ActionListener {

    public static final int DLUGOSCX = 560;
    public static final int DLUGOSCY = 460;
    public static final int SZEROKOSC_CALEGO_OKNA = 640;
    public static final int WYSOKOSC_CALEGO_OKNA = 650;
    public static final int MARGINES_LEWY = 40;
    public static final int MARGINES_GORNY_TYTUL = 10;
    public static final int MARGINES_GORNY_POLEGRY = 100;
    private static final int SZEROKOSC_PRZYCISKU = 70;
    private static final int WYSOKOSC_PRZYCISKU = 30;
    private static int szerokosc_obrazka_glowy;
    private static int wysokosc_obrazka_glowy;

    private static int szer_jablka;
    private static int wys_jablka;

    private Image nazwa;
    private Image glowa;
    private Image czlon;
    private Image jablko;

    public static Timer zegar;
    private int szybkoscporuszania = 150;

    public static boolean lewo = false;
    public static boolean prawo = false;
    public static boolean gora = false;
    public static boolean dol = false;

    public static int pozycja_x_weza = DLUGOSCX / 2 + MARGINES_LEWY;
    public static int pozycja_y_weza = ((DLUGOSCY / 2) + MARGINES_GORNY_POLEGRY) - 10;

    public int polozenie_x_jablka;
    public int polozenie_y_jablka;

    private int liczba_czlonow = 1;
    public static ArrayList<Integer> wspolrzedneX_czlonow = new ArrayList<>();
    public static ArrayList<Integer> wspolrzedneY_czlonow = new ArrayList<>();
    private JButton pause, start, zamknij, wroc, restart;
    private JPanel panelNaPrzyciski;

    public Gra() {
        zegar = new Timer(szybkoscporuszania, this);

        przygotuj_plansze();
        tworzPrzyciski();
        add(panelNaPrzyciski);

    }

    private void tworzPrzyciski() {

        panelNaPrzyciski = new JPanel();
        pause = new JButton();

        pause.setFocusable(false);
        pause.setText("Pauza");
        pause.setFont(new Font("Times New Roman", Font.PLAIN, 10));
        pause.setPreferredSize(new Dimension(SZEROKOSC_PRZYCISKU, WYSOKOSC_PRZYCISKU));
        pause.addActionListener(this);

        start = new JButton();

        start.setFocusable(false);
        start.setText("Wznów");
        start.setFont(new Font("Times New Roman", Font.PLAIN, 10));
        start.setPreferredSize(new Dimension(SZEROKOSC_PRZYCISKU, WYSOKOSC_PRZYCISKU));
        start.addActionListener(this);

        zamknij = new JButton("Zamknij");
        zamknij.setFocusable(false);
        zamknij.setPreferredSize(new Dimension(SZEROKOSC_PRZYCISKU, WYSOKOSC_PRZYCISKU));
        zamknij.setFont(new Font("Times New Roman", Font.PLAIN, 10));
        zamknij.addActionListener(this);

        wroc = new JButton("Wróć");
        wroc.setFocusable(false);
        wroc.setText("Wróć");
        wroc.setFont(new Font("Times New Roman", Font.PLAIN, 10));
        wroc.setPreferredSize(new Dimension(SZEROKOSC_PRZYCISKU, WYSOKOSC_PRZYCISKU));
        wroc.addActionListener(this);

        restart = new JButton("Restart");
        restart.setFocusable(false);
        restart.setFont(new Font("Times New Roman", Font.PLAIN, 10));
        restart.setPreferredSize(new Dimension(SZEROKOSC_PRZYCISKU, WYSOKOSC_PRZYCISKU));
        restart.addActionListener(this);

        panelNaPrzyciski.add(restart);
        panelNaPrzyciski.add(zamknij);
        panelNaPrzyciski.add(pause);
        panelNaPrzyciski.add(start);
        panelNaPrzyciski.add(wroc);
        panelNaPrzyciski.setVisible(true);
        panelNaPrzyciski.setBounds(50, (MARGINES_GORNY_POLEGRY + DLUGOSCY), 500, 40);

    }

    private void przygotuj_plansze() {
        addKeyListener(new Klawisze());
        zaladuj_grafiki();
        setFocusable(true);
        setDoubleBuffered(true);

        setPreferredSize(new Dimension(SZEROKOSC_CALEGO_OKNA, WYSOKOSC_CALEGO_OKNA));
        setLayout(null);
        przygotuj_gre();

    }

    private void przygotuj_gre() {
        losuj_pozycje_jablka();
        wspolrzedneX_czlonow.add(0, pozycja_x_weza);
        wspolrzedneY_czlonow.add(0, pozycja_y_weza);

    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        rysuj_plansze_gry(g);
        if (sprawdzCzyDotknalesKrawedzi() || sprawdzKolizjeZCzlonem()) {
            koniecGry(g);
            zegar.stop();
        }
        rysuj_weza(g);

        rysuj_jablko(g);

    }

    private void rysuj_plansze_gry(Graphics g) {

        g.setColor(Color.WHITE);
        g.drawRect(MARGINES_LEWY, MARGINES_GORNY_TYTUL, 550, 60);//utworzenie prostokata w ktorym znajduje sie logo gry

        g.setColor(Color.white);//rysowanie prostokata w ktorym bedzie toczyla sie gra
        g.drawRect(MARGINES_LEWY, MARGINES_GORNY_POLEGRY, DLUGOSCX, DLUGOSCY);

        g.setColor(Color.BLACK); //wypelnienie kolorem czarnym pola gry
        g.fillRect(MARGINES_LEWY, MARGINES_GORNY_POLEGRY, DLUGOSCX, DLUGOSCY);

        g.drawImage(nazwa, MARGINES_LEWY, 10, 550, 60, this);//rysuje nazwe gry 

    }

    private void rysuj_weza(Graphics g) {

        if (sprawdzCzyDotknalesKrawedzi() == false) {
            for (int i = 0; i < liczba_czlonow; i++) {
                if (i == 0) {
                    g.drawImage(glowa, wspolrzedneX_czlonow.get(i), wspolrzedneY_czlonow.get(i), this);
                } else {
                    g.drawImage(czlon, wspolrzedneX_czlonow.get(i), wspolrzedneY_czlonow.get(i), this);

                }
            }

        }

    }

    private void rysuj_jablko(Graphics g) {
        g.drawImage(jablko, polozenie_x_jablka, polozenie_y_jablka, this);

    }

    private void losuj_pozycje_jablka() {
        boolean czyPozycjaCzlonu = false;
        int x = (int) (Math.random() * 1000);
        int y = (int) (Math.random() * 1000);

        if ((x > MARGINES_LEWY && x < MARGINES_LEWY + DLUGOSCX)
                && (y > MARGINES_GORNY_POLEGRY && y < MARGINES_GORNY_POLEGRY + DLUGOSCY)
                && (x != pozycja_x_weza && y != pozycja_y_weza)
                && (x % szerokosc_obrazka_glowy == 0 && y % wysokosc_obrazka_glowy == 0) && czyPozycjaCzlonu == false) {
            polozenie_x_jablka = x;
            polozenie_y_jablka = y;
        } else {
            losuj_pozycje_jablka();
        }

    }

    private void zjedzenie_jablka() {
        if (sprawdzCzyZjadlesJablko()) {
            liczba_czlonow += 1;

            for (int i = 1; i < liczba_czlonow; i++) {

                wspolrzedneX_czlonow.add(i, wspolrzedneX_czlonow.set(i - 1, wspolrzedneX_czlonow.get(i - 1)));
                wspolrzedneY_czlonow.add(i, wspolrzedneY_czlonow.set(i - 1, wspolrzedneY_czlonow.get(i - 1)));
            }
            if (lewo) {
                wspolrzedneX_czlonow.set(0, wspolrzedneX_czlonow.get(0) - szerokosc_obrazka_glowy);
            }
            if (prawo) {
                wspolrzedneX_czlonow.set(0, wspolrzedneX_czlonow.get(0) + szerokosc_obrazka_glowy);
            }
            if (dol) {
                wspolrzedneY_czlonow.set(0, wspolrzedneY_czlonow.get(0) + wysokosc_obrazka_glowy);
            }
            if (gora) {
                wspolrzedneY_czlonow.set(0, wspolrzedneY_czlonow.get(0) - wysokosc_obrazka_glowy);
            }

            losuj_pozycje_jablka();
        }

    }

    private boolean sprawdzCzyZjadlesJablko() {

        Rectangle wazPolozenie1 = new Rectangle(wspolrzedneX_czlonow.get(0), wspolrzedneY_czlonow.get(0), szerokosc_obrazka_glowy, wysokosc_obrazka_glowy);

        Rectangle jablkoPolozenie1 = new Rectangle(polozenie_x_jablka, polozenie_y_jablka, szer_jablka, wys_jablka);
        if (jablkoPolozenie1.intersects(wazPolozenie1)) {
            return true;
        } else {
            return false;
        }

    }

    private boolean sprawdzKolizjeZCzlonem() {
        Rectangle glowa = new Rectangle(wspolrzedneX_czlonow.get(0), wspolrzedneY_czlonow.get(0), szerokosc_obrazka_glowy, wysokosc_obrazka_glowy);

        for (int i = 1; i < liczba_czlonow; i++) {
            Rectangle czlon = new Rectangle(wspolrzedneX_czlonow.get(i), wspolrzedneY_czlonow.get(i), szerokosc_obrazka_glowy, wysokosc_obrazka_glowy);
            if (czlon.intersects(glowa)) {
                return true;
            }

        }
        return false;
    }

    private void koniecGry(Graphics g) {
        String wiadomosc = "Koniec Gry. Przegrales";

        g.setColor(Color.red);
        g.drawString(wiadomosc, 300, 300);

    }

    private boolean sprawdzCzyDotknalesKrawedzi() {

        if (wspolrzedneX_czlonow.get(0) > (DLUGOSCX + MARGINES_LEWY - szerokosc_obrazka_glowy)//sprawdzenie krawedzi prawej pola gry
                || wspolrzedneX_czlonow.get(0) < (MARGINES_LEWY)//sprawdzenie krawedzi lewej pola gry
                || wspolrzedneY_czlonow.get(0) < MARGINES_GORNY_POLEGRY//sprawdzenie krawedzi gornej pola gry
                || wspolrzedneY_czlonow.get(0) > MARGINES_GORNY_POLEGRY + DLUGOSCY - wysokosc_obrazka_glowy) {//sprawdzenie krawedzi dolnej pola gry
            return true;
        } else {
            return false;
        }
    }

    private void zaladuj_grafiki() {
        ImageIcon nazwapomoc = new ImageIcon("E:\\moje programy\\do snake\\tytul.jpg");
        nazwa = nazwapomoc.getImage();
        ImageIcon pomocznicza = new ImageIcon("E:\\moje programy\\do snake\\czlon2.jpg");
        czlon = pomocznicza.getImage();
        ImageIcon nazwapomoc2 = new ImageIcon("E:\\moje programy\\do snake\\glowa2.jpg");
        glowa = nazwapomoc2.getImage();
        ImageIcon nazwapomoc3 = new ImageIcon("E:\\moje programy\\do snake\\jablko2.jpg");
        jablko = nazwapomoc3.getImage();
        szerokosc_obrazka_glowy = (glowa.getWidth(this));
        wysokosc_obrazka_glowy = (glowa.getHeight(this));
        szer_jablka = (jablko.getWidth(this));
        wys_jablka = (jablko.getHeight(this));
    }

    private void ruch() {

        for (int i = liczba_czlonow - 1; i > 0; i--) {

            wspolrzedneX_czlonow.set(i, wspolrzedneX_czlonow.get(i - 1));
            wspolrzedneY_czlonow.set(i, wspolrzedneY_czlonow.get(i - 1));

        }

        if (prawo && wspolrzedneX_czlonow.get(0) < (DLUGOSCX + MARGINES_LEWY)) {

            wspolrzedneX_czlonow.set(0, (wspolrzedneX_czlonow.get(0) + szerokosc_obrazka_glowy));
        }
        if (lewo && wspolrzedneX_czlonow.get(0) > MARGINES_LEWY - szerokosc_obrazka_glowy) {

            wspolrzedneX_czlonow.set(0, (wspolrzedneX_czlonow.get(0) - szerokosc_obrazka_glowy));
        }
        if (gora && wspolrzedneY_czlonow.get(0) > MARGINES_GORNY_POLEGRY - wysokosc_obrazka_glowy) {

            wspolrzedneY_czlonow.set(0, (wspolrzedneY_czlonow.get(0) - wysokosc_obrazka_glowy));
        }
        if (dol && wspolrzedneY_czlonow.get(0) < DLUGOSCY + MARGINES_GORNY_POLEGRY) {

            wspolrzedneY_czlonow.set(0, (wspolrzedneY_czlonow.get(0) + wysokosc_obrazka_glowy));
        }

    }

    @Override
    public void actionPerformed(ActionEvent e) {

        Object przycisk = e.getSource();
        if (przycisk == pause) {
            Gra.zegar.stop();
        }
        if (przycisk == wroc) {
            managerOkien.show(Snakev4.oknoMieszczaceInne, "powitanie");
            zegar.stop();

        }
        if (przycisk == zamknij) {
            System.exit(0);
        }
        if (przycisk == start) {
            Gra.zegar.start();
        }
        if (przycisk == restart) {
            przygotuj_gre();
            zegar.start();
            lewo = false;
            prawo = false;
            dol = false;
            gora = false;
            liczba_czlonow = 1;
        }

        ruch();
        zjedzenie_jablka();

        repaint();

    }

}



Klasa zawierająca wykrywanie zdarzeń klawiatury


import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;




public class Klawisze extends KeyAdapter{
  
    
    @Override
    public void keyPressed(KeyEvent e)
    {
 
        
     if(e.getKeyCode()==KeyEvent.VK_RIGHT&&!Gra.lewo)
    {
      
        Gra.prawo=true;
        Gra.dol=false;
         Gra.gora=false;
        
        
    }
    if(e.getKeyCode()==KeyEvent.VK_LEFT&&!Gra.prawo)
    {
        Gra.lewo=true;
        Gra.dol=false;
        Gra.gora=false;
    }
    if(e.getKeyCode()==KeyEvent.VK_UP&&!Gra.dol)
    {
      
        Gra.gora=true;
        Gra.prawo=false;
        Gra.lewo=false;
 
        
    }
    if(e.getKeyCode()==KeyEvent.VK_DOWN&&!Gra.gora)
    {
      Gra.dol=true;
      Gra.prawo=false;
      Gra.lewo=false;
     
    }

        
   
    }
    
}