问题标题: 联机贪吃蛇 模块开 发教程

1
2
已解决
薛乘志
薛乘志
初级启示者
初级启示者

Github Wiki:https://github.com/xgugugu/Socket-Snake/wiki/%5BRelease-%235%5D-%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B

 

 

 

通用**步骤:

  1. 下载模块模板(模块模板见此处
  2. 对模板进行一系列添改
  3. 编译后发布

模板接口详解:

extern "C" {后的内容为接口部分。

我们目前提供了3个函数接口,分别为:

  • 接口void mod_main(void):在模块被加载后即刻运行
  • 接口string edit_display(string, int):在对玩家生成的显示信息生成后运行,参数:显示内容字符串、玩家ID,返回值为修改后的字符串
  • 接口void read_keydown(string, int):在对玩家发送的按键信息接收到后运行,参数:接受按键信息字符串、玩家ID

5个数据接口,分别为:

  • 接口vector<SOCKET> *sock:一个指向服务端代码中变量snake::sock的指针
  • 接口vector<Snake> *snake:一个指向服务端代码中变量snake::s的指针
  • 接口vector<Snake> *food:一个指向服务端代码中变量snake::f的指针
  • 接口vector<Snake> *snake_color:一个指向服务端代码中变量snake::c的指针
  • 接口vector<Snake> *snake_name:一个指向服务端代码中变量snake::n的指针

指针指向变量详细说明参见服务端代码注释

注意事项:

如何编译:

  1. Dev-C++用户请在工具->编译选项中勾选编译时加入以下参数,并在其下方编辑框中输入-shared
  2. 点击编译(不要点击编译运行),如果没有提示undefined reference to 'WinMain@16'错误,并且编译后生成的可执行文件(*.exe)无法直接运行,就可以基本说明编译成功
  • 其余IDE请自行百度搜索XX IDE如何编译DLL

关于指针访问:

  • 指针访问需要使用间接寻址运算符*,如访问snake的成员函数size()使用(*snake).size(),访问snake下标为0的成员使用(*snake_name)[0]
  • 修改指针指向的数据后,其余模块及服务端内的同一数据将同步修改
  • 参见:https://www.runoob.com/cplusplus/cpp-pointers.html

关于下标起始点:

  • 接口函数提供的玩家ID从1开始
  • 接口vector<SOCKET> *sock的下标从1开始
  • 接口vector<Snake> *snakevector<Snake> *foodvector<Snake> *snake_colorvector<Snake> *snake_name的下标从0开始

使用示例:

实现在服务端内每1秒输出当前服务端玩家数:

extern "C" { ... }中加入:

DLL void mod_main() {
	while (1) {
		cout << "当前玩家数:" << (*snake).size() << endl;
		Sleep(1000);
	}
}

实现在客户端显示玩家按键信息:

//内部使用的变量、函数、类定义区后加入

string key = "";

extern "C" { ... }中加入:

DLL string edit_display(string str, int id) { 
	return str + "\n|2>Welcome \"" + (*snake_name)[id - 1] + "\",您按了\"" + key + "\"";
}
DLL void read_keydown(string input, int id) { 
	key = input;
}

 

 

 

 

模板内容:

/*Socket Snake Server Module Sample*/

//编译参数:-shared

//头文件可自行添加
#include <bits/stdc++.h>
#include <windows.h>

//定义
#define DLL __declspec(dllexport)

using namespace std;

//API定义
namespace basic {
	HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE), hin = GetStdHandle(STD_INPUT_HANDLE);
	void gotoxy(short x, short y) { //移动光标
		COORD coord = {x, y};
		SetConsoleCursorPosition(hout, coord);
	}
	void cursor(bool visible) { //控制光标
		CONSOLE_CURSOR_INFO CursorInfo;
		GetConsoleCursorInfo(hout, &CursorInfo);
		CursorInfo.bVisible = visible;
		SetConsoleCursorInfo(hout, &CursorInfo);
	}
	void color(int ForgC, int BackC) { //设置颜色
		WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
		SetConsoleTextAttribute(hout, wColor);
	}
	void color(int ForgC) { //设置颜色
		WORD wColor;
		CONSOLE_SCREEN_BUFFER_INFO csbi;
		if (GetConsoleScreenBufferInfo(hout, &csbi)) {
			wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F);
			SetConsoleTextAttribute(hout, wColor);
		}
	}
	std::string to_string(int _int) { //int转string
		char str[1005];
		sprintf(str, "%d", _int);
		return str;
	}
	int to_int(std::string str) { //string转int
		return atoi(str.c_str());
	}
	int Rand(int a, int b) { //生成随机数
		return (rand() % (b - a + 1)) + a;
	}
}
class Snake {
	public:
		struct Node { //蛇节位置
			int x, y;
			bool operator==(Node b) {
				return x == b.x && y == b.y;
			}
		};
		vector<Node> s_snake; //蛇节位置队列
		int way, dir[4][2]; //方向
		bool online, run; //是否在线,是否为跑步状态
		int dead, length; //**倒计时,未**亡为0
		Snake() {
			online = 1, dead = 0, run = 0;
			int _dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
			memcpy(dir, _dir, sizeof(_dir)); //初始化方向数组
			way = basic::Rand(0, 99) % 4; //取随机方向
			int X = basic::Rand(10, 190), Y = basic::Rand(10, 190); //取随机出生坐标
			length = 5; //出生长度
			Node temp_node;
			for (int i = 0; i < length; i++) { //生成初始蛇身
				temp_node.x = X;
				temp_node.y = Y;
				s_snake.insert(s_snake.begin(), temp_node);
				X += dir[way][0];
				Y += dir[way][1];
			}
		}
		void change_way(int _way) { //改变方向
			way = _way;
		}
		void grow() { //生长1格
			length = length + 1;
		}
		void shorten() { //缩短1格
			length = length - 1;
		}
		void update() { //蛇前进一次
			Node temp_node;
			temp_node.x = s_snake[0].x + dir[way][0];
			temp_node.y = s_snake[0].y + dir[way][1];
			s_snake.insert(s_snake.begin(), temp_node); //在队列首部加入蛇节
			while (s_snake.size() > length) {
				s_snake.pop_back(); //在队列尾部删去蛇节
			}
		}
		void stop() { //退出玩家
			online = 0;
		}
		Node next_coord() { //获取下一次的位置
			Node temp_node;
			temp_node.x = s_snake[0].x + dir[way][0];
			temp_node.y = s_snake[0].y + dir[way][1];
			return temp_node;
		}
		void die() { //蛇**亡
			dead = 5;
		}
		void reborn() { //**
			dead = 0, run = 0;
			way = basic::Rand(0, 199) % 4; //取随机方向
			int X = basic::Rand(10, 190), Y = basic::Rand(10, 190); //取随机出生坐标
			length = 5; //出生长度
			s_snake.clear(); //清空长度
			Node temp_node;
			for (int i = 0; i < length; i++) { //生成初始蛇身
				temp_node.x = X;
				temp_node.y = Y;
				s_snake.insert(s_snake.begin(), temp_node);
				X += dir[way][0];
				Y += dir[way][1];
			}
		}
};
class Food { //食物类
	public:
		int x, y, color;
		Food() {
			x = basic::Rand(0, 199), y = basic::Rand(0, 199);
			color = rand() % 15 + 1;
		}
};

