Added resource generation and resource display. Should commit more often...
This commit is contained in:
parent
189e840f25
commit
0d523b6541
11 changed files with 605 additions and 162 deletions
|
@ -1,3 +1,2 @@
|
|||
add_executable(Bob Main.cpp)
|
||||
add_library(GameMap GameMap.cpp)
|
||||
target_link_libraries(Bob GameMap ${SDL2_LIBRARY} ${SDL2GFX_LIBRARY} ${Boost_LIBRARIES})
|
||||
add_executable(Bob Main.cpp Main.hpp Grid.cpp Grid.hpp Gameplay.cpp Gameplay.hpp Gui.hpp Gui.cpp)
|
||||
target_link_libraries(Bob ${SDL2_LIBRARY} ${SDL2GFX_LIBRARY} ${Boost_LIBRARIES})
|
||||
|
|
162
src/Gameplay.cpp
Normal file
162
src/Gameplay.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
#include "Gameplay.hpp"
|
||||
|
||||
Player Player::default_player = Player("Default");
|
||||
|
||||
std::unordered_map<Field, FieldMeta *> FieldMeta::fields = std::unordered_map<Field, FieldMeta *>();
|
||||
|
||||
Player *FieldMeta::get_owner()
|
||||
{
|
||||
return this->owner;
|
||||
}
|
||||
|
||||
void FieldMeta::set_owner(Player *player)
|
||||
{
|
||||
this->owner = player;
|
||||
}
|
||||
|
||||
Field FieldMeta::get_field() { return this->field; }
|
||||
|
||||
void FieldMeta::render(SDL_Renderer *renderer, Layout *layout)
|
||||
{
|
||||
Point precise_location = field_to_point(this->field, layout);
|
||||
SDL_Point location;
|
||||
location.x = (int) precise_location.x;
|
||||
location.y = (int) precise_location.y;
|
||||
std::vector<Point> polygon = field_to_polygon(this->field, layout);
|
||||
SDL_Color color = this->owner->get_color();
|
||||
Sint16 vx[6];
|
||||
Sint16 vy[6];
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
vx[i] = (Sint16) polygon[i].x;
|
||||
vy[i] = (Sint16) polygon[i].y;
|
||||
}
|
||||
filledPolygonRGBA(renderer, vx, vy, 6, color.r, color.g, color.b, 0x22);
|
||||
SDL_Color inverse;
|
||||
inverse.r = (Uint8) (0xff - color.r);
|
||||
inverse.g = (Uint8) (0xff - color.g);
|
||||
inverse.b = (Uint8) (0xff - color.b);
|
||||
inverse.a = 0xff;
|
||||
|
||||
Uint16 resource_size = (Uint16) (layout->size / 3);
|
||||
if (this->resources_base.circle > 0)
|
||||
{
|
||||
circleRGBA(renderer, (Sint16) (location.x), (Sint16) (location.y), (Sint16) (resource_size), inverse.r,
|
||||
inverse.g, inverse.b, inverse.a);
|
||||
}
|
||||
if (this->resources_base.triangle > 0)
|
||||
{
|
||||
static const SDL_Point trigon[] = {{-1, 1},
|
||||
{1, 1},
|
||||
{0, -1}};
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
vx[i] = (Sint16) (location.x + (trigon[i].x) * resource_size);
|
||||
vy[i] = (Sint16) (location.y + (trigon[i].y) * resource_size);
|
||||
}
|
||||
trigonRGBA(renderer, vx[0], vy[0], vx[1], vy[1], vx[2], vy[2], inverse.r, inverse.g, inverse.b, inverse.a);
|
||||
}
|
||||
|
||||
if (this->resources_base.square > 0)
|
||||
{
|
||||
|
||||
static const SDL_Point square[] = {{-1, -1},
|
||||
{-1, 1},
|
||||
{1, 1},
|
||||
{1, -1}};
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vx[i] = (Sint16) (location.x + (square[i].x) * resource_size);
|
||||
vy[i] = (Sint16) (location.y + (square[i].y) * resource_size);
|
||||
}
|
||||
polygonRGBA(renderer, vx, vy, 4, inverse.r, inverse.g, inverse.b, inverse.a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FieldMeta::regenerate_resources()
|
||||
{
|
||||
resources = resources_base;
|
||||
switch (this->upgrades)
|
||||
{
|
||||
case (UPGRADE_REGENERATION_1):
|
||||
resources *= 2;
|
||||
case (UPGRADE_REGENERATION_2):
|
||||
resources *= 2;
|
||||
case (UPGRADE_REGENERATION_3):
|
||||
resources *= 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Resource FieldMeta::get_resources()
|
||||
{
|
||||
return this->resources;
|
||||
}
|
||||
|
||||
Resource FieldMeta::get_resources_of_cluster()
|
||||
{
|
||||
Resource res = {0, 0, 0};
|
||||
std::unordered_set<FieldMeta *> *cluster = new std::unordered_set<FieldMeta *>();
|
||||
this->get_cluster(cluster);
|
||||
for (FieldMeta *elem : *cluster)
|
||||
{
|
||||
Resource r_plus = elem->get_resources();
|
||||
res += r_plus;
|
||||
}
|
||||
delete cluster;
|
||||
return res;
|
||||
}
|
||||
|
||||
Uint32 FieldMeta::get_upgrades() { return this->upgrades; }
|
||||
|
||||
bool FieldMeta::upgrade(Upgrade upgrade)
|
||||
{
|
||||
// check available resources for cluster and consume resources
|
||||
Resource cluster_resources = this->get_resources_of_cluster();
|
||||
Resource costs;
|
||||
switch (upgrade)
|
||||
{
|
||||
case UPGRADE_REGENERATION_1:
|
||||
costs = {(1 << 1), (1 << 1), (1 << 1)};
|
||||
break;
|
||||
case UPGRADE_REGENERATION_2:
|
||||
costs = {(1 << 2), (1 << 2), (1 << 2)};
|
||||
break;
|
||||
case UPGRADE_REGENERATION_3:
|
||||
costs = {(1 << 3), (1 << 3), (1 << 3)};
|
||||
|
||||
break;
|
||||
default:
|
||||
std::cout << "Unknown update: " << upgrade;
|
||||
break;
|
||||
}
|
||||
if (cluster_resources > costs)
|
||||
{
|
||||
this->resources -= costs;
|
||||
this->upgrades |= upgrade;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_set<FieldMeta *> *FieldMeta::get_cluster(std::unordered_set<FieldMeta *> *visited)
|
||||
{
|
||||
assert(visited != nullptr);
|
||||
|
||||
if (visited->find(this) != visited->end()) // already been here before
|
||||
return visited;
|
||||
|
||||
visited->insert(this);
|
||||
|
||||
for (Uint8 i = 0; i < 6; i++)
|
||||
{
|
||||
auto neighbor_pair = FieldMeta::fields.find(hex_neighbor(i, this->get_field()));
|
||||
FieldMeta *neighbor = neighbor_pair->second;
|
||||
if (neighbor->get_owner() != this->get_owner()) // ignore meta if field not owned by specified owner
|
||||
return visited;
|
||||
else
|
||||
return neighbor->get_cluster(visited);
|
||||
}
|
||||
return visited;
|
||||
}
|
235
src/Gameplay.hpp
Normal file
235
src/Gameplay.hpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
#include <random>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <SDL2/SDL_pixels.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include "Grid.hpp"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UPGRADE_FIRST_UPGRADE = 0,
|
||||
UPGRADE_REGENERATION_1,
|
||||
UPGRADE_REGENERATION_2,
|
||||
UPGRADE_REGENERATION_3,
|
||||
UPGRADE_REPRODUCTION
|
||||
} Upgrade;
|
||||
|
||||
#ifndef Tagged
|
||||
|
||||
class Tagged
|
||||
{
|
||||
private:
|
||||
boost::uuids::uuid tag;
|
||||
|
||||
int state;
|
||||
public:
|
||||
// construct new
|
||||
Tagged()
|
||||
: tag(boost::uuids::random_generator()()), state(0) { }
|
||||
|
||||
// construct with state
|
||||
explicit Tagged(int state)
|
||||
: tag(boost::uuids::random_generator()()), state(state) { }
|
||||
|
||||
// clone
|
||||
Tagged(Tagged const &rhs)
|
||||
: tag(rhs.tag), state(rhs.state) { }
|
||||
|
||||
bool operator==(Tagged const &rhs) const
|
||||
{
|
||||
return tag == rhs.tag;
|
||||
}
|
||||
|
||||
bool operator!=(Tagged const &rhs) const
|
||||
{
|
||||
return !(tag == rhs.tag);
|
||||
}
|
||||
|
||||
int get_state() const { return state; }
|
||||
|
||||
void set_state(int new_state) { state = new_state; }
|
||||
|
||||
boost::uuids::uuid get_tag() { return tag; }
|
||||
|
||||
void set_tag(boost::uuids::uuid uuid_) { tag = uuid_; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Player
|
||||
|
||||
class Player : public Tagged
|
||||
{
|
||||
private:
|
||||
SDL_Color color;
|
||||
std::string name;
|
||||
|
||||
public:
|
||||
Player(std::string name_)
|
||||
: name(name_), Tagged()
|
||||
{
|
||||
// use the last 24 bits of the tag for the color
|
||||
boost::uuids::uuid id = get_tag();
|
||||
uint8_t *data = id.data;
|
||||
this->color = {data[13], data[14], data[15], 0xff};
|
||||
}
|
||||
|
||||
Player(std::string name_, boost::uuids::uuid tag_)
|
||||
: Tagged(), name(name_)
|
||||
{
|
||||
this->set_tag(tag_);
|
||||
}
|
||||
|
||||
SDL_Color get_color() { return color; }
|
||||
|
||||
std::string get_name()
|
||||
{
|
||||
std::ostringstream descriptor;
|
||||
boost::uuids::uuid id = get_tag();
|
||||
uint8_t *data = id.data;
|
||||
Uint16 number = (data[14] << 8) | (data[15]);
|
||||
descriptor << this->name << " (" << std::hex << number << ")";
|
||||
return descriptor.str();
|
||||
}
|
||||
|
||||
static Player default_player;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Resource
|
||||
|
||||
struct Resource
|
||||
{
|
||||
Uint8 circle;
|
||||
Uint8 triangle;
|
||||
Uint8 square;
|
||||
|
||||
Resource &operator+=(const Resource &rhs)
|
||||
{
|
||||
this->circle += rhs.circle;
|
||||
this->triangle += rhs.triangle;
|
||||
this->square += rhs.square;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend Resource operator+(Resource lhs, const Resource &rhs)
|
||||
{
|
||||
lhs += rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
Resource &operator-=(const Resource &rhs)
|
||||
{
|
||||
this->circle -= rhs.circle;
|
||||
this->triangle -= rhs.triangle;
|
||||
this->square -= rhs.square;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend Resource operator-(Resource lhs, const Resource &rhs)
|
||||
{
|
||||
lhs -= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
Resource &operator*=(const Resource &rhs)
|
||||
{
|
||||
this->circle *= rhs.circle;
|
||||
this->triangle *= rhs.triangle;
|
||||
this->square *= rhs.square;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend Resource operator*(Resource lhs, const Resource &rhs)
|
||||
{
|
||||
lhs *= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
Resource &operator*=(const double rhs)
|
||||
{
|
||||
this->circle *= rhs;
|
||||
this->triangle *= rhs;
|
||||
this->square *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend Resource operator*(const double lhs, Resource rhs)
|
||||
{
|
||||
rhs *= lhs;
|
||||
return rhs;
|
||||
}
|
||||
|
||||
friend Resource operator*(Resource lhs, const double rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
bool operator<(const Resource &rhs) const
|
||||
{
|
||||
return (this->circle < rhs.circle || this->triangle < rhs.triangle || this->square < rhs.square);
|
||||
}
|
||||
|
||||
inline bool operator>(const Resource &rhs) const { return rhs < *this; }
|
||||
|
||||
inline bool operator<=(const Resource &rhs) const { return !(*this > rhs); }
|
||||
|
||||
inline bool operator>=(const Resource &rhs) const { return !(*this < rhs); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef FieldMeta
|
||||
|
||||
class FieldMeta
|
||||
{
|
||||
public:
|
||||
FieldMeta(Field field_, Player *owner_ = &(Player::default_player))
|
||||
: field(field_), owner(owner_)
|
||||
{
|
||||
this->upgrades = 0;
|
||||
static std::random_device rd;
|
||||
std::mt19937 rng(rd());
|
||||
std::uniform_int_distribution<Uint8> distro(0, 1);
|
||||
this->resources_base.circle = distro(rng);
|
||||
this->resources_base.triangle = distro(rng);
|
||||
this->resources_base.square = distro(rng);
|
||||
std::pair<Field, FieldMeta *> pair(field, this);
|
||||
this->fields.insert(pair);
|
||||
}
|
||||
|
||||
Field get_field();
|
||||
|
||||
Player *get_owner();
|
||||
|
||||
void set_owner(Player *player);
|
||||
|
||||
void render(SDL_Renderer *renderer, Layout *layout);
|
||||
|
||||
Resource get_resources();
|
||||
|
||||
Resource get_resources_of_cluster();
|
||||
|
||||
std::unordered_set<FieldMeta *> *get_cluster(std::unordered_set<FieldMeta *> *visited);
|
||||
|
||||
Uint32 get_upgrades();
|
||||
|
||||
void regenerate_resources();
|
||||
|
||||
bool upgrade(Upgrade upgrade);
|
||||
|
||||
private:
|
||||
const Field field;
|
||||
static std::unordered_map<Field, FieldMeta *> fields;
|
||||
Player *owner;
|
||||
Uint32 upgrades;
|
||||
Resource resources_base; // without upgrades applied, used as basis of regeneration
|
||||
Resource resources; // actual current resources
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
#include "GameMap.hpp"
|
||||
#include "Grid.hpp"
|
||||
|
||||
SDL_Point operator+(SDL_Point left, SDL_Point right)
|
||||
{
|
||||
|
@ -20,24 +20,26 @@ SDL_Point operator/(SDL_Point left, SDL_Point right)
|
|||
return {(left.x / right.x), (left.x / right.y)};
|
||||
}
|
||||
|
||||
SDL_Point operator*(int left, SDL_Point right)
|
||||
SDL_Point operator*(double left, SDL_Point right)
|
||||
{
|
||||
return {left * right.x, left * right.y};
|
||||
int x = (int) (left * right.x);
|
||||
int y = (int) (left * right.y);
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
SDL_Point operator*(SDL_Point left, int right)
|
||||
SDL_Point operator*(SDL_Point left, double right)
|
||||
{
|
||||
return right * left;
|
||||
}
|
||||
|
||||
SDL_Point operator/(SDL_Point left, int right)
|
||||
SDL_Point operator/(SDL_Point left, double right)
|
||||
{
|
||||
return {left.x / right, left.y / right};
|
||||
return (1 / right) * left;
|
||||
}
|
||||
|
||||
int operator!(SDL_Point left)
|
||||
double operator!(SDL_Point left)
|
||||
{
|
||||
int length = (int) std::sqrt(left.x * left.x + left.y * left.y);
|
||||
double length = std::sqrt(left.x * left.x + left.y * left.y);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -142,55 +144,67 @@ int cubic_distance(Field a, Field b)
|
|||
return (abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z)) / 2;
|
||||
}
|
||||
|
||||
Field hex_direction(int direction)
|
||||
Field hex_direction(Uint8 direction)
|
||||
{
|
||||
assert (0 <= direction && direction <= 5);
|
||||
return hex_directions[direction];
|
||||
}
|
||||
|
||||
Field hex_neighbor(int8_t direction, Field f)
|
||||
Field hex_neighbor(Uint8 direction, Field f)
|
||||
{
|
||||
return hex_direction(direction) + f;
|
||||
}
|
||||
|
||||
Point field_to_point(const Field f, const Layout layout)
|
||||
Point field_to_point(const Field f, const Layout *layout)
|
||||
{
|
||||
const Orientation m = layout.orientation;
|
||||
double x = (m.f0 * f.x + m.f1 * f.y) * layout.size;
|
||||
double y = (m.f2 * f.x + m.f3 * f.y) * layout.size;
|
||||
return Point(x + layout.origin.x, y + layout.origin.y);
|
||||
const Orientation m = layout->orientation;
|
||||
double x = (m.f0 * f.x + m.f1 * f.y) * layout->size;
|
||||
double y = (m.f2 * f.x + m.f3 * f.y) * layout->size;
|
||||
return {x + layout->origin.x, y + layout->origin.y};
|
||||
}
|
||||
|
||||
Field point_to_field(Point point, const Layout layout)
|
||||
Field point_to_field(Point point, const Layout *layout)
|
||||
{
|
||||
const Orientation m = layout.orientation;
|
||||
double rel_x = (point.x - layout.origin.x) / layout.size;
|
||||
double rel_y = (point.y - layout.origin.y) / layout.size;
|
||||
const Orientation m = layout->orientation;
|
||||
double rel_x = (point.x - layout->origin.x) / layout->size;
|
||||
double rel_y = (point.y - layout->origin.y) / layout->size;
|
||||
double x = m.b0 * rel_x + m.b1 * rel_y;
|
||||
double y = m.b2 * rel_x + m.b3 * rel_y;
|
||||
return cubic_round(x, y, -x - y);
|
||||
}
|
||||
|
||||
Point field_corner_offset(uint8_t corner, const Layout layout)
|
||||
Point field_corner_offset(Uint8 corner, const Layout *layout)
|
||||
{
|
||||
double angle = 2.0 * M_PI * (corner + layout.orientation.start_angle) / 6;
|
||||
return Point(layout.size * cos(angle), layout.size * sin(angle));
|
||||
double angle = 2.0 * M_PI * (corner + layout->orientation.start_angle) / 6;
|
||||
double x = (layout->size * cos(angle));
|
||||
double y = (layout->size * sin(angle));
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
std::vector<Point> field_to_polygon(const Field field, const Layout layout)
|
||||
std::vector<Point> field_to_polygon(const Field field, const Layout *layout)
|
||||
{
|
||||
std::vector<Point> corners = {};
|
||||
std::vector<Point> corners = field_to_polygon_normalized(field, layout);
|
||||
Point center = field_to_point(field, layout);
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
for (Point &p : corners)
|
||||
{
|
||||
Point offset = field_corner_offset(i, layout);
|
||||
corners.push_back(Point(center.x + offset.x, center.y + offset.y));
|
||||
p = p + center;
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
|
||||
HexagonGrid::HexagonGrid(Sint16 grid_radius, Layout layout)
|
||||
: Grid(layout)
|
||||
std::vector<Point> field_to_polygon_normalized(const Field field, const Layout *layout)
|
||||
{
|
||||
std::vector<Point> corners;
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
{
|
||||
Point offset = field_corner_offset(i, layout);
|
||||
corners.push_back(offset);
|
||||
}
|
||||
return corners;
|
||||
}
|
||||
|
||||
HexagonGrid::HexagonGrid(Sint16 grid_radius, Layout *layout)
|
||||
: Grid(layout), radius(grid_radius)
|
||||
{
|
||||
// first lower half, then upper half
|
||||
for (Sint16 x = -grid_radius; x <= grid_radius; x++)
|
||||
|
@ -201,10 +215,7 @@ HexagonGrid::HexagonGrid(Sint16 grid_radius, Layout layout)
|
|||
{
|
||||
Sint16 z = -x - y;
|
||||
Field new_field = {x, y, z};
|
||||
FieldMeta *meta = new FieldMeta(nullptr);
|
||||
this->fields.insert(new_field);
|
||||
std::pair<Field, FieldMeta *> field_pair(new_field, meta);
|
||||
this->fields_meta.insert(field_pair);
|
||||
this->fields->insert(new_field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,64 +223,51 @@ HexagonGrid::HexagonGrid(Sint16 grid_radius, Layout layout)
|
|||
bool HexagonGrid::render(SDL_Renderer *renderer)
|
||||
{
|
||||
Field some_field = {0, 0, 0};
|
||||
std::vector<Point> polygon = field_to_polygon(some_field, this->layout);
|
||||
Point center = field_to_point(some_field, this->layout);
|
||||
std::vector<Point> polygon = field_to_polygon_normalized(some_field, this->layout);
|
||||
assert(polygon.size() > 5);
|
||||
Sint16 vx[6];
|
||||
Sint16 vy[6];
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
Sint16 x[6];
|
||||
Sint16 y[6];
|
||||
for (const Field &elem : *(this->fields))
|
||||
{
|
||||
vx[i] = (Sint16) (polygon[i].x - center.x);
|
||||
vy[i] = (Sint16) (polygon[i].y - center.y);
|
||||
}
|
||||
for (const Field &elem : this->fields)
|
||||
{
|
||||
center = field_to_point(elem, this->layout);
|
||||
Sint16 x[6];
|
||||
Sint16 y[6];
|
||||
Point center = field_to_point(elem, this->layout);
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
{
|
||||
x[i] = vx[i] + (Sint16) center.x;
|
||||
y[i] = vy[i] + (Sint16) center.y;
|
||||
x[i] = (Sint16) (center.x + polygon[i].x);
|
||||
y[i] = (Sint16) (center.y + polygon[i].y);
|
||||
}
|
||||
polygonRGBA(renderer, x, y, 6, 0xff, 0xff, 0xff, 0xff);
|
||||
const SDL_Color color = {0xff, 0xff, 0xff, 0xff};
|
||||
polygonRGBA(renderer, x, y, 6, color.r, color.g, color.b, color.a);
|
||||
if (elem == this->marker)
|
||||
{
|
||||
filledPolygonRGBA(renderer, x, y, 6, 0xff, 0x0, 0x0, 0xff);
|
||||
filledPolygonRGBA(renderer, x, y, 6, 0x77, 0x77, 0x77, 0x77);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Grid::move(SDL_Point move)
|
||||
{
|
||||
this->set_origin(this->layout.origin + move);
|
||||
}
|
||||
|
||||
void Grid::handle_event(SDL_Event *event)
|
||||
{
|
||||
|
||||
if (event->type == SDL_MOUSEWHEEL)
|
||||
{
|
||||
SDL_Point mouse = {0, 0};
|
||||
SDL_GetMouseState(&mouse.x, &mouse.y);
|
||||
int scroll = event->wheel.y;
|
||||
Uint16 old_size = this->layout.size;
|
||||
SDL_Point old_origin = this->layout.origin;
|
||||
|
||||
int scroll = this->layout->size / 10 * event->wheel.y;
|
||||
double old_size = this->layout->size;
|
||||
SDL_Point old_origin = this->layout->origin;
|
||||
if (old_size + scroll < 10)
|
||||
{
|
||||
this->layout.size = 10;
|
||||
this->layout->size = 10;
|
||||
}
|
||||
else if (old_size + scroll > 100)
|
||||
{
|
||||
this->layout.size = 100;
|
||||
this->layout->size = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->layout.size += scroll;
|
||||
this->set_origin(old_origin + (10 * scroll * (old_origin - mouse) / !(old_origin - mouse)));
|
||||
this->layout->size += scroll;
|
||||
|
||||
}
|
||||
this->move(((1.0 - (double) this->layout->size / old_size) * (mouse - old_origin)));
|
||||
}
|
||||
if (event->type == SDL_MOUSEMOTION)
|
||||
{
|
||||
|
@ -277,18 +275,44 @@ void Grid::handle_event(SDL_Event *event)
|
|||
}
|
||||
}
|
||||
|
||||
void Grid::set_origin(SDL_Point dm)
|
||||
void Grid::move(SDL_Point m)
|
||||
{
|
||||
this->layout.origin = dm;
|
||||
this->layout->origin = this->layout->origin + m;
|
||||
// check if some part is inside layout->box
|
||||
if (!on_rectangle(&layout->box))
|
||||
this->layout->origin = this->layout->origin - m;
|
||||
this->update_marker();
|
||||
}
|
||||
|
||||
void Grid::update_marker()
|
||||
{
|
||||
SDL_Point m;
|
||||
SDL_Point m = {0, 0};
|
||||
SDL_GetMouseState(&(m.x), &(m.y));
|
||||
Point p = {0.0, 0.0};
|
||||
p.x = m.x;
|
||||
p.y = m.y;
|
||||
this->marker = point_to_field(p, this->layout);
|
||||
}
|
||||
|
||||
bool Grid::on_rectangle(SDL_Rect *rect)
|
||||
{
|
||||
// check if center inside rect for ANY field
|
||||
for (const Field &f : *(this->fields))
|
||||
{
|
||||
Point precise_p = field_to_point(f, layout);
|
||||
SDL_Point p;
|
||||
p.x = (int) precise_p.x;
|
||||
p.y = (int) precise_p.y;
|
||||
if (p.x > rect->x && p.y > rect->y && p.x < (rect->x + rect->w) && p.y < (rect->y + rect->h))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Grid::update_box(int x, int y)
|
||||
{
|
||||
this->layout->box.w = x;
|
||||
this->layout->box.h = y;
|
||||
}
|
|
@ -6,9 +6,9 @@
|
|||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include "Player.hpp"
|
||||
|
||||
#ifndef POINT_OPERATORS
|
||||
#define POINT_OPERATORS
|
||||
SDL_Point operator+(SDL_Point left, SDL_Point right);
|
||||
|
||||
SDL_Point operator-(SDL_Point left, SDL_Point right);
|
||||
|
@ -19,16 +19,17 @@ SDL_Point operator/(SDL_Point left, SDL_Point right);
|
|||
|
||||
SDL_Point operator/(SDL_Point left, SDL_Point right);
|
||||
|
||||
SDL_Point operator*(int left, SDL_Point right);
|
||||
SDL_Point operator*(double left, SDL_Point right);
|
||||
|
||||
SDL_Point operator*(SDL_Point left, int right);
|
||||
SDL_Point operator*(SDL_Point left, double right);
|
||||
|
||||
SDL_Point operator/(SDL_Point left, int right);
|
||||
SDL_Point operator/(SDL_Point left, double right);
|
||||
|
||||
int operator!(SDL_Point left);
|
||||
double operator!(SDL_Point left);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Point
|
||||
|
||||
struct Point
|
||||
{
|
||||
double x;
|
||||
|
@ -38,6 +39,8 @@ struct Point
|
|||
{ }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Point operator+(Point left, Point right);
|
||||
|
||||
Point operator-(Point left, Point right);
|
||||
|
@ -56,10 +59,7 @@ Point operator/(Point left, double right);
|
|||
|
||||
double operator!(Point left);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Orientation
|
||||
|
||||
struct Orientation
|
||||
{
|
||||
// cubic to point
|
||||
|
@ -91,16 +91,16 @@ struct Layout
|
|||
const Orientation orientation;
|
||||
Uint16 size;
|
||||
SDL_Point origin;
|
||||
SDL_Rect box;
|
||||
|
||||
Layout(Orientation orientation_, Uint16 size_, SDL_Point origin_)
|
||||
: orientation(orientation_), size(size_), origin(origin_)
|
||||
Layout(Orientation orientation_, Uint16 size_, SDL_Point origin_, SDL_Rect box_)
|
||||
: orientation(orientation_), size(size_), origin(origin_), box(box_)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Field
|
||||
|
||||
struct Field
|
||||
{
|
||||
Sint16 x, y, z;
|
||||
|
@ -116,6 +116,8 @@ const std::vector<Field> hex_directions = {
|
|||
Field(1, 0, -1), Field(0, 1, -1), Field(-1, 1, 0), Field(-1, 0, 1), Field(-1, 1, 0)
|
||||
};
|
||||
|
||||
Field hex_direction(Uint8 direction);
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
|
@ -133,6 +135,8 @@ namespace std
|
|||
};
|
||||
}
|
||||
|
||||
Field hex_neighbor(Uint8 direction, Field f);
|
||||
|
||||
Field cubic_round(double x, double y, double z);
|
||||
|
||||
int cubic_distance(Field a, Field b);
|
||||
|
@ -148,57 +152,42 @@ Field operator-(Field left, Field right);
|
|||
Field operator*(Field left, Field right);
|
||||
|
||||
Field operator/(Field left, Field right);
|
||||
|
||||
#endif
|
||||
|
||||
Point field_to_point(const Field f, const Layout layout);
|
||||
Point field_to_point(const Field f, const Layout *layout);
|
||||
|
||||
Field point_to_field(Point point, const Layout layout);
|
||||
Field point_to_field(Point point, const Layout *layout);
|
||||
|
||||
Point field_corner_offset(int corner, const Layout layout);
|
||||
Point field_corner_offset(Uint8 corner, const Layout *layout);
|
||||
|
||||
std::vector<Point> field_to_polygon(const Field field, const Layout layout);
|
||||
std::vector<Point> field_to_polygon_normalized(const Field field, const Layout *layout);
|
||||
|
||||
#ifndef FieldMeta
|
||||
std::vector<Point> field_to_polygon(const Field field, const Layout *layout);
|
||||
|
||||
class FieldMeta
|
||||
{
|
||||
private:
|
||||
Player *owner;
|
||||
public:
|
||||
FieldMeta(Player *owner_) : owner(owner_)
|
||||
{ }
|
||||
// Player *get_owner();
|
||||
// bool set_owner(Player *owner);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef Grid
|
||||
|
||||
class Grid
|
||||
{
|
||||
protected:
|
||||
std::unordered_set<Field> fields;
|
||||
std::unordered_map<Field, FieldMeta *> fields_meta;
|
||||
Layout layout;
|
||||
std::unordered_set<Field> *fields;
|
||||
Layout *layout;
|
||||
Field marker;
|
||||
|
||||
bool on_rectangle(SDL_Rect *rect);
|
||||
public:
|
||||
Grid(Layout layout_) : layout(layout_), marker(0, 0, 0)
|
||||
Grid(Layout *layout_)
|
||||
: layout(layout_), marker(0, 0, 0)
|
||||
{
|
||||
this->fields = std::unordered_set<Field>();
|
||||
this->fields_meta = std::unordered_map<Field, FieldMeta *>();
|
||||
this->fields = new std::unordered_set<Field>();
|
||||
};
|
||||
|
||||
~Grid()
|
||||
{
|
||||
for (const Field &elem : this->fields)
|
||||
{
|
||||
delete this->fields_meta.at(elem);
|
||||
}
|
||||
delete this->fields;
|
||||
}
|
||||
|
||||
void set_origin(SDL_Point origin);
|
||||
std::unordered_set<Field> *get_fields() { return this->fields; }
|
||||
|
||||
void move(SDL_Point move);
|
||||
|
||||
|
@ -208,20 +197,22 @@ public:
|
|||
|
||||
void handle_event(SDL_Event *event);
|
||||
|
||||
void update_box(int x, int y);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef HexagonGrid
|
||||
|
||||
class HexagonGrid : public Grid
|
||||
{
|
||||
private:
|
||||
Sint16 radius;
|
||||
public:
|
||||
HexagonGrid(Sint16 grid_radius, Layout layout);
|
||||
HexagonGrid(Sint16 grid_radius, Layout *layout);
|
||||
|
||||
bool render(SDL_Renderer *renderer);
|
||||
|
||||
Sint16 get_radius() { return radius * layout->size; }
|
||||
};
|
||||
|
||||
#endif
|
60
src/Main.cpp
60
src/Main.cpp
|
@ -1,5 +1,3 @@
|
|||
#include <string>
|
||||
#include <SDL_video.h>
|
||||
#include "Main.hpp"
|
||||
|
||||
|
||||
|
@ -11,7 +9,7 @@ void logSDLError(std::ostream &os, const std::string &msg)
|
|||
SDL_Window *init_window()
|
||||
{
|
||||
|
||||
SDL_Window *window = SDL_CreateWindow("Hello World!", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_Window *window = SDL_CreateWindow(TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||
SCREEN_WIDTH, SCREEN_HEIGTH, SDL_WINDOW_OPENGL);
|
||||
if (window == NULL)
|
||||
{
|
||||
|
@ -60,6 +58,7 @@ void Game::toggle_fullscreen()
|
|||
this->full_screen = true;
|
||||
SDL_SetWindowSize(this->window, dm.w, dm.h);
|
||||
SDL_SetWindowFullscreen(this->window, SDL_WINDOW_FULLSCREEN);
|
||||
this->grid->update_box(dm.w, dm.h);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -67,6 +66,7 @@ void Game::toggle_fullscreen()
|
|||
SDL_SetWindowFullscreen(this->window, 0);
|
||||
SDL_SetWindowSize(this->window, SCREEN_WIDTH, SCREEN_HEIGTH);
|
||||
SDL_SetWindowPosition(this->window, dm.w / 4, dm.h / 4);
|
||||
this->grid->update_box(SCREEN_WIDTH, SCREEN_HEIGTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,21 +104,45 @@ void Game::handle_event(SDL_Event *event)
|
|||
if (key == SDLK_d)
|
||||
this->move[3] = false;
|
||||
}
|
||||
if (event->type == SDL_WINDOWEVENT)
|
||||
{
|
||||
if (event->window.windowID == SDL_GetWindowID(this->window))
|
||||
{
|
||||
switch (event->window.event)
|
||||
{
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
{
|
||||
this->grid->update_box(event->window.data1, event->window.data2);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Game::game_loop()
|
||||
{
|
||||
Timer *frame_timer = new Timer();
|
||||
frame_timer->start_timer();
|
||||
Timer *move_timer = new Timer();
|
||||
move_timer->start_timer();
|
||||
double fps;
|
||||
Uint32 frame_counter = 0;
|
||||
while (!this->quit)
|
||||
{
|
||||
if (move_timer->get_timer() > 10)
|
||||
{
|
||||
move_timer->reset_timer();
|
||||
SDL_Point move_by = {(this->move[1] - this->move[3]) * 10, (this->move[0] - this->move[2]) * 10};
|
||||
this->grid->move(move_by);
|
||||
}
|
||||
if (frame_timer->get_timer() > 1000.0)
|
||||
{
|
||||
fps = frame_counter / (frame_timer->reset_timer() / 1000.0);
|
||||
frame_counter = 0;
|
||||
std::cout << fps << std::endl;
|
||||
std::cout << fps << " fps" << std::endl;
|
||||
}
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
|
@ -130,26 +154,35 @@ int Game::game_loop()
|
|||
if (event.type == SDL_QUIT)
|
||||
{
|
||||
quit = true;
|
||||
break;
|
||||
}
|
||||
if (event.type == SDL_MOUSEMOTION || event.type == SDL_MOUSEWHEEL)
|
||||
{
|
||||
grid->handle_event(&event);
|
||||
}
|
||||
}
|
||||
SDL_Point move_by = {(this->move[1] - this->move[3]) * 10, (this->move[0] - this->move[2]) * 10};
|
||||
this->grid->move(move_by);
|
||||
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
|
||||
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
|
||||
this->grid->render(renderer);
|
||||
this->render(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
frame_counter++;
|
||||
}
|
||||
SDL_RenderClear(renderer);
|
||||
delete move_timer;
|
||||
delete frame_timer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Game::render(SDL_Renderer *renderer)
|
||||
{
|
||||
this->grid->render(renderer);
|
||||
for (FieldMeta *meta : this->fields_meta)
|
||||
{
|
||||
meta->render(renderer, this->layout);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||
|
@ -172,12 +205,21 @@ int main(int, char **)
|
|||
SDL_Quit();
|
||||
return -1;
|
||||
}
|
||||
Game *game = new Game(window, renderer);
|
||||
Layout *layout = new Layout(pointy_orientation, GRID_SIZE, {5 * SCREEN_WIDTH / 12, 5 * SCREEN_HEIGTH / 12},
|
||||
{0, 0, 5 * SCREEN_WIDTH / 6, 5 * SCREEN_HEIGTH / 6});
|
||||
Game *game = new Game(window, renderer, layout);
|
||||
int exit_status = game->game_loop();
|
||||
delete game;
|
||||
delete layout;
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
return exit_status;
|
||||
}
|
||||
|
||||
bool position_in_window(SDL_Point position, SDL_Window *window)
|
||||
{
|
||||
SDL_DisplayMode dm;
|
||||
SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(window), &dm);
|
||||
return position.x > 0 && position.x < dm.w && position.y > 0 && position.y < dm.h;
|
||||
}
|
||||
|
|
36
src/Main.hpp
36
src/Main.hpp
|
@ -1,12 +1,16 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <SDL2/SDL.h>
|
||||
#include "GameMap.hpp"
|
||||
#include <SDL_video.h>
|
||||
#include "Gameplay.hpp"
|
||||
#include <unordered_set>
|
||||
|
||||
#ifndef DEFAULTS
|
||||
const Sint16 GRID_SIZE = 20;
|
||||
const Sint16 GRID_SIZE = 4;
|
||||
const int SCREEN_WIDTH = 800;
|
||||
const int SCREEN_HEIGTH = 600;
|
||||
char TITLE[] = "Bob - Battles of Bacteria";
|
||||
#endif
|
||||
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
|
@ -44,31 +48,49 @@ private:
|
|||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
HexagonGrid *grid;
|
||||
// only deal with meta information
|
||||
std::unordered_set<FieldMeta *> fields_meta;
|
||||
Layout *layout;
|
||||
bool move[4];
|
||||
bool full_screen;
|
||||
bool quit;
|
||||
|
||||
public:
|
||||
Game(SDL_Window *window_, SDL_Renderer *renderer_)
|
||||
: window(window_), renderer(renderer_)
|
||||
Game(SDL_Window *window_, SDL_Renderer *renderer_, Layout *layout_)
|
||||
: window(window_), renderer(renderer_), layout(layout_)
|
||||
{
|
||||
Layout layout = {pointy_orientation, GRID_SIZE, {SCREEN_WIDTH / 2, SCREEN_HEIGTH / 2}};
|
||||
this->grid = new HexagonGrid(GRID_SIZE, layout);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
this->move[i] = false;
|
||||
}
|
||||
this->quit = false;
|
||||
// create meta information for every field on the grid
|
||||
for (const Field &elem : *(grid->get_fields()))
|
||||
{
|
||||
FieldMeta *meta = new FieldMeta(elem);
|
||||
fields_meta.insert(meta);
|
||||
}
|
||||
}
|
||||
|
||||
void toggle_fullscreen();
|
||||
|
||||
~Game()
|
||||
{
|
||||
for (const FieldMeta *elem : this->fields_meta)
|
||||
{
|
||||
delete elem;
|
||||
}
|
||||
delete this->grid;
|
||||
}
|
||||
|
||||
void render(SDL_Renderer *renderer);
|
||||
|
||||
void toggle_fullscreen();
|
||||
|
||||
void handle_event(SDL_Event *event);
|
||||
|
||||
int game_loop();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
bool position_in_window(SDL_Point position, SDL_Window *window);
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef Player
|
||||
|
||||
struct Player
|
||||
{
|
||||
const SDL_Color color;
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,23 +0,0 @@
|
|||
#include <SDL2/SDL.h>
|
||||
|
||||
#ifndef Upgrade
|
||||
|
||||
class Upgrade
|
||||
{
|
||||
SDL_Color color;
|
||||
public:
|
||||
static Upgrade *Instance();
|
||||
|
||||
private:
|
||||
Upgrade()
|
||||
{ };
|
||||
|
||||
Upgrade(Upgrade const &)
|
||||
{ };
|
||||
|
||||
Upgrade &operator=(Upgrade const &)
|
||||
{ };
|
||||
static Upgrade *m_pInstance;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue