更新内容:

1.迷宫地图使用prim算法生成看起来像回事的地图

2.修改后面启动的客户端不同步之前的客户端的游戏情况

逻辑实现:

1.服务器第一个接到客户端链接时,生成地图,初始坐标等信息。

2.有客户端链接时,给客户端发送地图,当前人物坐标等数据

3.客户端不生成地图,只接收服务器地图数据,每次成功行动后,发送坐标给服务器记录最新坐标

代码实现:

客户端

Game01  类#pragma once
#include<cstdio>
#include<string>
#include<vector>
#include"Common.h"using namespace std;
class Game01
{
public:Game01();~Game01();void init(); //初始化地图和坐标数据void createMap();  //随机生成地图void refreshMap(NodeData *data); //刷新地图,重绘当前位置void refreshMap(MAPData *data); //接受服务器地图bool MapIsOk();    //判断生成地图是否可用,不可用则完善地图通道,使其可通过bool IsSuccess(); // 是否到达终点void GetPositionData(int* command);  //获取服务器发送数据,并转换为下一步坐标void SetPosittionData(); // 给服务器发送下一步命令void PrintfMap(); //输出地图void GenerateAMap();void FindBlock();void setNewX(int x){m_newX = x;}void setNewY(int y){m_newY = y;}int getNewX(){return m_newX;}int getNewY(){return m_newY;}
private:int m_newX; //当前X坐标int m_newY; //当前Y坐标int m_beginX;  //起始X,Yint m_beginY;int m_endX;  //终点X,Yint m_endY; int m_MAP[MAXDATA][MAXDATA];vector<block> myblock;int x_num = 1, y_num = 1;//矿工位置
};#include "Game01.h"
#include <ctime>
#include"Client.h"Game01::Game01()
{//初始化地图和坐标数据m_newX = 0;m_newY = 0;m_beginX = 0;m_beginY = 0;m_endX = 0;m_endY = 0;memset(m_MAP, 0, sizeof(m_MAP));
}
Game01::~Game01()
{
}//void Game01::init()
//{
//
//  createMap();  //生成地图
//  //if (MapIsOk())  //完善地图通道
//  //{
//  //  int command[2] = { 0 };
//  //  while (!IsSuccess())   //未到达终点
//  //  {
//  //       GetPositionData(command);
//  //       if (command[0] == m_newX && command[1] == m_newY)
//  //       {
//  //           continue;  //与当前坐标一致,则不移动
//  //       }
//  //       else
//  //       {
//  //           m_newX = command[0];  //接受服务器数据重新定位的当前位置
//  //           m_newY = command[1];
//  //           //refreshMap();
//  //       }
//  //  }
//  //}
//
//}
void Game01::init() {//将地图全部置为墙//memset(m_MAP, M_WALL, sizeof(m_MAP));//定义起始点m_MAP[1][1] = M_NOTHING;m_beginX = 0;m_beginY = 1;//m_newX = 1;//m_newY = 1;m_endX = M_WEIDHT;m_endY = M_HIGNTH + 1;m_MAP[m_beginX][m_beginY] = M_NOTHING;m_MAP[m_newX][m_newY] = 3;m_MAP[m_endX][m_endY] = M_NOTHING;//GenerateAMap();PrintfMap();
}void Game01::GenerateAMap()
{srand((unsigned)time(NULL));//随机数种子FindBlock();//第一步压入两堵墙(起点右边和起点下面)进入循环while (myblock.size()) {int BlockSize = myblock.size();//随机选择一堵墙(生成0 ~ BlockSize-1之间的随机数,同时也是vector里墙的下标)int randnum = rand() % BlockSize;block SelectBlock = myblock[randnum];x_num = SelectBlock.row;//矿工来到我们“选择的墙”这里y_num = SelectBlock.column;//根据当前选择的墙的方向进行后续操作//此时,起始点 选择的墙 目标块 三块区域在同一直线上//我们让矿工从“选择的墙”继续前进到“目标块”//矿工有穿墙能力 :)switch (SelectBlock.direction) {case M_down: {x_num++;break;}case M_right: {y_num++;break;}case M_left: {y_num--;break;}case M_up: {x_num--;break;}}//目标块如果是墙if (m_MAP[x_num][y_num] == M_WALL) {//打通墙和目标块m_MAP[SelectBlock.row][SelectBlock.column] = m_MAP[x_num][y_num] = M_NOTHING;//再次找出与矿工当前位置相邻的墙FindBlock();}else {//如果不是呢?说明我们的矿工挖到了一个空旷的通路上面 休息一下就好了//relax}//删除这堵墙(把用不了的墙删了,对于那些已经施工过了不必再施工了,同时也是确保我们能跳出循环)myblock.erase(myblock.begin() + randnum);}
}void Game01::FindBlock() {//找出与当前位置相邻的墙if (x_num + 1 <= M_WEIDHT && m_MAP[x_num + 1][y_num] == M_WALL) {//downmyblock.push_back(block(x_num + 1, y_num, M_down));}if (y_num + 1 <= M_HIGNTH && m_MAP[x_num][y_num + 1] == M_WALL) {//rightmyblock.push_back(block(x_num, y_num + 1, M_right));}if (x_num - 1 >= 1 && m_MAP[x_num - 1][y_num] == M_WALL) {//upmyblock.push_back(block(x_num - 1, y_num, M_up));}if (y_num - 1 >= 1 && m_MAP[x_num][y_num - 1] == M_WALL) {//leftmyblock.push_back(block(x_num, y_num - 1, M_left));}
}void Game01::createMap()  //随机生成地图
{int64_t new_time = 0;int randVlaue = 0;int commont[2] = { 0 };m_newY = 1;m_beginY = 1;m_endX = 48;m_endY = 49;m_MAP[0][1] = 0;  //起始位置m_MAP[48][49] = 0;  //终点位置while (!IsSuccess())   //未到达终点){GetPositionData(commont);if (commont[0] == m_newX && commont[1] == m_newY){continue;  //与当前坐标一致,则不移动}else if (commont[0] == m_endX && commont[1] == m_endY){m_newX = commont[0];  //接受服务器数据重新定位的当前位置m_newY = commont[1];m_MAP[m_newX][m_newY] = 2;}else if ((commont[0] <= 0 || commont[0] >= 49 || commont[1] <= 0 || commont[1] >= 49)){continue;}//else if (m_MAP[commont[0]][commont[1]] == 2)//{//   continue;//}else{//if(0)m_newX = commont[0];  //接受服务器数据重新定位的当前位置m_newY = commont[1];m_MAP[m_newX][m_newY] = 2;//refreshMap();}}for (int i = 0; i < MAP_VALUE; i++){for (int j = 0; j < MAP_VALUE; j++){if (i == 0 || i == 49 || (i > 0 && j == 0) || (i > 0 && j == 49)) {m_MAP[i][j] = 1;}else {//srand((int)time(0));  // 产生随机种子  把0换成NULL也行new_time = random(10000000);//GetSysTimeMicros();randVlaue = random(100);if(m_MAP[i][j] != 2)m_MAP[i][j] = ((new_time * randVlaue) % 37 > 17 ? 0 : 1);  //随机生成迷宫数据  // 取余数 暂且可以预留为 难度标准//○}}}//m_newY = random(49);//m_beginY = m_newY;//m_endX = random(49);//m_endY = 49;//m_MAP[0][m_beginY] = 0;  //起始位置//m_MAP[m_endX][49] = 0;  //终点位置m_newX = 0;m_newY = 1;m_beginY = 1;m_endX = 48;m_endY = 49;m_MAP[0][1] = 0;  //起始位置m_MAP[48][49] = 0;  //终点位置m_MAP[m_newX][m_newY] = 3;PrintfMap();
}void Game01::PrintfMap() //输出地图  0 可移动路径  1 墙壁 2 可通行路径 3 当前位置
{system("cls");for (int i = 0; i < M_WEIDHT+2; i++){for (int j = 0; j < M_HIGNTH+2; j++){if (m_MAP[i][j] == M_WALL){printf("■");}//else if (m_MAP[i][j] == 2)//{//    //printf("○");//  printf("  ");//}else if (m_MAP[i][j] == 3){printf("○");}else {printf("  ");}}printf("\n");}
}void Game01::refreshMap(MAPData *data) //接受服务器地图
{if (data != nullptr){if (data->massage == MassgeType::INITIALIZEMAZE){//同步前面客户端的地图memcpy(m_MAP, data->Map, sizeof(m_MAP));//PrintfMap();//IsSuccess();}}
}void Game01::refreshMap(NodeData *data) //刷新地图,重绘当前位置
{if (data == nullptr)return;char massage = data->massgeData[0];//给后出现的客户端统一数据//m_newX = data->New_X;//m_newY = data->New_Y;//int commandif (data->massage == MassgeType::COMMAND && data->massgeData == "OK")//是否成功{printf("成功了\n");}if (data->massage == MassgeType::MAPDATA){//同步前面客户端的位置m_newX = data->New_X;m_newY = data->New_Y;m_MAP[m_newX][m_newY] = 3;PrintfMap();IsSuccess();}if (data->massage == MassgeType::DIRECTION){int x = m_newX;int y = m_newY;switch (massage){case 'W':case 'w':if (m_newX > 0 && m_MAP[m_newX - 1][m_newY] != M_WALL) {m_newX = m_newX - 1;m_MAP[m_newX + 1][m_newY] = 2;}break;case 'S':case 's':if (m_newX < 49 && m_MAP[m_newX + 1][m_newY] != M_WALL) {m_newX = m_newX + 1;m_MAP[m_newX - 1][m_newY] = 2;}break;case 'A':case 'a':if (m_newY > 0 && m_MAP[m_newX][m_newY - 1] != M_WALL) {m_newY = m_newY - 1;m_MAP[m_newX][m_newY + 1] = 2;}break;case 'D':case 'd':if (m_newY < 49 && m_MAP[m_newX][m_newY + 1] != M_WALL) {m_newY = m_newY + 1;m_MAP[m_newX][m_newY - 1] = 2;}break;}//移动成功,发送移动后的数据if (x != m_newX || y != m_newY){NodeData nodeData;nodeData.massage = MassgeType::MOBILE;nodeData.massgeData = "";nodeData.New_X = m_newX;nodeData.New_Y = m_newY;//发送数据Client::GetInfrance()->SendData(&nodeData);}m_MAP[m_newX][m_newY] = 3;PrintfMap();IsSuccess();}
}bool Game01::MapIsOk()    //判断生成地图是否可用,不可用则完善地图通道,使其可通过
{bool flag = false;int randVlaue = random(4);while (m_newX != m_endY && m_newY != m_endY)   //未到达终点{randVlaue = random(4);switch (randVlaue % 4){case 0:break;case 1:break;case 2:break;case 3:break;}}return flag;
}
bool Game01::IsSuccess() // 是否到达终点
{bool flag = false;if (m_newX == m_endX && m_newY == m_endY) // 到达终点,给服务器发送OK数据{SetPosittionData();flag = true;}return flag;
}void Game01::GetPositionData(int* command)  //获取服务器发送数据,并转换为下一步坐标
{//int command[2] = {0};   //0为X,1为Y//调用客户端类的单例  获取到massage   w a s dchar massge=' ';//  srand((int)time(0));  // 产生随机种子  把0换成NULL也行int randVlaue = random(100000)%10;if (randVlaue == 0 || randVlaue == 1)massge = 'w';else if (randVlaue == 2 || randVlaue == 3 || randVlaue == 4)massge = 's';else if (randVlaue == 6 || randVlaue == 5)massge = 'a';else// (randVlaue == 3)massge = 'd';//if (randVlaue == 0 )// massge = 'w';//else if (randVlaue == 1 /*|| randVlaue == 4*/)// massge = 's';//else if (randVlaue ==2)// massge = 'a';//else// (randVlaue == 3)// massge = 'd';switch (massge){case 'W':case 'w':command[0] = m_newX;command[1] = m_newY - 1;break;case 'S':case 's':command[0] = m_newX;command[1] = m_newY + 1;break;case 'A':case 'a':command[0] = m_newX -1;command[1] = m_newY;break;case 'D':case 'd':command[0] = m_newX + 1;command[1] = m_newY;break;}
}void Game01::SetPosittionData() // 给服务器发送下一步命令
{//调用客户端类的单例NodeData data;data.massage = MassgeType::COMMAND;data.massgeData = "SUCCESS";Client::GetInfrance()->SendData(&data);
}
Client#pragma once
//  从 Windows 头文件中排除极少使用的信息
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include<stdio.h>
#include<string>
#ifdef _WIN32
#include<WinSock2.h>
#include<Windows.h>#else
#include<unistd.h>
#include<arpa/inet.h>
#include<string.h>#define SOCKET int
#define SOCKET_ERROR -1
#endif#pragma comment(lib,"ws2_32.lib")
#include"Common.h"
using namespace std;class Client
{
public:void Init();void Connect();void Close();void SendData(NodeData *data);NodeData* RecvData();MAPData* RecvDataMap();static Client* GetInfrance();static Client* m_client;
private:Client() {}SOCKET sock;sockaddr_in sockadd;bool isClose = false;NodeData nodeData;MAPData mapData;
};#include "Client.h"
Client* Client::m_client = nullptr;void Client::Init()
{if (!isClose){//启动windows socket
#ifdef _WIN32WORD var = MAKEWORD(2, 2);WSADATA dar;WSAStartup(var, &dar);
#endifsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);sockadd.sin_family = AF_INET;sockadd.sin_port = htons(6666);
#ifdef _WIN32sockadd.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  //转换IP地址为网络字节数据
#elsesockadd.sin_addr.s_addr = inet_addr("192.168.126.128"); //192.168.128.1
#endif}
}Client* Client::GetInfrance()
{if (m_client == nullptr){m_client = new Client();}return m_client;
}void Client::Connect()
{if (!isClose){//连接服务器if (SOCKET_ERROR == connect(sock, (const sockaddr*)&sockadd, sizeof(sockaddr_in))){printf("错误,连接服务器失败!\n");}else{printf("连接服务器成功!\n");}}}void Client::Close()
{//关闭套接字//getchar();
#ifdef _WIN32closesocket(sock);WSACleanup();
#elseclose(sock);
#endifisClose = true;
}void Client::SendData(NodeData *data)
{if (!isClose){if (data != nullptr){send(sock, (char*)data, sizeof(NodeData), 0);}}
}NodeData* Client::RecvData()
{if (!isClose){memset(&nodeData,0,sizeof(NodeData));//接收发送数据if (recv(sock, (char*)&nodeData, sizeof(NodeData), 0) > 0){printf("服务端发送的数据,IP:%s\n", nodeData.massgeData.c_str());return &nodeData;}}return nullptr;
}MAPData* Client::RecvDataMap()
{if (!isClose){memset(&mapData, 0, sizeof(MAPData));//接收发送数据if (recv(sock, (char*)&mapData, sizeof(MAPData), 0) > 0){printf("服务端发送的地图数据");return &mapData;}}return nullptr;
}
Common.h
#pragma once#include<string>#define random(x) rand()%(x)
#define MAXDATA 100
#define MAP_VALUE 50
#define M_WEIDHT 21//row
#define M_HIGNTH 21
#define M_down 1
#define M_right 2
#define M_left 4
#define M_up 8
#define M_WALL -1
#define M_NOTHING 2enum MassgeType
{COMMAND=0,   //命令MAPDATA,     //初始化迷宫数据INITIALIZEMAZE,   //初始化迷宫,获取第一个登陆客户的迷宫DIRECTION,   //方向MOBILE,   //移动成功
};typedef struct NodeData
{MassgeType massage = COMMAND;   //消息类型std::string massgeData;   //消息数据int New_X;int New_Y;
};typedef struct MAPData
{MassgeType massage = INITIALIZEMAZE;   //消息类型int Map[MAXDATA][MAXDATA];
};struct block {int row, column, direction;block(int _row, int _column, int _direction) {row = _row;column = _column;direction = _direction;}
};
struct point {int x;int y;
};
main.c#include<stdio.h>
#include<iostream>
#include <thread>
#include<string>
#include"Game01.h"
#include"Common.h"
#include"Client.h"
using namespace std;//过去用户命令
void getCommand(Game01 *game)
{string str;NodeData nodeData = {};while (1){str.clear();cin >> str;//压力测试代码//static long time_stamp = GetCurrentTime();//getCurrentTime为上面介绍的函数;//int dis = GetCurrentTime() - time_stamp;//if (dis >= 80) {//    time_stamp = GetCurrentTime();//   srand((int)time(0));  // 产生随机种子  把0换成NULL也行//   int randVlaue = random(100000) % 10;// if (randVlaue == 0 || randVlaue == 1)//     str.append("w");//    else if (randVlaue == 2 || randVlaue == 3 || randVlaue == 4)//        str.append("s");//    else if (randVlaue == 6 || randVlaue == 5)//        str.append("a");//    else// (randVlaue == 3)//     str.append("d");//}if (str.size() == 1){switch (str[0]){case 'w':case 's':case 'a':case 'd':case 'W':case 'S':case 'A':case 'D':nodeData.massage = MassgeType::DIRECTION;nodeData.massgeData = str;nodeData.New_X = game->getNewX();nodeData.New_Y = game->getNewY();//发送数据Client::GetInfrance()->SendData(&nodeData);break;case 'q'://预留退出接口break;default:break;}}}
}//绘制用户命令
void SetCommand(Game01 *game)
{while (1){NodeData *nodedata = Client::GetInfrance()->RecvData();if (nodedata != nullptr){//有服务器发送的数据game->refreshMap(nodedata);}}
}int main()
{Game01 game;Client::GetInfrance()->Init();  //初始化客户单Client::GetInfrance()->Connect();  //链接服务器game.refreshMap(Client::GetInfrance()->RecvDataMap());   //接受服务器发送的地图数据game.refreshMap(Client::GetInfrance()->RecvData());   //接受服务器发送的初始化位置数据game.init();    //初始化显示地图thread first(getCommand,&game);thread scend(SetCommand,&game);first.join();scend.join();Client::GetInfrance()->Close();return 0;
}

服务器:

Common.h#include<vector>#define random(x) rand()%(x)
#define MAXDATA 100
#define MAP_VALUE 50
#define M_WEIDHT 21//row
#define M_HIGNTH 21
#define M_down 1
#define M_right 2
#define M_left 4
#define M_up 8
#define M_WALL -1
#define M_NOTHING 2enum MassgeType
{COMMAND = 0,   //命令MAPDATA,     //初始化迷宫数据INITIALIZEMAZE,   //初始化迷宫,获取第一个登陆客户的迷宫DIRECTION,   //方向MOBILE,   //移动成功
};typedef struct MAPData
{MassgeType massage = INITIALIZEMAZE;   //消息类型int Map[MAXDATA][MAXDATA];
};typedef struct NodeData
{MassgeType massage = COMMAND;   //消息类型std::string massgeData;   //消息数据int New_X;int New_Y;
}; struct block {int row, column, direction;block(int _row, int _column, int _direction) {row = _row;column = _column;direction = _direction;}
};
struct point {int x;int y;
};int m_MAP[MAXDATA][MAXDATA];
std::vector<block> myblock;
int x_num = 1, y_num = 1;//矿工位置void GenerateAMap();
void FindBlock();void init() {//将地图全部置为墙memset(m_MAP, M_WALL, sizeof(m_MAP));GenerateAMap();
}void GenerateAMap()
{srand((unsigned)time(NULL));//随机数种子FindBlock();//第一步压入两堵墙(起点右边和起点下面)进入循环while (myblock.size()) {int BlockSize = myblock.size();//随机选择一堵墙(生成0 ~ BlockSize-1之间的随机数,同时也是vector里墙的下标)int randnum = rand() % BlockSize;block SelectBlock = myblock[randnum];x_num = SelectBlock.row;//矿工来到我们“选择的墙”这里y_num = SelectBlock.column;//根据当前选择的墙的方向进行后续操作//此时,起始点 选择的墙 目标块 三块区域在同一直线上//我们让矿工从“选择的墙”继续前进到“目标块”//矿工有穿墙能力 :)switch (SelectBlock.direction) {case M_down: {x_num++;break;}case M_right: {y_num++;break;}case M_left: {y_num--;break;}case M_up: {x_num--;break;}}//目标块如果是墙if (m_MAP[x_num][y_num] == M_WALL) {//打通墙和目标块m_MAP[SelectBlock.row][SelectBlock.column] = m_MAP[x_num][y_num] = M_NOTHING;//再次找出与矿工当前位置相邻的墙FindBlock();}else {//如果不是呢?说明我们的矿工挖到了一个空旷的通路上面 休息一下就好了//relax}//删除这堵墙(把用不了的墙删了,对于那些已经施工过了不必再施工了,同时也是确保我们能跳出循环)myblock.erase(myblock.begin() + randnum);}
}void FindBlock() {//找出与当前位置相邻的墙if (x_num + 1 <= M_WEIDHT && m_MAP[x_num + 1][y_num] == M_WALL) {//downmyblock.push_back(block(x_num + 1, y_num, M_down));}if (y_num + 1 <= M_HIGNTH && m_MAP[x_num][y_num + 1] == M_WALL) {//rightmyblock.push_back(block(x_num, y_num + 1, M_right));}if (x_num - 1 >= 1 && m_MAP[x_num - 1][y_num] == M_WALL) {//upmyblock.push_back(block(x_num - 1, y_num, M_up));}if (y_num - 1 >= 1 && m_MAP[x_num][y_num - 1] == M_WALL) {//leftmyblock.push_back(block(x_num, y_num - 1, M_left));}
}
Service.cpp#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS#include<Windows.h>#include<WinSock2.h>#pragma comment(lib,"ws2_32.lib")
#else#include<unistd.h>#include<arpa/inet.h>#include<string.h>#define SOCKET int#define SOCKET_ERROR -1#define INVALID_SOCKET (SOCKET)(~0)
#endif
#include<vector>
#include<map>
#include<string>
#include"Common.h"
using namespace std;std::vector<SOCKET> g_socket;   //总的连接客户端
//std::vector<SOCKET> g_socket_Client;  //发送数据的客户端
std::map<std::string, int> MessageList;
int g_New_X = 0, g_New_Y = 1;   //客户端当前的XY坐标int MessageData(SOCKET socket)
{static long time_stamp = GetCurrentTime();//getCurrentTime为上面介绍的函数;static int count1, count2, count3, count4 = 0;//static int new_X, new_Y = 0;   //第一个客户端当前的XY坐标//==========================================================//要执行的代码//缓冲区char szRecv[1024] = { 0 };int nLen = recv(socket, szRecv, sizeof(NodeData), 0);NodeData *data = (NodeData*)szRecv;if (nLen <= 0){printf("客户端已退出\n");return -1;}if (data->massage == MassgeType::MOBILE)  //移动成功更新最新坐标数据{g_New_X = data->New_X;g_New_Y = data->New_Y;}//if (g_socket_Client.end() == find(g_socket_Client.begin(), g_socket_Client.end(), socket))  //当前集合中不存在时,加入//{//   g_socket_Client.push_back(socket);//}if (data->massage == DIRECTION){//消息发送接受处理std::string sss = data->massgeData;switch (sss[0]){case 'W':case 'w':MessageList.insert(pair<std::string, int>(sss, count1++));break;case 'S':case 's':MessageList.insert(pair<std::string, int>(sss, count2++));break;case 'A':case 'a':MessageList.insert(pair<std::string, int>(sss, count3++));break;case 'D':case 'd':MessageList.insert(pair<std::string, int>(sss, count4++));break;}//printf("客户端发送的数据,IP:%d , Data:%s, X:%d, Y:%d\n", socket, data->massgeData.c_str(), data->New_X,data->New_Y);}else if (data->massage == COMMAND && data->massgeData=="SUCCESS"){NodeData recvData;recvData.massage = COMMAND;recvData.massgeData = "OK";//recvData.New_X = new_X;//recvData.New_Y = new_Y;for (int i = 0; i < g_socket.size(); i++){send(g_socket[i], (char*)&recvData, sizeof(NodeData), 0);}printf("服务端发送的数据,IP:%d , Data:%s\n", socket, recvData.massgeData.c_str());return 1;}//==========================================================//计算睡眠时间(毫秒),保证每隔500ms循环一次,发送一次客户端需求最多的命令 是客户端实行int dis = GetCurrentTime() - time_stamp;if (dis >= 500 && MessageList.size() > 0) {//求四个方向最多的数 即为下一步方向NodeData recvData;recvData.massage = DIRECTION;recvData.New_X = 0;recvData.New_Y = 0;int num = max(max(max(count1, count2), count3), count4);if (num == count1){recvData.massgeData = "W";}else if (num == count2){recvData.massgeData = "S";}else if (num == count3){recvData.massgeData = "A";}else if (num == count4){recvData.massgeData = "D";}// if (g_socket.size() >= 10)  //压测代码//    {for (int i = 0; i < g_socket.size(); i++){send(g_socket[i], (char*)&recvData, sizeof(NodeData), 0);printf("服务端发出的数据,IP:%d , Data:%s\n", g_socket[i], recvData.massgeData.c_str());}//}count1 = 0;count2 = 0;count3 = 0;count4 = 0;MessageList.clear();time_stamp = GetCurrentTime();//getCurrentTime为上面介绍的函数;}return 1;
}int main()
{
#ifdef _WIN32//启动windows socket WORD var = MAKEWORD(2, 2);WSADATA dar;WSAStartup(var, &dar);
#endifSOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);sockaddr_in sockadd;sockadd.sin_family = AF_INET;sockadd.sin_port = htons(6666);SOCKET maxsock = sock;
#ifdef _WIN32sockadd.sin_addr.S_un.S_addr = INADDR_ANY;     //inet_addr("127.0.0.1");  转换IP地址为网络字节数据
#elsesockadd.sin_addr.s_addr = INADDR_ANY;
#endif//绑定socketif (SOCKET_ERROR == bind(sock, (sockaddr*)&sockadd, sizeof(sockaddr_in))){printf("错误,绑定端口失败!\n");}else{printf("绑定端口成功!\n");}//开启监听if (SOCKET_ERROR == listen(sock, 10)){printf("错误,监听端口失败!\n");}else{printf("监听端口成功!\n");}while (true){//开启select 等待消息fd_set dataRead;fd_set dataWrite;fd_set dataError;timeval t_val = { 1,0 };//初始化FD_ZERO(&dataRead);FD_ZERO(&dataWrite);FD_ZERO(&dataError);//绑定到sockFD_SET(sock, &dataRead);FD_SET(sock, &dataWrite);FD_SET(sock, &dataError);//将socket集合中的socket添加到可读集合中for (int i = 0; i < (int)g_socket.size(); i++){FD_SET(g_socket[i], &dataRead);if (maxsock < g_socket[i])maxsock = g_socket[i];}int ret = select(maxsock + 1, &dataRead, &dataWrite, &dataError, &t_val);if (ret < 0){//有错误printf("错误,select出错...\n");//            int nErr = WSAGetLastError();//          printf("select: %d, %s\n", nErr, strerror(errno));//break;}//判断sock是否可读,有则,游客户端接入if (FD_ISSET(sock, &dataRead)){FD_CLR(sock, &dataRead);//accept 等待接收客户端连接sockaddr_in sockadd_Client = {};int clientLen = sizeof(sockaddr_in);//接收客户端信息的socketSOCKET _cSocket = INVALID_SOCKET;
#ifdef _WIN32_cSocket = accept(sock, (sockaddr*)&sockadd_Client, &clientLen);
#else_cSocket = accept(sock, (sockaddr*)&sockadd_Client, (socklen_t*)&clientLen);
#endifif (INVALID_SOCKET == _cSocket){printf("错误,接收到无效客户端socket...\n");}printf("新客户段接入,socketID:%d,IP:%s \n", (int)_cSocket, inet_ntoa(sockadd_Client.sin_addr));char buff[128] = { 0 };strcpy(buff, inet_ntoa(sockadd_Client.sin_addr));for (int i = 0; i < (int)g_socket.size(); i++){send(g_socket[i], buff, 128, 0);}if (g_socket.size() == 0){g_New_X = 0;g_New_Y = 1;init();  //第一次有客户段链接,生成地图}//有新客户端上线,同步地图MAPData data;data.massage = INITIALIZEMAZE;memcpy(data.Map, m_MAP,sizeof(m_MAP));send(_cSocket, (char*)&data, sizeof(MAPData), 0);//有新客户端上线,同步位置NodeData data1;data1.massage = MAPDATA;data1.massgeData = "";data1.New_X = g_New_X;data1.New_Y = g_New_Y;send(_cSocket, (char*)&data1, sizeof(NodeData), 0);printf("当前位置 X:%d,Y:%d",g_New_X,g_New_Y);g_socket.push_back(_cSocket);}//消息处理for (int i = 0; i < (int)dataRead.fd_count; i++){if (-1 ==  MessageData(dataRead.fd_array[i]))  //客户端无消息{auto iter = find(g_socket.begin(), g_socket.end(), dataRead.fd_array[i]);if (iter != g_socket.end())  //但是sockrt在连接列表里面  则移除{g_socket.erase(iter);}}}// printf("未处理网络请求\n");}getchar();
#ifdef _WIN32//关闭套接字closesocket(sock);//接收发送数据WSACleanup();
#elseclose(sock);
#endifreturn 0;}

C++实现简易(多人弹幕控制主播游戏人物类型,CMD_迷宫小游戏)(二)相关推荐

  1. C++实现简易(多人弹幕控制主播游戏人物类型,CMD_迷宫小游戏)(一)

    1.原因: 因疫情原因,很多公司的年会取消了,修改为线上.就像线上有什么好玩的,突然想到外国主播,让水友发弹幕来控制游戏人物行动这件事情.感觉还挺好玩的. 就想是怎么做出来的.可以做一个这种类型的小游 ...

  2. python迷宫小游戏代码_pygame简易迷宫游戏_mask应用示例程序

    用pygame制作的迷宫小游戏.像这类碰撞检测用mask最好.下面是部分代码预览: """ 简易迷宫游戏.本程序演示一个非常简单的迷宫游戏原理. 采用mask进行碰撞检测 ...

  3. c语言自动按键脚本,C语言键盘控制走迷宫小游戏

    本文实例为大家分享了C语言键盘控制走迷宫小游戏的具体代码,供大家参考,具体内容如下 在看了<啊哈C语言>之后想写一个游戏demo 游戏的截图 首先是启动界面 然后是初始化 接下来是键盘操控 ...

  4. 游戏主播们为什么早上不玩游戏?直播圈里还有哪些不成文的规定呢?

    我们发现一件比较奇怪的事情,游戏主播基本上很少在早上进行直播游戏.为什么游戏主播选择不在早上直播游戏呢?我觉得这是非常能够理解的一件事情.我们和大家分析一下原因. 游戏主播不在早上直播.是因为大部分的 ...

  5. 人、狼、羊、草过河的小游戏Python实现

    人.狼.羊.草过河的小游戏 ''' 想要实现的功能是,智能的选择过河的顺序 '''def is_valid_status(status):if status[1] == status[2] and s ...

  6. OBS完美直播弹幕效果主播教程

    进入正题之前,先回答2个问题: 您是斗鱼,熊猫,全民,板栗,B站主播? 您用OBS,Xsplit直播? 如果上面的关键字,你都不熟悉,说明这个教程可能不适合您. 为什么要继续往下看?先看直播弹幕效果 ...

  7. OBS直播弹幕效果主播教程

    进入正题之前,先回答2个问题: 您是斗鱼,熊猫,全民,板栗,B站主播? 您用OBS,Xsplit直播? 如果上面的关键字,你都不熟悉,说明这个教程可能不适合您. 为什么要继续往下看?先看直播弹幕效果 ...

  8. 能爬旅游景点数据的知名网站_某知名网站公布年度数据,十大吸金主播斗鱼独占前四,小团团终成“女幻神”,339斩获一哥...

    转眼间斗鱼直播平台又陪伴大家度过了愉快的一年,如今回顾整个2019年,我们收获了很多快乐,与此同时创下无数个记录!比如在知名数据网站"头榜"近日发布的"2019头榜星势力 ...

  9. 《游戏视频主播手册》——2.4 选择游戏视频直播平台

    本节书摘来自异步社区<游戏视频主播手册>一书中的第2章,第2.4节,作者 王岩,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.4 选择游戏视频直播平台 游戏 ...

最新文章

  1. Field、CopyField、DynamicField的一些简介,用法
  2. linux - python - 异常:error while loading shared libraries
  3. cmd oracle 连接实例_基于winserver的Oracle数据库跨版本下的rman备份恢复
  4. springboot中使用缓存shiro-ehcache
  5. html 新浪博客,html
  6. 开始Azure之旅,参加深度培训 (转)
  7. lstm原文_对时间序列分类的LSTM全卷积网络的见解
  8. python获取窗口控件属性_Python——tkinter窗口视窗的功能部件
  9. Mac电脑:Flutter开发环境配置小白教程
  10. 1. jQuery 简介
  11. HTTP报文-请求方式
  12. MAXON RE40直流有刷电机在Elmo SimplIQ cello系列驱动器的增益调节
  13. 如何长期且快乐的学习?
  14. list数组遍历时能不能使用remove()方法,要注意什么
  15. 每日三思:优化微信小程序中倒计时占内存较大(19-0612-1917)
  16. MongoDB4.0 配置文件
  17. [C] 腾讯公司后台服务器经典面试题 (2009年5月)
  18. 识别图片中曲线并获取其坐标
  19. 冗余分析(RDA)中若包含生物学重复会怎样?
  20. 征途2s 服务器文件,征途2 经典专区28日服务器重组公告

热门文章

  1. 【代理设置】Linux Windows 系统下各工具设置代理方式笔记(整理中)
  2. Objective-C文件和目录操作,IOS文件操作,NSFileManager使用文件操作
  3. 流水线加法器的实现(verilog)
  4. 在Dreamware中使用Struts标签来开发
  5. thinkphp生成带二维码的海报
  6. 手撕系列:原生python实现汽车牌照识别
  7. 手把手教你安装telnet(离线方式+在线方式)
  8. 鲁大师4月新机性能/流畅榜:vivo霸榜,最流畅折叠屏手机出现
  9. File not found: ..\target\m2e-wtp\web-resources\META-INF\MANIFEST.MF.
  10. 百度SEO优化之sitemap系列