Regulacja prędkość obiektu w SFML

0

Witam.

Chciałem się zapytać czy ktoś ma jakieś fajne sposoby na płyną regulację prędkości obiektu typu np sf::RectangleShape w C++ SFML na ekranie?
Wykorzystałem sposób regulacji prędkość obiektu przy pomocy sf::Clock i sf::Time ale mam wrażenie że efekt ruchu tego węża jest trochę taki jak by się przycinał chociaż działa prawidłowo i mogą to być moje odczucia, ale piszę tego posta bo mimo wszystko chciał bym poznać jakieś inne sposoby które istnieją na rozwiązanie tego typu problemu.
Jak coś ruch o 21 bo pozycji bo sf::RectangleShape jest wymiarem 20x20 i chcę mieć takie fajne odstępy oraz klasa Snake dziedziczy po sf::Drawable.
Oto kod:

//main.cpp

sf::RenderWindow window(sf::VideoMode(640, 320), "SFML SnakeMoveLogic");
window.setFramerateLimit(60);

Snake obj;
sf::Clock clock;

//Zmienne do regulacji prędkości węża [POCZĄTEK]
sf::Clock test;
float moveDelay = 0.1f;
float lastMoveTime = 0.0f;
//Zmienne do regulacji prędkości węża [KONIEC]

while (window.isOpen())
{
	sf::Time deltaTime = clock.restart();
	sf::Event event;
	while (window.pollEvent(event))
	{
		if (event.type == sf::Event::Closed)
			window.close();
		else if (event.type == sf::Event::Resized)
		{
			window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, event.size.width, event.size.height)));
		}
		else if (event.type == sf::Event::KeyPressed) {
			// Zmiana kierunku ruchu

			switch (event.key.code)
			{
			  case sf::Keyboard::Up:
  			  {
				  obj.ChangeDirection(MoveSnake::UP);
			  }
			  break;

			  case sf::Keyboard::Down:
			  {
				  obj.ChangeDirection(MoveSnake::DOWN);
				
			  }
			  break;

			  case sf::Keyboard::Left:
			  {
				  obj.ChangeDirection(MoveSnake::LEFT);
				
			  }
			  break;

			  case sf::Keyboard::Right:
			  {
				  obj.ChangeDirection(MoveSnake::RIGHT);
			  }
			  break;

			  case sf::Keyboard::F1:
			  {
				  obj.grow();
			  }
			  break;
			}
			
		}

	}

	//Kod do regulacji prędkości węża [POCZĄTEK]
    float DeltaTime = test.restart().asSeconds();
	lastMoveTime += DeltaTime;

	if (lastMoveTime >= moveDelay)
	{
		obj.GoodMoveSnakeLogic();
		
		lastMoveTime = 0.f;
	}
	//Kod do regulacji prędkości węża [KONIEC]

	window.clear();
	window.draw(obj);
	window.display();
	
	
}

A tak wygląda kod funkcji GoodMoveSnakeLogic():

//Snake.cpp
void Snake::GoodMoveSnakeLogic() // <--- Metoda do implementacji ruchów węża
{

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

	auto TmpHead = SnakeBody.begin();

	switch (HeadMove)
	{
	case MoveSnake::UP:
	{
		

		TmpHead->move(0, -21);
	}
	break;

	case MoveSnake::DOWN:
	{
		

		TmpHead->move(0, 21);
	

	}
	break;

	case MoveSnake::LEFT:
	{

		TmpHead->move(-21, 0);
	}
	break;

	case MoveSnake::RIGHT:
	{
		
		TmpHead->move(21, 0);
	}
	break;

	}
	
	this->DetectCollision();
}

Dziękuję za każdą cenną uwagę i informację oraz jeśli będzie coś jeszcze potrzebne to postaram się to jak najszybciej dostarczyć.

3

