Kiedyś zrobiłem coś takiego: gameplay.webm
Tak wyglądała klasa bazowa:
#pragma once
#include "math/2d/point.hpp"
#include "math/2d/matrix.hpp"
#include "game/board/board.hpp"
#include "game/chessmans/ids.hpp"
#include "console/graphics-utils/colors/color.hpp"
enum class side{ none, light = 1, dark = -1 };
side detect_side(console::graphics::color c);
class chessman{
public:
using side = side;
using dead_mark = bool;
using movement_matrix = math::matrix2d<int/*becouse vector<bool> is broken*/>;
public:
chessman(board &, side, math::point2d);
movement_matrix get_movement_matrix() const;
math::point2d get_pos() const;
void virtual set_pos(math::point2d);
side get_side() const;
virtual ~chessman();
virtual chessmans_id id() const abstract;
bool is_alive() const;
void kill();
protected:
virtual movement_matrix gen_movement_matrix() const abstract;
protected:
dead_mark dead = false;
board &gameboard;
const side force_side;
math::point2d position;
};
#include "chessman.hpp"
side detect_side(console::graphics::color c){
switch(c){
case console::graphics::color::white:
return side::light;
case console::graphics::color::black:
return side::dark;
}
return side::none;
}
chessman::chessman(
board &gboard,
side fside,
math::point2d pos
): gameboard(gboard), force_side(fside), position(pos){}
chessman::movement_matrix chessman::get_movement_matrix() const{
return gen_movement_matrix();
}
math::point2d chessman::get_pos() const{
return position;
}
void chessman::set_pos(math::point2d pos){
position = pos;
}
chessman::side chessman::get_side() const{
return force_side;
}
chessman::movement_matrix chessman::gen_movement_matrix() const{
return movement_matrix(0, 0);
}
bool chessman::is_alive() const{
return !dead;
}
void chessman::kill(){
dead = true;
}
chessman::~chessman(){}
a tak wyglądał przykładowy pionek:
#pragma once
#include "game/chessmans/chessman/chessman.hpp"
class knight final: public chessman{
public:
knight(board &, side, math::point2d);
public:
virtual chessmans_id id() const override;
protected:
virtual movement_matrix gen_movement_matrix() const override;
};
#include "knight.hpp"
#include "game/chessmans/helper/movement-helper.hpp"
knight::knight(board &b, side s, math::point2d pos):
chessman(b, s, pos){}
chessmans_id knight::id() const{
return chessmans_id::knight;
}
knight::movement_matrix knight::gen_movement_matrix() const{
auto movement = prepared_movement_matrix(gameboard);
auto position = get_pos();
math::point2d lookup_table[] = {
//up-left
{ position.x - 1, position.y - 2 },
//up-right
{ position.x + 1, position.y - 2 },
//down-left
{ position.x - 1, position.y + 2 },
//down-right
{ position.x + 1, position.y + 2 },
//right-up
{ position.x + 2, position.y - 1 },
//right-down
{ position.x + 2, position.y + 1 },
//left-up
{ position.x - 2, position.y - 1 },
//left-down
{ position.x - 2, position.y + 1 }
};
for(const auto &point: lookup_table){
if(field_exists(gameboard, point)){
if(field_free(gameboard, point) || force_side != detect_side(gameboard[point.x][point.y].foreground)){
movement[point.x][point.y] = true;
}
}
}
return movement;
}
a tak wyglądało zbijanie pionków:
#include "killing.hpp"
#include <algorithm>
using namespace std;
void mark_dead_ones(const turns_manager &tm, chessmans_container &chessmans){
auto last_player = tm.get_player();
for(auto &st : chessmans){
for(auto &nd : chessmans){
if(st->get_pos() == nd->get_pos() && st->get_side() != nd->get_side()){
if(tm.get_player() == st->get_side()){
nd->kill();
}
else{
st->kill();
}
}
}
}
}
void remove_dead_ones(chessmans_container &chessmans){
auto it = begin(chessmans);
while(it != end(chessmans)){
if(!(*it)->is_alive())
it = chessmans.erase(it);
else
++it;
}
}
a jeśli pomoże Ci to w zobrazowaniu sobie "jak można ułożyć strukturę projektu pod to", to main wyglądał tak:
#include "console/console.hpp"
#include "console/canvas/console-canvas.hpp"
#include "console/canvas/console-drawer.hpp"
#include "game/board/board.hpp"
#include "game/board/board-drawer.hpp"
#include "game/board/board-filler.hpp"
#include "game/chessmans/chessmans.hpp"
#include "game/visualizer/movement_visualizer.hpp"
#include "game/starter/starter.hpp"
#include "game/core/core.hpp"
#include "game/core/rules/select-chessman.hpp"
#include "game/ui/initialize-core-ui.hpp"
#include "game/ui/input-helper/consume-input.hpp"
#include "game/ui/turn-routine/turn-routine.hpp"
#include "console/ui/label.hpp"
#include "game/core/rules/killing.hpp"
#include <functional>
#include <algorithm>
using console::graphics::color;
using namespace std;
struct game{
console_canvas &canvas;
board &gameboard;
chessmans_container &chessmans;
turns_manager &turns_manag;
chessman_selector &chessman_sel;
console::ui::core &ui_core;
ui::turn_routine &routine;
void init(){
routine.set_on_move_destination_selected([&](chessman *chess, math::point2d sel){
chess->set_pos(sel);
mark_dead_ones(turns_manag, chessmans);
remove_dead_ones(chessmans);
turns_manag.next_turn();
});
}
void update(frame_t frame){
chessman_sel.update();
auto rchessman = routine.get_chessman();
ui_core
.access_element_by_tag("current_chessman")
.as<console::ui::label>()
.set_text("Current chessman id: " + std::to_string(chessman_sel.get_selected_chessman_id()));
ui_core
.access_element_by_tag("current_frame")
.as<console::ui::label>()
.set_text("Current frame: " + std::to_string(frame));
ui_core
.access_element_by_tag("current_player")
.as<console::ui::label>()
.set_text("Current player: " + (turns_manag.get_player() == side::light? string("White") : "Black"));
ui_core
.access_element_by_tag("current_chessman")
.as<console::ui::label>()
.set_text("Current chessman: " + (rchessman == nullptr? string("none") : rchessman->get_pos().str()));
ui_core.update();
ui::consume_remaining_input();
};
void draw(frame_t frame){
console_drawer console_drawer(canvas);
board_filler gameboard_filler(gameboard);
board_drawer gameboard_drawer(gameboard, canvas);
console::set_cursor_visibility(false);
board_field f = { chessmans_id::no_chessman, color::cyan, color::cyan };
std::fill(begin(gameboard), end(gameboard), f);
gameboard_filler.fill_background();
gameboard_filler.put_chessmans(chessmans);
if(auto rc = routine.get_chessman()){
visualize_movement(gameboard, *rc, color::green);
}
gameboard_drawer.draw();
ui_core.draw();
if(frame == 1) console_drawer.draw();
else console_drawer.update_drawing();
console::set_cursor_visibility(true);
}
};
int main(){
console_canvas canvas(70, 20);
board gameboard(8, 8);
chessmans_container chessmans;
put_chessmans(gameboard, chessmans);
turns_manager turns_manager;
chessman_selector chessman_selector(chessmans, turns_manager);
console::ui::core ui_core;
ui::initialize(ui_core, canvas);
ui::turn_routine routine(turns_manager, chessmans, ui_core);
game thegame{
canvas, gameboard, chessmans, turns_manager, chessman_selector, ui_core, routine
};
thegame.init();
auto input = [&](frame_t frame){
if(frame == 1)
return;
};
auto update = [&](frame_t frame){
thegame.update(frame);
};
auto draw = [&](frame_t frame){
thegame.draw(frame);
};
auto end_turn = [&](frame_t frame){ /* jak dobrze pamiętam to było do wywalenia */ };
auto game_winner = [&]{
return winner::none;
};
game_loop(
input,
update,
draw,
end_turn,
game_winner
);
}