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
游戏代码:
- #-*- coding:utf-8 -*-
- import sys,struct
- import random,math,thread,time,socket,string,re
- try:
- from OpenGL.GLUT import *
- from OpenGL.GL import *
- from OpenGL.GLU import *
- except:
- print '''''
- ERROR: PyOpenGL not installed properly.
- '''
- sys.exit()
- x_coord=10
- y_coord=10
- isAserver=False #True为服务端,False为客户端
- #数值统统为4个字节,最高位为符号位,1600万足矣,低字节为低位
- def westicenumtostring(num):
- tempnum=abs(num)
- tempnum=int(tempnum)
- s=''
- i=0
- while tempnum>0:
- s=s+chr(tempnum%256)
- tempnum=int(tempnum/256)
- i+=1
- while len(s)<3:#补齐3位
- s=s+chr(0)
- if num<0:
- s=s+chr(1)
- else:#0和正数最高位为0
- s=s+chr(0)
- return s
- def westicestringtonum(s):
- if len(s)!=4:
- print 'len(s) must be 4'
- return None
- n0=ord(s[0])
- n1=ord(s[1])
- n2=ord(s[2])
- n3=ord(s[3])
- num=n0+256*n1+256*256*n2
- if n3==1:#负数
- num=(-num)
- if n3!=0 and n3!=1:
- return "wrong string when convert ro number"
- return num
- def drawenemy(x,y): #画敌人形象
- glLoadIdentity()
- glTranslate(x,y,0.0)
- glScale(0.2,0.2,0.2)
- glBegin(GL_POLYGON)
- glVertex3f(1.0,1.0,0)
- glVertex3f(1.0,-1.0,0)
- glColor3f(1.0,0.0,0.0)
- glVertex3f(-1.0,-1.0,0)
- glVertex3f(-1.0,1.0,0)
- glEnd()
- def drawbullet(x,y):#画子弹形象
- glLoadIdentity()
- glTranslate(x,y,0.0)
- glScale(0.1,0.1,0.1)
- glBegin(GL_POLYGON)
- glColor3f(0.0,1.0,0.0)
- glVertex3f(0.5,1.0,0)
- glVertex3f(0.5,-1.0,0)
- glVertex3f(-0.5,-1.0,0)
- glVertex3f(-0.5,1.0,0)
- glEnd()
- def drawpalne(x,y,rquad):#画玩家飞机形象
- glLoadIdentity()
- glTranslate(x,y,0.0)
- glRotatef(rquad,0.0,1.0,0.0) # Rotate
- glScale(0.5,0.5,0.5)
- glBegin(GL_POLYGON) # Start drawing
- glColor3f(1.0,0.0,0.0)
- glVertex3f(1.0,0.0,0.0)
- glColor3f(0.0,1.0,0.0)
- glVertex3f(-1.0,0.0,0.0)
- glColor3f(0.0,0.0,1.0)
- glVertex3f(0.0,3.0,0.0)
- glEnd() # We are done with the polygon
- glBegin(GL_POLYGON)
- glVertex3f(0.0,0.0,0)
- glVertex3f(0.0,3.0,0)
- glColor3f(1.0,0.0,0.0)
- glVertex3f(0.0,0.5,0.5)
- glEnd()
- class Enemy(): #定义敌人
- def __init__(self):
- self.reset()
- def update(self):
- if self.live:
- self.y-=0.01
- self.draw()
- if self.y<0:
- self.live=False
- def setxy(self,x,y):
- self.x=x
- self.y=y
- def draw(self):
- drawenemy(self.x,self.y)
- def reset(self):
- self.x=x_coord*random.random()
- self.y=y_coord
- self.live=True #活着状态
- class Bullet():#定义子弹
- def __init__(self,x,y):
- self.reset(x,y)
- self.live=False
- def update(self):
- if self.live:
- self.y+=0.05
- self.draw()
- if self.y>y_coord:
- self.live=False
- def draw(self):
- drawbullet(self.x,self.y)
- def reset(self,x,y):
- self.x=x
- self.y=y
- self.live=True
- class Plane():
- def __init__(self,x,y):
- self.x=x
- self.y=y
- self.rquad=0
- def update(self):
- self.draw()
- if self.rquad<0:
- self.rquad+=1.0
- if self.rquad>0:
- self.rquad-=1.0
- def draw(self):
- drawpalne(self.x,self.y,self.rquad)
- def left(self):
- self.x-=0.1
- if self.rquad>-40:#限制
- self.rquad-=3
- def right(self):
- self.x+=0.1
- if self.rquad<40:
- self.rquad+=3
- westiceplane=None
- myenemylist=None
- bulletlist=None
- otherplane=None
- otherenemylist=None
- otherbulletlist=None
- frameobj=None
- #网络用帧
- class netframe():
- def __init__(self,player,mybulletlist,enemylist):
- self.player=player
- self.mybulletlist=mybulletlist
- self.enemylist=enemylist
- def senddata(self,conn):
- global isconnected
- senddata=''
- senddata+=westicenumtostring(self.player.x*1000)
- senddata+=westicenumtostring(self.player.y*1000)
- senddata+=westicenumtostring(self.player.rquad*1000)#自己的位置
- senddata+=westicenumtostring(len(self.mybulletlist))#子弹个数
- for bullet in self.mybulletlist:
- senddata+=westicenumtostring(bullet.x*1000)
- senddata+=westicenumtostring(bullet.y*1000)#子弹位置
- senddata+=westicenumtostring(len(self.enemylist))#敌人个数
- for enemy in self.enemylist:
- senddata+=westicenumtostring(enemy.x*1000)
- senddata+=westicenumtostring(enemy.y*1000)#敌人位置
- if isconnected:
- try:
- conn.send(senddata)
- except socket.error:
- isconnected=False
- #conn.sendall(senddata)
- #接收数据
- def recvdata(self,conn):
- global otherplane
- global otherenemylist
- global otherbulletlist
- global isconnected
- if isconnected:
- try:
- recvdata=conn.recv(4)
- otherplanex=westicestringtonum(recvdata)/1000.0
- recvdata=conn.recv(4)
- otherplaney=westicestringtonum(recvdata)/1000.0
- otherplane=Plane(otherplanex,otherplaney)
- recvdata=conn.recv(4)
- otherplane.rquad=westicestringtonum(recvdata)/1000.0
- recvdata=conn.recv(4)#接收子弹数据
- bulletnum=westicestringtonum(recvdata)
- otherbulletlist=[]
- for i in range(bulletnum):
- recvdata=conn.recv(4)
- bulletx=westicestringtonum(recvdata)/1000.0
- recvdata=conn.recv(4)
- bullety=westicestringtonum(recvdata)/1000.0
- bullet=Bullet(bulletx,bullety)
- bullet.live=True
- otherbulletlist.append(bullet)
- recvdata=conn.recv(4)
- enemynum=westicestringtonum(recvdata)
- otherenemylist=[]
- for i in range(enemynum):
- recvdata=conn.recv(4)
- enemyx=westicestringtonum(recvdata)/1000.0
- recvdata=conn.recv(4)
- enemyy=westicestringtonum(recvdata)/1000.0
- enemy=Enemy()
- enemy.setxy(enemyx,enemyy)
- otherenemylist.append(enemy)
- except socket.error:
- isconnected=False
- #游戏服务器
- port=8088 #主数据通道
- conn=None#socket连接对象,可能是服务器或客户端
- serverUDPport=9090
- clientTCPport=9091
- isconnected=False
- class GameServer():
- def __init__(self):
- print '初始化游戏服务器'
- global conn
- global otherplane
- global otherenemylist
- global otherbulletlist
- global frameobj
- global isconnected
- global serverUDPport
- global clientTCPport
- #服务器接收客户UDP报文,如果验证通过向客户发送TCP回应
- UDPsock0=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
- UDPsock0.bind(("",serverUDPport))
- #还需验证客户端,用udp
- recvstring,clientaddr=UDPsock0.recvfrom(1024)
- if recvstring=="west":
- print "服务器收到验证from ",clientaddr[0]
- UDPsock0.close()
- #服务器发送tcp回应
- tempconn=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- tempconn.connect((clientaddr[0],clientTCPport))
- tempconn.send("sure")
- tempconn.close()
- #创建TCP服务器
- TCPsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- TCPsock.bind(('',port))
- TCPsock.listen(5)
- conn,clientaddr=TCPsock.accept()
- print "来自客户端:",clientaddr
- isconnected=True
- while isconnected: #服务端循环,先发后收
- frameobj.senddata(conn)
- time.sleep(0.02)
- frameobj.recvdata(conn)
- conn.close()
- #游戏客户端
- class GameClient():
- def __init__(self):
- print '初始化游戏客户端'
- global conn
- global frameobj
- global isconnected
- global serverUDPport
- global clientTCPport
- self.lanserverip=None
- #搜索服务器,向局域网内发送udp数据
- ip=socket.gethostbyname(socket.gethostname())
- match_str="\d+\.\d+\.\d+\."
- ipheader=re.match(match_str,ip)
- ipheader=ipheader.group()
- UDPsock0=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
- for i in range(1,256):
- self.lanserverip=ipheader+str(i)
- UDPsock0.sendto("west",(self.lanserverip,serverUDPport))
- UDPsock0.close()
- #客户端建立tcp服务器 接收服务器ip和其它信息,之后断开,连接服务器的tcp
- TCPsock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- TCPsock.bind(('',clientTCPport))
- TCPsock.listen(5)
- tempconn,serveraddr=TCPsock.accept()
- hellomsg=tempconn.recv(4)
- tempconn.close()
- self.lanserverip=serveraddr[0]
- print "服务器为:",self.lanserverip
- print "服务器信息:",hellomsg
- #连接tcp服务器发送数据
- conn=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- conn.connect((self.lanserverip,port))
- isconnected=True
- while isconnected:#客户端循环,先收后发
- frameobj.recvdata(conn)
- frameobj.senddata(conn)
- time.sleep(0.02)
- conn.close()
- def threadfunc():#线程函数
- global isAserver
- if isAserver:
- gameserver=GameServer()
- else:
- gameclient=GameClient()
- def GameInit():
- global x_coord
- global y_coord
- global westiceplane
- global myenemylist
- global mybulletlist
- global frameobj
- westiceplane=Plane(x_coord/2,1)#加入飞机
- myenemylist=[]
- for i in range(4): #加入敌人
- westiceenemy=Enemy()
- myenemylist.append(westiceenemy)
- mybulletlist=[]
- for i in range(20):
- mywesticebullet=Bullet(westiceplane.x,westiceplane.y)
- mybulletlist.append(mywesticebullet)
- #新建一个线程处理网络
- thread.start_new_thread(threadfunc,())
- frameobj=netframe(westiceplane,mybulletlist,myenemylist)
- def init():
- glClearColor(0.5,0.5,0.5,0.0)
- glClearDepth(1.0) # Enables Clearing Of The Depth Buffer
- glDepthFunc(GL_LESS) # The Type Of Depth Test To Do
- glEnable(GL_DEPTH_TEST) # Enables Depth Testing
- glShadeModel(GL_SMOOTH) # Enables Smooth Color Shading
- def calcdistance(object0,object1):
- return math.sqrt(pow(object0.x-object1.x,2)+pow(object0.y-object1.y,2))
- count=0
- def display():
- #print 'display'
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
- westiceplane.update()
- for enemy in myenemylist:
- enemy.update()
- if not enemy.live:
- enemy.reset()
- for bullet in mybulletlist:
- if calcdistance(bullet,enemy)<=0.2:#是否相遇
- bullet.live=False
- enemy.live=False
- #自动发射子弹
- global count
- if count>=15:
- count=0
- for bullet in mybulletlist:
- if not bullet.live:
- bullet.reset(westiceplane.x,westiceplane.y+1)#激活一颗
- break
- for bullet in mybulletlist:
- bullet.update()
- count+=1
- #显示网络来的数据
- global otherplane
- global otherenemylist
- global otherbulletlist
- if isconnected and otherplane:
- otherplane.draw()
- if isconnected and otherbulletlist and otherenemylist and otherplane:
- otherplane.draw()
- for myenemy in myenemylist:
- for otherbullet in otherbulletlist:
- if calcdistance(otherbullet,myenemy)<=0.2:#是否相遇
- otherbullet.live=False
- myenemy.live=False
- for otherenemy in otherenemylist:
- if otherenemy.live:
- otherenemy.draw()
- for otherbullet in otherbulletlist:
- if otherbullet.live:
- otherbullet.draw()
- glutSwapBuffers()
- #glFlush()
- def reshape(w,h):
- print 'reshape'
- glViewport(0,0,w,h)
- glMatrixMode(GL_PROJECTION)
- glLoadIdentity()
- print 'w:',w,' h:',h
- if w!=0 and h!=0:
- global x_coord
- global y_coord
- if(w<=h):
- gluOrtho2D(0.0,x_coord,0.0,x_coord*h/w)
- else:
- gluOrtho2D(0.0,x_coord*w/h,0.0,x_coord)
- glMatrixMode(GL_MODELVIEW)
- def keyboard(key,x,y):
- # if key==chr(27):
- # sys.exit(0)
- if key=='a'or key=='A':
- westiceplane.left()
- if key=='d'or key=='D':
- westiceplane.right()
- GameInit()
- glutInit(sys.argv)
- glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH) #使用双缓冲和深度测试
- glutInitWindowSize(600,500)
- glutInitWindowPosition(100,100)
- if isAserver:
- glutCreateWindow('Game Server')
- else:
- glutCreateWindow('Game Client')
- init()
- glutReshapeFunc(reshape)
- glutKeyboardFunc(keyboard)
- glutDisplayFunc(display)
- glutIdleFunc(display)
- glutMainLoop()
From:http://westice.iteye.com/blog/979045
- PyOpenGL网络游戏应用
- PyOpenGL
- p2p在网络游戏中的应用
- 网络游戏
- 网络游戏
- 网络游戏
- SPSS数据分析网络游戏行业应用范例
- SPSS数据分析网络游戏行业应用范例
- PyOpenGl 1 -- 环境安装
- pyOpenGL实例讲解
- pyopengl glutInit error
- ubuntu 下 安装 PyOpenGL
- PyOpenGL 资料汇总
- PyOpenGL做曲面
- PyOpenGL-安装与测试
- ACE框架在网络游戏服务器中的设计与应用
- ACE框架在网络游戏服务器中的设计与应用
- ACE框架在网络游戏服务器中的设计与应用
- DataSet与XML的交互
- SQL Server SQL高级查询语句小结
- Linux命令之sort的使用
- 面向过程和面向对象的编程----话题讲座
- CRectTracker(橡皮筋)类的使用
- PyOpenGL网络游戏应用
- 基础总结篇之一:Activity生命周期
- ACM题目推荐(刘汝佳书上出现的一些题目)
- typedef (包含对复杂函数声明的理解)
- 反序列化一个复杂的JSON结果(数组字典与TouchJSON)
- 一些话
- Java读取properties文件 【转】
- 鼠标拖动动态改变表格的宽度的js脚本 兼容ie/firefox
- axis1.4将默认的HTTP1.0短连接设置成HTTP1.1短连接