diff --git a/Games/Snake/SnakeGame.cpp b/Games/Snake/SnakeGame.cpp index e69de29bb2d..a0ed4175ad2 100644 --- a/Games/Snake/SnakeGame.cpp +++ b/Games/Snake/SnakeGame.cpp @@ -0,0 +1,151 @@ +#include "SnakeGame.h" +#include +#include +#include + +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 01e13aabbfd..2e8d04c00d4 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 m_tail; + + Coordinate m_fruit; + + int m_length { 0 }; }; diff --git a/Games/Snake/main.cpp b/Games/Snake/main.cpp index 6443761bfad..7cf72b64ff3 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(Orientation::Vertical)); - - auto* game = new SnakeGame(widget); + auto* game = new SnakeGame; + window->set_main_widget(game); auto menubar = make(); diff --git a/Kernel/init.cpp b/Kernel/init.cpp index f9636cfdef2..0081b88ece7 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -26,14 +26,14 @@ #include #include -//#define SPAWN_TERMINAL +#define SPAWN_TERMINAL //#define SPAWN_LAUNCHER //#define SPAWN_GUITEST2 //#define SPAWN_FILE_MANAGER //#define SPAWN_PROCESS_MANAGER //#define SPAWN_TEXT_EDITOR //#define SPAWN_FONTEDITOR -#define SPAWN_VISUAL_BUILDER +//#define SPAWN_VISUAL_BUILDER //#define SPAWN_MULTIPLE_SHELLS //#define STRESS_TEST_SPAWNING diff --git a/Kernel/makeall.sh b/Kernel/makeall.sh index 055b5c057cd..c1ddc9c9528 100755 --- a/Kernel/makeall.sh +++ b/Kernel/makeall.sh @@ -44,6 +44,8 @@ $make_cmd -C ../Applications/VisualBuilder clean && \ $make_cmd -C ../Applications/VisualBuilder && \ $make_cmd -C ../Games/Minesweeper clean && \ $make_cmd -C ../Games/Minesweeper && \ +$make_cmd -C ../Games/Snake clean && \ +$make_cmd -C ../Games/Snake && \ $make_cmd clean &&\ $make_cmd && \ sudo ./sync.sh diff --git a/Kernel/sync.sh b/Kernel/sync.sh index d9c57a0bf7d..72ca5cb8935 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -61,6 +61,8 @@ cp -v ../Applications/VisualBuilder/VisualBuilder mnt/bin/VisualBuilder ln -s VisualBuilder mnt/bin/vb cp -v ../Games/Minesweeper/Minesweeper mnt/bin/Minesweeper ln -s Minesweeper mnt/bin/ms +cp -v ../Games/Snake/Snake mnt/bin/Snake +ln -s Snake mnt/bin/sn cp -v kernel.map mnt/ sh sync-local.sh umount mnt || ( sleep 0.5 && sync && umount mnt )