PyGame游戏开发(含源码+演示视频+开结题报告+设计文档)

前言:

大二小学期python课上基于pygame做的一个游戏小demo,当时老师花了一天讲解了下python基础语法后(也是整个大学四年唯一学习python的时间),便让我们自学网课一周然后交项目,所以做的非常仓促(当时没有面向对象概念,以及功能拆分的思想,所以所有代码全堆在一个文件了),也算是自己做的第一个游戏,做完还是有些成就感的,不过很难崩的是结题演示的时候好多同学居然能做出植物大战僵尸这种难度的游戏,(除去看网课去掉二十几个小时基本每天我都在写代码找素材才能做一个相对完整的demo),虽然后来确实在网上看到有用pygame做植物大战僵尸的源码安慰自己他们可能有所参考,不过还是有挺强挫败感的,好在老师人美心善,最后成绩90+,前20%。最近计划重装旧电脑时,还是计划整理下自己的项目,也算是自己大学四年的青春,如果是biter可以关注下,说不定就有你的课设分享。

最后提交内容链接:

Release origin · wlf728050719/BallGamehttps://github.com/wlf728050719/BallGame/releases/tag/1.0.0从release/origin下载BallGame.zip解压即可(含源码+演示视频+开结题报告+设计文档),不建议直接从code下代码,后续可能会基于这个game用强化学习或深度学习设计下人机对战,如果只是完成课设为目标大可不必,不过可以star下关注后续。


环境配置:

只需要安装pygame即可

这是旧电脑没使用anoconda的环境,python3.10.7 pygame 2.1.2

这是新电脑使用的anoconda的环境配置python3.11 pygame 2.6.0

两种配置都能运行,(虽然感觉使用任意版本的python和pygame应该都能正常运行,不过为了严谨还是写下配置)


代码:

显然直接粘贴代码会缺少资源文件无法运行,不过还是把代码放上来,帮助大家了解pygame设计游戏的基本流程。(虽然无论从变量命名还是逻辑设计都能感受到当时的不成熟)

python 复制代码
import random
import sys
import pygame

pygame.init()
size = width, height = 400, 600  # 初始化屏幕

speed: list[int] = [0, 0]  # 小球运动速度
speed1 = [0, 0]  # 挡板向上移动速度
speed2 = [0, 0]  # 挡板向下移动速度
speed3 = [0, 0]  # 障碍物0移动速度
speed4 = [0, 0]  # 障碍物1移动速度
speed5 = [0, 0]  # 障碍物2移动速度
speed6 = [0, 0]  # 障碍物3移动速度


speedx = [0, 0]  # 缓存各对象速度
speed1x = [0, 0]
speed2x = [0, 0]
speed3x = [0, 0]
speed4x = [0, 0]
speed5x = [0, 0]
speed6x = [0, 0]

active: int = 0  # 游戏运行参数 0:游戏第一次开始等待 1:游戏运行 2:游戏暂停 3:游戏结束重新开始等待
case = 0    # 缓冲参数初始化

WHITE = 255, 255, 255  # 字体颜色
m: int = 0  # 当前帧数
z =0

c = 0  # 初始化道具效果随机数
last = 0  # 上一次碰撞板子
gamemap = 1   # 游戏地图序号
speedmode = 1  # 速度模式
myfont = pygame.font.Font(None, 30)  # 设置字体以及大小
long_press = {'up': False, 'down': False}  # 实现连续移动
long_press2 = {'up': False, 'down': False}
bg = pygame.image.load("resources/img/page/game.png")  # 设置背景图片

score1 = 0  # 设置初始得分
score2 = 0

mi = True
screen = pygame.display.set_mode(size, pygame.FULLSCREEN)  # 全屏
a = screen.get_width()  # 获取屏幕宽度
b = screen.get_height()  # 获取屏幕高度
pygame.display.set_caption("双人弹球")  # 标题名
fps: int = 100  # 刷新速度
# 生成 surface对象以及rect对象
ball = pygame.image.load("resources/img/component/ball/ball_0.png")    # 小球运动动图
ballrect = ball.get_rect()
ball1 = pygame.image.load("resources/img/component/ball/ball_1.png")
ball2 = pygame.image.load("resources/img/component/ball/ball_2.png")
ball3 = pygame.image.load("resources/img/component/ball/ball_3.png")
ball4= pygame.image.load("resources/img/component/ball/ball_4.png")

