Skip to content

Commit

Permalink
Collisions, effects
Browse files Browse the repository at this point in the history
  • Loading branch information
IgorKhramtsov committed Aug 1, 2020
1 parent 1094987 commit a41a159
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 59 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Simple OpenGL Arkanoid game.
- bottom side is endgame
- bricks generates randomly on the start

![Screenshot of program](assets/screenshot.jpg)

## Build

```
Expand All @@ -31,5 +33,10 @@ make # your build command dependent on platform
2. [X] Creating a window (glfw)
3. [X] Drawing (glew, glm)
4. [X] Input control
5. [ ] Collisions
6. [ ] Game logic
5. [X] Collisions
6. [X] Game logic
7. [X] Effects

## Known Bugs

1. Physics: Ball bounces incorrectly in some circumstances.
Binary file added assets/screenshot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 7 additions & 3 deletions src/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ void Application::Run() {
auto lastTime = glfwGetTime();
double curTime;
double deltaTime = 0.;
double updateRate = 1. / 40.;

while(!glfwWindowShouldClose(m_Window)) {
m_Renderer.Clear();
Expand All @@ -61,9 +60,14 @@ void Application::Run() {
deltaTime += (curTime - lastTime);
lastTime = curTime;

if(deltaTime >= updateRate) {
if(isKeyPressed(GLFW_KEY_LEFT_SHIFT))
m_UpdateRate = 1;
else
m_UpdateRate = 1. / 30.;
if(deltaTime >= m_UpdateRate) {

onUpdate();
deltaTime -= updateRate;
deltaTime -= m_UpdateRate;
}

onDraw();
Expand Down
4 changes: 2 additions & 2 deletions src/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
class Application {
private:
static Application *instance;
int m_Width, m_Height;
GLFWwindow *m_Window;
bool m_Initialized = false;
double m_UpdateRate = 1. / 30.;

static void glfw_error_callback(int error, const char* desc);
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods);
void gldebug(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);

protected:
Renderer m_Renderer;
int m_Width, m_Height;

public:
Application(const char*, int, int);
Expand All @@ -34,7 +35,6 @@ class Application {
virtual void onKeyCallback(int key, int action) = 0;

Renderer *getRenderer() { return &m_Renderer; };
void getSize(int &width, int &height) { width = m_Width; height = m_Height; };
bool isInitialized() { return m_Initialized; };
bool isKeyPressed(int key);
};
1 change: 0 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ list(APPEND SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Shader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/GameObject.h
${CMAKE_CURRENT_SOURCE_DIR}/GameObject.cpp
${CMAKE_CURRENT_SOURCE_DIR}/FileWatcher.h
${CMAKE_CURRENT_SOURCE_DIR}/Application.h
${CMAKE_CURRENT_SOURCE_DIR}/Application.cpp
${CMAKE_CURRENT_SOURCE_DIR}/MyApp.h
Expand Down
29 changes: 24 additions & 5 deletions src/GameObject.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#include "GameObject.h"
#include "utils.h"

GameObject::GameObject(Renderable r, Transform t, glm::vec4 c) : transform(t), color(c)
{
this->renderebale = r;
glm::vec2 GameObject::getCenter() const {
return glm::vec2(transform.pos.x + m_Renderebale.width / 2., transform.pos.y + m_Renderebale.height / 2.);
}

glm::vec2 GameObject::getCenter() const {
return glm::vec2(transform.pos.x + renderebale.width / 2., transform.pos.y + renderebale.height / 2.);
void GameObject::setRenderable(Renderable r) {
m_Renderebale = r;
transform.size = glm::vec2(r.width, r.height);
m_Radius = MAX(r.width, r.height);
}

Renderable const &GameObject::getRenderable() const {
return m_Renderebale;
}

void GameObject::setColor(float v0, float v1, float v2, float v3) {
Expand All @@ -26,4 +32,17 @@ void GameObject::move(float x, float y) {
void GameObject::setScale(float x, float y) {
transform.scale[0] = x;
transform.scale[1] = y;
}

void GameObject::Destroy() {
m_Dead = true;
}

bool GameObject::isDead() const {
return m_Dead;
}

float GameObject::getDestroyEffRadius() {
m_Radius = MAX(0, (m_Radius - m_RadiusShrink));
return m_Radius;
}
12 changes: 10 additions & 2 deletions src/GameObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@
#include "Renderer.h"

class GameObject {
Renderable m_Renderebale;
bool m_Dead = false;
float m_Radius; // Destroy effect
float m_RadiusShrink = 2.f; // Destroy effect

public:
Renderable renderebale;
Transform transform;
glm::vec4 color = glm::vec4(1.f, 0.f, 0.f, 1.f);

GameObject() = default;
GameObject(Renderable r, Transform t, glm::vec4 c);

glm::vec2 getCenter() const;
void setRenderable(Renderable);
Renderable const &getRenderable() const;
void setColor(float v0, float v1, float v2, float v3);
void setPosition(float x, float y);
void move(float x, float y);
void setScale(float x, float y);
void Destroy();
bool isDead() const;
float getDestroyEffRadius();
};
183 changes: 149 additions & 34 deletions src/MyApp.cpp
Original file line number Diff line number Diff line change
@@ -1,88 +1,203 @@
#include "MyApp.h"
#include "utils.h"

float MyApp::colorRate = 0.005f;
float MyApp::blinkingColor = 0.8f;
MyApp::MyApp(const char *title, int width, int height) : Application(title, width, height) {
m_Renderer.setClearColor(0.1f, 0.1f, 0.1f, 1.f);

Start();
}

void MyApp::Start() {
int width, height;
getSize(width, height);
const int lines = 3;
const int perLine = 14;
m_BricksNumber = perLine * lines;
const int brick_w = ((m_Width - padding_x * 2) - (spacing * perLine)) / perLine;
const int brick_h = 20;
const auto renderable = m_Renderer.CreateRect(brick_w, brick_h);
delete m_Bricks;
m_Bricks = new GameObject[m_BricksNumber];


int brick_w = ((width - padding_x * 2) - (spacing * 15)) / 15;
int brick_h = 20;
auto renderable = m_Renderer.CreateRect(brick_w, brick_h);

for (int i = 0; i < 30; i++) {
m_Bricks[i] = GameObject();
m_Bricks[i].renderebale = renderable;
m_Bricks[i].setPosition(
padding_x + (brick_w + spacing) * (i % 15),
((float)height - padding_y) - ((brick_h + spacing) * (i % 2))
);
m_Bricks[i].setColor(0.3f, 0.3f, 0.7f, 1.f);
for (int k = 0; k < lines; ++k) {
for (int i = 0; i < perLine; ++i) {
m_Bricks[i + (k * perLine)] = GameObject();
m_Bricks[i + (k * perLine)].setRenderable(renderable);
m_Bricks[i + (k * perLine)].setPosition(
padding_x + (brick_w + spacing) * (i),
((float)m_Height - padding_y) - ((brick_h + spacing) * (k))
);
m_Bricks[i + (k * perLine)].setColor(0.3f, 0.3f, 0.7f, 1.f);
}
}

srand((unsigned int)glfwGetTime());
for (int k = 0; k < lines; ++k) {
for (int i = 0; i < perLine / 2; ++i) {
if (std::rand() % 4 == 0) {
m_Bricks[(k * perLine) + i].Destroy();
m_Bricks[(k * perLine) + (perLine - i - 1)].Destroy();
}
}
}

m_Platform = GameObject();
m_Platform.renderebale = m_Renderer.CreateRect(120, 20);
m_Platform.setColor(0.3f, 0.43f, 0.3f, 1.f);
m_Platform.setPosition(width / 2.f - 120.f / 2.f, 20.f + 30.f);
m_Platform.setRenderable(m_Renderer.CreateRect(120, 20));
m_Platform.setColor(0.22f, 0.45f, 0.22f, 1.f);
m_Platform.setPosition(m_Width / 2.f - 120.f / 2.f + 16.f, 20.f + 30.f);

m_Ball = GameObject();
m_Ball.renderebale = m_Renderer.CreateRect(25, 25);
m_Ball.setColor(0.7f, 0.3f, 0.3f, 1.f);
m_Ball.setRenderable(m_Renderer.CreateRect(25, 25));
m_Ball.setColor(0.9f, 0.35f, 0.35f, 1.f);
m_Ball.setPosition(m_Platform.transform.pos.x + 120.f / 2.f - 25.f / 2.f, m_Platform.transform.pos.y + 30.f);

m_State = STATE_START;
}

void MyApp::onUpdate() {
// TODO: Movement should be rewrited
// Platform movement
auto ballSpeed = m_Platform.transform.velocity.x;
if (isKeyPressed(GLFW_KEY_LEFT)) {
curAccelerationSpeed -= accelerationSpeed * (MAX(abs(curAccelerationSpeed), 0.25f) / topAccelerationSpeed);
} else if (isKeyPressed(GLFW_KEY_RIGHT)) {
curAccelerationSpeed += accelerationSpeed * (MAX(abs(curAccelerationSpeed), 0.25f) / topAccelerationSpeed);
if (isKeyPressed(GLFW_KEY_LEFT) || isKeyPressed(GLFW_KEY_RIGHT)) {
curAccelerationSpeed += accelerationSpeed * (MAX(abs(curAccelerationSpeed), topAccelerationSpeed * 0.15f));
} else {
curAccelerationSpeed -= MIN(friction / 2., abs(curAccelerationSpeed)) * sign(curAccelerationSpeed);
if (abs(ballSpeed) > 0)
ballSpeed += MIN(friction * (MAX(abs(ballSpeed), 0.25f) / topSpeed), abs(ballSpeed)) * -sign(ballSpeed);
}
ballSpeed += curAccelerationSpeed;
ballSpeed += curAccelerationSpeed * (isKeyPressed(GLFW_KEY_LEFT) ? -1 : 1);
curAccelerationSpeed = MIN(abs(curAccelerationSpeed), topAccelerationSpeed) * sign(curAccelerationSpeed);
ballSpeed = MIN(abs(ballSpeed), topSpeed) * sign(ballSpeed);

m_Platform.move(ballSpeed, 0.f);
m_Platform.transform.velocity.x = ballSpeed;

// Sides block
if (m_Platform.transform.pos.x < 0) {
m_Platform.transform.pos.x = 0;
m_Platform.transform.velocity.x = 0;
curAccelerationSpeed = 0;
} else if (m_Platform.transform.pos.x > m_Width - m_Platform.transform.size.x) {
m_Platform.transform.pos.x = m_Width - m_Platform.transform.size.x;
m_Platform.transform.velocity.x = 0;
curAccelerationSpeed = 0;
}

// Ball movement
if (m_State == STATE_START) {
auto center = m_Platform.getCenter();
const auto center = m_Platform.getCenter();
m_Ball.setPosition(center.x - (25.f / 2.f), center.y + 30.f);
} else {
const auto ballNextPos = glm::vec3(m_Ball.getCenter(), .1f) + m_Ball.transform.velocity;
const auto radius = m_Ball.transform.size.y / 2.;
m_Ball.transform.velocity *= bounceVector(ballNextPos, radius);
if ((ballNextPos.y - radius) < 0) {
Start();
return;
}
m_Ball.move(m_Ball.transform.velocity.x, m_Ball.transform.velocity.y);
}

std::cout << "curAcc: " << curAccelerationSpeed << " curSpeed: " << ballSpeed << '\n';

if (blinkingColor >= 0.9f || blinkingColor <= 0.6f) colorRate *= -1;
blinkingColor += colorRate;
// std::cout << "curAcc: " << curAccelerationSpeed << " curSpeed: " << ballSpeed << '\n';
}

glm::vec3 MyApp::bounceVector(const glm::vec3 ballPos, const float radius) {
glm::vec3 bVec(1.f, 1.f, 1.f);
if ((ballPos.x + radius) > m_Width || (ballPos.x - radius) < 0)
bVec.x = -1;
if ((ballPos.y + radius) > m_Height)
bVec.y = -1;

const auto r_ang = radius * 0.75;
const auto ballT = glm::vec3(ballPos.x, ballPos.y + radius, 0.f);
const auto ballB = glm::vec3(ballPos.x, ballPos.y - radius, 0.f);
const auto ballL = glm::vec3(ballPos.x + radius, ballPos.y, 0.f);
const auto ballR = glm::vec3(ballPos.x - radius, ballPos.y, 0.f);
const auto ballLT = glm::vec3(ballPos.x + r_ang, ballPos.y + r_ang, 0.f);
const auto ballRT = glm::vec3(ballPos.x - r_ang, ballPos.y + r_ang, 0.f);
const auto ballLB = glm::vec3(ballPos.x + r_ang, ballPos.y - r_ang, 0.f);
const auto ballRB = glm::vec3(ballPos.x - r_ang, ballPos.y - r_ang, 0.f);
for (int i = 0; i < m_BricksNumber; i++) {
if (m_Bricks[i].isDead())
continue;
if (isInside(ballT, m_Bricks[i].transform) || isInside(ballB, m_Bricks[i].transform) ||
isInside(ballL, m_Bricks[i].transform) || isInside(ballR, m_Bricks[i].transform) ) {
if ( abs(ballPos.x - m_Bricks[i].getCenter().x) / m_Bricks[i].transform.size.x >
abs(ballPos.y - m_Bricks[i].getCenter().y) / m_Bricks[i].transform.size.y)
bVec.x = -1;
else
bVec.y = -1;

m_Bricks[i].Destroy();
// return bVec;
}
else if (isInside(ballLT, m_Bricks[i].transform) || isInside(ballRT, m_Bricks[i].transform) ||
isInside(ballLB, m_Bricks[i].transform) || isInside(ballRB, m_Bricks[i].transform)) {
bVec.x = -1;
bVec.y = -1;
m_Bricks[i].Destroy();
}
}

if (isInside(ballT, m_Platform.transform) || isInside(ballB, m_Platform.transform) ||
isInside(ballL, m_Platform.transform) || isInside(ballR, m_Platform.transform) ) {
if ( abs(ballPos.x - m_Platform.getCenter().x) / m_Platform.transform.size.x >
abs(ballPos.y - m_Platform.getCenter().y) / m_Platform.transform.size.y)
bVec.x = -1;
else
bVec.y = -1;
m_Ball.transform.velocity.x = MIN(10.f, abs(m_Platform.transform.velocity.x)) * sign(m_Platform.transform.velocity.x);
}

return bVec;
}

bool MyApp::isInside(glm::vec3 point, Transform target) {
return (point.x >= target.pos.x && point.x <= target.pos.x + target.size.x) &&
(point.y >= target.pos.y && point.y <= target.pos.y + target.size.y);
}

// bool MyApp::isColide() {

// }

void MyApp::onDraw() {
for (int i = 0; i < 30; i++) {
m_Renderer.Draw(m_Bricks[i], m_SimpleShader);
for (int i = 0; i < m_BricksNumber; i++) {
if(m_Bricks[i].isDead()) {
if (m_Bricks[i].getDestroyEffRadius() > 0) {
m_Renderer.UseShader(m_BallShader);
m_BallShader.setUniformVec2f("u_Center", m_Bricks[i].getCenter());
m_BallShader.setUniform1f("u_Radius", m_Bricks[i].getDestroyEffRadius());
m_Bricks[i].setColor(m_Bricks[i].color.r + 0.1f, m_Bricks[i].color.g, m_Bricks[i].color.b, m_Bricks[i].color.a);
m_Renderer.Draw(m_Bricks[i], m_BallShader);
} else {
continue;
}
} else {
m_Bricks[i].setColor(m_Bricks[i].color.r, m_Bricks[i].color.g, blinkingColor, m_Bricks[i].color.a);
m_Renderer.Draw(m_Bricks[i], m_SimpleShader);
}
}

m_Renderer.Draw(m_Platform, m_SimpleShader);

m_Renderer.UseShader(m_BallShader);
m_BallShader.setUniformVec2f("u_Center", m_Ball.getCenter());
m_BallShader.setUniform1f("u_Radius", m_Ball.renderebale.height / 2.);
m_BallShader.setUniform1f("u_Radius", m_Ball.transform.size.y / 2.);
m_Renderer.Draw(m_Ball, m_BallShader);
}

void MyApp::onKeyCallback(int key, int action) {
if (m_State == STATE_START && key == GLFW_KEY_SPACE && action == GLFW_PRESS) {
m_Ball.transform.velocity.x = m_Platform.transform.velocity.x;
m_Ball.transform.velocity.y = 6.f;
m_State = STATE_GAME;
if (key == GLFW_KEY_SPACE && action == GLFW_PRESS) {
if (m_State == STATE_START) {
m_Ball.transform.velocity.x = MIN(10.f, abs(m_Platform.transform.velocity.x)) * sign(m_Platform.transform.velocity.x);
m_Ball.transform.velocity.y = 6.f;
m_State = STATE_GAME;
} else {
Start();
}
}
}
Loading

0 comments on commit a41a159

Please sign in to comment.