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

Snake klasyczny problem z ogonem

0 głosów
438 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,300 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,300 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 (158,940 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 1,040 wizyt
pytanie zadane 19 lutego 2017 w C i C++ przez fenq80 Bywalec (2,940 p.)
+4 głosów
0 odpowiedzi 443 wizyt
pytanie zadane 1 listopada 2016 w Nasze projekty przez Ehlert Ekspert (215,070 p.)
+2 głosów
1 odpowiedź 1,022 wizyt
pytanie zadane 2 czerwca 2016 w C i C++ przez Pixel040 Gaduła (3,100 p.)

93,604 zapytań

142,528 odpowiedzi

322,995 komentarzy

63,090 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

Kursy INF.02 i INF.03
...