win1 = pygame.image.load("resources/img/component/win/player1_win.png")
win2 = pygame.image.load("resources/img/component/win/player2_win.png")
start = pygame.image.load("resources/img/page/start.png")
banzi1 = pygame.image.load("resources/img/component/player/player.png")
banzi1rect = banzi1.get_rect()
banzi2 = pygame.image.load("resources/img/component/player/player.png")
banzi2rect = banzi2.get_rect()
redball = pygame.image.load("resources/img/component/red_prop/red_prop_1.png")
redballrect = redball.get_rect()

barrier = pygame.image.load("resources/img/component/barrier/barrier_v.png")
barrierrect = barrier.get_rect()
barrier1 = pygame.image.load("resources/img/component/barrier/barrier_v.png")
barrier1rect = barrier1.get_rect()
barrier2 = pygame.image.load("resources/img/component/barrier/barrier_h.png")
barrier2rect = barrier2.get_rect()
barrier3 = pygame.image.load("resources/img/component/barrier/barrier_h.png")
barrier3rect = barrier3.get_rect()

jiantouleft = pygame.image.load("resources/img/component/tip/left.png")
jiantouright = pygame.image.load("resources/img/component/tip/right.png")
xuanzhong = pygame.image.load("resources/img/component/tip/selected.png")
map1 = pygame.image.load("resources/img/component/map/map1.png")
map2 = pygame.image.load("resources/img/component/map/map2.png")
map3= pygame.image.load("resources/img/component/map/map3.png")


banzi2rect = banzi2rect.move(a - 8, 500)  # 确认各对象初始位置
banzi1rect = banzi1rect.move(0, 500)
redballrect = redballrect.move(100, 100)
ballrect = ballrect.move(a / 2, 10)
fclock = pygame.time.Clock()  # 计时

pygame.mixer.init()  # 初始化音频文件

music = pygame.mixer.music.load("resources/audio/bgm/main_bgm_1.mp3")      # 加载音乐文件
pygame.mixer.music.set_volume(0.01)  # 控制背景音乐声音大小
pygame.mixer.music.play()  # 开始播放音乐流
bang = pygame.mixer.Sound("resources/audio/sound_effect/hit.wav")
pop = pygame.mixer.Sound("resources/audio/sound_effect/pop.wav")
shao = pygame.mixer.Sound("resources/audio/sound_effect/whistle.wav")
huanhu = pygame.mixer.Sound("resources/audio/sound_effect/cheer.wav")
anjian = pygame.mixer.Sound("resources/audio/sound_effect/click.wav")

