diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-04-20 03:24:50 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-04-20 03:24:50 +0200 |
commit | e24e4867142d1ae2a495060fa07629f941e8e4ee (patch) | |
tree | 789d7ef6bd703a65efcd61a912ad2fca5704df34 /Games/Snake | |
parent | eca9494adfcdd0acb6a27172053195b0c4c8ec09 (diff) | |
download | serenity-e24e4867142d1ae2a495060fa07629f941e8e4ee.zip |
Snake: Flesh out a basic snake game :^)
Diffstat (limited to 'Games/Snake')
-rw-r--r-- | Games/Snake/SnakeGame.cpp | 151 | ||||
-rw-r--r-- | Games/Snake/SnakeGame.h | 37 | ||||
-rw-r--r-- | Games/Snake/main.cpp | 9 |
3 files changed, 190 insertions, 7 deletions
diff --git a/Games/Snake/SnakeGame.cpp b/Games/Snake/SnakeGame.cpp index e69de29bb2..a0ed4175ad 100644 --- a/Games/Snake/SnakeGame.cpp +++ b/Games/Snake/SnakeGame.cpp @@ -0,0 +1,151 @@ +#include "SnakeGame.h" +#include <LibGUI/GPainter.h> +#include <stdlib.h> +#include <time.h> + +SnakeGame::SnakeGame(GWidget* parent) + : GWidget(parent) +{ + srand(time(nullptr)); + reset(); +} + +SnakeGame::~SnakeGame() +{ +} + +void SnakeGame::reset() +{ + m_head = { m_rows / 2, m_columns / 2 }; + m_tail.clear_with_capacity(); + m_length = 2; + stop_timer(); + start_timer(120); + spawn_fruit(); +} + +bool SnakeGame::is_available(const Coordinate& coord) +{ + for (int i = 0; i < m_tail.size(); ++i) { + if (m_tail[i] == coord) + return false; + } + if (m_head == coord) + return false; + if (m_fruit == coord) + return false; + return true; +} + +void SnakeGame::spawn_fruit() +{ + Coordinate coord; + for (;;) { + coord.row = rand() % m_rows; + coord.column = rand() % m_columns; + if (is_available(coord)) + break; + } + m_fruit = coord; +} + +void SnakeGame::timer_event(CTimerEvent&) +{ + m_tail.prepend(m_head); + + if (m_tail.size() > m_length) + m_tail.take_last(); + + m_head.row += m_vertical_velocity; + m_head.column += m_horizontal_velocity; + + m_last_vertical_velocity = m_vertical_velocity; + m_last_horizontal_velocity = m_horizontal_velocity; + + if (m_head.row >= m_rows) + m_head.row = 0; + if (m_head.row < 0) + m_head.row = m_rows - 1; + if (m_head.column >= m_columns) + m_head.column = 0; + if (m_head.column < 0) + m_head.column = m_columns - 1; + + for (int i = 0; i < m_tail.size(); ++i) { + if (m_head == m_tail[i]) { + game_over(); + return; + } + } + + if (m_head == m_fruit) { + ++m_length; + spawn_fruit(); + } + update(); +} + +void SnakeGame::keydown_event(GKeyEvent& event) +{ + switch (event.key()) { + case KeyCode::Key_A: + case KeyCode::Key_Left: + if (m_last_horizontal_velocity == 1) + break; + m_vertical_velocity = 0; + m_horizontal_velocity = -1; + break; + case KeyCode::Key_D: + case KeyCode::Key_Right: + if (m_last_horizontal_velocity == -1) + break; + m_vertical_velocity = 0; + m_horizontal_velocity = 1; + break; + case KeyCode::Key_W: + case KeyCode::Key_Up: + if (m_last_vertical_velocity == 1) + break; + m_vertical_velocity = -1; + m_horizontal_velocity = 0; + break; + case KeyCode::Key_S: + case KeyCode::Key_Down: + if (m_last_vertical_velocity == -1) + break; + m_vertical_velocity = 1; + m_horizontal_velocity = 0; + break; + default: + break; + } +} + +void SnakeGame::paint_event(GPaintEvent& event) +{ + GPainter painter(*this); + painter.fill_rect(event.rect(), Color::Black); + + auto game_rect = rect(); + auto cell_size = Size(game_rect.width() / m_columns, game_rect.height() / m_rows); + + auto cell_rect = [&] (const Coordinate& coord) -> Rect { + return { + coord.column * cell_size.width(), + coord.row * cell_size.height(), + cell_size.width(), + cell_size.height() + }; + }; + + painter.fill_rect(cell_rect(m_head), Color::Yellow); + for (auto& coord : m_tail) + painter.fill_rect(cell_rect(coord), Color::from_rgb(0xaaaa00)); + + painter.fill_rect(cell_rect(m_fruit), Color::Red); +} + +void SnakeGame::game_over() +{ + reset(); +} diff --git a/Games/Snake/SnakeGame.h b/Games/Snake/SnakeGame.h index 01e13aabbf..2e8d04c00d 100644 --- a/Games/Snake/SnakeGame.h +++ b/Games/Snake/SnakeGame.h @@ -4,8 +4,43 @@ class SnakeGame : public GWidget { public: - explicit SnakeGame(GWidget* parent); + explicit SnakeGame(GWidget* parent = nullptr); + virtual ~SnakeGame() override; + + void reset(); private: virtual void paint_event(GPaintEvent&) override; + virtual void keydown_event(GKeyEvent&) override; + virtual void timer_event(CTimerEvent&) override; + + struct Coordinate { + int row { 0 }; + int column { 0 }; + + bool operator==(const Coordinate& other) const + { + return row == other.row && column == other.column; + } + }; + + void game_over(); + void spawn_fruit(); + bool is_available(const Coordinate&); + + int m_rows { 20 }; + int m_columns { 20 }; + + int m_horizontal_velocity { 1 }; + int m_vertical_velocity { 0 }; + + int m_last_horizontal_velocity { 1 }; + int m_last_vertical_velocity { 0 }; + + Coordinate m_head; + Vector<Coordinate> m_tail; + + Coordinate m_fruit; + + int m_length { 0 }; }; diff --git a/Games/Snake/main.cpp b/Games/Snake/main.cpp index 6443761bfa..7cf72b64ff 100644 --- a/Games/Snake/main.cpp +++ b/Games/Snake/main.cpp @@ -13,13 +13,10 @@ int main(int argc, char** argv) auto* window = new GWindow; window->set_title("Snake"); - window->set_rect(100, 100, 139, 175); + window->set_rect(100, 100, 300, 300); - auto* widget = new GWidget; - window->set_main_widget(widget); - widget->set_layout(make<GBoxLayout>(Orientation::Vertical)); - - auto* game = new SnakeGame(widget); + auto* game = new SnakeGame; + window->set_main_widget(game); auto menubar = make<GMenuBar>(); |