C++实现简易(多人弹幕控制主播游戏人物类型,CMD_迷宫小游戏)(二)
更新内容:
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_迷宫小游戏)(二)相关推荐
- C++实现简易(多人弹幕控制主播游戏人物类型,CMD_迷宫小游戏)(一)
1.原因: 因疫情原因,很多公司的年会取消了,修改为线上.就像线上有什么好玩的,突然想到外国主播,让水友发弹幕来控制游戏人物行动这件事情.感觉还挺好玩的. 就想是怎么做出来的.可以做一个这种类型的小游 ...
- python迷宫小游戏代码_pygame简易迷宫游戏_mask应用示例程序
用pygame制作的迷宫小游戏.像这类碰撞检测用mask最好.下面是部分代码预览: """ 简易迷宫游戏.本程序演示一个非常简单的迷宫游戏原理. 采用mask进行碰撞检测 ...
- c语言自动按键脚本,C语言键盘控制走迷宫小游戏
本文实例为大家分享了C语言键盘控制走迷宫小游戏的具体代码,供大家参考,具体内容如下 在看了<啊哈C语言>之后想写一个游戏demo 游戏的截图 首先是启动界面 然后是初始化 接下来是键盘操控 ...
- 游戏主播们为什么早上不玩游戏?直播圈里还有哪些不成文的规定呢?
我们发现一件比较奇怪的事情,游戏主播基本上很少在早上进行直播游戏.为什么游戏主播选择不在早上直播游戏呢?我觉得这是非常能够理解的一件事情.我们和大家分析一下原因. 游戏主播不在早上直播.是因为大部分的 ...
- 人、狼、羊、草过河的小游戏Python实现
人.狼.羊.草过河的小游戏 ''' 想要实现的功能是,智能的选择过河的顺序 '''def is_valid_status(status):if status[1] == status[2] and s ...
- OBS完美直播弹幕效果主播教程
进入正题之前,先回答2个问题: 您是斗鱼,熊猫,全民,板栗,B站主播? 您用OBS,Xsplit直播? 如果上面的关键字,你都不熟悉,说明这个教程可能不适合您. 为什么要继续往下看?先看直播弹幕效果 ...
- OBS直播弹幕效果主播教程
进入正题之前,先回答2个问题: 您是斗鱼,熊猫,全民,板栗,B站主播? 您用OBS,Xsplit直播? 如果上面的关键字,你都不熟悉,说明这个教程可能不适合您. 为什么要继续往下看?先看直播弹幕效果 ...
- 能爬旅游景点数据的知名网站_某知名网站公布年度数据,十大吸金主播斗鱼独占前四,小团团终成“女幻神”,339斩获一哥...
转眼间斗鱼直播平台又陪伴大家度过了愉快的一年,如今回顾整个2019年,我们收获了很多快乐,与此同时创下无数个记录!比如在知名数据网站"头榜"近日发布的"2019头榜星势力 ...
- 《游戏视频主播手册》——2.4 选择游戏视频直播平台
本节书摘来自异步社区<游戏视频主播手册>一书中的第2章,第2.4节,作者 王岩,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.4 选择游戏视频直播平台 游戏 ...
最新文章
- Field、CopyField、DynamicField的一些简介,用法
- linux - python - 异常:error while loading shared libraries
- cmd oracle 连接实例_基于winserver的Oracle数据库跨版本下的rman备份恢复
- springboot中使用缓存shiro-ehcache
- html 新浪博客,html
- 开始Azure之旅,参加深度培训 (转)
- lstm原文_对时间序列分类的LSTM全卷积网络的见解
- python获取窗口控件属性_Python——tkinter窗口视窗的功能部件
- Mac电脑:Flutter开发环境配置小白教程
- 1. jQuery 简介
- HTTP报文-请求方式
- MAXON RE40直流有刷电机在Elmo SimplIQ cello系列驱动器的增益调节
- 如何长期且快乐的学习?
- list数组遍历时能不能使用remove()方法,要注意什么
- 每日三思:优化微信小程序中倒计时占内存较大(19-0612-1917)
- MongoDB4.0 配置文件
- [C] 腾讯公司后台服务器经典面试题 (2009年5月)
- 识别图片中曲线并获取其坐标
- 冗余分析(RDA)中若包含生物学重复会怎样?
- 征途2s 服务器文件,征途2 经典专区28日服务器重组公告
热门文章
- 【代理设置】Linux Windows 系统下各工具设置代理方式笔记(整理中)
- Objective-C文件和目录操作,IOS文件操作,NSFileManager使用文件操作
- 流水线加法器的实现(verilog)
- 在Dreamware中使用Struts标签来开发
- thinkphp生成带二维码的海报
- 手撕系列:原生python实现汽车牌照识别
- 手把手教你安装telnet(离线方式+在线方式)
- 鲁大师4月新机性能/流畅榜:vivo霸榜,最流畅折叠屏手机出现
- File not found: ..\target\m2e-wtp\web-resources\META-INF\MANIFEST.MF.
- 百度SEO优化之sitemap系列