while True:
    if pygame.mixer.music.get_busy() == False:  # 检查是否正在播放音乐
        pygame.mixer.music.play()  # 开始播放音乐流
    for i in pygame.event.get():
        if i.type == pygame.QUIT:    # 退出
            sys.exit()

        elif i.type == pygame.KEYDOWN:  # 挡板连续移动
            if i.key == pygame.K_UP:
                long_press['up'] = True
            if i.key == pygame.K_DOWN:
                long_press['down'] = True
            if i.key == pygame.K_w:
                long_press2['up'] = True
            if i.key == pygame.K_s:
                long_press2['down'] = True

            if i.key == pygame.K_h:   # 选择速度模式
                if active == 0:
                    speedmode = 3
                    anjian.play()
            if i.key == pygame.K_m:
                if active == 0:
                    speedmode = 2
                    anjian.play()
            if i.key == pygame.K_l:
                if active == 0:
                    speedmode = 1
                    anjian.play()

            if i.key == pygame.K_RETURN:  # 按下回车开始游戏
                if active != 1:
                    anjian.play()
                if active == 0:
                    if speedmode == 1:
                        speed = [1, 1]  # 小球运动速度
                        speed1 = [0, -2]  # 挡板向上移动速度
                        speed2 = [0, 2]  # 挡板向下移动速度
                        speed3 = [0, 2]  # 障碍物0移动速度
                        speed4 = [0, -2]  # 障碍物1移动速度
                        speed5 = [2, 0]   # 障碍物2移动速度
                        speed6 = [-2, 0]  # 障碍物3移动速度
                    elif speedmode == 2:
                        speed = [2, 2]  # 小球运动速度
                        speed1 = [0, -3]  # 挡板向上移动速度
                        speed2 = [0, 3]  # 挡板向下移动速度
                        speed3 = [0, 3]  # 障碍物0移动速度
                        speed4 = [0, -3]  # 障碍物1移动速度
                        speed5 = [3, 0]  # 障碍物2移动速度
                        speed6 = [-3, 0]  # 障碍物3移动速度
                    elif speedmode == 3:
                        speed = [3, 3]  # 小球运动速度
                        speed1 = [0, -4]  # 挡板向上移动速度
                        speed2 = [0, 4]  # 挡板向下移动速度
                        speed3 = [0, 4]  # 障碍物0移动速度
                        speed4 = [0, -4]  # 障碍物1移动速度
                        speed5 = [4, 0]  # 障碍物2移动速度
                        speed6 = [-4, 0]  # 障碍物3移动速度
                    active = 1      # 进入游戏运行状态
                elif active == 3:
                    score1 = 0
                    score2 = 0
                    speed = [0, 0]
                    speed1 = [0, 0]
                    speed2 = [0, 0]
                    speed3 = [0, 0]
                    speed4 = [0, 0]
                    speed5 = [0, 0]
                    speed6 = [0, 0]
                    active = 0   # 游戏结束后回到开始界面

            if i.key == pygame.K_SPACE:    # 游戏运行时按下空格暂停,再次按下继续
                anjian.play()
                if active == 1:
                    speedx = speed.copy()
                    speed1x = speed1.copy()
                    speed2x = speed2.copy()
                    speed3x = speed3.copy()
                    speed4x = speed4.copy()
                    speed5x = speed5.copy()
                    speed6x = speed6.copy()
                    speed = [0, 0]
                    speed1 = [0, 0]
                    speed2 = [0, 0]
                    speed3 = [0, 0]
                    speed4 = [0, 0]
                    speed5 = [0, 0]
                    speed6 = [0, 0]
                    active = 2
                elif active == 2:
                    speed = speedx.copy()
                    speed1 = speed1x.copy()
                    speed2 = speed2x.copy()
                    speed3 = speed3x.copy()
                    speed4 = speed4x.copy()
                    speed5 = speed5x.copy()
                    speed6 = speed6x.copy()
                    active = 1

            if i.key == pygame.K_1 or i.key == pygame.K_KP1:  # 选择地图
                if active == 0:
                    anjian.play()
                    gamemap = 1
            if i.key == pygame.K_2 or i.key == pygame.K_KP2:
                if active == 0:
                    anjian.play()
                    gamemap = 2
            if i.key == pygame.K_3 or i.key == pygame.K_KP3:
                if active == 0:
                    anjian.play()
                    gamemap = 3

            elif i.key == pygame.K_ESCAPE:
                sys.exit()
        if i.type == pygame.KEYUP:
            if i.key == pygame.K_UP:
                long_press['up'] = False
            if i.key == pygame.K_DOWN:
                long_press['down'] = False
            if i.key == pygame.K_w:
                long_press2['up'] = False
            if i.key == pygame.K_s:
                long_press2['down'] = False

    if long_press['up']:
        banzi2rect = banzi2rect.move(speed1)
    if long_press['down']:
        banzi2rect = banzi2rect.move(speed2)
    if long_press2['up']:
        banzi1rect = banzi1rect.move(speed1)
    if long_press2['down']:
        banzi1rect = banzi1rect.move(speed2)

    if banzi1rect.top < 0:   # 限制挡板高度
        banzi1rect.top = 0
    if banzi1rect.bottom > height:
        banzi1rect.bottom = height
    if banzi2rect.top < 0:
        banzi2rect.top = 0
    if banzi2rect.bottom > height:
        banzi2rect.bottom = height

    if active == 0:      # 初始化地图
        if gamemap == 1:       # 地图1
            barrierrect.x = a / 2 - 100
            barrierrect.y = b / 2
            barrier1rect.x = a / 2 + 100
            barrier1rect.y = b / 2
        if gamemap == 2:       # 地图2
            barrier2rect.x = 200
            barrier2rect.y = 200
            barrier3rect.x = 550
            barrier3rect.y = 400
        if gamemap == 3:
            barrierrect.x = a / 2 - 100
            barrierrect.y = b / 2
            barrier1rect.x = a / 2 + 100
            barrier1rect.y = b / 2
            barrier2rect.x = 200
            barrier2rect.y = 200
            barrier3rect.x = 550
            barrier3rect.y = 400

    if active == 1:    # 设置不同地图障碍物运行规律以及球与障碍物碰撞效果
        if gamemap == 1:
            barrierrect = barrierrect.move(speed3)  # 障碍物上下移动
            barrier1rect = barrier1rect.move(speed4)
            if barrierrect.top < 0 or barrierrect.bottom > b:
                speed3[1] = -speed3[1]
            if barrier1rect.top < 0 or barrier1rect.bottom > b:
                speed4[1] = -speed4[1]
            f = ballrect.colliderect(barrierrect)
            v = ballrect.colliderect(barrier1rect)
            if f:
                if speed[0] > 0:
                    ballrect.right = barrierrect.left
                    bang.play()
                    speed[0] = - speed[0]
                elif speed[0] < 0:
                    ballrect.left = barrierrect.right
                    bang.play()
                    speed[0] = - speed[0]
            if v:
                if speed[0] > 0:
                    ballrect.right = barrier1rect.left
                    bang.play()
                    speed[0] = - speed[0]
                elif speed[0] < 0:
                    ballrect.left = barrier1rect.right
                    bang.play()
                    speed[0] = - speed[0]



        if gamemap == 2:
            barrier2rect = barrier2rect.move(speed5)  # 障碍物左右移动
            barrier3rect = barrier3rect.move(speed6)
            if barrier2rect.left < 200 or barrier2rect.right > 600:
                speed5[0] = -speed5[0]
            if barrier3rect.left < 200 or barrier3rect.right > 600:
                speed6[0] = -speed6[0]
            f1 = ballrect.colliderect(barrier2rect)
            v1 = ballrect.colliderect(barrier3rect)
            if f1:
                if speed[1] > 0:
                    ballrect.bottom = barrier2rect.top
                    bang.play()
                    speed[1] = - speed[1]
                elif speed[1] < 0:
                    ballrect.top = barrier2rect.bottom
                    bang.play()
                    speed[1] = - speed[1]
            if v1:
                if speed[1] > 0:
                    ballrect.bottom = barrier3rect.top
                    bang.play()
                    speed[1] = - speed[1]
                elif speed[1] < 0:
                    ballrect.top = barrier3rect.bottom
                    bang.play()
                    speed[1] = - speed[1]

        if gamemap == 3:
            barrierrect = barrierrect.move(speed3)  # 障碍物上下移动
            barrier1rect = barrier1rect.move(speed4)
            barrier2rect = barrier2rect.move(speed5)  # 障碍物左右移动
            barrier3rect = barrier3rect.move(speed6)
            if barrierrect.top < 0 or barrierrect.bottom > b:
                speed3[1] = -speed3[1]
            if barrier1rect.top < 0 or barrier1rect.bottom > b:
                speed4[1] = -speed4[1]
            if barrier2rect.left < 200 or barrier2rect.right > 600:
                speed5[0] = -speed5[0]
            if barrier3rect.left < 200 or barrier3rect.right > 600:
                speed6[0] = -speed6[0]
            f = ballrect.colliderect(barrierrect)
            v = ballrect.colliderect(barrier1rect)
            f1 = ballrect.colliderect(barrier2rect)
            v1 = ballrect.colliderect(barrier3rect)
            if f:
                if speed[0] > 0:
                    ballrect.right = barrierrect.left
                    bang.play()
                    speed[0] = - speed[0]
                elif speed[0] < 0:
                    ballrect.left = barrierrect.right
                    bang.play()
                    speed[0] = - speed[0]
            if v:
                if speed[0] > 0:
                    ballrect.right = barrier1rect.left
                    bang.play()
                    speed[0] = - speed[0]
                elif speed[0] < 0:
                    ballrect.left = barrier1rect.right
                    bang.play()
                    speed[0] = - speed[0]
            if f1:
                if speed[1]>0:
                    ballrect.bottom=barrier2rect.top
                    bang.play()
                    speed[1] = - speed[1]
                elif speed[1]<0:
                    ballrect.top = barrier2rect.bottom
                    bang.play()
                    speed[1] = - speed[1]
            if v1:
                if speed[1] > 0:
                    ballrect.bottom = barrier3rect.top
                    bang.play()
                    speed[1] = - speed[1]
                elif speed[1] < 0:
                    ballrect.top = barrier3rect.bottom
                    bang.play()
                    speed[1] = - speed[1]

    screen.blit(bg, (0, 0))   # 绘制背景
    if active == 0:             # 绘制开始界面
        screen.blit(start, (0, 0))

        if speedmode == 1:         # 绘制选中速度效果
            screen.blit(xuanzhong, (52, 335))
        elif speedmode == 2:
            screen.blit(xuanzhong, (201, 335))
        elif speedmode == 3:
            screen.blit(xuanzhong, (346, 335))

        if gamemap == 1:         # 绘制选中地图效果
            screen.blit(xuanzhong, (49, 459))
            screen.blit(map1, (475, 316))
        elif gamemap == 2:
            screen.blit(xuanzhong, (201, 459))
            screen.blit(map2, (475, 316))
        elif gamemap == 3:
            screen.blit(xuanzhong, (346, 459))
            screen.blit(map3, (475, 316))

    if ballrect.right < 0:  # 小球得分判定
        score2 = score2 + 1
    if ballrect.left > a:
        score1 = score1 + 1
    wenzi1 = str(score1)
    wenzi2 = str(score2)
    textImage1 = myfont.render("playerA:" + wenzi1, True, WHITE)
    textImage2 = myfont.render("playerB:" + wenzi2, True, WHITE)

    m = m + 1  # 记录帧数

    if ballrect.right < 0 or ballrect.left > a:  # 小球出界后重新发球

        ballrect.top = 10
        ballrect.left = a / 2+10
        last = 0
        speed = [0, 0]
        z = random.randint(1, 2)
        if active != 3:
            shao.play()
        case = 1
    if m % 400 != 0 and case == 1:  # 预告小球发球方向
        if z == 1:
            screen.blit(jiantouright, (450, 300))
        if z == 2:
            screen.blit(jiantouleft, (310, 300))
    if m % 400 == 0 and case == 1:  # 小球出界后缓冲后并以随机速度及方向发出
        case = 0
        bang.play()
        if z == 1:
            if speedmode == 1:
                speed[0] = random.randint(1, 2)
                speed[1] = random.randint(1, 2)
            elif speedmode == 2:
                speed[0] = random.randint(2, 3)
                speed[1] = random.randint(2, 3)
            elif speedmode == 3:
                speed[0] = random.randint(3, 4)
                speed[1] = random.randint(3, 4)

        elif z == 2:
            if speedmode == 1:
                speed[0] = random.randint(-2, -1)
                speed[1] = random.randint(1, 2)
            elif speedmode == 2:
                speed[0] = random.randint(-3, -2)
                speed[1] = random.randint(2, 3)
            elif speedmode == 3:
                speed[0] = random.randint(-4, -3)
                speed[1] = random.randint(3, 4)

    ballrect = ballrect.move(speed)  # 小球运动
    if ballrect.top < 0 or ballrect.bottom > height:  # 小球上下运动反弹
        speed[1] = - speed[1]
        bang.play()

    # 球与两边挡板撞击效果
    t = ballrect.colliderect(banzi1rect)
    k = ballrect.colliderect(banzi2rect)
    if t:
        ballrect.left = banzi1rect.right
        speed[0] = - speed[0]
        last = 1
        bang.play()

    if k:
        ballrect.right = banzi2rect.left
        speed[0] = - speed[0]
        last = 2
        bang.play()

    f = ballrect.colliderect(redballrect)  # 红色小球被吃掉效果
    if f == True:
        mi = False
        pop.play()
    if mi == False:
        redballrect.left = 2 * a
        redballrect.top = 2 * b  # 小球被吃掉后移出屏幕产生消失效果
        c = random.randint(1, 2)  # 生成随机数c,产生相应效果

    if c == 1:  # 道具效果1:让球上一次碰撞挡板一方加分
        if last == 1:
            score1 = score1 + 5
        if last == 2:
            score2 = score2 + 5

    if c == 2:   # 道具效果2:让球速度最大
        if speed[0] > 0:
            speed[0] = 4
        if speed[0] < 0:
            speed[0] = -4
        if speed[1] > 0:
            speed[1] = 4
        if speed[1] < 0:
            speed[1] = -4

    c = 0  # 重置道具效果

    if m % 2000 == 0:  # 小球位置随机
        x = random.randint(200, 300)
        y = random.randint(200, 300)
        redballrect.left = x
        redballrect.top = y

    if int(m / 1000) % 2 == 0 and active == 1:  # 红色小球周期性出现
        mi = True
        screen.blit(redball, redballrect)
    else:
        redballrect.left = 2 * a
        redballrect.top = 2 * b


    if active == 1 or active == 2:
        if m % 5 == 0:    # 实现小球滚动
            screen.blit(ball, ballrect)
        elif m % 5 == 1:
            screen.blit(ball1, ballrect)
        elif m % 5 == 2:
            screen.blit(ball2, ballrect)
        elif m % 5== 3:
            screen.blit(ball3, ballrect)
        elif m % 5 == 4:
            screen.blit(ball4, ballrect)
        if gamemap == 1:
            screen.blit(barrier, barrierrect)
            screen.blit(barrier1, barrier1rect)
        if gamemap == 2:
            screen.blit(barrier2, barrier2rect)
            screen.blit(barrier3, barrier3rect)
        if gamemap == 3:
            screen.blit(barrier, barrierrect)
            screen.blit(barrier1, barrier1rect)
            screen.blit(barrier2, barrier2rect)
            screen.blit(barrier3, barrier3rect)

        screen.blit(banzi1, banzi1rect)
        screen.blit(banzi2, banzi2rect)
        screen.blit(textImage1, (100, 100))  # 显示字体,确定出现位置
        screen.blit(textImage2, (a - 200, 100))

    if score1 >= 5:  # 游戏结束判定 绘制结束图像
        screen.blit(win1,(300,200))
        active = 3
    if score2 >= 5:
        screen.blit(win2, (300, 200))
        active = 3
    if active == 3:   # 一方获胜暂停游戏
        speed = [0, 0]
        speed1 = [0, 0]
        speed2 = [0, 0]
        speed3 = [0, 0]
        speed4 = [0, 0]
    pygame.display.update()
    fclock.tick(fps)

