• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Snake klasyczny problem z ogonem

Object Storage Arubacloud
0 głosów
263 wizyt
pytanie zadane 30 października 2017 w C i C++ przez CPP_Newbie Użytkownik (770 p.)

Witam,

Zacznę od tego, że szukałem i czytałem wiele wątków dotyczących tego problemu i mimo to, drugi dzień już męczę się z tym problemem. Mianowicie ogon węża nie podąża za głową. Tzn. częściowo udało mi się to osiągnąć, ale nie działa to, jak należy.

Czy ktoś może mi to wyjaśnić łopatologicznie ?

 

#include <SFML\Graphics.hpp>

using namespace sf;

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

void respawnFood(RectangleShape& food)
{
	float foodSize = 20;
	food.setFillColor(Color::Red);
	food.setSize({ foodSize, foodSize });
	food.setPosition(rand() % 640, rand() % 480);
}

bool isColliding(RectangleShape& snake, RectangleShape& food)
{
	if (snake.getGlobalBounds().intersects(food.getGlobalBounds()))
		return true;

	return false;
}

int main()
{
	RenderWindow window(VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT), "SFML");

	// MISC
	srand( time (NULL ) );
	Clock clock;
	Time time;

	// SNAKE
	enum SnakeDirection { LEFT, RIGHT, UP, DOWN, NONE };
	SnakeDirection currentDirection = NONE;

	RectangleShape snakeHead;
	float snakeSize = 20;
	float snakeSpeed = 200.f;
	snakeHead.setFillColor(Color::Green);
	snakeHead.setSize({ snakeSize, snakeSize });
	snakeHead.setPosition(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);

	std::vector<RectangleShape> snakeBody;

	// FOOD
	RectangleShape food;
	respawnFood(food);

	// MAIN LOOP
	clock.restart();
	while (window.isOpen())
	{
		time = clock.getElapsedTime();

		// HANDLE INPUT
		Event ev;
		while (window.pollEvent(ev))
		{
			if (ev.type == Event::Closed || ev.type == Event::KeyPressed && ev.key.code == Keyboard::Escape)
				window.close();
		}

		if ((Keyboard::isKeyPressed(Keyboard::D) || Keyboard::isKeyPressed(Keyboard::Right)) && currentDirection != LEFT)
			currentDirection = RIGHT;
		if ((Keyboard::isKeyPressed(Keyboard::A) || Keyboard::isKeyPressed(Keyboard::Left)) && currentDirection != RIGHT)
			currentDirection = LEFT;
		if ((Keyboard::isKeyPressed(Keyboard::W) || Keyboard::isKeyPressed(Keyboard::Up)) && currentDirection != DOWN)
			currentDirection = UP;
		if ((Keyboard::isKeyPressed(Keyboard::S) || Keyboard::isKeyPressed(Keyboard::Down)) && currentDirection != UP)
			currentDirection = DOWN;

		// UPDATE
		if (currentDirection == RIGHT)
			snakeHead.move(time.asSeconds() * snakeSpeed, 0);
		if (currentDirection == LEFT)
			snakeHead.move(-time.asSeconds() * snakeSpeed, 0);
		if (currentDirection == UP)
			snakeHead.move(0, -time.asSeconds() * snakeSpeed);
		if (currentDirection == DOWN)
			snakeHead.move(0, time.asSeconds() * snakeSpeed);

		// collision check
		if (isColliding(snakeHead, food))
		{
			snakeBody.push_back(snakeHead);
			printf("%i\n", snakeBody.size());

			respawnFood(food);
		}

		for (int i = 1; i < snakeBody.size(); i++)
		{
			snakeBody[0].setPosition(snakeHead.getPosition());

			if(currentDirection == RIGHT)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x - snakeSize - 3, snakeBody[i - 1].getPosition().y);
			if (currentDirection == LEFT)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x + snakeSize + 3, snakeBody[i - 1].getPosition().y);
			if (currentDirection == UP)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x, snakeBody[i - 1].getPosition().y - snakeSize - 3);
			if (currentDirection == DOWN)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x, snakeBody[i - 1].getPosition().y + snakeSize + 3);

		}

		clock.restart();
		// END OF UPDATE
		
		// RENDER
		window.clear(Color::Black);

		window.draw(snakeHead);
		window.draw(food);

		for (int i = 0; i < snakeBody.size(); i++)
		{
			window.draw(snakeBody[i]);
		}

		window.display();
	}

	return EXIT_SUCCESS;
}

 

3 odpowiedzi

+1 głos
odpowiedź 30 października 2017 przez mtk3d Nałogowiec (46,690 p.)
Nie pracuje na co dzień z c++, więc nie czyta mi się go zbyt wygodnie, ale po szybkim rzuceniu okiem widzę, że chyba próbujesz dla każdego elementu ogona wyliczyć pozycję.

