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;
}
}
}