基于OpenCV的飞行棋小游戏
利用了opencv的一些函数写的飞行棋,花了一个晚上写出来的东西,目前还很满意。
运行示例在博客末尾。
工程除了opencv还需要两个文件,一个背景图片,一个点参数文档。
背景图片下载:
点坐标参数文档,要是觉得点不好,可以用这个工程重描点,点的顺序一言难尽,自己琢磨。
main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <opencv.hpp>
#define DEBUG 0
using namespace std;
using namespace cv;
const char* map_file = "2019091013500077.png";//背景图片
const char* win_name = "摸鱼飞行棋";
ifstream point_in("point.txt");//点坐标参数
vector<Point> map_deque;
enum class TEAM_COLOR { blue, green, red, yellow };
void init();
int dice();
void show(Mat, int, TEAM_COLOR);
void draw_piece(Mat&, Point, TEAM_COLOR, int);
void win(Mat, TEAM_COLOR);
Scalar team_color(TEAM_COLOR);
class MP {
private:
int x, y;
bool flag;
public:
MP() :flag(0) { x = y = 0; }
void flash_position(int x, int y) {
this->x = x;
this->y = y;
flag = 1;
}
bool empty() { return !flag; }
Point get_position() {
if (flag) {
flag = 0;
return Point(x, y);
}
}
} mouse_position;
class team {
private:
TEAM_COLOR color;
Point home[4];
Point start, end;
int first, last;
int fly_point, fly_dist;
int planes_inv[4];
Point planes[4];
bool tail_pg[4];
Point tail[6];
public:
team(TEAM_COLOR c) :color(c) {
for (int i = 0; i < 4; ++i) {
planes_inv[i] = -2;
tail_pg[i] = 0;
}
}
void init(vector<Point>&, int, int, int, int);
bool all_home();
bool run(int, Point);
void draw(Mat&);
bool win();
void turn_home(int inv);
};
team blue(TEAM_COLOR::blue),
green(TEAM_COLOR::green),
red(TEAM_COLOR::red),
yellow(TEAM_COLOR::yellow);
int main() {
int dn;
Mat map_org = imread(map_file);
#if DEBUG & 1
Mat cp = map_org.clone();
while (!point_in.eof()) {
int x, y;
point_in >> x >> y;
circle(cp, Point(x, y), 5, Scalar(255, 0, 255), FILLED);
} imshow("map", cp);
#endif
init();
while (1) {
do {
dn = dice();
show(map_org.clone(), dn, TEAM_COLOR::green);
do {
while (mouse_position.empty()) waitKey(100);
} while (!green.run(dn, mouse_position.get_position()));
if(green.win()) win(map_org.clone(), TEAM_COLOR::green);
} while (dn == 6);
do {
dn = dice();
show(map_org.clone(), dn, TEAM_COLOR::red);
do {
while (mouse_position.empty()) waitKey(100);
} while (!red.run(dn, mouse_position.get_position()));
if (red.win()) win(map_org.clone(), TEAM_COLOR::red);
} while (dn == 6);
do {
dn = dice();
show(map_org.clone(), dn, TEAM_COLOR::yellow);
do {
while (mouse_position.empty()) waitKey(100);
} while (!yellow.run(dn, mouse_position.get_position()));
if (yellow.win()) win(map_org.clone(), TEAM_COLOR::yellow);
} while (dn == 6);
do {
dn = dice();
show(map_org.clone(), dn, TEAM_COLOR::blue);
do {
while (mouse_position.empty()) waitKey(100);
} while (!blue.run(dn, mouse_position.get_position()));
if (blue.win()) win(map_org.clone(), TEAM_COLOR::blue);
} while (dn == 6);
}
return 0;
}
void show(Mat img, int dn, TEAM_COLOR tc) {
green.draw(img);
blue.draw(img);
red.draw(img);
yellow.draw(img);
putText(img, (string)"Moving forward " + to_string(dn) + " steps", Point(0, img.rows - 20), 1, 3, team_color(tc), 5);
imshow(win_name, img);
}
void OnMouse(int e, int x, int y, int flag, void* data) {
if (e == EVENT_LBUTTONDOWN) {
mouse_position.flash_position(x, y);
}
}
Point get_point() {
int x, y;
point_in >> x >> y;
return Point(x, y);
}
void init() {
namedWindow(win_name);
setMouseCallback(win_name, OnMouse);
vector<Point> blue_p, green_p, red_p, yellow_p;
for (int i = 0; i < 5; ++i)
green_p.push_back(get_point());
for (int i = 0; i < 5; ++i)
red_p.push_back(get_point());
for (int i = 0; i < 5; ++i)
yellow_p.push_back(get_point());
for (int i = 0; i < 5; ++i)
blue_p.push_back(get_point());
for (int i = 0; i < 52; ++i)
map_deque.push_back(get_point());
for (int i = 0; i < 6; ++i)
red_p.push_back(get_point());
for (int i = 0; i < 6; ++i)
yellow_p.push_back(get_point());
for (int i = 0; i < 6; ++i)
blue_p.push_back(get_point());
for (int i = 0; i < 6; ++i)
green_p.push_back(get_point());
Point tmp = get_point();
red_p.push_back(tmp);
yellow_p.push_back(tmp);
blue_p.push_back(tmp);
green_p.push_back(tmp);
red.init(red_p, 3, 0, 20, 32);
yellow.init(yellow_p, 16, 13, 33, 45);
blue.init(blue_p, 29, 26, 46, 6);
green.init(green_p, 42, 39, 7, 19);
}
int dice() {
#if DEBUG == 2
return waitKey(0) - '0';
#endif
static bool flag = 1;
if (flag) srand(time(0)), flag = 0;
return rand() % 6 + 1;
}
Scalar team_color(TEAM_COLOR color) {
switch (color) {
case TEAM_COLOR::blue:
return Scalar(255, 0, 0);
break;
case TEAM_COLOR::green:
return Scalar(0, 255, 0);
break;
case TEAM_COLOR::red:
return Scalar(0, 0, 255);
break;
case TEAM_COLOR::yellow:
return Scalar(0, 255, 255);
break;
default: break;
}
}
void draw_piece(Mat& img, Point p, TEAM_COLOR c, int n) {
circle(img, p, 20, team_color(c), FILLED);
circle(img, p, 20, Scalar(0, 0, 0), 3);
putText(img, to_string(n), p - Point(10, -10), 1, 2, Scalar(0, 0, 0), 3);
}
void team::init(vector<Point>& init_point, int fir, int las, int ff, int fd) {
int cnt = 0;
for (int i = 0; i < 4; ++i)
home[i] = init_point[cnt++];
start = init_point[cnt++];
first = fir;
last = las;
fly_point = ff;
fly_dist = fd;
for (int i = 0; i < 6; ++i)
tail[i] = init_point[cnt++];
end = init_point[cnt++];
for (int i = 0; i < 4; ++i)
planes[i] = home[i];
}
bool team::all_home() {
for (int i = 0; i < 4; ++i) {
if (planes_inv[i] != -2 && planes_inv[i] != -3)
return false;
}
return true;
}
double p2p_dis(const Point& a, const Point& b) {
return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}
bool team::run(int p, Point n) {
if (all_home() && p != 6)
return true;
int res = -1;
for (int i = 0; i < 4; ++i) {
int dis = p2p_dis(n, planes[i]);
if (dis < 20) res = i;
}
if (!~res) return false;
if (planes_inv[res] == -2) {
if (p == 6) {
planes_inv[res] = -1;
planes[res] = start;
return true;
}
else return false;
}
if (tail_pg[res]) {
if (p > 6 - planes_inv[res])
planes_inv[res] += ((6 - planes_inv[res]) << 1) - p;
else if (p == 6 - planes_inv[res]) {
planes_inv[res] = -3;
planes[res] = end;
return true;
}
else planes_inv[res] += p;
}
else {
if (planes_inv[res] + p > 51) {
p -= 52 - planes_inv[res];
planes_inv[res] = 0;
}
if (planes_inv[res] == -1) {
planes_inv[res] = first + p;
}
else if (planes_inv[res] <= last && planes_inv[res] + p > last) {
tail_pg[res] = 1;
planes_inv[res] = p - (last - planes_inv[res] + 1);
}
else {
planes_inv[res] += p;
}
}
if (tail_pg[res]) {
planes[res] = tail[planes_inv[res]];
}
else {
if (planes_inv[res] == fly_point) planes_inv[res] = fly_dist;
planes[res] = map_deque[planes_inv[res]];
if (color != TEAM_COLOR::blue) blue.turn_home(planes_inv[res]);
if (color != TEAM_COLOR::red) red.turn_home(planes_inv[res]);
if (color != TEAM_COLOR::green) green.turn_home(planes_inv[res]);
if (color != TEAM_COLOR::yellow) yellow.turn_home(planes_inv[res]);
}
return true;
}
void team::draw(Mat& img) {
for (int i = 0; i < 4; ++i)
draw_piece(img, planes[i], color, i);
}
bool team::win() {
for (int i = 0; i < 4; ++i)
if (planes[i] != end)
return false;
return true;
}
void team::turn_home(int inv) {
for (int i = 0; i < 4; ++i)
if (!tail_pg[i] && planes_inv[i] == inv) {
planes_inv[i] = -2;
planes[i] = home[i];
}
}
void win(Mat img, TEAM_COLOR c) {
putText(img, "WIN!", Point((img.cols >> 1) - 150, (img.rows >> 1) + 50), 1, 10, team_color(c), 20);
imshow(win_name, img);
waitKey(0);
exit(0);
}