diff --git a/Example/MyPongScene.cpp b/Example/MyPongScene.cpp index 6aade5b..4f0d9c0 100644 --- a/Example/MyPongScene.cpp +++ b/Example/MyPongScene.cpp @@ -1,7 +1,12 @@ #include "MyPongScene.h" +#include // rand + #include +#include +#include + #include #include @@ -9,16 +14,24 @@ #define OUTLINE_THICKNESS 25.0f #define OUTLINE_OFFSET 25.0f -#define OUTLINE_INWARDS OUTLINE_OFFSET + OUTLINE_THICKNESS +#define OUTLINE_INWARDS (OUTLINE_OFFSET + OUTLINE_THICKNESS) #define PADDLE_THICKNESS 25.0f #define PADDLE_HEIGHT 150.0f +#define LIFE_THICKNESS 15.0f +#define LIFE_OFFSET 10.0f +#define LIFE_INWARDS (OUTLINE_INWARDS + LIFE_THICKNESS) + #define BALL_THICKNESS 25.0f #define HALF_BALL_THICKNESS 12.5f -#define PADDLE_SPEED 5.0f +#define INITIAL_BALL_SPEED 250.0f +#define BALL_SPEED_INCREMENT 50.0f +#define PADDLE_SPEED 500.0f + +#define STARTING_LIVES 5 MyPongScene::MyPongScene(Application& application) @@ -27,11 +40,13 @@ MyPongScene::MyPongScene(Application& application) m_outline_column(meshgenerator::gen_rect_p(DRAW_TRIANGLES, m_screen_size.x - 2 * OUTLINE_THICKNESS, OUTLINE_THICKNESS), DRAW_TRIANGLES), m_outline_row(meshgenerator::gen_rect_p(DRAW_TRIANGLES, OUTLINE_THICKNESS, m_screen_size.y - 2 * OUTLINE_THICKNESS), DRAW_TRIANGLES), m_ball(meshgenerator::gen_rect_p(DRAW_TRIANGLES, BALL_THICKNESS, BALL_THICKNESS), DRAW_TRIANGLES), + m_life(meshgenerator::gen_rect_p(DRAW_TRIANGLES, LIFE_THICKNESS, LIFE_THICKNESS), DRAW_TRIANGLES), m_paddle(meshgenerator::gen_rect_p(DRAW_TRIANGLES, PADDLE_THICKNESS, PADDLE_HEIGHT), DRAW_TRIANGLES), m_outline_column_batch(&m_outline_column, 2), m_outline_row_batch(&m_outline_row, 2), m_ball_batch(&m_ball, 1), + m_life_batch(&m_life, STARTING_LIVES * 2), m_paddle_batch(&m_paddle, 2), m_outline_top_pose(glm::vec3(0.0f, (m_screen_size.y - OUTLINE_THICKNESS) / 2.0f - OUTLINE_OFFSET, 0.0f)), @@ -40,14 +55,18 @@ MyPongScene::MyPongScene(Application& application) m_outline_right_pose(glm::vec3((m_screen_size.x - OUTLINE_THICKNESS) / 2.0f - OUTLINE_OFFSET, 0.0f, 0.0f)), m_ball_pose(glm::vec3(0.0f, 0.0f, 0.0f)), - m_paddle_left_pose(glm::vec3(-(m_screen_size.x / 2.0f - OUTLINE_INWARDS - 3.5f * PADDLE_THICKNESS), 0.0f, 0.0f)), - m_paddle_right_pose(glm::vec3(m_screen_size.x / 2.0f - OUTLINE_INWARDS - 3.5f * PADDLE_THICKNESS, 0.0f, 0.0f)), + m_paddle_left_pose(glm::vec3(-(m_screen_size.x / 2.0f - OUTLINE_INWARDS - 2.5f * PADDLE_THICKNESS), 0.0f, 0.0f)), + m_paddle_right_pose(glm::vec3(m_screen_size.x / 2.0f - OUTLINE_INWARDS - 2.5f * PADDLE_THICKNESS, 0.0f, 0.0f)), - m_camera(m_screen_size) + m_camera(m_screen_size), + + m_left_lives(STARTING_LIVES), + m_right_lives(STARTING_LIVES) { m_pipeline.add_batch(&m_outline_column_batch); m_pipeline.add_batch(&m_outline_row_batch); m_pipeline.add_batch(&m_ball_batch); + m_pipeline.add_batch(&m_life_batch); m_pipeline.add_batch(&m_paddle_batch); m_pipeline.set_camera(&m_camera); @@ -59,6 +78,7 @@ void MyPongScene::init() m_outline_column_batch.init(); m_outline_row_batch.init(); m_ball_batch.init(); + m_life_batch.init(); m_paddle_batch.init(); // Set these once here since they will never change @@ -70,14 +90,47 @@ void MyPongScene::init() m_outline_row_batch.add_rendered(m_outline_left_pose); m_outline_row_batch.add_rendered(m_outline_right_pose); - // Ball - m_ball_speed = 250.0f; - m_ball_direction = glm::normalize(glm::vec2(1.0f, 1.0f)); + reset_ball(); } void MyPongScene::update(float delta_time, clock_t clock) { - m_ball_pose.translate(glm::vec3(m_ball_direction * m_ball_speed * delta_time, 0.0f)); + // Move Paddles + + const glm::vec3 up(0.0f, 1.0f, 0.0f); + const glm::vec3 down(0.0f, -1.0f, 0.0f); + + if (m_left_lives > 0) + { + if (m_input_manager.is_key_down(GLFW_KEY_A)) + { + m_paddle_left_pose.translate(up * PADDLE_SPEED * delta_time); + } + if (m_input_manager.is_key_down(GLFW_KEY_Z)) + { + m_paddle_left_pose.translate(down * PADDLE_SPEED * delta_time); + } + } + + if (m_right_lives > 0) + { + if (m_input_manager.is_key_down(GLFW_KEY_APOSTROPHE)) + { + m_paddle_right_pose.translate(up * PADDLE_SPEED * delta_time); + } + + if (m_input_manager.is_key_down(GLFW_KEY_SLASH)) + { + m_paddle_right_pose.translate(down * PADDLE_SPEED * delta_time); + } + } + + // Move ball + + if (m_right_lives > 0 && m_left_lives > 0) + { + m_ball_pose.translate(glm::vec3(m_ball_direction * m_ball_speed * delta_time, 0.0f)); + } vec3 ball_position = m_ball_pose.get_position(); @@ -93,24 +146,68 @@ void MyPongScene::update(float delta_time, clock_t clock) m_ball_direction.y = glm::abs(m_ball_direction.y); } - // Bounce Left Right (temp) + // Bounce Left Right (temp. should be adding points) if (ball_position.x + HALF_BALL_THICKNESS + OUTLINE_INWARDS > m_screen_size.x / 2.0f) { - m_ball_direction.x = -glm::abs(m_ball_direction.x); + m_right_lives -= 1; + reset_ball(); } if (ball_position.x - HALF_BALL_THICKNESS - OUTLINE_INWARDS < -m_screen_size.x / 2.0f) { - m_ball_direction.x = glm::abs(m_ball_direction.x); + m_left_lives -= 1; + reset_ball(); } + // Bounce off Paddles + + glm::vec3 left_paddle_position = m_paddle_left_pose.get_position(); + glm::vec3 right_paddle_position = m_paddle_right_pose.get_position(); + + physics::Rect ball_hitbox(glm::vec2(ball_position.x, ball_position.y), BALL_THICKNESS, BALL_THICKNESS); + physics::Rect left_paddle_hitbox(glm::vec2(left_paddle_position.x, left_paddle_position.y), PADDLE_THICKNESS, PADDLE_HEIGHT); + physics::Rect right_paddle_hitbox(glm::vec2(right_paddle_position.x, right_paddle_position.y), PADDLE_THICKNESS, PADDLE_HEIGHT); + + if (physics::collision::rect_in_rect(ball_hitbox, left_paddle_hitbox)) + { + m_ball_direction = rand_dir((float)charcoal::TAU_7_8, (float)charcoal::TAU_7_8 + (float)charcoal::TAU_1_4); + m_ball_speed += BALL_SPEED_INCREMENT; + } + + if (physics::collision::rect_in_rect(ball_hitbox, right_paddle_hitbox)) + { + m_ball_direction = rand_dir((float)charcoal::TAU_3_8, (float)charcoal::TAU_5_8); + m_ball_speed += BALL_SPEED_INCREMENT; + } + + // Update Render Batches + m_ball_batch.reset_rendered(); m_ball_batch.add_rendered(m_ball_pose); m_paddle_batch.reset_rendered(); m_paddle_batch.add_rendered(m_paddle_left_pose); m_paddle_batch.add_rendered(m_paddle_right_pose); + + // Update Life Render Batch + + m_life_batch.reset_rendered(); + + Poseable left_life_pose(glm::vec3(-m_screen_size.x / 2.0f + LIFE_INWARDS, -m_screen_size.y / 2.0f + LIFE_INWARDS, 0.0f)); + Poseable right_life_pose(glm::vec3(m_screen_size.x / 2.0f - LIFE_INWARDS, -m_screen_size.y / 2.0f + LIFE_INWARDS, 0.0f)); + + for (int i = 0; i < m_left_lives; ++i) + { + m_life_batch.add_rendered(left_life_pose); + left_life_pose.translate(glm::vec3(LIFE_THICKNESS + LIFE_OFFSET, 0.0f, 0.0f)); + } + + for (int i = 0; i < m_right_lives; ++i) + { + m_life_batch.add_rendered(right_life_pose); + right_life_pose.translate(glm::vec3(-(LIFE_THICKNESS + LIFE_OFFSET), 0.0f, 0.0f)); + } } void MyPongScene::prerender() @@ -119,6 +216,7 @@ void MyPongScene::prerender() m_outline_column_batch.prerender(); m_outline_row_batch.prerender(); m_ball_batch.prerender(); + m_life_batch.prerender(); m_paddle_batch.prerender(); } @@ -128,3 +226,29 @@ void MyPongScene::render() m_pipeline.render(); } +float MyPongScene::random() +{ + return rand() / (float)RAND_MAX; +} + +vec2 MyPongScene::rand_dir(float radians_low, float radians_high) +{ + float radians = radians_low + random() * (radians_high - radians_low); + return glm::vec2(glm::cos(radians), glm::sin(radians)); +} + +void MyPongScene::reset_ball() +{ + m_ball_speed = INITIAL_BALL_SPEED; + m_ball_pose.update_position(vec3(0.0f, 0.0f, 0.0f)); + if (random() < 0.5) + { + // Toward right + m_ball_direction = rand_dir((float)charcoal::TAU_7_8, (float)charcoal::TAU_7_8 + (float)charcoal::TAU_1_4); + } + else + { + // Toward left + m_ball_direction = rand_dir((float)charcoal::TAU_3_8, (float)charcoal::TAU_5_8); + } +} diff --git a/Example/MyPongScene.h b/Example/MyPongScene.h index 345e565..e695a9d 100644 --- a/Example/MyPongScene.h +++ b/Example/MyPongScene.h @@ -26,14 +26,24 @@ public: void render() override; private: + float random(); + + vec2 rand_dir(float radians_low, float radians_high); + + float add_magnitude(float value, float added); + + void reset_ball(); + basic::Renderable m_outline_column; basic::Renderable m_outline_row; basic::Renderable m_ball; + basic::Renderable m_life; basic::Renderable m_paddle; basic::Batch m_outline_column_batch; basic::Batch m_outline_row_batch; basic::Batch m_ball_batch; + basic::Batch m_life_batch; basic::Batch m_paddle_batch; Poseable m_outline_top_pose; @@ -50,4 +60,7 @@ private: float m_ball_speed; glm::vec2 m_ball_direction; + + int m_left_lives; + int m_right_lives; }; \ No newline at end of file diff --git a/OpenGLEngine/Collision.h b/OpenGLEngine/Collision.h new file mode 100644 index 0000000..62062f8 --- /dev/null +++ b/OpenGLEngine/Collision.h @@ -0,0 +1,37 @@ +#pragma once + +#include "PhysicsTypes.h" + +namespace charcoal +{ + namespace physics + { + namespace collision + { + // 4 comparisons + bool point_in_rect(const Rect& rect, float x, float y) + { + return + y < rect.top && + y > rect.bottom && + x > rect.left && + x < rect.right; + } + + // 8 * 4 = 32 comparisons + bool rect_in_rect(const Rect& a, const Rect& b) + { + return + point_in_rect(a, b.left, b.top) || + point_in_rect(a, b.left, b.bottom) || + point_in_rect(a, b.right, b.top) || + point_in_rect(a, b.right, b.bottom) || + + point_in_rect(b, a.left, a.top) || + point_in_rect(b, a.left, a.bottom) || + point_in_rect(b, a.right, a.top) || + point_in_rect(b, a.right, a.bottom); + } + } + } +} \ No newline at end of file diff --git a/OpenGLEngine/OpenGLEngine.vcxproj b/OpenGLEngine/OpenGLEngine.vcxproj index 736f2fa..9852794 100644 --- a/OpenGLEngine/OpenGLEngine.vcxproj +++ b/OpenGLEngine/OpenGLEngine.vcxproj @@ -173,12 +173,14 @@ copy "$(ProjectDir)*.h" "$(SolutionDir)include\charcoal\" + + diff --git a/OpenGLEngine/OpenGLEngine.vcxproj.filters b/OpenGLEngine/OpenGLEngine.vcxproj.filters index 1fee18f..c6d514e 100644 --- a/OpenGLEngine/OpenGLEngine.vcxproj.filters +++ b/OpenGLEngine/OpenGLEngine.vcxproj.filters @@ -49,6 +49,9 @@ {c8d9e420-19ab-4706-9a82-5a4537142b5c} + + {4bd056e0-f68e-4aa4-b62d-a142ccf08a21} + @@ -188,5 +191,11 @@ Header Files\Types + + Header Files\Physics + + + Header Files\Physics + \ No newline at end of file diff --git a/OpenGLEngine/PhysicsTypes.h b/OpenGLEngine/PhysicsTypes.h new file mode 100644 index 0000000..41271d8 --- /dev/null +++ b/OpenGLEngine/PhysicsTypes.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace charcoal +{ + namespace physics + { + using namespace glm; + + struct Rect + { + Rect(float top, float bottom, float left, float right) + : top(top), bottom(bottom), left(left), right(right) + {} + Rect(const glm::vec2& top_left, const glm::vec2& bottom_right) + : top(top_left.y), bottom(bottom_right.y), left(top_left.x), right(bottom_right.x) + {} + Rect(const glm::vec2& center, float width, float height) + : top(center.y + height / 2.0f), bottom(center.y - height / 2.0f), left(center.x - width / 2.0f), right(center.x + width / 2.0f) + {} + + float top; + float bottom; + float left; + float right; + }; + } +} \ No newline at end of file