This is the Polish translation of In-Practice/2D-Game/Collisions/Ball article of learnopengl.com tutorial series.
W tej chwili mamy poziom pełen cegieł i ruchome wiosło gracza. Jedyne czego brakuje w klasycznym przepisie na Breakout to piłka. Celem jest, aby piłka zderzyła się ze wszystkimi cegłami, aż zniszczona zostanie każda ze zniszczalnych cegieł, ale wszystko to pod warunkiem, że piłka nie dosięgnie dolnej krawędzi ekranu.
Oprócz ogólnych elementów obiektu gry, piłka ma promień i dodatkową wartość boolowską wskazującą, czy piłka jest
Ponieważ piłka jest w zasadzie
class BallObject : public GameObject
{
public:
// Ball state
GLfloat Radius;
GLboolean Stuck;
BallObject();
BallObject(glm::vec2 pos, GLfloat radius, glm::vec2 velocity, Texture2D sprite);
glm::vec2 Move(GLfloat dt, GLuint window_width);
void Reset(glm::vec2 position, glm::vec2 velocity);
};
Konstruktor
glm::vec2 BallObject::Move(GLfloat dt, GLuint window_width)
{
// If not stuck to player board
if (!this->Stuck)
{
// Move the ball
this->Position += this->Velocity * dt;
// Check if outside window bounds; if so, reverse velocity and restore at correct position
if (this->Position.x <= 0.0f)
{
this->Velocity.x = -this->Velocity.x;
this->Position.x = 0.0f;
}
else if (this->Position.x + this->Size.x >= window_width)
{
this->Velocity.x = -this->Velocity.x;
this->Position.x = window_width - this->Size.x;
}
if (this->Position.y <= 0.0f)
{
this->Velocity.y = -this->Velocity.y;
this->Position.y = 0.0f;
}
}
return this->Position;
}
Oprócz odwrócenia prędkości piłki, chcemy również przenieść piłkę z powrotem wzdłuż krawędzi. Piłka może się poruszać tylko wtedy, gdy nie utknęła.
Ponieważ gracz przegrywa (lub traci życie), jeśli piłka dosięgnie dolną krawędź, nie ma kodu pozwalającego na odbijanie się piłki od dolnej krawędzi. Musimy jednak później wdrożyć tę logikę w kodzie gry.
Poniżej znajdziesz kod obiektu piłki:
Najpierw dodajmy piłkę do gry. Podobnie jak dla wiosła gracza tworzymy obiekt
// Initial velocity of the Ball
const glm::vec2 INITIAL_BALL_VELOCITY(100.0f, -350.0f);
// Radius of the ball object
const GLfloat BALL_RADIUS = 12.5f;
BallObject *Ball;
void Game::Init()
{
[...]
glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2);
Ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY,
ResourceManager::GetTexture("face"));
}
Następnie musimy zaktualizować pozycję piłki co klatkę, wywołując jej funkcję
void Game::Update(GLfloat dt)
{
Ball->Move(dt, this->Width);
}
Ponadto, ponieważ piłka jest początkowo przyklejona do wiosła, musimy dać graczowi możliwość wybicia piłki. Wybieramy klawisz spacji, aby wybić piłkę z wiosła. Oznacza to, że musimy nieco zmienić funkcję
void Game::ProcessInput(GLfloat dt)
{
if (this->State == GAME_ACTIVE)
{
GLfloat velocity = PLAYER_VELOCITY * dt;
// Move playerboard
if (this->Keys[GLFW_KEY_A])
{
if (Player->Position.x >= 0)
{
Player->Position.x -= velocity;
if (Ball->Stuck)
Ball->Position.x -= velocity;
}
}
if (this->Keys[GLFW_KEY_D])
{
if (Player->Position.x <= this->Width - Player->Size.x)
{
Player->Position.x += velocity;
if (Ball->Stuck)
Ball->Position.x += velocity;
}
}
if (this->Keys[GLFW_KEY_SPACE])
Ball->Stuck = false;
}
}
W tym przypadku, jeśli użytkownik naciśnie klawisz spacji, zmienna Stuck piłki zostanie ustawiona na false
. Zaktualizowaliśmy również funkcję
Na koniec musimy wyrenderować piłkę, co powinno być dość oczywiste:
void Game::Render()
{
if (this->State == GAME_ACTIVE)
{
[...]
Ball->Draw(*Renderer);
}
}
Rezultatem jest piłka podążająca za wiosłem i swobodnie poruszająca się za każdym razem kiedy gracz naciśnie spację. Piłka również odbija się od lewej, prawej i górnej krawędzi, ale zdaje się, że nie koliduje ona z żadną z cegieł, co możemy zobaczyć na poniższym filmie:
Chcemy utworzyć jedną lub kilka funkcji sprawdzających, czy obiekt piłki koliduje z którąkolwiek z cegieł w poziomie, a jeśli tak, to niech zniszczy tę cegłę. Te tzw. Funkcje