PyOpenGL网络游戏应用
这个游戏很简单,可以操纵的飞机不断发子弹,前面不断有敌机来袭,子弹打中敌机然后敌机和子弹消失,最后实现了网络互联功能,允许两个人在局域网中不同机器上操作各自的飞机,平且两个游戏界面是同步的。
我这样设计的:自己维护一个飞机,子弹队列,敌机队列,将网络来的数据打包成另一个飞机,子弹队列,敌机队列,所以这里面传送的数据有自己飞机数据,子弹队列,敌机队列,这些数据通过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网络游戏应用相关推荐
- uc的剪切板能关掉吗_关掉网络游戏,小孩就有美好的未来吗?
"关掉,关掉!一定要关掉!再不关掉那些网络游戏,小孩哪有美好的未来,哪有美好的前程,祖国哪有栋梁之才."最近,一条魔性的小视频在网上刷屏.这条小视频里,一个小女孩用朗诵腔调大喊上面 ...
- 跨平台网络游戏趋势和优势
跨平台网络游戏趋势和优势 前几年还是网页游戏蓬勃发展的状态,就有分析指出从明年开始网页游戏市场已经饱和,想想几年前客户端游戏也是同样的窘境,如果将桌面.移动设备.网页统称一个词汇的话,那就是终端,现在 ...
- 网络游戏性能测试的几点想法
进入游戏行业也有一段时间了,在日常的工作中对游戏的性能测试也产生了一些想法,因此写出来与大家讨论讨论. 网络游戏行业现在越做越大,面也越来越广了,依我的观点主要分为以下几个方面: 1.传统的c/s架构 ...
- 浅谈网络游戏的设计——服务器端编程 (3)
关键词: 网络游戏 构思 策划 创意 竞争机制 竞争系统 本系列文章始终以浅谈二字开头,所以内容简单,不够深入,希望大家谅解. 但是,正如人类的学习过程一样,是一个由浅入深的过程.市面上很多昂贵的图书 ...
- python 粒子动画_初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞
我认为比较完善的GPU粒子系统应该如下,粒子初始化可以放在CPU里,但是相关数据运算首先要放在GPU里,并且运算后的数据也应该放在显存里,而不是内存里.故用第三篇实现GPU粒子系统不满足,因为他数据是 ...
- C++网络游戏程序员笔试题
转自:http://www.yjbys.com/Qiuzhizhinan/show-68301.html 以下给出的是我之前参加一家网络游戏公司招聘C++程序员的笔试题,这套题目整个测试的时间长达三个 ...
- 计算机学院特色游戏,网络游戏七大特点浅析
摘 要:作为国家文化产业发展战略的重要一环和互联网文化产业的重要组成部分,网络游戏的发展研究一直颇受关注.尽管网络游戏迅猛发展,其最基本特点一直未曾改变.本文将以传播学角度出发点,浅析网络游戏的七大特 ...
- python pyOpenGL安装
win10直接安装会报错,需要下载安装:3.1.5测试成功 下载地址: https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl https://pyp ...
- 浅谈网络游戏《天龙X部》的文件加密格式
三月份时玩了某狐公司的网络游戏<天龙X部>,感觉还是蛮有意思的,遂研究了一下. 这个游戏是利用开源游戏引擎OGRE进行开发的,看了一下目录里面的文件结构,主要的数 据都放在Data目录下面 ...
最新文章
- [Spark][翻译]Spark 架构: Shuffle过程分析
- asp.net用户登录 用户验证
- 好程序员技术教程分享JavaScript运动框架
- mysql移动文件后打不开_Windows端MySQL data目录迁移(貌似会启动不了)
- 织梦php网站修改教程,织梦DEDEcms织梦软件模型增加图集功能教程(含修改文件下载)...
- 操作系统课设之Windows 进程管理
- 年轻人逃离大城市之后的下一站选哪儿?用数据来为你揭晓
- 408中的计算机组成原理,2021考研计算机大纲408计算机组成原理部分原文解析
- 二分查找 —— 有序数组不小于(不大于)某数的第一个(最后一个)元素
- Linux系统的Redis的安装与运行
- DFM弹幕库在直播中的使用
- 3D模型欣赏:反派角色部落女战士 【3D游戏建模教程】
- 微信人脸识别-采集个人信息
- SMS之SMS2003+SP3
- Liber 1. 《活着》:人生如逆旅,我亦是行人
- 卡券、直充订单列表(post 表单提交)接口
- MySQL里什么是主键_mysql主键是什么?
- C#链接SQL知识点
- NCBI|16S原始数据上传
- 更新Qt Creator版本后打开之前的项目,只有.Pro的问题.
热门文章
- TS流包长的简单判断(188/204B)
- 收银员是这样给万像做手脚的(转)
- 朱光潜《给青年的十二封信》
- 寻找手机手势解锁共有多少种解法
- 《云计算应用架构》连载三:Amazon EC2
- 网络安全行业需要学历吗?需要考研吗?
- 感性电路电流计算_220和380V功率和电流计算知识
- ArcGIS VS QGIS——两者之间的27点比较
- 【Spark】Could not locate executable null\bin\winutils.exe in the Hadoop binaries
- {literal} php 标签,Smarty中{literal}的使用详解