印象比较深的一个bug是道具球被吃掉时,要么会持续触发道具效果以及会一直渲染在画面中,当时冥思苦想很久最后想出将它移动到屏幕外面,当时简直感觉自己是天才,虽然现在感觉好像没啥。不过好像大多数bug都是没解决的时候很难,解决后感觉这么简单为啥会难住自己这么久。


设计文档:(压缩包里有完整doc文件,这里仅做展示)

(关于分工部分,其实整个项目都是独立开发的,为了老师那边不出问题还是平均分的工,当然这里不是说另外一位同学是摆子,只是他在另外一个小组课设有很大投入,但我在那个项目就单纯做做美工,最终也是90+,所以相当于等价交换了,如果你的课设需要有分工的话可以参考我的划分)以及如果觉得游戏设计文档过于简单,可以参考我大三unity项目的设计文档。

基于Unity3D的游戏开发项目(包含源码与演示视频)_汪洛飞-CSDN博客https://blog.csdn.net/wlf2030/article/details/144664436?spm=1001.2014.3001.5501

整体目标设计:

本游戏在"壁球"游戏上进行改良,扩充为双人对抗类游戏,玩家双方分别使用键盘的"W""S"以及上下键分别控制屏幕最左侧和最右侧的挡板拦截壁球并进行反弹,屏幕上下边缘以及屏幕中对称排列的挡板会将壁球反弹,屏幕特定区域会定时随机位置出现道具小球,当壁球碰撞到道具小球时会根据道具效果,改变小球的速度以及方向,或者增加壁球上一次碰撞方得分。增加开始与一轮游戏结束界面,玩家能够自由选择游戏难度以及游戏地图,添加小球运动动画效果,添加游戏背景音乐以及音效具有暂停功能,小球出界后不会直接游戏结束,会重新发球,并预告发球方向,直到一方目标达到预设得分玩家在一轮游戏结束后能够选择返回开始界面继续游玩,或者直接退出。

