IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Pygame游戏飞机大战《星野守望》 -> 正文阅读

[游戏开发]Pygame游戏飞机大战《星野守望》

想体验一下的话,文末给出百度网盘网址和密码供大家获取完整源码(没有打包,请大家运行main.py这个脚本,也是第一次分享代码,出了问题请私信我,唯一的外部依赖库是pygame,用pip install pygame即可安装,python版本建议3.8,因为我就是3.8)

大家好,我是CSDN新人,也是一名在校大一学生,第一次写博客,有什么写的不好的地方,或者做的不对的地方,希望大家能指出来,十分感谢!

最近接触了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:
                    self.nextframe()
                    self.updateframe()
                self.go()
            else:
                if self.thisgone >= self.thisfnum:
                    self.changecondition(self.next_code)
                else:
                    self.go()
    def set_certain(self, new_thisframe, new_condition_code, sticked=False):
        self.this_code = new_condition_code
        self.thisframe = new_thisframe
        self.thiscondition = self.framelist[self.this_code]
        self.updateframe()
        self.thiscdlen = len(self.thiscondition)
        self.thisgone = 0
        self.next_code = self.LASTSTICK if sticked else self.LASTCIRCLE
        self.sticked = False

    def nextframe(self):
        self.thisgone = 0
        self.thisframe += 1

    def updateframe(self):
        self.image = self.thiscondition[self.thisframe][0]
        self.thisfnum = self.thiscondition[self.thisframe][1]

    def go(self):
        self.thisgone += 1

    def copy(self):
        return Frame(self.framelist, self.leisureframe)






2.按钮制作

按钮是和鼠标放上和鼠标点击时间交互的精灵对象,我用两个旗帜onCovered和onClicked来保存鼠标放上和点击按钮的状态,并且鼠标放上将使按钮变得更亮,移开后按钮又恢复原状。点击按钮又是另一种动画帧。有了以上Frame对象管理帧,这个整体变得不难实现。

3.游戏开始前的背景

游戏开始前的背景是用29帧动画重复播放实现的

4.游戏背景循环滚动设计

正式进入游戏,希望能模拟飞机战场的推进,背景向下方不断滚动,并循环播放,此代码保证一次最多只渲染两个背景图片,当滚动出界时回到原处重复过程,能做到无缝衔接

最终游戏背景为如下VerticalUSBG对象

import pygame
from myGametools import mySprite
from myGametools import mypoint

class BackGround(mySprite.MyMoveSprite):
    def draw(self, screen:pygame.Surface):
        screen.blit(self.image, self.rect)
        self.update()

class UnStopBG(BackGround):
    def __init__(self, frame, position:mypoint.Mypoint, speed=0, accelerate=0):
        self.frame  = frame
        self.image  = self.frame.image
        self.rect   = pygame.Rect(*position.position, *self.image.get_size())
        self.speed  = speed
        self.accelerate = accelerate

