PyOpenGL网络游戏应用

来源:互联网 发布:袜子淘宝店铺名字大全 编辑:程序博客网 时间:2024/06/05 07:11

  这个游戏很简单,可以操纵的飞机不断发子弹,前面不断有敌机来袭,子弹打中敌机然后敌机和子弹消失,最后实现了网络互联功能,允许两个人在局域网中不同机器上操作各自的飞机,平且两个游戏界面是同步的。

我这样设计的:自己维护一个飞机,子弹队列,敌机队列,将网络来的数据打包成另一个飞机,子弹队列,敌机队列,所以这里面传送的数据有自己飞机数据,子弹队列,敌机队列,这些数据通过TCP在服务器和客户端之间不断更新,传递。

     图形用opengl渲染,由于python不能直接访问指针,通过网络只能传递字符串型,所以传送二进制数据有点问题,自己写了对函数,用于字符串和二进制数的转换,每个数由长度为4的字符串组成,索引高的为数据高位,最高位为符号位,所以只能保存-1600万到1600万之间的数,对于视频游戏这个范围足矣,但有个缺陷,不知道怎么传浮点数,所以需要浮点数的地方先*1000,传送后除以1000得到浮点数。

     为了更像网络游戏,跟CS一样能自动搜索局域网中的服务器,实现了一个较简单实用的方法,大致是这样的:服务器启动后开放一个udp端口udpport,客户端向局域网中所有机器udpport发送验证信息,建立一个临时TCP端口tcpport0,当服务器端客户验证通过后向刚才的客户机tcpport0发送欢迎信息,这样客户机就得到了服务器的ip地址(还可同时进行一些必要的初始化),到此客户端便开始正式通过tcp与服务器交换游戏信息。

 

pyOpengl安装方法:http://pyopengl.sourceforge.net/documentation/installation.html

 

游戏代码:

 