//内部使用的变量、函数、类定义区


extern "C" {
	//玩家id下标从1开始
	DLL vector<SOCKET> *sock = NULL; //socket列表,下标从1开始
	DLL vector<Snake> *snake = NULL; //蛇,下标从0开始
	DLL vector<Food> *food = NULL; //食物,下标从0开始
	DLL vector<string> *snake_color = NULL; //颜色,下标从0开始
	DLL vector<string> *snake_name = NULL; //名字,下标从0开始
	DLL void mod_main() { //处理游戏信息,在被加载时运行,建议循环
		//循环处理游戏信息
	}
	DLL string edit_display(string str, int id) { //在玩家显示内容生成完毕时运行,用于显示自定义内容
		//在|和>间的数字表示后面文本使用的文字颜色
                //修改字符串
		return str;
	}
	DLL void read_keydown(string input, int id) { //在收到玩家的按键信息后运行,用于自定义操作
	        //处理按键操作
	}
}

 

薛乘志在2022-02-08 16:25:30追加了内容

为什么开 发是屏蔽词!!!

薛乘志在2022-02-27 13:42:42追加了内容

回复下,结帖


0
已采纳
沙宸安
沙宸安
高级启示者
高级启示者

已收藏,有时间我会研究一下的。

0
0
0
我要回答