Spróbuj zrobić tak, że ruszasz tylko głową, a każdy następny element ciała węża, dostaje parametry swojego poprzednika.
2
komentarz 30 października 2017 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Spróbuj zrobić tak, że ruszasz tylko głową, a każdy następny element ciała węża, dostaje parametry swojego poprzednika.

A po co? Wystarczy zamieniać tylko pierwszy z ostatnim elementem - oszczędzi się dużo zbędnych przypisań laugh

komentarz 30 października 2017 przez mtk3d Nałogowiec (46,690 p.)
No zamiana nic nie da, ale chyba wiem o co ci chodzi. Teoretycznie usuwanie ostatniego elementu i dodawanie głowy, jest spoko, tylko jak masz tablicę z ciałem węża, to jedyną opcją, żeby to osiągnąć, to indexowanie węża od końca, z tym że wtedy z każdym przesunięciem masz tablicę o 1 większą.

Chyba, że masz jakiś inny pomysł i czegoś nie zrozumiałem.
komentarz 31 października 2017 przez CPP_Newbie Użytkownik (770 p.)

Nadal nie czaję crying

Napotkałem już wcześniej sugestie z tą zamianą ostatniego elementu wektora z pierwszym, ale wciąż nie wiem, jak to zaimplementować do powyższego kodu :(

komentarz 31 października 2017 przez event15 Szeryf (93,790 p.)
To znaczy, że nie stworzyłeś tego kodu sam tylko skopiowałeś bez namysłu
komentarz 31 października 2017 przez CPP_Newbie Użytkownik (770 p.)
Wszystko, co jest zawarte w powyższym kodzie, zostało napisane przeze mnie, a nie skopiowane.

Irytują mnie takie osoby...
komentarz 31 października 2017 przez event15 Szeryf (93,790 p.)
W takim razie nie powinieneś mieć problemu z zamianą ostatniego elementu wektora z pierwszym.
+1 głos
odpowiedź 31 października 2017 przez obl Maniak (51,280 p.)

Zdejmij ostatni element  tablicy snakeBody i przypisz mu pozycję głowy + przemieszczenie w danym kroku.

komentarz 31 października 2017 przez CPP_Newbie Użytkownik (770 p.)

Zmodyfikowałem pętlę for z powyższego kodu, ale po skompilowaniu nadal nie działa to tak, jak powinno (ogon węża dziwnie się zachowuje). Męczę się z tym trzeci dzień. Poddaje się....

for (int i = snakeBody.size() - 1; i >= 1 ; i--)
		{
			snakeBody[i].setPosition(snakeBody[i-1].getPosition());

			if (currentDirection == RIGHT)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x - snakeSize - 3, snakeBody[i - 1].getPosition().y);
			if (currentDirection == LEFT)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x + snakeSize + 3, snakeBody[i - 1].getPosition().y);
			if (currentDirection == UP)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x, snakeBody[i - 1].getPosition().y - snakeSize - 3);
			if (currentDirection == DOWN)
				snakeBody[i].setPosition(snakeBody[i - 1].getPosition().x, snakeBody[i - 1].getPosition().y + snakeSize + 3);

			snakeBody[0].setPosition(snakeHead.getPosition());
		}

 

komentarz 31 października 2017 przez obl Maniak (51,280 p.)
auto endOfSnake = snakeBody.back() ;
snakeBody.pop_back();

// najpierw przepisujesz z pierwszego elementu współrzędne do endOfSnake
// później ustawiasz przemieszczenie elementu endOfSnake z uwzględnieniem kierunku
// na koniec dodajesz na początek

snakeBody.insert(snakeBody.begin(), endOfSnake);

 

0 głosów
odpowiedź 31 października 2017 przez mokrowski Mędrzec (155,460 p.)
https://pl.wikipedia.org/wiki/Bufor_cykliczny

Czyli aby uniknąć ciągłych de/re/alokacji pamięci, deklaruj kontener z maksymalną długością węża i indeksuj go modulo długość tego węża. Pamiętaj także gdzie jest jego głowa. W ten sposób naturalnie będziesz niszczył jego ogon :-).

W trakcie powiększania węża, zwiększ wartość długości (brana później do modulo) i informację o współrzędnych głowy, zapisz o indeks dalej bez niszczenia ogona.

Podobne pytania

+2 głosów
4 odpowiedzi 503 wizyt
pytanie zadane 19 lutego 2017 w C i C++ przez fenq80 Bywalec (2,940 p.)
+4 głosów
0 odpowiedzi 396 wizyt
pytanie zadane 1 listopada 2016 w Nasze projekty przez Ehlert Ekspert (212,670 p.)
+2 głosów
1 odpowiedź 803 wizyt
pytanie zadane 2 czerwca 2016 w C i C++ przez Pixel040 Gaduła (3,100 p.)

92,551 zapytań

141,393 odpowiedzi

319,523 komentarzy

61,936 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...