Python代码  收藏代码
  1. #-*- coding:utf-8 -*-  
  2.   
  3. import sys,struct  
  4. import random,math,thread,time,socket,string,re  
  5. try:  
  6.   from OpenGL.GLUT import *  
  7.   from OpenGL.GL import *  
  8.   from OpenGL.GLU import *  
  9. except:  
  10.   print ''''' 
  11. ERROR: PyOpenGL not installed properly.   
  12.         '''  
  13.   sys.exit()  
  14. x_coord=10  
  15. y_coord=10  
  16. isAserver=False     #True为服务端,False为客户端  
  17.   
  18. #数值统统为4个字节,最高位为符号位,1600万足矣,低字节为低位  
  19. def westicenumtostring(num):  
  20.     tempnum=abs(num)  
  21.     tempnum=int(tempnum)  
  22.     s=''  
  23.     i=0  
  24.     while tempnum>0:  
  25.        s=s+chr(tempnum%256)  
  26.        tempnum=int(tempnum/256)   
  27.        i+=1  
  28.     while len(s)<3:#补齐3位  
  29.        s=s+chr(0)  
  30.     if num<0:  
  31.         s=s+chr(1)  
  32.     else:#0和正数最高位为0  
  33.         s=s+chr(0)  
  34.     return s  
  35.   
  36. def westicestringtonum(s):  
  37.     if len(s)!=4:  
  38.         print 'len(s) must be 4'  
  39.         return None  
  40.     n0=ord(s[0])  
  41.     n1=ord(s[1])  
  42.     n2=ord(s[2])  
  43.     n3=ord(s[3])  
  44.     num=n0+256*n1+256*256*n2  
  45.     if n3==1:#负数  
  46.         num=(-num)  
  47.     if n3!=0 and n3!=1:  
  48.         return "wrong string when convert ro number"  
  49.     return num  
  50.   
  51. def drawenemy(x,y): #画敌人形象  
  52.     glLoadIdentity()  
  53.     glTranslate(x,y,0.0)  
  54.     glScale(0.2,0.2,0.2)  
  55.     glBegin(GL_POLYGON)    
  56.     glVertex3f(1.0,1.0,0)  
  57.     glVertex3f(1.0,-1.0,0)  
  58.     glColor3f(1.0,0.0,0.0)  
  59.     glVertex3f(-1.0,-1.0,0)  
  60.     glVertex3f(-1.0,1.0,0)  
  61.     glEnd()  
  62.   
  63. def drawbullet(x,y):#画子弹形象  
  64.    glLoadIdentity()  
  65.    glTranslate(x,y,0.0)  
  66.    glScale(0.1,0.1,0.1)  
  67.    glBegin(GL_POLYGON)    
  68.    glColor3f(0.0,1.0,0.0)            
  69.    glVertex3f(0.5,1.0,0)  
  70.    glVertex3f(0.5,-1.0,0)  
  71.    glVertex3f(-0.5,-1.0,0)  
  72.    glVertex3f(-0.5,1.0,0)  
  73.    glEnd()  
  74.   
  75. def drawpalne(x,y,rquad):#画玩家飞机形象  
  76.     glLoadIdentity()  
  77.     glTranslate(x,y,0.0)  
  78.     glRotatef(rquad,0.0,1.0,0.0)        # Rotate   
  79.     glScale(0.5,0.5,0.5)  
  80.     glBegin(GL_POLYGON)                   # Start drawing   
  81.     glColor3f(1.0,0.0,0.0)  
  82.     glVertex3f(1.0,0.0,0.0)         
  83.     glColor3f(0.0,1.0,0.0)  
  84.     glVertex3f(-1.0,0.0,0.0)           
  85.     glColor3f(0.0,0.0,1.0)  
  86.     glVertex3f(0.0,3.0,0.0)           
  87.     glEnd()                             # We are done with the polygon  
  88.       
  89.     glBegin(GL_POLYGON)    
  90.     glVertex3f(0.0,0.0,0)  
  91.     glVertex3f(0.0,3.0,0)  
  92.     glColor3f(1.0,0.0,0.0)  
  93.     glVertex3f(0.0,0.5,0.5)  
  94.     glEnd()  
  95.       
  96. class Enemy(): #定义敌人  
  97.     def __init__(self):  
  98.         self.reset()  
  99.     def update(self):  
  100.         if self.live:  
  101.            self.y-=0.01  
  102.            self.draw()  
  103.            if self.y<0:  
  104.                self.live=False   
  105.     def setxy(self,x,y):  
  106.         self.x=x  
  107.         self.y=y  
  108.     def draw(self):  
  109.         drawenemy(self.x,self.y)  
  110.     def reset(self):  
  111.         self.x=x_coord*random.random()  
  112.         self.y=y_coord  
  113.         self.live=True #活着状态  
  114.           
  115. class Bullet():#定义子弹  
  116.     def __init__(self,x,y):  
  117.         self.reset(x,y)  
  118.         self.live=False  
  119.     def update(self):  
  120.         if self.live:  
  121.            self.y+=0.05  
  122.            self.draw()  
  123.            if self.y>y_coord:  
  124.                self.live=False             
  125.     def draw(self):  
  126.         drawbullet(self.x,self.y)  
  127.     def reset(self,x,y):  
  128.         self.x=x  
  129.         self.y=y  
  130.         self.live=True  
  131.   
  132. class Plane():  
  133.     def __init__(self,x,y):  
  134.         self.x=x  
  135.         self.y=y  
  136.         self.rquad=0  
  137.     def update(self):  
  138.         self.draw()  
  139.         if self.rquad<0:  
  140.            self.rquad+=1.0  
  141.         if self.rquad>0:  
  142.            self.rquad-=1.0  
  143.     def draw(self):  
  144.         drawpalne(self.x,self.y,self.rquad)  
  145.     def left(self):  
  146.         self.x-=0.1  
  147.         if self.rquad>-40:#限制  
  148.            self.rquad-=3  
  149.     def right(self):  
  150.         self.x+=0.1  
  151.         if self.rquad<40:  
  152.            self.rquad+=3  
  153.              
  154. westiceplane=None  
  155. myenemylist=None  
  156. bulletlist=None  
  157. otherplane=None  
  158. otherenemylist=None  
  159. otherbulletlist=None  
  160. frameobj=None  
  161. #网络用帧  
  162. class netframe():  
  163.     def __init__(self,player,mybulletlist,enemylist):  
  164.         self.player=player  
  165.         self.mybulletlist=mybulletlist  
  166.         self.enemylist=enemylist  
  167.     def senddata(self,conn):  
  168.         global isconnected  
  169.         senddata=''  
  170.         senddata+=westicenumtostring(self.player.x*1000)  
  171.         senddata+=westicenumtostring(self.player.y*1000)   
  172.         senddata+=westicenumtostring(self.player.rquad*1000)#自己的位置  
  173.         senddata+=westicenumtostring(len(self.mybulletlist))#子弹个数  
  174.         for bullet in self.mybulletlist:  
  175.             senddata+=westicenumtostring(bullet.x*1000)  
  176.             senddata+=westicenumtostring(bullet.y*1000)#子弹位置  
  177.         senddata+=westicenumtostring(len(self.enemylist))#敌人个数  
  178.         for enemy in self.enemylist:  
  179.             senddata+=westicenumtostring(enemy.x*1000)  
  180.             senddata+=westicenumtostring(enemy.y*1000)#敌人位置  
  181.         if isconnected:  
  182.            try:       
  183.               conn.send(senddata)  
  184.            except socket.error:  
  185.               isconnected=False  
  186.         #conn.sendall(senddata)  
  187.     #接收数据  
  188.     def recvdata(self,conn):  
  189.         global otherplane  
  190.         global otherenemylist  
  191.         global otherbulletlist  
  192.         global isconnected  
  193.         if isconnected:  
  194.             try:  
  195.                  recvdata=conn.recv(4)  
  196.                  otherplanex=westicestringtonum(recvdata)/1000.0  
  197.                  recvdata=conn.recv(4)  
  198.                  otherplaney=westicestringtonum(recvdata)/1000.0  
  199.                  otherplane=Plane(otherplanex,otherplaney)  
  200.                  recvdata=conn.recv(4)  
  201.                  otherplane.rquad=westicestringtonum(recvdata)/1000.0  
  202.                  recvdata=conn.recv(4)#接收子弹数据  
  203.                  bulletnum=westicestringtonum(recvdata)  
  204.                  otherbulletlist=[]  
  205.                  for i in range(bulletnum):  
  206.                      recvdata=conn.recv(4)  
  207.                      bulletx=westicestringtonum(recvdata)/1000.0  
  208.                      recvdata=conn.recv(4)  
  209.                      bullety=westicestringtonum(recvdata)/1000.0  
  210.                      bullet=Bullet(bulletx,bullety)  
  211.                      bullet.live=True  
  212.                      otherbulletlist.append(bullet)  
  213.                        
  214.                  recvdata=conn.recv(4)  
  215.                  enemynum=westicestringtonum(recvdata)  
  216.                  otherenemylist=[]  
  217.                  for i in range(enemynum):  
  218.                      recvdata=conn.recv(4)  
  219.                      enemyx=westicestringtonum(recvdata)/1000.0  
  220.                      recvdata=conn.recv(4)  
  221.                      enemyy=westicestringtonum(recvdata)/1000.0  
  222.                      enemy=Enemy()      
  223.                      enemy.setxy(enemyx,enemyy)  
  224.                      otherenemylist.append(enemy)  
  225.             except socket.error:  
  226.                 isconnected=False  
  227.       
  228. #游戏服务器  
  229. port=8088  #主数据通道  
  230. conn=None#socket连接对象,可能是服务器或客户端  
  231. serverUDPport=9090    
  232. clientTCPport=9091    
  233. isconnected=False  
  234. class GameServer():  
  235.     def __init__(self):  
  236.         print '初始化游戏服务器'  
  237.         global conn  
  238.         global otherplane  
  239.         global otherenemylist  
  240.         global otherbulletlist  
  241.         global frameobj  
  242.         global isconnected  
  243.         global serverUDPport  
  244.         global clientTCPport  
  245.           
  246.         #服务器接收客户UDP报文,如果验证通过向客户发送TCP回应  
  247.         UDPsock0=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)      
  248.         UDPsock0.bind(("",serverUDPport))  
  249.         #还需验证客户端,用udp  
  250.         recvstring,clientaddr=UDPsock0.recvfrom(1024)  
  251.         if recvstring=="west":  
  252.             print "服务器收到验证from ",clientaddr[0]  
  253.         UDPsock0.close()  
  254.           
  255.         #服务器发送tcp回应  
  256.         tempconn=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    
  257.         tempconn.connect((clientaddr[0],clientTCPport))  
  258.         tempconn.send("sure")  
  259.         tempconn.close()  
  260.           
  261.         #创建TCP服务器  
  262.         TCPsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
  263.         TCPsock.bind(('',port))  
  264.         TCPsock.listen(5)          
  265.         conn,clientaddr=TCPsock.accept()  
  266.         print "来自客户端:",clientaddr  
  267.         isconnected=True      
  268.         while isconnected: #服务端循环,先发后收  
  269.             frameobj.senddata(conn)  
  270.             time.sleep(0.02)  
  271.             frameobj.recvdata(conn)  
  272.         conn.close()  
  273.               
  274. #游戏客户端  
  275. class GameClient():  
  276.     def __init__(self):  
  277.         print '初始化游戏客户端'  
  278.         global conn  
  279.         global frameobj  
  280.         global isconnected  
  281.         global serverUDPport  
  282.         global clientTCPport  
  283.         self.lanserverip=None  
  284.         #搜索服务器,向局域网内发送udp数据  
  285.         ip=socket.gethostbyname(socket.gethostname())  
  286.         match_str="\d+\.\d+\.\d+\."  
  287.         ipheader=re.match(match_str,ip)  
  288.         ipheader=ipheader.group()  
  289.         UDPsock0=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)      
  290.         for i in range(1,256):  
  291.             self.lanserverip=ipheader+str(i)  
  292.             UDPsock0.sendto("west",(self.lanserverip,serverUDPport))  
  293.         UDPsock0.close()  
  294.           
  295.         #客户端建立tcp服务器  接收服务器ip和其它信息,之后断开,连接服务器的tcp  
  296.         TCPsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
  297.         TCPsock.bind(('',clientTCPport))  
  298.         TCPsock.listen(5)      
  299.         tempconn,serveraddr=TCPsock.accept()  
  300.         hellomsg=tempconn.recv(4)  
  301.         tempconn.close()  
  302.         self.lanserverip=serveraddr[0]  
  303.         print "服务器为:",self.lanserverip  
  304.         print "服务器信息:",hellomsg  
  305.           
  306.         #连接tcp服务器发送数据  
  307.         conn=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    
  308.         conn.connect((self.lanserverip,port))  
  309.         isconnected=True  
  310.         while isconnected:#客户端循环,先收后发  
  311.             frameobj.recvdata(conn)  
  312.             frameobj.senddata(conn)  
  313.             time.sleep(0.02)  
  314.         conn.close()  
  315.   
  316. def threadfunc():#线程函数  
  317.     global isAserver  
  318.     if isAserver:  
  319.         gameserver=GameServer()  
  320.     else:  
  321.         gameclient=GameClient()  
  322.   
  323. def GameInit():  
  324.     global x_coord  
  325.     global y_coord  
  326.     global westiceplane  
  327.     global myenemylist  
  328.     global mybulletlist  
  329.     global frameobj  
  330.     westiceplane=Plane(x_coord/2,1)#加入飞机  
  331.     myenemylist=[]  
  332.     for i in range(4):  #加入敌人  
  333.         westiceenemy=Enemy()  
  334.         myenemylist.append(westiceenemy)  
  335.     mybulletlist=[]  
  336.     for i in range(20):  
  337.         mywesticebullet=Bullet(westiceplane.x,westiceplane.y)  
  338.         mybulletlist.append(mywesticebullet)  
  339.     #新建一个线程处理网络  
  340.     thread.start_new_thread(threadfunc,())  
  341.     frameobj=netframe(westiceplane,mybulletlist,myenemylist)  
  342.       
  343. def init():  
  344.     glClearColor(0.5,0.5,0.5,0.0)  
  345.     glClearDepth(1.0)                    # Enables Clearing Of The Depth Buffer  
  346.     glDepthFunc(GL_LESS)                # The Type Of Depth Test To Do  
  347.     glEnable(GL_DEPTH_TEST)                # Enables Depth Testing  
  348.     glShadeModel(GL_SMOOTH)                # Enables Smooth Color Shading  
  349.   
  350. def calcdistance(object0,object1):  
  351.     return math.sqrt(pow(object0.x-object1.x,2)+pow(object0.y-object1.y,2))  
  352.   
  353. count=0  
  354. def display():  
  355.     #print 'display'  
  356.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)  
  357.     westiceplane.update()  
  358.     for enemy in myenemylist:  
  359.         enemy.update()  
  360.         if not enemy.live:  
  361.             enemy.reset()   
  362.         for bullet in mybulletlist:  
  363.             if calcdistance(bullet,enemy)<=0.2:#是否相遇  
  364.                 bullet.live=False  
  365.                 enemy.live=False  
  366.     #自动发射子弹  
  367.     global count  
  368.     if count>=15:  
  369.         count=0  
  370.         for bullet in mybulletlist:  
  371.             if not bullet.live:  
  372.                 bullet.reset(westiceplane.x,westiceplane.y+1)#激活一颗  
  373.                 break  
  374.       
  375.     for bullet in mybulletlist:  
  376.         bullet.update()      
  377.     count+=1  
  378.     #显示网络来的数据  
  379.     global otherplane  
  380.     global otherenemylist  
  381.     global otherbulletlist  
  382.     if isconnected and otherplane:  
  383.        otherplane.draw()  
  384.     if isconnected and otherbulletlist and otherenemylist and otherplane:  
  385.         otherplane.draw()  
  386.         for myenemy in myenemylist:  
  387.             for otherbullet in otherbulletlist:  
  388.                 if calcdistance(otherbullet,myenemy)<=0.2:#是否相遇  
  389.                    otherbullet.live=False      
  390.                    myenemy.live=False     
  391.         for otherenemy in otherenemylist:  
  392.             if otherenemy.live:  
  393.                otherenemy.draw()  
  394.         for otherbullet in otherbulletlist:  
  395.             if otherbullet.live:  
  396.                otherbullet.draw()  
  397.       
  398.     glutSwapBuffers()  
  399.     #glFlush()  
  400.   
  401. def reshape(w,h):  
  402.    print 'reshape'  
  403.    glViewport(0,0,w,h)  
  404.    glMatrixMode(GL_PROJECTION)  
  405.    glLoadIdentity()  
  406.    print 'w:',w,' h:',h  
  407.    if w!=0 and h!=0:  
  408.        global x_coord  
  409.        global y_coord  
  410.        if(w<=h):  
  411.           gluOrtho2D(0.0,x_coord,0.0,x_coord*h/w)  
  412.        else:  
  413.           gluOrtho2D(0.0,x_coord*w/h,0.0,x_coord)  
  414.    glMatrixMode(GL_MODELVIEW)  
  415.   
  416. def keyboard(key,x,y):  
  417. #   if key==chr(27):  
  418. #      sys.exit(0)  
  419.     if key=='a'or key=='A':  
  420.        westiceplane.left()  
  421.     if key=='d'or key=='D':  
  422.        westiceplane.right()  
  423.   
  424.   
  425. GameInit()  
  426. glutInit(sys.argv)  
  427. glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH) #使用双缓冲和深度测试  
  428. glutInitWindowSize(600,500)   
  429. glutInitWindowPosition(100,100)  
  430. if isAserver:  
  431.     glutCreateWindow('Game Server')  
  432. else:  
  433.     glutCreateWindow('Game Client')  
  434. init()  
  435. glutReshapeFunc(reshape)  
  436. glutKeyboardFunc(keyboard)  
  437. glutDisplayFunc(display)  
  438. glutIdleFunc(display)  
  439.   
  440. glutMainLoop()  
 

 From:http://westice.iteye.com/blog/979045

原创粉丝点击