From 4570d6e593f5f43d8f070907fa0134aa24adf410 Mon Sep 17 00:00:00 2001 From: programsnail Date: Sun, 21 Jul 2024 22:02:19 +0300 Subject: [PATCH] moving circle prototype, circle and square drawing, part of food map implementation, utils --- include/Bot.hpp | 6 +++ include/Canvas.hpp | 123 +++++++++++++++++++++++++++++++++++++++++++++ include/Map.hpp | 62 +++++++++++++++++++++++ include/Player.hpp | 6 +++ include/Snake.hpp | 0 include/Utils.hpp | 41 +++++++++++++++ include/Vec.hpp | 99 ++++++++++++++++++++++++++++++++++++ src/Canvas.cpp | 0 src/Game.cpp | 59 +++++++++++++++------- 9 files changed, 378 insertions(+), 18 deletions(-) create mode 100644 include/Bot.hpp create mode 100644 include/Canvas.hpp create mode 100644 include/Map.hpp create mode 100644 include/Player.hpp create mode 100644 include/Snake.hpp create mode 100644 include/Utils.hpp create mode 100644 include/Vec.hpp create mode 100644 src/Canvas.cpp diff --git a/include/Bot.hpp b/include/Bot.hpp new file mode 100644 index 0000000..983c1c6 --- /dev/null +++ b/include/Bot.hpp @@ -0,0 +1,6 @@ +#pragma once + +class Bot { +public: +private: +}; diff --git a/include/Canvas.hpp b/include/Canvas.hpp new file mode 100644 index 0000000..f842dbd --- /dev/null +++ b/include/Canvas.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include +#include +#include +# + +#include "Engine.h" +#include "Utils.hpp" + +enum class Color : uint32_t { + BLACK = 0x000000ff, + WHITE = 0x00ff6000, + + BLUE = 0x000000ff, + GREEN = 0x0000ff00, + CYAN = 0x0000ffff, + RED = 0x00ff0000, + MAGENTA = 0x00ff00ff, + YELLOW = 0x00ffff00, + GRAY = 0x001f1f1f, + ORANGE = 0x00ff6000, +}; +constexpr Color CL_BG = Color::BLACK; + +using Screen = uint32_t[SCREEN_HEIGHT][SCREEN_WIDTH]; + +class CanvasObject { +public: + struct Config { + Veci pos; + int size; + Color color = Color ::WHITE; + }; + CanvasObject(Config config) + : pos_(config.pos), size_(config.size), color_(config.color), + shown_(false) {} + + virtual void move_to(Veci) = 0; + virtual void show() = 0; + virtual void hide() = 0; + + virtual ~CanvasObject() { + if (shown_) { + // hide(); // TODO + } + } + +protected: + Veci pos_; + int size_; + Color color_; + bool shown_; +}; + +class StatelessCanvasObject : public CanvasObject { +public: + using CanvasObject::CanvasObject; + + void move_to(Veci pos) override { + if (not shown_) { + return; + } + hide(); + pos_ = pos; + show(); + } + + void show() override { fill(color_); } + + void hide() override { fill(CL_BG); } + +protected: + virtual void fill(Color color) = 0; +}; + +class Square : public StatelessCanvasObject { +public: + using StatelessCanvasObject::StatelessCanvasObject; + +protected: + void fill(Color color) override { + for (int x = pos_.x; x < pos_.x + size_; ++x) { + std::fill(screen_at(x, pos_.y), screen_at(x, pos_.y + size_), + static_cast(color)); + } + } +}; + +class Circle : public StatelessCanvasObject { +public: + using StatelessCanvasObject::StatelessCanvasObject; + +protected: + void fill(Color color) override { + for (int x = -size_; x < size_; ++x) { + int size_y = std::sqrt(size_ * size_ - std::abs(x) * std::abs(x)); + std::fill(screen_at(pos_.x + x, pos_.y - size_y), + screen_at(pos_.x + x, pos_.y + size_y), + static_cast(color)); + } + } +}; + +class Worm : public CanvasObject { + Worm(CanvasObject::Config config, size_t max_track_size) + : CanvasObject(config), max_track_size_(max_track_size) {} + +protected: + const size_t max_track_size_; + std::vector track_; +}; + +// class Canvas { +// public: +// Canvas(Screen &screen) : screen_(screen) {} + +// size_t insert(CanvasObject obj) {} +// void erase(size_t id) {} + +// private: +// Screen &screen_; +// }; diff --git a/include/Map.hpp b/include/Map.hpp new file mode 100644 index 0000000..faa239b --- /dev/null +++ b/include/Map.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include "Utils.hpp" +#include "Vec.hpp" + +class Map : public GameObject { + struct Food { + size_t gen; + Veci pos; + int weight; + bool eaten = false; + }; + + static constexpr double GEN_INTERVAL = 1.0; + static constexpr size_t FOOD_EXISTS_GENS = 10; + static constexpr size_t GEN_FOOD_COUNT = 1000; + static constexpr int SIZE_X = 20000; + static constexpr int SIZE_Y = 20000; + +public: + void act(float dt) override { + time_from_last_gen_ += dt; + if (time_from_last_gen_ > GEN_INTERVAL) { + time_from_last_gen_ -= GEN_INTERVAL; + generate(); + } + } + + int eat(Veci pos, int dist) { // TODO: faster variant ? + size_t eaten_weight = 0; + for (auto &food : food_) { + if ((pos - food.pos).len_sq() < dist * dist and not food.eaten) { + food.eaten = true; + eaten_weight += food.weight; + } + } + return eaten_weight; + } + + void draw() override {} // TODO + +private: + void generate() { + ++current_gen_; + while (food_.front().gen + FOOD_EXISTS_GENS < current_gen_) { + food_.pop_front(); + } + + for (size_t i = 0; i < GEN_FOOD_COUNT; ++i) { + food_.push_back({.gen = current_gen_, + .pos = {.x = rand() % SIZE_X, .y = rand() % SIZE_Y}, + .weight = 1}); + } + } + +private: + double time_from_last_gen_ = 0; + size_t current_gen_ = 0; + std::deque food_ = {}; +}; diff --git a/include/Player.hpp b/include/Player.hpp new file mode 100644 index 0000000..7132100 --- /dev/null +++ b/include/Player.hpp @@ -0,0 +1,6 @@ +#pragma once + +class Player { +public: +private: +}; diff --git a/include/Snake.hpp b/include/Snake.hpp new file mode 100644 index 0000000..e69de29 diff --git a/include/Utils.hpp b/include/Utils.hpp new file mode 100644 index 0000000..c68737e --- /dev/null +++ b/include/Utils.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "Engine.h" +#include "Vec.hpp" + +namespace safe { + +inline int lx(int x) { return std::max(0, x); } + +inline int ly(int y) { return std::max(0, y); } + +inline int ux(int x) { return std::min(SCREEN_HEIGHT - 1, x); } + +inline int uy(int y) { return std::min(SCREEN_WIDTH - 1, y); } + +inline int x(int x) { return safe::ux(safe::lx(x)); } +inline int y(int y) { return safe::uy(safe::ly(y)); } +} // namespace safe + +inline uint32_t *screen_at(int x, int y) { + return &buffer[safe::x(x)][safe::y(y)]; +} + +template inline bool is_valid_pos(Vec pos) { + return pos.x >= 0 and pos.x < SCREEN_HEIGHT and pos.y >= 0 and + pos.y < SCREEN_WIDTH; +} + +inline Veci get_cursor() { return {.x = get_cursor_y(), .y = get_cursor_x()}; } + +// + +class GameObject { +public: + virtual void act(float dt) = 0; + virtual void draw() = 0; + + virtual ~GameObject() {} +}; diff --git a/include/Vec.hpp b/include/Vec.hpp new file mode 100644 index 0000000..0352b80 --- /dev/null +++ b/include/Vec.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include + +template struct Vec { + T x; + T y; + + // + + template explicit operator Vec() { + return Vec{.x = x, .y = y}; + } + + // + + Vec &operator-() { + x = -x; + y = -y; + return *this; + } + + Vec &operator*=(const T &value) { + x *= value; + y *= value; + return *this; + } + + Vec &operator/=(const T &value) { + x /= value; + y /= value; + return *this; + } + + Vec operator*(const T &value) const { + auto copy = Vec{*this}; + copy *= value; + return copy; + } + + Vec operator/(const T &value) const { + auto copy = Vec{*this}; + copy /= value; + return copy; + } + + // + + Vec &operator+=(const Vec &other) { + x += other.x; + y += other.y; + return *this; + } + + Vec &operator-=(const Vec &other) { + x -= other.x; + y -= other.y; + return *this; + } + + Vec operator+(const Vec &other) const { + auto copy = Vec{*this}; + copy += other; + return copy; + } + + Vec operator-(const Vec &other) const { + auto copy = Vec{*this}; + copy -= other; + return copy; + } + + // + + bool operator==(const Vec &other) const = default; + + bool operator!=(const Vec &other) const = default; + + // + + int len_sq() const { return dot(*this, *this); } + + double len() const { return std::sqrt(len_sq()); } + + Vec norm() { return Vec(*this) / len(); } + + // + + int static dot(Vec left, Vec right) { + return left.x * right.x + left.y * right.y; + } + + int static cross(Vec left, Vec right) { + return left.x * right.y - left.y * right.x; + } +}; + +using Veci = Vec; +using Vecf = Vec; diff --git a/src/Canvas.cpp b/src/Canvas.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/Game.cpp b/src/Game.cpp index 589b305..3c4dbfd 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,46 +1,69 @@ #include "Engine.h" -#include +#include #include +#include -#include +// #include + +#include "Canvas.hpp" + +constexpr double MIN_CONTROL_DISTANCE = 10; // // You are free to modify this file // // is_key_pressed(int button_vk_code) - check if a key is pressed, -// use keycodes (VK_SPACE, VK_RIGHT, VK_LEFT, VK_UP, VK_DOWN, VK_RETURN) +// use keycodes (VK_SPACE, VK_RIGHT, +// VK_LEFT, VK_UP, VK_DOWN, VK_RETURN) // // get_cursor_x(), get_cursor_y() - get mouse cursor position -// is_mouse_button_pressed(int button) - check if mouse button is pressed (0 - left button, 1 - right button) -// schedule_quit_game() - quit game after act() - +// is_mouse_button_pressed(int button) - check if mouse button is pressed (0 - +// left button, 1 - right button) schedule_quit_game() - quit game after act() // initialize game data in this function -void initialize() -{ -} +void initialize() {} + +float game_time = 0.0f; +Vecf pos = {.x = 20, .y = 20}; +Vecf direction{.x = 1.0, .y = 0.0}; +Veci prev_cursor = {.x = 0, .y = 0}; // this function is called to update game data, // dt - time elapsed since the previous update (in seconds) -void act(float dt) -{ +void act(float dt) { if (is_key_pressed(VK_ESCAPE)) schedule_quit_game(); + Veci cursor = get_cursor(); + if (cursor != prev_cursor and is_valid_pos(cursor)) { + Vecf diff = Vecf(cursor) - pos; + + if (diff.len() > MIN_CONTROL_DISTANCE) { + direction = diff.norm(); + } + } + + int speed = 200; + pos += direction * dt * speed; + + game_time += dt; + prev_cursor = cursor; + // std::cout << "pos: " << pos.x << ' ' << pos.y << std::endl; + // std::cout << "curs: " << get_cursor().x << ' ' << get_cursor().y << + // std::endl; } // fill buffer in this function -// uint32_t buffer[SCREEN_HEIGHT][SCREEN_WIDTH] - is an array of 32-bit colors (8 bits per R, G, B) -void draw() -{ +// uint32_t buffer[SCREEN_HEIGHT][SCREEN_WIDTH] - is an array of 32-bit colors +// (8 bits per R, G, B) +void draw() { // clear backbuffer memset(buffer, 0, SCREEN_HEIGHT * SCREEN_WIDTH * sizeof(uint32_t)); + Circle sq({.pos = Veci(pos), .size = 20}); + sq.show(); } // free game data in this function -void finalize() -{ -} - +void finalize() {}