花了两天多的时间写了个泡泡堂联机游戏。感觉其实单机版的实现不难,麻烦的是多人联机的实现。
先说下思路吧,程序分为服务端和客户端。服务端器一个中转作用,但客户端的状态改变,比如用户进入,放下泡泡,移动等时,会发送信息给服务端,服务端收到后会转发给其他客户端。服务端开辟5个线程,等待客户端连接,也就是最多只能连接5个客户端。具体的大家可以看代码:
下面是客户端的:
#include<iostream>
#include<vector>
#include"winsock2.h"
#include "mysocket.cpp"
#include"sdl/sdl.h"
#include"time.h"
#pragma comment(lib,"ws2_32")
using namespace std;
SDL_Surface *screen;
SDL_Surface *play;
SDL_Surface *mplay;
SDL_Surface *ball;
SDL_Surface *ball1;
SDL_Surface *ball2;
int hall[48][64];
struct info{
int flag; //1,新用户;2,新子弹;3.用户移动
int id;
int x;
int y;
int a;
};
struct bb{
SDL_Rect r;
int t;
};
struct pp{
SDL_Rect point;
int id;
int port;
};
vector<bb> b;
vector<pp> p;
mysocket sock;
mysocket sock1;
mysocket sock2;
int id;
char ip[20];
void myexit(){
}
DWORD WINAPI get(LPVOID l){
info f;
while(1){
memset((void*)&f,0,sizeof(f));
sock.recv((char*)&f,sizeof(f));
if(f.flag==1){
pp p1;
p1.id=f.id;
p1.point.x=f.x;
p1.point.y=f.y;
p1.port=9999+f.id;
p.push_back(p1);
cout<<f.x<<" "<<f.y<<endl;
// cout<<1<<endl;
}else if(f.flag==2){
bb b1;
b1.r.x=f.x;
b1.r.y=f.y;
b1.t=100;
b.push_back(b1);
}else if(f.flag==3){
for(int i=0;i<p.size();i++){
if(f.id==p[i].id){
p[i].point.x=f.x;
p[i].point.y=f.y;
}
}
}
}
return 0;
}
DWORD WINAPI get1(LPVOID l){
info f;
while(1){
memset((void*)&f,0,sizeof(f));
sock2.recvfrom((char*)&f,sizeof(f));
if(f.flag==1){
pp p1;
p1.id=f.id;
p1.point.x=f.x;
p1.point.y=f.y;
p1.port=9999+f.id;
p.push_back(p1);
for(int i=0;i<6;i++){
for(int i1=0;i1<6;i1++){
hall[p1.point.y/10+i][p1.point.x/10+i1]=0;
}
}
// cout<<f.x<<" "<<f.y<<endl;
}else if(f.flag==2){
bb b1;
b1.r.x=f.x;
b1.r.y=f.y;
b1.t=100;
//cout<<b1.t;
b.push_back(b1);
}else if(f.flag==3){
for(int i=0;i<p.size();i++){
if(f.id==p[i].id){
p[i].point.x=f.x;
p[i].point.y=f.y;
}
}
}else if(f.flag==4){
f.id=hall[f.x][f.y];
//cout<<10005+f.a;
sock2.sendto((char*)&f,sizeof(f),ip,10005+f.a);
// cout<<id;
}else if(f.flag==5){
for(int i=0;i<b.size();i++){
f.flag=5;
f.id=b[i].t;
f.x=b[i].r.x;
f.y=b[i].r.y;
sock2.sendto((char*)&f,sizeof(f),ip,10005+f.a);
}
f.flag=5;
f.id=-1;
f.x=-1;
f.y=-1;
sock2.sendto((char*)&f,sizeof(f),ip,10005+f.a);
//cout<<1;
}else if(f.flag==6){
for(int i=0;i<p.size();i++){
if(p[i].id==f.id){
p.erase(p.begin()+i);
break;
}
}
}
}
return 0;
}
int main(int argc, char *argv[]){
srand(time(0));
cin>>ip;
// strcpy(ip,"127.0.0.1");
WSADATA data;
WORD v=MAKEWORD(2,2);
WSAStartup(v,&data);
mysocket s;
s.init(0);
s.connect(ip,9999);
s.recv((char*)&id,sizeof(id));
int fid=0;
if(id==0){
id=1;
fid=1;
}
s.close();
int port=9999+id;
sock2.init(1);
sock2.bind(id+19999);
pp p1;
p1.id=id;
p1.port=port;
p1.point.x=rand()%550/10*10;
p1.point.y=rand()%400/10*10;
p.push_back(p1);
sock.init(0);
sock.connect(ip,id+9999);
info f={1,id,p1.point.x,p1.point.y};
sock.send((char*)&f,sizeof(f));
for(int i=0;i<48;i++){
for(int i1=0;i1<64;i1++){
hall[i][i1]=1;
}
}
if(fid==1){
for(i=0;i<50;i++){
a: int x=rand()%48,y=rand()%64;
if(hall[x][y]==0){
goto a;
}else{
for(int i1=0;i1<4;i1++){
for(int i2=0;i2<4;i2++){
if(x+i1<48 && y+i2<64){
hall[x+i1][y+i2]=0;
}
}
}
}
}
}else{
info f;
//cout<<id;
for(int i=0;i<48;i++){
for(int i1=0;i1<64;i1++){
sock2.recvfrom((char*)&f,sizeof(f));
// Sleep(1);
hall[f.x][f.y]=f.id;
}
}
//cout<<"sx";
while(1){
sock2.recvfrom((char*)&f,sizeof(f));
if(f.id==-1){
break;
}
bb b1;
b1.r.x=f.x;
b1.r.y=f.y;
b1.t=f.id;
b.push_back(b1);
}
}
SDL_Init(SDL_INIT_EVERYTHING);
atexit(SDL_Quit);
screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
CreateThread(0,0,get,0,0,0);
CreateThread(0,0,get1,0,0,0);
play=SDL_LoadBMP("1.bmp");
ball=SDL_LoadBMP("2.bmp");
ball1=SDL_LoadBMP("3.bmp");
ball2=SDL_LoadBMP("4.bmp");
mplay=SDL_LoadBMP("5.bmp");
for(i=0;i<6;i++){
for(int i1=0;i1<6;i1++){
hall[p[0].point.y/10+i][p[0].point.x/10+i1]=0;
}
}
while(1){
Uint8 *key=SDL_GetKeyState(0);
if(key[SDLK_UP]){
if(p[0].point.y-10>=0 && hall[(p[0].point.y-10)/10][p[0].point.x/10]==0 && hall[(p[0].point.y-10)/10][p[0].point.x/10+1]==0 && hall[(p[0].point.y-10)/10][p[0].point.x/10+2]==0){
p[0].point.y-=10;
info f={3,id,p[0].point.x,p[0].point.y};
sock.send((char*)&f,sizeof(f));
}
}
if(key[SDLK_DOWN]){
if(p[0].point.y+10+30<=480 && hall[(p[0].point.y+30)/10][p[0].point.x/10]==0 && hall[(p[0].point.y+30)/10][p[0].point.x/10+1]==0 && hall[(p[0].point.y+30)/10][p[0].point.x/10+2]==0){
p[0].point.y+=10;
info f={3,id,p[0].point.x,p[0].point.y};
sock.send((char*)&f,sizeof(f));
}
}
if(key[SDLK_LEFT]){
if(p[0].point.x-10>=0 && hall[p[0].point.y/10][(p[0].point.x-10)/10]==0 && hall[p[0].point.y/10+1][(p[0].point.x-10)/10]==0 && hall[p[0].point.y/10+2][(p[0].point.x-10)/10]==0){
p[0].point.x-=10;
info f={3,id,p[0].point.x,p[0].point.y};
sock.send((char*)&f,sizeof(f));
}
}
if(key[SDLK_RIGHT]){
if(p[0].point.x+10+30<=640 && hall[p[0].point.y/10][(p[0].point.x+30)/10]==0 && hall[p[0].point.y/10+1][(p[0].point.x+30)/10]==0 && hall[p[0].point.y/10+2][(p[0].point.x+30)/10]==0){
p[0].point.x+=10;
info f={3,id,p[0].point.x,p[0].point.y};
sock.send((char*)&f,sizeof(f));
}
}
if(key[SDLK_SPACE]){
bb b1;
b1.r.x=p[0].point.x;
b1.r.y=p[0].point.y;
b1.t=100;
b.push_back(b1);
info f={2,id,p[0].point.x,p[0].point.y};
sock.send((char*)&f,sizeof(f));
}
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type) {
case SDL_KEYUP:
// If escape is pressed, return (and thus, quit)
if (event.key.keysym.sym == SDLK_ESCAPE){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
break;
case SDL_QUIT:
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return(0);
break;
}
}
for(i=0;i<48;i++){
for(int i1=0;i1<64;i1++){
SDL_Rect r;
r.x=i1*10;
r.y=i*10;
r.h=10;
r.w=10;
if(hall[i][i1]==0){
SDL_FillRect(screen,&r,SDL_MapRGB(screen->format,255,255,0));
}else{
SDL_FillRect(screen,&r,SDL_MapRGB(screen->format,100,100,0));
}
}
}
for(i=0;i<b.size();i++){
if(b[i].t<=0){
for(int i1=0;i1<3;i1++){
for(int i2=0;i2<6;i2++){
if(b[i].r.x/10-i2-1>=0){
hall[b[i].r.y/10+i1][b[i].r.x/10-i2-1]=0;
SDL_Rect r;
r.x=(b[i].r.x/10-i2-1)*10;
r.y=(b[i].r.y/10+i1)*10;
r.h=10;
r.w=10;
SDL_FillRect(screen,&r,SDL_MapRGB(screen->format,255,100,0));
SDL_UpdateRect(screen,r.x,r.y,r.w,r.h);
}
}
}
for(i1=0;i1<6;i1++){
for(int i2=0;i2<3;i2++){
if(b[i].r.y/10-i1-1>=0){
hall[b[i].r.y/10-i1-1][b[i].r.x/10+i2]=0;
SDL_Rect r;
r.x=(b[i].r.x/10+i2)*10;
r.y=(b[i].r.y/10-i1-1)*10;
r.h=10;
r.w=10;
SDL_FillRect(screen,&r,SDL_MapRGB(screen->format,255,100,0));
SDL_UpdateRect(screen,r.x,r.y,r.w,r.h);
}
}
}
for(i1=0;i1<3;i1++){
for(int i2=0;i2<6;i2++){
if(b[i].r.x/10+i2+3<=63){
hall[b[i].r.y/10+i1][b[i].r.x/10+i2+3]=0;
SDL_Rect r;
r.x=(b[i].r.x/10+i2+3)*10;
r.y=(b[i].r.y/10+i1)*10;
r.h=10;
r.w=10;
SDL_FillRect(screen,&r,SDL_MapRGB(screen->format,255,100,0));
SDL_UpdateRect(screen,r.x,r.y,r.w,r.h);
}
}
}
for(i1=0;i1<6;i1++){
for(int i2=0;i2<3;i2++){
if(b[i].r.y/10+i1+3<=47){
hall[b[i].r.y/10+i1+3][b[i].r.x/10+i2]=0;
SDL_Rect r;
r.x=(b[i].r.x/10+i2)*10;
r.y=(b[i].r.y/10+i1+3)*10;
r.h=10;
r.w=10;
SDL_FillRect(screen,&r,SDL_MapRGB(screen->format,255,100,0));
SDL_UpdateRect(screen,r.x,r.y,r.w,r.h);
}
}
}
if((p[0].point.x>=b[i].r.x && p[0].point.x<b[i].r.x+30 && p[0].point.y>b[i].r.y-60 && p[0].point.y<b[i].r.y+90)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x>=b[i].r.x-60 && p[0].point.x<b[i].r.x+90 && p[0].point.y>=b[i].r.y && p[0].point.y<b[i].r.y+30)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x+30>b[i].r.x && p[0].point.x+30<b[i].r.x+30 && p[0].point.y>b[i].r.y-60 && p[0].point.y<b[i].r.y+90)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x+30>b[i].r.x-60 && p[0].point.x+30<b[i].r.x+90 && p[0].point.y>b[i].r.y && p[0].point.y<b[i].r.y+30)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x>b[i].r.x && p[0].point.x<b[i].r.x+30 && p[0].point.y+30>b[i].r.y-60 && p[0].point.y+30<b[i].r.y+90)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x>b[i].r.x-60 && p[0].point.x<b[i].r.x+90 && p[0].point.y+30>b[i].r.y && p[0].point.y+30<b[i].r.y+30)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x+30>b[i].r.x && p[0].point.x+30<b[i].r.x+30 && p[0].point.y+30>b[i].r.y-60 && p[0].point.y+30<b[i].r.y+90)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
if((p[0].point.x+30>b[i].r.x-60 && p[0].point.x+30<b[i].r.x+90 && p[0].point.y+30>b[i].r.y && p[0].point.y+30<b[i].r.y+30)){
info f={6,id,0,0};
sock.send((char*)&f,sizeof(f));
return 0;
}
b.erase(b.begin()+i);
continue;
}
b[i].t-=2;
if(b[i].t>50){
SDL_BlitSurface(ball,0,screen,&b[i].r);
}else if(b[i].t>20){
SDL_BlitSurface(ball2,0,screen,&b[i].r);
}else{
SDL_BlitSurface(ball1,0,screen,&b[i].r);
}
}
for(i=0;i<p.size();i++){
if(i==0){
SDL_BlitSurface(mplay,0,screen,&p[i].point);
}else{
SDL_BlitSurface(play,0,screen,&p[i].point);
}
}
SDL_Flip(screen);
SDL_Delay(80);
}
return 0;
}
下面是服务端的 :
#include<iostream>
#include<vector>
#include"winsock2.h"
#include "mysocket.cpp"
#include"windows.h"
#pragma comment(lib,"ws2_32")
using namespace std;
CRITICAL_SECTION cs;
struct info{
int flag; //1,新用户;2,新子弹;3.用户移动,4,地图;5,泡泡;6,用户退出
int id;
int x;
int y;
int a;
};
struct play{
int id;
char ip[20];
int x;
int y;
};
vector<play> p;
DWORD WINAPI sendinfo(LPVOID l){
while(1){
mysocket ss;
ss.init(0);
ss.bind(9999);
ss.listen();
mysocket ss1;
ss.accept(ss1);
cout<<"sx"<<endl;
int id;
if(p.size()==0){
id=0;
ss1.send((char*)&id,sizeof(id));
}else{
for(int i=1;i<=5;i++){
int f=0;
for(int i1=0;i1<p.size();i1++){
if(p[i1].id==i){
f=1;
}
}
if(f==0){
id=i;
break;
}
}
cout<<id;
ss1.send((char*)&id,sizeof(id));
}
ss1.close();
ss.close();
}
return 0;
}
DWORD WINAPI user(LPVOID l){
int port=(long)l;
EnterCriticalSection(&cs);
cout<<port<<endl;
LeaveCriticalSection(&cs);
init: mysocket s;
s.init(0);
s.bind(port);
s.listen();
mysocket s1;
s.accept(s1);
info f;
while(1){
memset((void*)&f,0,sizeof(f));
s1.recv((char*)&f,sizeof(f));
if(f.flag==1){
for(int i=0;i<p.size();i++){
info f1={1,p[i].id,p[i].x,p[i].y};
int e=s1.send((char*)&f1,sizeof(f1));
cout<<p[i].x<<" "<<p[i].y<<endl;
}
cout<<p.size()<<endl;
if(p.size()>0){
mysocket s2;
s2.init(1);
s2.bind(10005+port-9999);
// cout<<10005+port-9999;
// cout<<p[0].ip<<" "<<p[0].id+19999;
for(int i=0;i<48;i++){
for(int i1=0;i1<64;i1++){
info f2={4,0,i,i1,port-9999};
s2.sendto((char*)&f2,sizeof(f2),p[0].ip,p[0].id+19999);
// Sleep(1);
s2.recvfrom((char*)&f2,sizeof(f2));
// cout<<f.id;
// Sleep(1);
s2.sendto((char*)&f2,sizeof(s2),s1.getaddr(),f.id+19999);
}
}
info f2={5,0,0,0,port-9999};
s2.sendto((char*)&f2,sizeof(f2),p[0].ip,p[0].id+19999);
while(1){
// Sleep(1);
s2.recvfrom((char*)&f2,sizeof(f2));
//cout<<f.id;
// Sleep(1);
s2.sendto((char*)&f2,sizeof(s2),s1.getaddr(),f.id+19999);
if(f2.id==-1){
break;
}
}
s2.close();
}
info f2={1,f.id,f.x,f.y};
mysocket s2;
s2.init(1);
for(i=0;i<p.size();i++){
s2.sendto((char*)&f2,sizeof(f2),p[i].ip,p[i].id+19999);
}
play p1;
p1.id=f.id;
p1.x=f.x;
p1.y=f.y;
sockaddr_in addr;
int n=sizeof(addr);
::getpeername(s1.getsocket(),(sockaddr*)&addr,&n);
// int peerport=::ntohs(addr.sin_port);
char *peerip=::inet_ntoa(addr.sin_addr);
cout<<peerip<<endl;
strcpy(p1.ip,peerip);
p.push_back(p1);
}else if(f.flag==2){
info f2={2,f.id,f.x,f.y};
mysocket s2;
s2.init(1);
for(int i=0;i<p.size();i++){
if(p[i].id!=f.id){
int e= s2.sendto((char*)&f2,sizeof(f2),p[i].ip,p[i].id+19999);
}
}
}else if(f.flag==3){
//cout<<"sx"<<endl;
info f2={3,f.id,f.x,f.y};
mysocket s2;
s2.init(1);
for(int i=0;i<p.size();i++){
if(p[i].id!=f.id){
s2.sendto((char*)&f2,sizeof(f2),p[i].ip,p[i].id+19999);
}else{
p[i].x=f.x;
p[i].y=f.y;
}
}
}else if(f.flag==6){
for(int i=0;i<p.size();i++){
if(p[i].id==f.id){
p.erase(p.begin()+i);
break;
}
}
info f2={6,f.id,0,0};
mysocket s2;
s2.init(1);
for(i=0;i<p.size();i++){
s2.sendto((char*)&f2,sizeof(f2),p[i].ip,p[i].id+19999);
}
s.close();
s1.close();
cout<<p.size()<<endl;
goto init;
}
}
return 0;
}
HANDLE t;
main(){
InitializeCriticalSection(&cs);
WSADATA data;
WORD v=MAKEWORD(2,2);
WSAStartup(v,&data);
t=CreateThread(0,0,sendinfo,0,0,0);
for(int i=0;i<5;i++){
CreateThread(0,0,user,(void*)(10000+i),0,0);
}
WaitForSingleObject(t,-1);
DeleteCriticalSection(&cs);
}
代码写的不是很好,在多线程的处理上有缺陷。测试时发现有时会发生客户端得不到服务端发送数据的情况,可能是我用UDP通信的缘故吧。
本文有不足之处,还望大家多多指正。