diff --git a/include/Bot.hpp b/include/Bot.hpp index 82cd52b..a7e2378 100644 --- a/include/Bot.hpp +++ b/include/Bot.hpp @@ -5,29 +5,27 @@ #include "Map.hpp" #include "Snake.hpp" -class Bot : public Snake, public GameObject { +class Bot : public Snake { public: struct Config { float time_between_targets; - double speed; - float move_interval; }; - Bot(canvas::SnakeObject obj, Config config, Map &map) - : Snake(obj), config_(config), map_(map), real_pos_(obj.pos) {} + Bot(canvas::SnakeObject::Config canvas_config, Snake::Config snake_config, + Config bot_config, Map &map) + : Snake(canvas_config, snake_config, map), bot_config_(bot_config) {} - void act(float dt) override { +protected: + void change_direction(float dt) override { time_from_target_set_ += dt; - int eaten = map_.eat(utils::to_world_coord(pos), 20); - inc_length(eaten); - if (not target_.has_value() or - time_from_target_set_ >= config_.time_between_targets or - (target_.value() - pos).len_sq() < radius * radius) { + time_from_target_set_ >= bot_config_.time_between_targets or + (target_.value() - get_pos()).len_sq() < + canvas_config_.radius * canvas_config_.radius) { time_from_target_set_ = 0; - target_ = map_.find_nearest_food(pos); + target_ = map_.find_nearest_food(get_pos()); } // check for case when no food found @@ -35,29 +33,11 @@ public: direction_ = (Vecf(target_.value()) - real_pos_).norm(); // TODO: manually change direction } - - move(dt); } - void draw(Veci offset) override { Snake::draw(offset); } - protected: - void move(float dt) { - real_pos_ += direction_ * dt * config_.speed; - move_time_delta_ += dt; - if (move_time_delta_ > config_.move_interval) { - move_time_delta_ -= config_.move_interval; - add(Veci(real_pos_)); - } - } + const Config bot_config_; -private: - const Config config_; - Map &map_; - - Vecf real_pos_; - Vecf direction_ = {}; std::optional target_ = {}; float time_from_target_set_ = 0; - float move_time_delta_ = 0; }; diff --git a/include/Params.hpp b/include/Params.hpp index 6926448..6889156 100644 --- a/include/Params.hpp +++ b/include/Params.hpp @@ -3,3 +3,5 @@ #include "Vec.hpp" constexpr Veci WORLD_SIZE = {.x = 10000, .y = 10000}; + +constexpr double MIN_CONTROL_DISTANCE = 10; diff --git a/include/Player.hpp b/include/Player.hpp index 0a29d27..3216b05 100644 --- a/include/Player.hpp +++ b/include/Player.hpp @@ -1,11 +1,48 @@ #pragma once -#include "Vec.hpp" +#include "Snake.hpp" -struct Player { - Vecf pos; - Vecf direction; - double speed; - double move_interval; - double move_time_delta; +// struct Player { +// Vecf pos; +// Vecf direction; +// double speed; +// double move_interval; +// double move_time_delta; +// }; + +class Player : public Snake { +public: + using Snake::Snake; + + void act(float dt) override { + int eaten = map_.eat( + utils::to_world_coord(get_pos() + utils::get_screen_center()), 20); + inc_length(eaten); + + change_direction(dt); + + move(dt); + } + + void draw(Veci offset) override { + Snake::draw(offset - utils::get_screen_center()); + } + +protected: + void change_direction(float) override { + Veci cursor = utils::get_cursor(); + + if (cursor != prev_cursor_ and utils::is_on_screen(cursor)) { + Vecf diff(cursor - utils::get_screen_center()); // - pos; + + if (diff.len() > MIN_CONTROL_DISTANCE) { + direction_ = diff.norm(); + } + } + + prev_cursor_ = cursor; + } + +protected: + Veci prev_cursor_ = {}; }; diff --git a/include/Snake.hpp b/include/Snake.hpp index 760f53b..6f3bf98 100644 --- a/include/Snake.hpp +++ b/include/Snake.hpp @@ -3,19 +3,21 @@ #include #include "Canvas.hpp" +#include "Map.hpp" namespace canvas { -struct SnakeObject : public Object { - size_t length; - int radius; -}; - -} // namespace canvas - -class Snake : protected canvas::SnakeObject { +class SnakeObject { public: - Snake(canvas::SnakeObject obj) : SnakeObject(obj), track_{pos} {} + struct Config { + Object obj; + size_t initial_length; + int radius; + }; + + SnakeObject(Config config) + : canvas_config_(config), length_{config.initial_length}, + track_{config.obj.pos} {} void add(Veci pos); @@ -23,26 +25,80 @@ public: // - Veci get_pos() { return pos; } + Veci get_pos() { + if (track_.empty()) { + throw std::exception(); + } + return track_.back(); + } // - size_t get_length() { return length; } + size_t get_length() { return length_; } - void set_length(size_t length) { this->length = length; } + void set_length(size_t length) { length_ = length; } void inc_length(int inc) { - if (-inc > static_cast(length)) { - length = 0; + if (-inc > static_cast(length_)) { + length_ = 1; } else { - length += inc; + length_ += inc; } } // - bool touches(const Snake &other); + bool touches(const SnakeObject &other); protected: + const Config canvas_config_; + + size_t length_; std::deque track_; }; + +} // namespace canvas + +class Snake : public canvas::SnakeObject, public GameObject { +public: + struct Config { + double speed; + float move_interval; + }; + + Snake(canvas::SnakeObject::Config canvas_config, Config snake_config, + Map &map) + : SnakeObject(canvas_config), snake_config_(snake_config), map_(map), + real_pos_(canvas_config.obj.pos) {} + + void act(float dt) override { + int eaten = map_.eat(utils::to_world_coord(get_pos()), 20); + inc_length(eaten); + + change_direction(dt); + + move(dt); + } + + void draw(Veci offset) override { SnakeObject::draw(offset); } + +protected: + virtual void change_direction(float dt) = 0; + + virtual void move(float dt) { + real_pos_ += direction_ * dt * snake_config_.speed; + move_time_delta_ += dt; + if (move_time_delta_ > snake_config_.move_interval) { + move_time_delta_ -= snake_config_.move_interval; + add(Veci(real_pos_)); + } + } + +protected: + const Config snake_config_; + Map &map_; + + Vecf real_pos_; + Vecf direction_ = {}; + float move_time_delta_ = 0; +}; diff --git a/src/Game.cpp b/src/Game.cpp index 74766f8..237a23a 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -12,8 +12,6 @@ #include "Utils.hpp" #include "World.hpp" -constexpr double MIN_CONTROL_DISTANCE = 10; - // // You are free to modify this file // @@ -31,14 +29,6 @@ void initialize() { std::srand(std::time(0)); } float game_time = 0.0f; -Player player{ - .pos = {.x = 20, .y = 20}, - .direction = {.x = 1.0, .y = 0.0}, - .speed = 200.0, - .move_interval = 0.01, - .move_time_delta = 0, -}; - World world; Map map{{ @@ -51,13 +41,18 @@ Map map{{ .food_color = {color::RED}, }}; -// std::vector bots; // TODO +Player player{canvas::SnakeObject::Config{ + .obj = {.pos = {}, .color = {color::GREEN}}, + .initial_length = 10, + .radius = 10, + }, + Snake::Config{ + .speed = 200.0, + .move_interval = 0.01, + }, + map}; -auto snake = Snake(canvas::SnakeObject{ - {.pos = Veci(player.pos), .color = {color::GREEN}}, - 10, - 10, -}); +// std::vector bots; // TODO // this function is called to update game data, // dt - time elapsed since the previous update (in seconds) @@ -68,30 +63,11 @@ void act(float dt) { map.act(dt); - world.cursor = utils::get_cursor(); - if (world.cursor != world.prev_cursor and utils::is_on_screen(world.cursor)) { - Vecf diff(world.cursor - utils::get_screen_center()); // - pos; - - if (diff.len() > MIN_CONTROL_DISTANCE) { - player.direction = diff.norm(); - } - } - - player.pos += player.direction * dt * player.speed; + player.act(dt); game_time += dt; world.prev_cursor = world.cursor; - player.move_time_delta += dt; - if (player.move_time_delta > player.move_interval) { - player.move_time_delta -= player.move_interval; - snake.add(Veci(player.pos)); - } - - int eaten = map.eat( - utils::to_world_coord(Veci(player.pos) + utils::get_screen_center()), 20); - snake.inc_length(eaten); - // TODO // for (const auto &bot : bots) { // if (snake.touches(bot)) { // GAME OVER @@ -110,9 +86,9 @@ void draw() { // clear backbuffer memset(buffer, 0, SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint32_t)); - Veci map_offset = Veci(snake.get_pos()); + Veci map_offset = Veci(player.get_pos()); - snake.draw(map_offset - utils::get_screen_center()); + player.draw(map_offset); map.draw(map_offset); } diff --git a/src/Snake.cpp b/src/Snake.cpp index fb1f961..275c1fd 100644 --- a/src/Snake.cpp +++ b/src/Snake.cpp @@ -1,25 +1,29 @@ #include "Snake.hpp" -void Snake::add(Veci pos) { - this->pos = pos; +namespace canvas { + +void SnakeObject::add(Veci pos) { track_.push_back(pos); - if (track_.size() > length) { + if (track_.size() > length_) { track_.pop_front(); } } -void Snake::draw(Veci offset) const { +void SnakeObject::draw(Veci offset) const { for (const auto &pos : track_) { - paint::circle({{.pos = pos - offset, .color = color}, radius}); + paint::circle({{.pos = pos - offset, .color = canvas_config_.obj.color}, + canvas_config_.radius}); } } -bool Snake::touches(const Snake &other) { - int dist = radius + other.radius; +bool SnakeObject::touches(const SnakeObject &other) { + int dist = canvas_config_.radius + other.canvas_config_.radius; for (const auto &elem : other.track_) { - if ((pos - elem).len_sq() < dist * dist) { + if ((get_pos() - elem).len_sq() < dist * dist) { return true; } } return false; } + +} // namespace canvas