class LevelUSBG(UnStopBG):
    def draw(self, screen:pygame.Surface):
        lastrect = self.rect
        for i in range(screen.get_width()//self.rect.width + 1):
            screen.blit(self.image, lastrect)
            lastrect.topleft = lastrect.topright
        if self.speed > 0:
            if 0 < self.rect.left < self.rect.width:
                screen.blit(self.image, (self.rect.left-self.rect.width, self.rect.top))
            elif self.rect.left >= self.rect.width:
                self.rect.left = 0
        elif self.speed < 0:
            if lastrect.left <= screen.get_width():
                screen.blit(self.image, lastrect)
            if self.rect.right <= 0:
                self.rect.left = 0
        else:
            return
        self.rect = self.rect.move(self.speed, 0)
        self.speed += self.accelerate

class VerticalUSBG(UnStopBG):
    def draw(self, screen: pygame.Surface):
        lastrect = self.rect.copy()
        for i in range(screen.get_height() // self.rect.height + 1):
            screen.blit(self.image, lastrect)
            lastrect.topleft = lastrect.bottomleft
        if self.speed > 0:
            if 0 < self.rect.top < self.rect.height:
                screen.blit(self.image, (self.rect.left, self.rect.top-self.rect.height, self.rect.width, self.rect.height))
            elif self.rect.top >= self.rect.height:
                self.rect.top = 0
        elif self.speed < 0:
            if lastrect.bottom <= screen.get_height():
                screen.blit(self.image, lastrect)
            if self.rect.bottom <= 0:
                self.rect.top = 0
        else:
            return

        self.rect = self.rect.move(0, self.speed)
        self.speed += self.accelerate






5.玩家飞机操纵逻辑和飞机姿态转换逻辑

玩家飞机控制的最开始版本为飞机只有一个正面的姿态,没有侧翻的姿态,并且飞机不能加速,只能匀速运动,控制键为"wasd"系(w向前,a向左,s向后,d向右)

但这样玩起来十分枯燥,手感单一。于是想到模拟飞机控制的实际情景,为飞机添加加速度。如当玩家按下a时,飞机就像左加速,当玩家松开时,飞机就减速直到速度为0。而加速有一个最大值。并且要保证飞机不飞出窗口,由于编写飞机的过程中多次涉及到“限制”这个概念,于是想到写Bound类系:

import pygame

import sys
# bound族都有limit协议

class BoundUnit:
    NEGATIVE_INFINITY = b'\x11'
    POSITIVE_INFINITY = b'\x01'
    def __init__(self, floor=NEGATIVE_INFINITY, ceiling=POSITIVE_INFINITY):
        self.__floor = floor
        self.__ceiling = ceiling
        self.__room = (floor, ceiling)

    def __getf(self):
        return self.__floor

    def __getc(self):
        return self.__ceiling

    def __getroom(self):
        return self.__room

    floor = property(__getf)
    ceiling = property(__getc)
    room = property(__getroom)

    def floorlimit(self, other, eq=True):
        if self.floor == self.NEGATIVE_INFINITY:
            return True
        if eq:
            return self.floor <= other
        else:
            return self.floor < other

    def ceilinglimit(self, other, eq=True):
        if self.ceiling == self.POSITIVE_INFINITY:
            return True
        if eq:
            return other <= self.ceiling
        else:
            return other < self.ceiling

    def limit(self, other, eqf=True, eqc=True):
        return self.floorlimit(other, eqf) and self.ceilinglimit(other, eqc)

    def setin(self, other, eqf=True, eqc=True):
        if not self.floorlimit(other, eqf):
            other = self.floor
        elif not self.ceilinglimit(other,eqc):
            other = self.ceiling
        return other

    def __getitem__(self, item):
        return self.room[item]


class BoundGroup:
    # 限制群
    def __init__(self, *groups):
        self.bounds = set(groups)

    def __add__(self, other):
        return self.bounds + other.bounds

    def __radd__(self, other):
        return self + other

    def __iadd__(self, other):
        self.bounds += set(other)
        return self

    def limit(self, other):
        for i in self.bounds:
            if not i.limit(other):
                return False
        return True


class BoundLine:
    # 切割数轴的有序bound
    # 必须为升序
    def __init__(self, boundpoints):
        bounds = []
        self.boundlen = len(boundpoints) + 1
        if self.boundlen  == 1:
            bounds.append(BoundUnit(BoundUnit.NEGATIVE_INFINITY, BoundUnit.POSITIVE_INFINITY))
        else:
            bounds.append(BoundUnit(BoundUnit.NEGATIVE_INFINITY, boundpoints[0]))
            for i in range(self.boundlen-2):
                if not boundpoints[i] < boundpoints[i+1]:
                    raise ValueError('please garantee its ascending order')
                bounds.append(BoundUnit(boundpoints[i], boundpoints[i+1]))
            bounds.append(BoundUnit(boundpoints[-1], BoundUnit.POSITIVE_INFINITY))
        self.bounds = bounds

    def detect_section(self, other, righteq=True):
        for i in range(self.boundlen):
            if self.bounds[i].limit(other, not righteq, righteq):
                return i


class BoundLineSymmetry(BoundLine):
    def __init__(self, boundpoints):
        bounds = []
        boundpoints.reverse()
        negboundpoints = [-i for i in boundpoints]
        self.lefthalfbounds = BoundLine(negboundpoints)
        for i in negboundpoints:
            bounds.append(i)
        boundpoints.reverse()
        self.righthalfbounds  = BoundLine(boundpoints)
        if boundpoints[0]:
            bounds.append(boundpoints[0])
        for i in boundpoints[1:]:
            bounds.append(i)
        super().__init__(bounds)

    def detect_section(self, other, righteq=True):
        leftdetect = self.lefthalfbounds.detect_section(other, not righteq)
        rightdetect = self.righthalfbounds.detect_section(other, righteq)
        return leftdetect + rightdetect

class Boundlftb:
    # 目前不支持改变
    def __init__(self, bound_1: bound.BoundUnit, bound_2: bound.BoundUnit):
        self.__left = bound_1[0]
        self.__right = bound_1[1]
        self.__top   = bound_2[0]
        self.__bottom = bound_2[1]
        self.__leftright = bound_1.room
        self.__topbottom = bound_2.room
        self.bound_1 = bound_1
        self.bound_2 = bound_2
        self.__bound = (self.bound_1, self.bound_2)

    def __getl(self):
        return self.__left

    def __getr(self):
        return self.__right

    def __gett(self):
        return self.__top

    def __getb(self):
        return self.__bottom

    def __getlr(self):
        return self.__leftright

    def __gettb(self):
        return self.__topbottom

    left = property(__getl)
    right = property(__getr)
    top = property(__gett)
    bottom = property(__getb)
    leftright = property(__getlr)
    topbottom = property(__gettb)

    def leftlimit(self, other, eq=True):
        return self.bound_1.floorlimit(other, eq)

    def rightlimit(self, other, eq=True):
        return self.bound_1.ceilinglimit(other, eq)

    def xlimit(self, other, eql=True, eqr=True):
        return self.bound_1.limit(other, eql, eqr)

    def toplimit(self, other, eq=True):
        return self.bound_2.floorlimit(other, eq)

    def bottomlimit(self, other, eq=True):
        return self.bound_2.ceilinglimit(other, eq)

    def ylimit(self, other, eqt=True, eqb=True):
        return self.bound_2.limit(other, eqt, eqb)

    def limit(self, x, y, xeqf=True, xeqc=True, yeqf=True, yeqc=True):
        return self.xlimit(x, xeqf, xeqc) and self.ylimit(y, yeqf, yeqc)

    def __getitem__(self, item):
        return self.__bound[item]

总之它们封装了可用于限制速度和飞机位置的代码,并在飞机的实现中用到

对于飞机的姿态问题也就迎刃而解了,就根据其向左或向右的速度区间,利用以上的数轴对称区间划分BuondLineSemmetry类来判断飞机速度所在区间,并确定将信息返回给飞机,使得飞机具备相应的状态stage属性,在根据该属性调整显示图片

6.飞机发射武器

武器可以看作子弹的群组,于是从pygame.sprite.Sprite继承了Bullet子弹类,从pygame.sprite.Group继承了Gun武器类。武器能间隔一段时间在飞机的固定的一些相对位置生成子弹,因此武器也需要和飞机绑定配置在一起。于是飞机和武器又是has-a关系。注意到飞机的组成如此复杂,为了避免写出有极多属性的飞机类,于是用ControlCenter控制中心类来封装飞机的运动,并用Engine类封装飞机运动的控制:

# controlcenter.py
import random
import pygame
from . import engine
from classes import bound, boundlrtb
from init import constants
from init import globalsInit

class ControlCenter:
    '''
    manage move and location
    '''
    def __init__(self, engine:engine.Engine):
        # engine only manage speed changing and accelerate changing
        self.engine = engine
        # 预加载screen_bound 免得每次都重复生成
        self.space_b = globalsInit.screen_bound

    def configure(self, plane):
        # 初始位置
        self.plane = plane
        self.rect = pygame.Rect(
            int(constants.SCREEN_SIZE[0] / 2 - plane.rect.width),
            int(constants.BeginLocCEnter - plane.rect.height / 2),
            plane.rect.width,
            plane.rect.height
        )
        plane.rect = self.rect

    def control(self):
        self.engine.drive()
        self.updatelocation()
        self.plane.rect = self.rect

    def updatelocation(self):
        if not self.space_b.leftlimit(self.rect.left, True):
            self.rect.left = self.space_b.left
        elif not self.space_b.rightlimit(self.rect.right, True):
            self.rect.right = self.space_b.right
        if not self.space_b.toplimit(self.rect.top, True):
            self.rect.top = self.space_b.top
        elif not self.space_b.bottomlimit(self.rect.bottom, True):
            self.rect.bottom = self.space_b.bottom
        self.rect.left += self.engine.speed[0]
        self.rect.top += self.engine.speed[1]

    def copy(self):
        return ControlCenter(self.engine.copy())

class Enemy_Controlcenter(ControlCenter):
    def configure(self, plane):
        self.plane = plane
        self.rect = plane.rect

class Sa_1_Controlcenter(Enemy_Controlcenter):
# 敌人的中央控制器
    def control(self):
        if self.rect.bottom < 0:
            self.engine.a_acce()
        else:
            super().control()








# engine.py
import pygame, random
from pygame.locals import *
from myGametools import mymove
from classes import boundlrtb, bound
from classes.planes import plane

class Engine(mymove.Mymove):
    # only for speed and accelerate(manally, just for player)
    # 目前在Engine类中硬编码所有飞船都应遵守的协议
    ACCE_x  = 1
    ACCE_y  = 0.2
    ACCE_F  = 0.5
    LEFT = 0
    LEISURE = 1
    RIGHT = 2
    STAGE_P = bound.BoundLineSymmetry([1, 4, 6, 10])
    (STAGE_LEFT3, STAGE_LEFT2, STAGE_LEFT1,
     STAGE_LEISURE,
     STAGE_RIGHT1, STAGE_RIGHT2, STAGE_RIGHT3) = (1, 2, 3,
                                                  4,
                                                  5, 6, 7)
    def __init__(self,  speedbound:boundlrtb.Boundlftb, speed=None, accelerate=None):
        super().__init__(speed, accelerate)
        self.speed_b = speedbound
        self.stage = self.STAGE_P.detect_section(self.speed[0])

    def w_acce(self):
        if self.speed_b.ylimit(self.speed[1]):
            if self.speed[1] > 0:
                self.setyAccelerate(-(self.ACCE_y + self.ACCE_F))
            else:
                self.setyAccelerate(-self.ACCE_y)

    def a_acce(self):
        if self.speed_b.xlimit(self.speed[0]):
            if self.speed[0] > 0:
                self.setxAccelerate(-(self.ACCE_x + self.ACCE_F))
            else:
                self.setxAccelerate(-self.ACCE_x)

    def s_acce(self):
        if self.speed_b.ylimit(self.speed[1]):
            if self.speed[1] < 0:
                self.setyAccelerate(self.ACCE_y + self.ACCE_F)
            else:
                self.setyAccelerate(self.ACCE_y)

    def d_acce(self):
        if self.speed_b.xlimit(self.speed[0]):
            if self.speed[0] < 0:
                self.setxAccelerate(self.ACCE_x + self.ACCE_F)
            else:
                self.setxAccelerate(self.ACCE_x)

    def drive(self):
        keys = pygame.key.get_pressed()
        if keys[K_w] and not keys[K_s]:
            self.w_acce()
        elif keys[K_s] and not keys[K_w]:
            self.s_acce()
        else:
            if self.accelerate[1]:
                self.accelerate[1] = 0
            if self.speed[1] > 0:
                self.speed[1] -= self.ACCE_F
                if self.speed[1] < 0:
                    self.speed[1] = 0
            elif self.speed[1] < 0:
                self.speed[1] += self.ACCE_F
                if self.speed[1] > 0:
                    self.speed[1] = 0
        if keys[K_a] and not keys[K_d]:
            self.a_acce()
        elif keys[K_d] and not keys[K_a]:
            self.d_acce()
        else:
            if self.accelerate[0]:
                self.accelerate[0] = 0
            if self.speed[0] > 0:
                self.speed[0] -= self.ACCE_F
                if self.speed[0] < 0:
                    self.speed[0] = 0
            elif self.speed[0] < 0:
                self.speed[0] += self.ACCE_F
                if self.speed[0] > 0:
                    self.speed[0] = 0
        self.updatespeed()
        self.updatestage()

    def updatestage(self):
        self.stage = self.STAGE_P.detect_section(self.speed[0])

    def updatespeed(self):
        self.speed[0] += self.accelerate[0]
        self.speed[1] += self.accelerate[1]
        self.speed[0] = self.speed_b.bound_1.setin(self.speed[0])
        self.speed[1] = self.speed_b.bound_2.setin(self.speed[1])

    def copy(self):
        return Engine(self.speed_b, self.speed[:], self.accelerate[:])



class Enemy_Engine(mymove.Mymove):
# 敌人的引擎
    def __init__(self):
        super().__init__()
        self.last_acce = pygame.time.get_ticks()
        self.acce_time = self.ACCE_TIME
        self.sleep_time = self.SLEEP_TIME
        self.sleeping = False
        self.acceing = False

    def copy(self):
        return Enemy_Engine()

class Sa_1_Engine(Enemy_Engine):
    ACCE_X = 1
    ACCE_Y = 0.1
    ACCE_F = 0.5
    ACCE_TIME = 300
    SLEEP_TIME = 100
    def drive(self):
        # 睡眠结束
        super().updatespeed()
        if not self.acceing and not self.sleeping:
            d = random.randint(1, 4)
            if d == 1:
                self.w_acce()
            if d == 2:
                self.a_acce()
            if d == 3:
                self.s_acce()
            if d == 4:
                self.d_acce()
            self.acceing = True
        # 加速中
        elif self.acceing and not self.sleeping:
            now = pygame.time.get_ticks()
            if now - self.last_acce >= self.ACCE_TIME:
                self.sleeping = True
                self.acceing = False
                self.accelerate = [0,0]
                self.last_acce = now
        # 睡眠中
        elif self.sleeping:
            if self.speed[0] > 0:
                self.speed[0] -= self.ACCE_F
                if self.speed[0] < 0:
                    self.speed[0] = 0
            elif self.speed[0] < 0:
                self.speed[0] += self.ACCE_F
                if self.speed[0] > 0:
                    self.speed[0] = 0
            if self.speed[1] > 0:
                self.speed[1] -= self.ACCE_F
                if self.speed[1] < 0:
                    self.speed[1] = 0
            elif self.speed[1] < 0:
                self.speed[1] += self.ACCE_F
                if self.speed[1] > 0:
                    self.speed[1] = 0
            now = pygame.time.get_ticks()
            if now - self.last_acce >= self.SLEEP_TIME:
                self.sleeping = False
                self.last_acce = now

    def w_acce(self):
        self.accelerate[1] = -self.ACCE_Y
    def a_acce(self):
        self.accelerate[0] = -self.ACCE_X
    def s_acce(self):
        # can use to drive show
        self.accelerate[1] = self.ACCE_Y
    def d_acce(self):
        self.accelerate[0] = self.ACCE_X

    def copy(self):
        return Sa_1_Engine()













这样,飞机就只有controlcenter属性和weapon属性了

7.敌人飞机生成

敌人飞机生成涉及到实例对象产生的问题,和炮弹生成一样,用一个群组Group类的子类封装敌人的每隔一段时间随机生成的逻辑。为保证每个敌人完全独立,为每个组件都增加了一个copy函数,使之在内存中复制,从而不相互干扰

8.生命值的计算和显示逻辑。

如果没有生命值外框,又怎么知道扣了多少生命值呢?于是我设计了HpFrameBar(继承自pygame.sprite.Group)来封装外框和实条。

用Hp类来封装数值的运算代码(很简单,只有加和减)

玩家生命值条和外框的显示位置可以硬编码在左下角,但敌人的生命显示只能随敌人位置变化。于是也增加了HpFrameBar于一个敌人实例的绑定函数configure,且随敌人位置移动而移动

由于篇幅限制,没有讨论子弹和飞机爆炸播放逻辑和音效播放逻辑的实现。

技术介绍完。

目前游戏没有实现的是游戏结束逻辑,更丰富的战斗体验以及游戏进度保存。因为最近要学JavaScript/HTML/CSS了,所以这个游戏做到这样能玩就收手了,各位还请海涵。

承诺的源代码:

链接: https://pan.baidu.com/s/1SwBsF-bjoBbHkN_LY4Ddqw

提取码: mnfc?
--来自百度网盘超级会员v1的分享

使用注意:仅包含自己手写python代码和doc文档,依赖库pygame请用pip install pygame安装。也建议各位和我一样用Pycharm跑。因为技术有限,不好意思放在github,也没打包,就是纯纯的剁手代码。

链接永远有效,请放心食用!

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:27:57  更:2022-02-16 13:29:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:46:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码