PAOGD个人作业5-简单的服务端

任务介绍

  • 为贪吃蛇游戏添加多人游戏功能:多个玩家可以分别控制贪吃蛇在游戏区域里驰骋,避免碰到自己、同类或障碍物,尽可能地吃更多的食物以生长!

开发环境

  • OpenGL3
  • GLUT
  • GLAD
  • C++

要求:

  1. 完成多人贪吃蛇游戏的C-S框架搭建(50%)(达成)
  2. 多客户端能够分别连接服务器并有正确的响应(连接成功、连接失败)(20%)(达成)
  3. 服务器能够正确处理客户端的动作请求,客户端能够正确更新蛇的移动状态(25%)(达成)
  4. 蛇的碰撞检测、奖励生成、胜负判断等内容的实现(10%+5% with bonus)(未达成)

参考资料

1.《网络多人游戏架构与编程》

实现内容

1. 当前功能介绍
  • 客户端登入时询问是否进入多人游戏,如果否,则不与服务器连接,正常进行单人游戏
  • 与服务器成功连接后返回用户编号,当连接用户数达到指定数目后进入游戏(当前指定人数为2),人数已满后其他用户无法加入
  • 服务器缓存蛇的移动状态,客户端根据服务端返回的数据正确更新蛇的移动
  • 未实现两人以上连接功能

在这里插入图片描述

2. 服务端

服务端的缓存区缓存一定的状态数,客户端加载蛇的时候通过当前状态的序号向客户端查询,客户端向服务端更新蛇的时候服务端更新当前状态的下一个状态

服务端返回字符串:

wait:蛇不进行移动,状态序号不更新

ok:更新移动状态后返回讯息

整数(1,2,3……):用户编号

状态字符串(ad,aw……):蛇的移动状态,第1个字符是编号1的蛇,第2个字符是编号2的蛇,以此类推
	while (true) {
		int message = recvfrom(server, receBuf, 1024, 0, (SOCKADDR*)&addrClient, &fromlen);
		if (message > 0) {      //判断接收到的数据是否为空
			receBuf[message] = '\0';//给字符数组加一个'\0',表示结束了。不然输出有乱码
			// 返回编号
			if ((receBuf[1] == 'i')) {
				if (id == 0) {
					id++;
					const char* Response = "1";
					sendto(server, Response, strlen(Response), 0, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));
				}
				else if (id == 1) {
					id++;
					const char* Response = "2";
					sendto(server, Response, strlen(Response), 0, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));
				}
			}
			// 超出人数
			else if (id < 2) {
				const char* Response = "wait";
				sendto(server, Response, strlen(Response), 0, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));
			}
			// 返回对应移动状态
			else if (receBuf[1] == 'g') {
				int num = atoi(receBuf + 2);

				if (lastTime >= 0 && control == 0) {
					int index = (num) % 100;
					int index1 = (num + 1) % 100;
					dirBuffer[index1] = dirBuffer[index];
				}
				// 还有玩家未更新时其他玩家等待
				if (num > lastTime) {
					const char* Response = "wait";
					sendto(server, Response, strlen(Response), 0, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));
				}
				else {
					int index = (num)%100;
					const char* Response = dirBuffer[index].c_str();
					sendto(server, Response, strlen(Response), 0, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));
					control++;
					if (control == 2) {
						lastTime++;
						control = 0;

					}
				}

			}
			// 更新对应移动状态
			else {
				int index1 = receBuf[0] - '1';
				int index2 = (lastTime + 1) % 100;
				dirBuffer[index2][index1] = receBuf[1];
				const char* Response = "ok";
				sendto(server, Response, strlen(Response), 0, (SOCKADDR*)&addrClient, sizeof(SOCKADDR));
			}
		}


	}
3. 客户端

在上一次作业的基础上,增加一个蛇停止的状态,修改键盘事件,根据是否进入多人游戏决定触发事件。

服务端发送字符串(identity + dir + time):

用户id:由服务端返回,用于标识用户

命令:i表示请求id,g表示请求状态,wasd表示更新(成功返回ok)

状态序号:time表示客户端当前所处状态
        string send = identity + dir + to_string(time);
	int last = recvfrom(sock_Client, receBuf, 1024, 0, (SOCKADDR*)&sock, &len);
	if (last > 0) {
		receBuf[last] = '\0';      

		if (dir == "i") {
			id = receBuf;
		}
		else if (strcmp(receBuf, "wait") == 0) {
			snake1->move(D_STOP);
			snake2->move(D_STOP);
		}
		else if (strcmp(receBuf, "ok") == 0) {
			cout << "  UPDATE..." << endl; // update direction success
		}
		else if (dir == "g") {
			time++;
			switch (receBuf[0]) {
			case 'w':
				snake1->move(D_UP);
				break;
			case 's':
				snake1->move(D_DOWN);
				break;
			case 'a':
				snake1->move(D_LEFT);
				break;
			case 'd':
				snake1->move(D_RIGHT);
				break;
			default:
				break;
			}
			switch (receBuf[1]) {
			case 'w':
				snake2->move(D_UP);
				break;
			case 's':
				snake2->move(D_DOWN);
				break;
			case 'a':
				snake2->move(D_LEFT);
				break;
			case 'd':
				snake2->move(D_RIGHT);
				break;
			default:
				break;
			}

		}

	}

实验思考及感想

这个学期各个课程的作业很多,这次作业的工作量对我而言还是大了点,和上次一样花了很多时间。实现的和课件提到的功能部分有不少出入,但要求是大部分完成了的(大概)。上一次的作业只实现了一些基本的功能,代码也写得比较混乱,但由于时间关系没办法进一步改进了,希望以后这项作业能有更充分的时间吧。

从难度上来讲,使用UDP传输数据是很简单的,但实现不同客户端之间的绝对同步相对较难,耗时也最长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值