Collision Resolution
This commit is contained in:
102
src/game.cpp
102
src/game.cpp
@@ -1,5 +1,8 @@
|
||||
#include "game.h"
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
typedef std::tuple<bool, Direction,glm::vec2> Collision;
|
||||
|
||||
SpriteRenderer* Renderer;
|
||||
|
||||
@@ -16,6 +19,30 @@ const float BALL_RADIUS = 12.5f;
|
||||
|
||||
BallObject* ball;
|
||||
|
||||
Direction VectorDirection(glm::vec2 target)
|
||||
{
|
||||
glm::vec2 compass[] = {
|
||||
glm::vec2(0.0f, 1.0f), // up
|
||||
glm::vec2(1.0f, 0.0f), // right
|
||||
glm::vec2(0.0f,-1.0f), // down
|
||||
glm::vec2(-1.0f, 0.0f) //left
|
||||
};
|
||||
|
||||
float max = 0.0f;
|
||||
unsigned int best_match = -1;
|
||||
for (unsigned int i = 0; i < 4; i++)
|
||||
{
|
||||
float dot_product = glm::dot(glm::normalize(target), compass[i]);
|
||||
if( dot_product > max )
|
||||
{
|
||||
max = dot_product;
|
||||
best_match = i;
|
||||
}
|
||||
|
||||
}
|
||||
return (Direction) best_match;
|
||||
}
|
||||
|
||||
// AABB with AABB collision detection
|
||||
bool CheckCollisions(GameObject& one, GameObject& two)
|
||||
{
|
||||
@@ -30,7 +57,7 @@ bool CheckCollisions(GameObject& one, GameObject& two)
|
||||
}
|
||||
|
||||
// AABB with circle collision detection
|
||||
bool CheckCollisions(BallObject& one, GameObject& two)
|
||||
Collision CheckCollisions(BallObject& one, GameObject& two)
|
||||
{
|
||||
// Calculate the closest point on two's border to the center point of one
|
||||
glm::vec2 center (one.Position + one.Radius);
|
||||
@@ -44,11 +71,16 @@ bool CheckCollisions(BallObject& one, GameObject& two)
|
||||
|
||||
// Calculate the distance and check if it is less then two's radius
|
||||
difference = closest - center;
|
||||
return glm::length(difference) < one.Radius;
|
||||
if( glm::length(difference) < one.Radius)
|
||||
{
|
||||
return std::make_tuple(true, VectorDirection(difference), difference);
|
||||
} else
|
||||
{
|
||||
return std::make_tuple(false, UP, glm::vec2(0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Game::~Game()
|
||||
{
|
||||
delete Renderer;
|
||||
@@ -106,15 +138,52 @@ void Game::DoCollisions()
|
||||
{
|
||||
if(!box.Destroyed)
|
||||
{
|
||||
if(CheckCollisions(*ball, box))
|
||||
Collision collision = CheckCollisions(*ball, box);
|
||||
if(std::get<0>(collision)) // If we have collided
|
||||
{
|
||||
if(!box.IsSolid)
|
||||
{
|
||||
box.Destroyed = true;
|
||||
}
|
||||
// Collision resolution
|
||||
Direction dir = std::get<1>(collision);
|
||||
glm::vec2 diff_vector = std::get<2>(collision);
|
||||
if (dir == LEFT || dir == RIGHT )
|
||||
{
|
||||
ball->Velocity.x = -ball->Velocity.x;
|
||||
// relocate
|
||||
float penetration = ball->Radius - std::abs(diff_vector.x);
|
||||
if(dir == LEFT)
|
||||
ball->Position.x += penetration;
|
||||
else
|
||||
ball->Position.x -= penetration;
|
||||
}
|
||||
else
|
||||
{
|
||||
ball->Velocity.y = -ball->Velocity.y;
|
||||
float penetration = ball->Radius - std::abs(diff_vector.y);
|
||||
if(dir == UP)
|
||||
ball->Position.y -= penetration;
|
||||
else
|
||||
ball->Position.y += penetration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collision result = CheckCollisions(*ball, *player);
|
||||
if(!ball->Stuck && std::get<0>(result)) // if we collided with player paddle
|
||||
{
|
||||
float centerBoard = player->Position.x + player->Size.x /2.0f;
|
||||
float distance = (ball->Position.x + ball->Radius) - centerBoard;
|
||||
float percentage = distance/ (player->Size.x / 2.0f);
|
||||
|
||||
float strength = 2.0f;
|
||||
glm::vec2 oldVelocity = ball->Velocity;
|
||||
ball->Velocity.x = INITIAL_BALL_VELOCITY.x * percentage * strength;
|
||||
ball->Velocity.y = -1.0f * abs(ball->Velocity.y);
|
||||
ball->Velocity = glm::normalize(ball->Velocity) * glm::length(oldVelocity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,6 +226,12 @@ void Game::Update(float dt)
|
||||
{
|
||||
ball->Move(dt, this->Width);
|
||||
this->DoCollisions();
|
||||
|
||||
if(ball->Position.y >= this->Height)
|
||||
{
|
||||
this->ResetLevel();
|
||||
this->ResetPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
void Game::Render()
|
||||
@@ -173,4 +248,23 @@ void Game::Render()
|
||||
player->Draw(*Renderer);
|
||||
ball->Draw(*Renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::ResetLevel()
|
||||
{
|
||||
if(this->Level == 0)
|
||||
this->Levels[0].Load("levels/one.lvl", this->Width, this->Height /2 );
|
||||
if(this->Level == 1)
|
||||
this->Levels[1].Load("levels/two.lvl", this->Width, this->Height /2 );
|
||||
if(this->Level == 2)
|
||||
this->Levels[2].Load("levels/three.lvl", this->Width, this->Height /2 );
|
||||
if(this->Level == 3)
|
||||
this->Levels[3].Load("levels/four.lvl", this->Width, this->Height /2 );
|
||||
}
|
||||
|
||||
void Game::ResetPlayer()
|
||||
{
|
||||
player->Size = PLAYER_SIZE;
|
||||
player->Position = glm::vec2(this->Width / 2.0f - PLAYER_SIZE.x /2.0f, this->Height - PLAYER_SIZE.y);
|
||||
ball->Reset(player->Position + glm::vec2(PLAYER_SIZE.x / 2.0f - BALL_RADIUS,-(BALL_RADIUS * 2.0f) ), INITIAL_BALL_VELOCITY);
|
||||
}
|
||||
10
src/game.h
10
src/game.h
@@ -14,6 +14,12 @@ enum GameState {
|
||||
GAME_MENU,
|
||||
GAME_WIN
|
||||
};
|
||||
enum Direction {
|
||||
UP,
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT
|
||||
};
|
||||
class Game {
|
||||
public:
|
||||
// game state
|
||||
@@ -36,6 +42,10 @@ class Game {
|
||||
void Update(float dt);
|
||||
void Render();
|
||||
void DoCollisions();
|
||||
|
||||
void ResetLevel();
|
||||
void ResetPlayer();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user