程序地址:网页链接
注意:目前只支持win系统。
游戏做的不完整,只能用来体验体验。
最近接触了Pygame游戏编程,十分感兴趣,学习了一本相关书籍以及查阅了Pygame的官网https://www.pygame.org的资料,花了一周的时间写出了这个飞机大战的游戏。主体玩法相对完整,模拟的是逝去的手游帝王《雷霆战机》,算是对它多舛命运的哀悼吧。
话不多说,先看效果
什么,你问我素材哪里找的?万能的淘宝在这时候总不会让你失望!所有音频和图片素材均来自于淘宝。
这里跟大家分享几个制作过程中遇到的几个技术细节的解决方法,以及优化措施:
1.帧率不同步问题。
我用pygame.time.Clock对象来控制整个游戏的最大帧率为60。为什么说是最大呢?不是因为性能原因导致游戏帧率真的低于60(虽然在某些过程优化之前的确出现过卡的低于60帧的情况),是因为某些动画过程的帧率本就不是60,比如飞机爆炸的动画,就那么9帧,若60Hz播放的话就显得太快了,起初,我想到用重复的图片Surface对象填充这些应该重复的几帧,使得切换到下一帧的速度没那么快,但重复的图片对象会导致成倍数的内存占用,这是我不能忍受的。于是我用了一个FramNum对象,将重复的次数用正整数num表示,并增加计数点属性,当运行到下一次就增加一个计数点,若计数点达到了num,则运行下一帧。于是一个完整的动画帧Frame对象被设计成由FramNum对象组成,能够成倍数地减少在动画帧方面内存使用。
以下实现代码看不懂没关系,因为注释不清楚,而且有一些额外的设计没有被提及。
import pygame
class FrameNum:
def __init__(self, frame:pygame.Surface, num:int):
self.frame = frame
self.num = num
def __getframe(self):
return self.__frame
def __setframe(self, other):
self.__frame = other
frame = property(__getframe, __setframe)
def __getnum(self):
return self.__num
def __setnum(self, other):
self.__num = other
num = property(__getnum, __setnum)
def __mul__(self, other):
self.num *= other
return self
def __imul__(self, other):
self.num *= other
return self
def __getitem__(self, item):
if item == 0:
return self.frame
elif item == 1:
return self.num
else:
raise ValueError('indexvalue not 0 or 1!')
class Frame:
'like [[(frame1,num1),(frame2,num2)],[...]]'
LASTCIRCLE= b'\x01'
LASTSTICK = b'\x00'
def __init__(self, framelist, leisureframe=0):
self.framelist = framelist
# this condition
self.this_code = leisureframe
self.thiscondition = framelist[self.this_code]
# this condition len
self.thiscdlen = len(self.thiscondition)
# this frame
self.thisframe = 0
# this frame num
self.thisfnum = self.thiscondition[self.thisframe][1]
self.thisgone = 0
self.image = self.thiscondition[self.thisframe][0]
self.next_code = self.LASTCIRCLE
self.sticked = False
# 得到本状态的虚拟帧数目
self.leisureframe = leisureframe
def set_stick(self):
self.next_code = self.LASTSTICK
def unsetonce(self):
self.next_code = self.LASTCIRCLE
def update(self):
# 若为循环播放
if not self.sticked:
if self.next_code == self.LASTCIRCLE:
self.circleupdate()
elif self.next_code == self.LASTSTICK:
self.stickupdate()
else:
self.onceupdate()
def changecondition(self, condition_code):
self.thiscondition = self.framelist[condition_code]
self.thisgone = 0
self.thisframe = 0
self.this_code = condition_code
self.thiscdlen = len(self.thiscondition)
self.updateframe()
# 跳转condition代码
def set_next(self, next_code):
self.next_code = next_code
def set_condition(self, this_code):
self.this_code = this_code
def circleupdate(self):
# 若达到这一帧的最后一个
if self.thisgone >= self.thisfnum:
# 进入下一帧
self.nextframe()
# 若超过最后一帧
if self.thisframe >= self.thiscdlen:
self.thisframe = 0
self.thisgone = 0
# 图像变化
self.updateframe()
# 下一个虚帧
self.go()
def stickupdate(self):
if self.thisframe < self.thiscdlen - 1:
if self.thisgone >= self.thisfnum - 1:
self.nextframe()
self.updateframe()
else:
self.go()
elif self.thisframe == self.thiscdlen - 1:
if self.thisgone < self.thisfnum - 1:
self.go()
else:
if not self.sticked:
self.sticked = True
def onceupdate(self):
if not self.thisframe == self.next_code:
if self.thisframe < self.thiscdlen - 1:
if self.thisgone >= self.thisfnum: