Snake - problem ze zmiennymiy

0

Cześć
Sprawa wygląda tak, że muszę zrobić projekt z programowania obiektowego. Ale w związku z tym, że programowanie nie jest moją mocną stroną to wziąłem jakiś gotowy projekt z internetu. No i tu zaczęły się schody bo okazało się, że dwie klasy to za mało więc postanowiłem to rozdzielić na własną rękę. Z klasy PanelGry wziąłem kod na sterowanie wężem i zrobiłem z tego klasę Gracz. Są tam zmienne gora, dol, lewo, prawo, start. Ale w klasie PanelGry została metoda, która te zmienne wykorzystuje (drugi kod). Próbowałem to zrobić tym samym sposobem jak przy rozdzielaniu innych klas, więc dałem private Gracz gora, dol, lewo, prawo, start; myśląc że to zadziała. Niestety skończyło się to na błędach typu Type mismatch: cannot convert from Gracz to boolean oraz The operator && is undefinied for the argument type Gracz, boolean. Kiedy ten kod był w jednej klasie to cały Snake działał bez problemu. Problem pewnie jest banalny, ale sam tego nie zrobię dlatego liczę na czyjąś pomoc.

public class Gracz implements KeyListener{
	 
	 private boolean gora, dol, lewo, prawo, start;
	
	 @Override
		public void keyPressed(KeyEvent e) {
	
			int k = e.getKeyCode();

			if (k == KeyEvent.VK_UP || k == KeyEvent.VK_W)
				gora = true;
			if (k == KeyEvent.VK_DOWN || k == KeyEvent.VK_S)
				dol = true;
			if (k == KeyEvent.VK_LEFT || k == KeyEvent.VK_A)
				lewo = true;
			if (k == KeyEvent.VK_RIGHT || k == KeyEvent.VK_D)
				prawo = true;
			if (k == KeyEvent.VK_SPACE)
				start = true;

		}

		@Override
		public void keyReleased(KeyEvent e) {
			int k = e.getKeyCode();

			if (k == KeyEvent.VK_UP || k == KeyEvent.VK_W)
				gora = false;
			if (k == KeyEvent.VK_DOWN || k == KeyEvent.VK_S)
				dol = false;
			if (k == KeyEvent.VK_LEFT || k == KeyEvent.VK_A)
				lewo = false;
			if (k == KeyEvent.VK_RIGHT || k == KeyEvent.VK_D)
				prawo = false;
			if (k == KeyEvent.VK_SPACE)
				start = false;

		}

		@Override
		public void keyTyped(KeyEvent e) {

		}
}
private void update() {
		
		if(koniecgry){
			if(start){
				sDzwiek.play();
				sDzwiek.petla();
				setNastPoziom();
				}
			return;
		}
		if (gora && dy == 0) {
			dy = -ROZMIAR;
			dx = 0;
		}
		if (dol && dy == 0) {
			dy = ROZMIAR;
			dx = 0;
		}
		if (lewo && dx == 0) {
			dy = 0;
			dx = -ROZMIAR;
		}
		if (prawo && dx == 0 && dy != 0) {
			dy = 0;
			dx = ROZMIAR;
		}
1

W klasie PanelGry zapewne tworzysz instancję Gracz.
np.

Gracz gracz = new Gracz();

Więc w swoim update musisz się odnieść do tych zmiennych:

        if (gracz.gora && dy == 0) {
            dy = -ROZMIAR;
            dx = 0;
        }
        if (gracz.dol && dy == 0) {
            dy = ROZMIAR;
            dx = 0;
        }

No i te pola muszą być publiczne, albo posiadać gettery.

No i chyba nie muszę wspominać, że

private Gracz gora, dol, lewo, prawo, start;

to totalna patologia i trzeba ją usunąć :) ?

Fajnie, że coś próbujesz jednak zrobić, ale lepiej by było, żebyś sam to zrobił od podstaw. Według doniesień prasy, programistą można zostać już w pół roku!
http://di.com.pl/polacy-chca-zostac-programistami-ale-83-proc-z-nich-nie-wie-jak-58059
haha :D

