20241118 实验四《Python程序设计》实验报告
20241118 2024-2025-2 《Python程序设计》实验四报告
课程:《Python程序设计》
班级:2411
姓名: 戴子涵
学号:20241118
实验教师:王志强
实验日期:2025年6月1日
必修/选修: 公选课
前言
想必大家都看过这只呆呆鸟把,今天我们就在python上设计一个让呆呆鸟飞行的游戏
一、实验内容
设计一个呆呆鸟的游戏,让其可以由玩家操控持续飞行。
二、实验过程
(一)实验内容
1.安装所需要的平台
使用python写游戏,据说有一个万金油,那就是pygame,它基于 SDL 库开发,支持 2D 和 3D 游戏开发。它可以在几乎所有平台和操作系统上运行,非常轻便。所以我们要先下载安装pygame。
2.准备好游戏所需要的素材
正所谓一个好的游戏需要好的画面,而画面的好坏就与游戏的建模、背景有关,如果只使用像素点构成的图像可能有点朴素,于是我决定使用原生原态的游戏图片素材。
3.引入数据库和函数
成功安装好了pygame,引入使用。
#####################引用数据库与函数#####################
import pygame
from random import randrange
pygame.init()
4.定义基本变量
定义map_width、map_height,这两个为屏幕的宽和高,构造一个平面,FPS为游戏的帧数,帧数越高看起来越舒服,gameScree调用了屏幕的宽和高(width和height),使用pygame.image.load调用文件夹里准备好的背景图片,bird_wing_up与bird_wing_down表现出笨笨鸟的图像,同样需要调用准备好的飞行图片。
#########################定义变量#########################
frame=0
map_width=284
map_height=512
FPS=60
pipes=[[150,4]]
gameScreen = pygame.display.set_mode((map_width,map_height))
clock=pygame.time.Clock()
bird_wing_up = pygame.image.load("images/bird_wing_up.png")
bird_wing_down = pygame.image.load("images/bird_wing_down.png")
background = pygame.image.load("images/background.png")
pipe_body = pygame.image.load("images/pipe_body.png")
pipe_end = pygame.image.load("images/pipe_end.png")
5.定义基本函数
使用True语句保持循环,定义def draw_bird(x,y)函数,定义出呆呆鸟的位置,draw_bird(20,map_height//2),其中前者为横坐标,后者为纵坐标,让呆呆鸟先显示在屏幕中。如图
但是此时呆呆鸟还是静止的,该如何让呆呆鸟动起来呢,就需要使用到pygame里的函数了clock(时间函数),还记得我们定义了FPS这个变量,我们再定义一个frame变量,当frame为0到30,让呆呆鸟翅膀向上,30到60时,翅膀向下,frame逐渐增加,到60时归零,接下来再使用pygame.display.update()语句,让画面持续跟更新,这样我们的笨鸟也就可以永久动起来了。
def draw_bird(x,y):
global frame
if 0<=frame<=30:
gameScreen.blit(bird_wing_up,(x,y))
frame += 1
elif 30<frame<=60 :
gameScreen.blit(bird_wing_down,(x,y))
frame += 1
if frame==60 : frame=0
6.补充函数
(1).制作管道
呆呆鸟有了,接下来要为游戏添加一些障碍,管道是这个游戏不可缺少的部分,管道的表现原理与呆呆鸟差不多,同样是需要调用图片,区别在于管道需要随机出现,同时要在管道中留出空间给呆呆鸟通过。因此我们把管道分成许多份,随机取中间几份删除。
先定义一个管道,还有管道体和管道头,同样需要调用图片。
pipes=[[150,4]]
pipe_body = pygame.image.load("images/pipe_body.png")
pipe_end = pygame.image.load("images/pipe_end.png")
接下来绘画管道体,使用range函数随机管道体(pipe_body)开口位置,除空缺位置都绘制管道,之后两边补充管道头( pipe_end )
def draw_pipes():
global pipes
for n in range( len(pipes) ):
for m in range( pipes[n][1] ):
gameScreen.blit( pipe_body , ( pipes[n][0] , m*32 ) )
for m in range( pipes[n][1]+6 , 16 ):
gameScreen.blit( pipe_body , ( pipes[n][0] , m*32 ) )
gameScreen.blit( pipe_end , (pipes[n][0] , (pipes[n][1])*32 ) )
gameScreen.blit( pipe_end , (pipes[n][0] , (pipes[n][1]+5)*32 ) )
接下来是让管道移动,实际呆呆鸟一直是只有上下移动,管道一直向左移动,才呈现出呆呆鸟在向右边移动的感觉只需添加这个代码即可
pipes[n][0] -= 1
如果只有一个管道怎么够呢,我们应该设计多一点管道,给游戏添加一点难度,所以在画面函数中补充
def gameLoop():
while True:
if len(pipes)<4:
x = pipes[-1][0] + 200
open_pos = randrange(1,9)
pipes.append([x,open_pos])
if pipes[0][0]<-100:
pipes.pop(0)
即可让画面中同时出现多个管道
(2)呆呆鸟坠落
目前管道横向移动有了,接下来就是呆呆鸟上下移动了,我们知道,这个经典的游戏中我们只能控制呆呆鸟的上升,下落是由于重力导致呆呆鸟鸟下降的。而下降只需要每帧减少笨鸟的纵坐标即可,那我们先给小鸟添加重力gravty,为了更符合现实,呆呆鸟鸟的下落肯定是越来越快的,那我们再定义一个初始速度为零的velocity,使它下落有个加速的过程
gravity = 0.2
velocity = 0
接下来把位置与速度结合
velocity += gravity
bird[1] += velocity
这样呆呆鸟就可以坠机了(doge)
(3)呆呆鸟起飞
为了让呆呆鸟逃脱困境,我们要给它一个飞行的能力,而且这个能力要由玩家来赋予,即通过操控键盘来实现。还记得之前有个读取的鼠标代码吗(如果不记得可以看一下问题解惑那里)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
我们在里面加入一个读取键盘的语句
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
bird[1] -= 40
velocity = 0
if event.type == pygame.QUIT:
pygame.quit()
return
这样,每次玩家按键的时候,呆呆鸟的竖直位置都会上升40,下落速度也会重新归零,呆呆鸟的基本操作就已经做好了。
(4)添加一点点细节
由图看出,目前呆呆鸟的下落没有一点动作,看起来有点僵硬,我们给它加点“摇头晃脑”。
我们首先需要更改一下之前的代码,就是翅膀上下动的代码
bird_wing_up = bird_wing_up_copy = pygame.image.load("images/bird_wing_up.png")
bird_wing_down = bird_wing_down_copy = pygame.image.load("images/bird_wing_down.png")
这样我们可以拥有一个旋转后的参数,原始图片的参数也可以被保留,现在图片进行旋转,由速度决定旋转的角度。
bird_wing_down = pygame.transform.rotate(bird_wing_down_copy,-90*(velocity/15))
bird_wing_up = pygame.transform.rotate(bird_wing_up_copy,-90*(velocity/15))
这样呆呆鸟的头就可以旋转了
(5)添加游戏结束条件
如果一个游戏结束不了,那一定会让人无聊,所以我们要添加死亡条件,那就是触碰到边界和管道时游戏就会结束,那接下来我们就要添加语句,去判断呆呆鸟是否与管道有碰撞。
def safe():
if bird[1] > map_height - 35:
print("hit floor")
return False
if bird[1] < 0:
print("hit ceiling")
return False
if pipes[0][0] - 30 < bird[0] < pipes[0][0] + 79:
if bird[1] < (pipes[0][1] + 1) * 32 or bird[1] > (pipes[0][1] + 4) * 32:
print("hit pipe")
return False
return True
呆呆鸟坐标分别于上下边界、管道坐标作比较,如果都没有碰到,则继续返Ture,即继续刷新图像;如果碰到了,则判定为False,则应该图像生成代码中加入
if not safe():
sleep(3) //游戏暂停3秒
reset() //重置参数
clock.tick(FPS)
这样即使死亡,游戏又可以重新开始了。
(二)实验代码
#####################引用数据库与函数#####################
import pygame
from random import randrange
from time import sleep
pygame.init()
#########################定义变量#########################
frame=0
map_width=284
map_height=512
FPS=60
pipes=[[180,4]]
bird=[40,map_height//2-50]
gravity = 0.2
velocity = 0
gameScreen = pygame.display.set_mode((map_width,map_height))
clock=pygame.time.Clock()
bird_wing_up = bird_wing_up_copy = pygame.image.load("images/bird_wing_up.png")
bird_wing_down = bird_wing_down_copy = pygame.image.load("images/bird_wing_down.png")
background = pygame.image.load("images/background.png")
pipe_body = pygame.image.load("images/pipe_body.png")
pipe_end = pygame.image.load("images/pipe_end.png")
#########################定义函数#########################
def draw_pipes():
global pipes
for n in range( len(pipes) ):
for m in range( pipes[n][1] ):
gameScreen.blit( pipe_body , ( pipes[n][0] , m*32 ) )
for m in range( pipes[n][1]+6 , 16 ):
gameScreen.blit( pipe_body , ( pipes[n][0] , m*32 ) )
gameScreen.blit( pipe_end , (pipes[n][0] , (pipes[n][1])*32 ) )
gameScreen.blit( pipe_end , (pipes[n][0] , (pipes[n][1]+5)*32 ) )
pipes[n][0] -= 1
def draw_bird(x,y):
global frame
if 0<=frame<=30:
gameScreen.blit(bird_wing_up,(x,y))
frame += 1
elif 30<frame<=60 :
gameScreen.blit(bird_wing_down,(x,y))
frame += 1
if frame==60 : frame=0
def safe():
if bird[1] > map_height - 35:
print("hit floor")
return False
if bird[1] < 0:
print("hit ceiling")
return False
if pipes[0][0] - 30 < bird[0] < pipes[0][0] + 79:
if bird[1] < (pipes[0][1] + 1) * 32 or bird[1] > (pipes[0][1] + 4) * 32:
print("hit pipe")
return False
return True
def reset():
global frame,map_width,map_height,FPS,pipes,bird,gravity,velocity
frame=0
map_width=284
map_height=512
FPS=60
pipes.clear()
bird.clear()
pipes=[[180,4]]
bird=[40,map_height//2-50]
gravity = 0.2
velocity = 0
def gameLoop():
global velocity,bird_wing_down,bird_wing_up
while True:
if len(pipes)<4:
x = pipes[-1][0] + 200
open_pos = randrange(1,9)
pipes.append([x,open_pos])
if pipes[0][0]<-80:
pipes.pop(0)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
bird[1] -= 40
velocity = 0
if event.type == pygame.QUIT:
pygame.quit()
return
velocity += gravity
bird[1] += velocity
bird_wing_down = pygame.transform.rotate(bird_wing_down_copy,-90*(velocity/15))
bird_wing_up = pygame.transform.rotate(bird_wing_up_copy,-90*(velocity/15))
gameScreen.blit(background,(0,0))
draw_pipes()
draw_bird(bird[0],bird[1])
pygame.display.update()
if not safe():
sleep(3)
reset()
clock.tick(FPS)
##########################主程序##########################
gameLoop()
(三)代码托管到码云
https://gitee.com/dzh1602230848/dai/commit/bf88b66bf079fd65c8ae8c8ccb253d285e1537b7
三、实验结果
四、实验中遇到的问题及解决办法
1.无法安装pygame
可能是当时下载pycharm时什么路径调错了,一直显示pip错误,于是我尝试下载个VScode安装pygame,结果很顺利,成功安装了pygame。
2.屏幕无法关闭
在最开始运行表现出屏幕时,出现了无法关闭程序的情况
经过查阅资料与浏览视频,明白了是因为画面是由pygame生成的,而对于画面的鼠标操作pygame是需要识别的,于是我加入了语句
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
通过get语句读取鼠标状态,再用quit结束程序,就可解决关闭不了程序的问题了。
3.代码运行错误
在运行safe时,一直显示我出现问题,可是我无论肉眼怎么看都看出来哪里有问题,最后没法,只能让AI帮我看看,结果AI一眼顶真,说我缩进有问题,结果还真是,真的就是一点细节决定成败啊。
五、收获、心得体会
1.收获
第一,我终于学会打代码格式了(哈哈哈),果然还是得百度,如果有人不会格式还能看到这篇文章,那你有福了,我来给你总结一下。
(标题区分用# , 大标题就用# , 中标题就用## ,以此类推)
(添加代码要用```,在要添加的代码前一行和结尾下一行添加三个`符号即可)
第二,我学会了给函数调用图片了,这样的话就可以用代码完成很多有意思的事情,如给图片添加运动等等,这次的呆呆鸟游戏就非常需要图像。我感觉通过这个,可以用python给物理的实验作许多视频,这样既清晰,还能自己改数据,呆呆鸟里的许多参数就都是物理参数。
2.心得体会
通过这个实验四,我首先有个感慨:python nb!,说实话,我是真没想到有一天我也能用代码手搓一个游戏了。作为一个游戏佬,当自己真的能玩到在自己电脑运行的游戏,这种感觉是非常自豪和骄傲的,python选修课相对我们课堂上学的课程更加自由,我也非常感谢这次的实验四的机会,让我有了这次心流状态(说实话,我已经好久没有在图书馆一坐坐6个小时了),而真正做完实验的那一刻,我的心情是愉悦的。python课已经结束了,志强老师似乎也要离我而去了(doge),师恩难忘,感谢您的辛勤付出!