分工说明:

游戏基本框架讨论后共同搭建,游戏文件共享,并标明注释,便于个人测试。

游戏主要功能各自提出自己看法,讨论并测试后编写

个人完成部分功能后向另外成员解释代码含义,发现bug后提出各自意见修复。

杨宜松: 汪洛飞:

游戏方案及类型提出 碰撞检测

挡板连续移动 碰撞检测改进

碰撞检测 道具小球消失

道具小球消失 道具小球消失改进

得分记录及文本显示 小球发球预告

小球道具效果,音效播放 页面跳转及难度设置

图片,音乐素材

(以上有相同部分表示两人对同一功能有不同的方法或共同参与设计)

代码总体框架:

初始化各种参数,生成surface对象,rect对象。

根据游戏运行参数的不同对不同事件做出相应的处理,包括地图参数以及速度参数的生成

根据地图参数初始化地图,以及地图中障碍物的碰撞效果

绘制开始页面时选中效果

小球得分判定

小球出界后发球以及预告

小球上下边界以及两边挡板反弹效果

道具小球被吃掉以及产生道具效果

小球动图效果以及得分文本显示

游戏结束判定

第三方库介绍:

本游戏仅使用pygame,sys,random库,未引用其他第三方库

运行环境配置以及运行指导说明:

本游戏背景图为800*600像素大小,显示器大小不得小于此。

游戏帧率默认设为100,若显示器无法稳定满足此帧率请自行在代码第49行修改fps数值,(此数值不建议小于60,否则会产生较差视觉效果以及游戏体验)

软件运行截图:

(以下图片均为实机演示,非图片编辑软件修改)

完成度自我评价:

个人认为游戏开发已经十分完整,增加许多功能,已经大大超过游戏设计预期,同时游戏引导人性化,与玩家交互性高。

个人工作:

python 复制代码
if m % 5 == 0:    # 实现小球滚动
    screen.blit(ball, ballrect)
elif m % 5 == 1:
    screen.blit(ball1, ballrect)
elif m % 5 == 2:
    screen.blit(ball2, ballrect)
elif m % 5== 3:
    screen.blit(ball3, ballrect)
elif m % 5 == 4:
    screen.blit(ball4, ballrect)

由于pygame不支持播放gif形式图片,使用在不同帧数的情况下,在小球上绘制不同的图片从而达到动图效果的方法

2:

python 复制代码
f = ballrect.colliderect(barrierrect)
v = ballrect.colliderect(barrier1rect)
if f:
    if speed[0] > 0:
        ballrect.right = barrierrect.left
        bang.play()
        speed[0] = - speed[0]
    elif speed[0] < 0:
        ballrect.left = barrierrect.right
        bang.play()
        speed[0] = - speed[0]