0

Wszystko poszło elegancko, nie ma już błędów. Wielkie dzięki :)
Snake się już rusza, tylko taka sytuacja, że "jedzenie" nie zmienia swojej pozycji, jest ciągle w tym samym miejscu. Poniżej wrzucę kod z PanelGry, który odpowiada za to i całą klasę Jedzenie. Może to starczy do wychwycenia co jest nie tak, bo ciężko mi to określić jak nie są pokazane żadne błędy.

if(jedzenie.jestKolizja(head)){
			wynik++;
			setJedzenie();
			
			Snake e = new Snake(ROZMIAR);
			e.setPozycja(-100, -100);
			snake.add(e);
			if(wynik % 10 == 0){
				poziom++;
				if(poziom > 10) poziom=10;
				setFPS(poziom * 10);
public class Jedzenie{
	
	PanelGry panelgry = new PanelGry();
	Snake jedzenie;

	public void setJedzenie(){
		int x = (int)(Math.random() * (PanelGry.SZEROKOSC - panelgry.ROZMIAR)); 
		int y = (int)(Math.random() * (PanelGry.WYSOKOSC - panelgry.ROZMIAR)); 
		x = x -(x % panelgry.ROZMIAR);
		y = y -(y % panelgry.ROZMIAR);
		
		jedzenie.setPozycja(x, y);
		
	}
Spine napisał(a):

Fajnie, że coś próbujesz jednak zrobić, ale lepiej by było, żebyś sam to zrobił od podstaw. Według doniesień prasy, programistą można zostać już w pół roku!

Samemu za żadne skarby świata nie dałbym rady. Programowanie to kompletnie nie moja bajka, a projekt trzeba zrobić :D

0

Czemu dla jedzenia tworzysz instancję PanelGry!? Mniejsza o to, bo w tym kodzie to raczej nie powoduje błędu...

Jakie wartości mają szerokość, wysokość i rozmiar?

Zresztą.... zobacz co dają obliczenia wykonywane w metodzie set jedzenie:

Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 14
>>> x = x - (x % 20)
>>> x
0
>>> x = 9
>>> x = x - (x % 20)
>>> x
0
>>>

przypisujemy x "losową pozycję na planszy", potem przypisujemy x - (x mod ROZMIAR) i zawsze mamy zero...

Wywal te linijki z modulo.

0

Dałem instancję, ponieważ te zmienne mam stworzone właśnie w PanelGry i nie chciałem żeby wywalało błędów jak w tym moim pierwszym poście.
Szerokość i wysokość mają wartość 500, a rozmiar 10.
Ogólnie to wygląda tak, że dopóki ten kod na ustawianie jedzenia był w klasie PanelGry to działało. A teraz cały czas jest w lewym górnym rogu. Może metodę setJedzenie powinienem w jakiś konkretny sposób zainicjować w PanelGry?

0

Czy panelgry.ROZMIAR jest inicjowany (otrzymuje wartość) gdzieś poza konstruktorem/ciałem klasy?
Bo jeśli tak, to PanelGry panelgry = new PanelGry(); daje Ci ROZMIAR z niezainicjowaną wartością.

0

Kurczę, nie bardzo zrozumiałem o co chodzi. W PanelGry mam coś takiego public final int ROZMIAR = 10;, ale nie wiem czy o takie coś Ci chodziło. W dodatku w tej samej klasie mam coś takiego. Może z tym coś jest nie tak? O ile dobrze pamiętam to na początku wpisałem Jedzenie setJedzenie();, ale był błąd, więc zrobiłem to co za zalecał Eclipse.

Jedzenie setJedzenie() {
		return null;
	}
0

public final int ROZMIAR = 10; - czyli rozmiar jest inicjowany w ciele klasy, to jest ok.

No tak... setJedzenie() w klasie PanelGry nie robi nic!
Powinieneś gdzieś w klasie PanelGry zrobić sobie instancję klasy Jedzenie, np. Jedzenie j = new Jedzenie(); i potem wykonywać:

if(jedzenie.jestKolizja(head)){
            wynik++;
            j.setJedzenie();

a to setJedzenie, co zwraca null to wywal.

I naprawdę przydałoby się napisać ten kod po ludzku, a nie np. robić zmienną jedzenie typu Snake....

Obiektowość jest po to, żeby nam ułatwić sprawę, a nie zagmatwać kod.

Twój snake co ma? Człony.
Jedzenie to odrębny obiekt, który w wyniku zjedzenia dodaje człon.
Który człon zjada jedzenie? Pierwszy. Więc gdy pozycja pierwszego członu jest taka sama jak pozycja jedzenia, to snake dodaje sobie człon.
Każdy ruch węża przesuwa pierwszy człon w kierunku poruszania węża, a pozostałe człony na miejsce członu o indeksie o jeden mniejszym.

Niech każdy obiekt odpowiada za siebie - posiada metody operujące na jego polach.

Obiektowość to przede wszystkim uproszczenie zapisu, który bez obiektów robi spaghetti.

0

Teraz przy próbie uruchomienia w konsoli wyskakuje błąd <init> odwołujący się do linijek klasy PanelGry i Jedzenie, gdzie mam odpowiednio Jedzenie j = new Jedzenie(); oraz PanelGry panelgry = new PanelGry();. Czym jest to spowodowane?

0

Czy Tobie coś mówi "błąd <init>"?
Nic więcej nie jest napisane?

Mogę się tylko domyślać.

Może java chce, żebyś w ciele klasy deklarował zmienne, a dopiero w konstruktorze tworzył obiekty?

A może zrobiła się pętla, bo tworzysz instancję obiektu w obiekcie, którego instancję tworzysz?
Jeśli Jedzenie tworzy nowe jedzenie, to utworzenie tego nowego jedzenia również utworzy nowe jedzenie, i tak w kółko, aż przepełni się pamięć...

0

Racja, mój błąd. Nie zauważyłem, że w tej konsoli było tego więcej i tylko wrzuciłem to z <init>.

Exception in thread "main" java.lang.StackOverflowError
	at java.awt.Component.setBackground(Unknown Source)
	at javax.swing.JComponent.setBackground(Unknown Source)
	at javax.swing.LookAndFeel.installColors(Unknown Source)
	at javax.swing.LookAndFeel.installColorsAndFont(Unknown Source)
	at javax.swing.plaf.basic.BasicPanelUI.installDefaults(Unknown Source)
	at javax.swing.plaf.basic.BasicPanelUI.installUI(Unknown Source)
	at javax.swing.JComponent.setUI(Unknown Source)
	at javax.swing.JPanel.setUI(Unknown Source)
	at javax.swing.JPanel.updateUI(Unknown Source)
	at javax.swing.JPanel.<init>(Unknown Source)
	at javax.swing.JPanel.<init>(Unknown Source)
	at javax.swing.JPanel.<init>(Unknown Source)
	at projekt.snake.PanelGry.<init>(PanelGry.java:52)
	at projekt.snake.Jedzenie.<init>(Jedzenie.java:6)
	at projekt.snake.PanelGry.<init>(PanelGry.java:43)

Gdzie linijka 6 i 43 to to co podawałem,a linijka 52 to rozpoczęcie metody public PanelGry()

0

StackOverflowError - przepełnienie stosu, czyli to co pisałem, musisz gdzieś tworzyć obiekt w obiekcie. Albo lepiej, np. w klasie Jedzenie tworzysz PanelGry, który tworzy Jedzenie, które znowu tworzy PanelGry i tak w kółko.

Potraktuj PanelGry jako singleton. Nawet nie od strony technicznej, tylko po prostu zadbaj o to, żeby PanelGry był tworzony tylko raz. Stałe (ROZMIAR, SZEROKOSC, WYSOKOSC) możesz przekazać do innych obiektów bez konieczności tworzenia instancji PanelGry. Możesz np. zrobić klasę statyczną, posiadającą te pola i wszystkie obiekty będą mogły ją wykorzystać.

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