Jeżeli masz dynamiczny obiekt na scenie, który reaguje na wejście użytkownika, czyli takiego węża, to aktualizacja jego pozycji powinna odbywać się co każdą klatę. Warunkowa zmiana stanu to bardziej dla obiektów, na które uzytkownik nie ma aż takiego wpływu, np. w gierce strategicznej jak zaczynasz budowę domku i po jakimś czasie ma Ci się zmienić tekstura.

Delta time Ci się przyda, ale policz to zaraz na początku pętli, powinieneś go użyć mniej więcej w ten sposób, bez żadnych warunków


auto last_frame = GetTick();

while(true) {
  const auto curr_frame = GetTick();
  const auto delta_time = curr_frame - last_frame;
  last_frame = curr_frame;

  // do other stuff

  snake.position += speed * delta_time;
}

Takie podejście będzie też bardziej odporne na skoki klatek.

0

Posiedziałem nad kodem i udało mi się coś takiego wyrzeźbić i działa czyli ciało podążą za głową tylko nachodzi na nią i ciało nachodzi na głowę i nie umiem zrobić taki stały odstęp między nimi np żeby zawsze był odstęp 21.0f pozycji itp.

Kod:

#include<SFML/Graphics.hpp>
#include<vector>
#include<iostream>

sf::Vector2f normalize(sf::Vector2f vec)
{
	constexpr auto units_in_last_place = 2;
	auto norm = std::sqrt((vec.x * vec.x) + (vec.y * vec.y));
	// Prevent division by zero
	if (norm <= std::numeric_limits<float>::epsilon() * norm * units_in_last_place
		|| norm < std::numeric_limits<float>::min())
	{
		return sf::Vector2f{};
	}
	return vec / norm;
}




auto main() -> int
{
	sf::RenderWindow window(sf::VideoMode(640, 320), "Regulate Speed Object");
	window.setFramerateLimit(60);

	std::vector<sf::RectangleShape> vectorShape;

	sf::RectangleShape obj(sf::Vector2f{ 20,20 });
	obj.setFillColor(sf::Color::Yellow);
	obj.setPosition(sf::Vector2f{ 121,100 });

	sf::RectangleShape follow;
	follow.setFillColor(sf::Color::Green);
	follow.setPosition(sf::Vector2f{ 100,100 });
	follow.setSize(sf::Vector2f{ 20,20 });


	vectorShape.push_back(obj);

	/*float position = 100;
	for (int i = 0; i < 10; i++)
	{
		position += 21;
		sf::RectangleShape body(sf::Vector2f{ 20,20 });
		body.setFillColor(sf::Color::Green);
		body.setPosition(sf::Vector2f{ position,100 });
		vectorShape.push_back(body);
	}*/


	sf::Clock clock;
	while (window.isOpen())
	{
		sf::Event event;
		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::Closed)
				window.close();
		}
		float deltaTime = clock.restart().asSeconds();

		sf::Vector2f calculation =obj.getPosition()  - follow.getPosition();
		sf::Vector2f test = normalize(calculation);	
	    
		

		if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
		{
			obj.move(0.f, -400.f * deltaTime);
			follow.move(400.0f * deltaTime * test);
		}
		else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
		{
			obj.move(0.f, 400.0f * deltaTime);
			follow.move(400.0f * deltaTime * test);
		
		}
		else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
		{
			obj.move(-400.0f * deltaTime, 0.f);
			follow.move(400.0f * deltaTime * test);
		}
		else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
		{
			obj.move(400.0f * deltaTime, 0.f);
			follow.move(400.0f * deltaTime * test);
		}

		window.clear();
		/*for (const auto& thisShape : vectorShape)
		{
			window.draw(thisShape);
		}*/
		window.draw(obj);
		window.draw(follow);
		window.display();
	}

}

Jeśli trzeba zamieścić jakieś zdjęcia efektu jaki chcę osiągnąć to proszę pisać. Chyba że ktoś ma lepszy pomysł na ten problem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.