改进前没有ballrect.right = barrierrect.left部分,导致小球在某些特殊情况下会出现黏在挡板上震动的效果,对游戏体验影响较大

3:

python 复制代码
if ballrect.right < 0 or ballrect.left > a:  # 小球出界后重新发球
    ballrect.top = 10
    ballrect.left = a / 2+10
    last = 0
    speed = [0, 0]
    z = random.randint(1, 2)
    if active != 3:
        shao.play()
    case = 1
if m % 400 != 0 and case == 1:  # 预告小球发球方向
    if z == 1:
        screen.blit(jiantouright, (450, 300))
    if z == 2:
        screen.blit(jiantouleft, (310, 300))
if m % 400 == 0 and case == 1:  # 小球出界后缓冲后并以随机速度及方向发出
    case = 0
    bang.play()
    if z == 1:
        if speedmode == 1:
            speed[0] = random.randint(1, 2)
            speed[1] = random.randint(1, 2)

在小球出界后,用帧数是否整除400来进行时间的计算,,先生成随机数后再绘制预告图片,并增加参数case防止预告图片持续显示,时间条件满足后根据生成随机数以及对应的速度模式发球。

4:

python 复制代码
f = ballrect.colliderect(redballrect)  # 红色小球被吃掉效果
if f == True:
    mi = False
    pop.play()
if mi == False:
    redballrect.left = 2 * a
    redballrect.top = 2 * b  # 小球被吃掉后移出屏幕产生消失效果
    c = random.randint(1, 2)  # 生成随机数c,产生相应效果

....................................

...................................

...................................

..................................(道具具体效果代码)

if int(m / 1000) % 2 == 0 and active == 1:  # 红色小球周期性出现
    mi = True
    screen.blit(redball, redballrect)
else:
    redballrect.left = 2 * a
    redballrect.top = 2 * b

道具小球与球碰撞后移出屏幕外产生被吃掉效果,并映入mi这一参数,当碰撞后为false,使道具球移出,用int(m/1000)%2==0作为时间判定语句,满足后使mi=true,小球重新回到屏幕

5:

python 复制代码
active: int = 0  # 游戏运行参数 0:游戏第一次开始等待 1:游戏运行 2:游戏暂停 3:游戏结束重新开始等待

......

if i.key == pygame.K_1 or i.key == pygame.K_KP1:  # 选择地图
    if active == 0:
        anjian.play()
        gamemap = 1

.....................

if score1 >= 6:  # 游戏结束判定 绘制结束图像
    screen.blit(win1,(300,200))
    active = 3

....................
if active == 3:   # 一方获胜暂停游戏
    speed = [0, 0]
    speed1 = [0, 0]
    speed2 = [0, 0]
    speed3 = [0, 0]
    speed4 = [0, 0]

(由于游戏运行参数作为游戏状态判定的依据,在游戏代码中出现次数过多,且位于各个部分,现只展示代表性代码)

引入游戏运行参数,使游戏避免引用pgu库便产生多级页面效果,并根据玩家产生的事件改变参数的数值,从而产生页面的跳转效果,但分析后得知,此方法仅适用于页面较少的情况,页面过多会导致参数值太多,代码层次混乱,不建议大量使用。


开题PPT:(压缩包里有完整ppt文件,这里仅做展示)


结题PPT:(压缩包里有完整ppt文件,这里仅做展示)


演示视频:

因为以现在的眼光确实很简单就不上传到b站或博客了,需要可自行解压压缩包查看。


最后:

兴趣确实是最好的老师,写这篇博客感觉像是和过去的自己对话,当时确实仍有满腔热血,能熬夜两三点写游戏代码,现在读研感觉无论找工作或是做学术都会有很大压力,以及从我的博客也能看出比较偏向java分布式以及python深度学习了,以后从业也基本与游戏无缘了,还是有些可惜。最后还是祝各位能永远热爱你所热爱的!

相关推荐
笨鸟先飞,勤能补拙1 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能2 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂3 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study3 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境4 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境4 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1234 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102165 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb005 小时前
一个项目带你入门AI应用开发01
python
0566465 小时前
Python康复训练——常用标准库
开发语言·python·学习