20232201实验四《Python程序设计》实验报告

20232201 2024-2025-4 《Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2322
姓名: 田欣冉
学号:20232201
实验教师:王志强
实验日期:2025年6月2日
必修/选修: 公选课

1.实验内容

【1】供选择的实验内容:

Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。

  • 编写从社交网络爬取数据,实现可视化舆情监控或者情感分析;
  • 利用公开数据集,开展图像分类、恶意软件检测等;
  • 利用Python库,基于OCR技术实现自动化提取图片中数据,并填入excel中;
  • 爬取天气数据,实现自动化微信提醒;
  • 利用爬虫,实现自动化下载网站视频、文件等;
  • 编写小游戏:坦克大战、贪吃蛇、扫雷等等。

注:在Windows/Linux系统上使用VIM、PDB、IDLE、Pycharm等工具编程实现。

【2】本人实验具体内容:

利用Python编写小恐龙快跑小游戏,平常感到压力大时可以缓解压力带来的郁闷、沮丧。

2. 实验过程

想要用Pycharm项目来实现一个小恐龙跑酷游戏,里面包括游戏初始化、事件处理、游戏元素的更新和绘制、碰撞检测等。玩家可以通过↑键来控制小恐龙躲避障碍物,不断奔跑并尽量获得更高的分数。(由于才疏学浅,游戏中的图片元素不是本人绘制)

【1】主运行文件

定义主要的运行方法,并且执行主运行方法。

(1)导入所需的模块和库:

import cfg
import sys
import random
import pygame
from modules.sprites.scene import *
from modules.sprites.obstacle import *
from modules.sprites.dinosaur import *
from modules.interfaces.gameend import GameEndInterface
from modules.interfaces.gamestart import GameStartInterface

(2)游戏主函数 main()

包括了游戏的初始化、主循环和事件处理等逻辑。在循环中,不断更新游戏元素的位置,处理玩家输入,并在屏幕上绘制游戏元素。

def main(highest_score):
 # 游戏初始化
 pygame.init()
 # 创建屏幕
 screen = pygame.display.set_mode(cfg.SCREENSIZE)
 pygame.display.set_caption('小恐龙快跑!!!')
 # 导入声音文件
 sounds = {}
 for key, value in cfg.AUDIO_PATHS.items():
     sounds[key] = pygame.mixer.Sound(value)
 
 # 游戏开始界面
 GameStartInterface(screen, sounds, cfg)
 
 # 定义游戏中的元素和变量
 score = 0
 # 其他游戏元素的初始化
 
 # 游戏主循环
 while True:
     # 事件处理,包括退出游戏和玩家输入
     for event in pygame.event.get():
         # 事件处理逻辑
 
     # 更新游戏元素的位置
     # 绘制游戏元素到屏幕上
 
     # 碰撞检测
 
     # 更新屏幕
     pygame.display.update()
     # 控制帧率
     clock.tick(cfg.FPS)
     # 判断游戏是否结束
     # 如果结束,跳出循环
 
 # 游戏结束界面
 return GameEndInterface(screen, cfg), highest_score

这只是一个游戏主函数大致的框架,后续还得填充完整。

(3) if __name__ == '__main__':部分:

这是主程序的入口,通过调用main()函数来运行整个游戏。
初始的游戏主窗体界面:

【2】配置文件

定义界面大小和获取图片、音乐素材的路径、地址以及背景颜色等。

'''配置文件'''
# 这段代码是一个配置文件,用来存储游戏中所需的参数和资源路径
import os
 
'''屏幕大小'''
SCREENSIZE = (600, 150)   # 定义了游戏窗口的大小,宽度为 600 像素,高度为 150 像素
'''FPS'''
FPS = 60   # 指定了游戏的帧率为 60 帧每秒,即画面更新的频率
'''音频素材路径'''
AUDIO_PATHS = {       # 存储了游戏中所需的音频文件路径,包括小恐龙死亡、跳跃和得分音效的路径
    'die': os.path.join(os.getcwd(), 'resources/audios/die.wav'),
    'jump': os.path.join(os.getcwd(), 'resources/audios/jump.wav'),
    'point': os.path.join(os.getcwd(), 'resources/audios/point.wav')
}
'''图片素材路径'''   # 存储了游戏中所需的图片素材路径,包括仙人掌、云、小恐龙、游戏结束画面、地面、数字、翼龙和重新开始按钮等图片素材路径
IMAGE_PATHS = {
    'cacti': [os.path.join(os.getcwd(), 'resources/images/cacti-big.png'),
              os.path.join(os.getcwd(), 'resources/images/cacti-small.png')],
    'cloud': os.path.join(os.getcwd(), 'resources/images/cloud.png'),
    'dino': [os.path.join(os.getcwd(), 'resources/images/dino.png'),
             os.path.join(os.getcwd(), 'resources/images/dino_ducking.png')],
    'gameover': os.path.join(os.getcwd(), 'resources/images/gameover.png'),
    'ground': os.path.join(os.getcwd(), 'resources/images/ground.png'),
    'numbers': os.path.join(os.getcwd(), 'resources/images/numbers.png'),
    'ptera': os.path.join(os.getcwd(), 'resources/images/ptera.png'),
    'replay': os.path.join(os.getcwd(), 'resources/images/replay.png')
}
'''背景颜色'''
BACKGROUND_COLOR = (235, 235, 235)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# 定义了背景颜色

【3】资源(游戏运行过程的图片素材、部分背景音乐)

上网获取所需要的素材:在文件夹里面分别存储游戏运行过程当中所需要用到的图片素材(恐龙、云朵、飞鸟、仙人掌、结束语等以及有部分的背景音乐)

【4】在项目下创建sprites文件夹

该文件夹分别用面向对象的方式封装了各类的游戏角色

(1)恐龙 dinosaur.py:

这个文件当中封装了小恐龙这个游戏角色,并且在小恐龙的这个类里面定义属于小恐龙这个游戏角色的属性和相关的功能方法。

'''
定义一个:小恐龙类
'''
import pygame  #导入 Pygame 模块,用于实现游戏开发
 
 
'''小恐龙'''
class Dinosaur(pygame.sprite.Sprite):
    #定义了一个名为 Dinosaur 的类,继承自 pygame.sprite.Sprite,表示小恐龙是一个 Sprite 对象
    def __init__(self, imagepaths, position=(40, 147), size=[(44, 47), (59, 47)], **kwargs):  #初始化方法,用于设置小恐龙的属性和状态
        pygame.sprite.Sprite.__init__(self)
        # 导入所有图片
        # 首先加载小恐龙的不同动作的图片,根据给定的大小参数对图片进行缩放,并存储在 self.images 列表中
        self.images = []
        image = pygame.image.load(imagepaths[0])
        for i in range(5):
            self.images.append(pygame.transform.scale(image.subsurface((i*88, 0), (88, 95)), size[0]))
        image = pygame.image.load(imagepaths[1])
        for i in range(2):
            self.images.append(pygame.transform.scale(image.subsurface((i*118, 0), (118, 95)), size[1]))
        self.image_idx = 0
        self.image = self.images[self.image_idx]
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.bottom = position
        self.mask = pygame.mask.from_surface(self.image)
        # 定义一些必要的变量,设置小恐龙的初始属性
        self.init_position = position
        self.refresh_rate = 5
        self.refresh_counter = 0
        self.speed = 11.5
        self.gravity = 0.6
        self.is_jumping = False
        self.is_ducking = False
        self.is_dead = False
        self.movement = [0, 0]
    '''跳跃'''
    def jump(self, sounds):
        if self.is_dead or self.is_jumping:
            return
        sounds['jump'].play()
        self.is_jumping = True
        self.movement[1] = -1 * self.speed
    '''低头'''
    def duck(self):
        if self.is_jumping or self.is_dead:
            return
        self.is_ducking = True
    '''不低头'''
    def unduck(self):
        self.is_ducking = False
    '''死掉了'''
    def die(self, sounds):
        if self.is_dead:
            return
        sounds['die'].play()
        self.is_dead = True
    '''将恐龙画到屏幕'''
    def draw(self, screen):
        screen.blit(self.image, self.rect)
    '''载入当前状态的图片'''
    def loadImage(self):
        self.image = self.images[self.image_idx]
        rect = self.image.get_rect()
        rect.left, rect.top = self.rect.left, self.rect.top
        self.rect = rect
        self.mask = pygame.mask.from_surface(self.image)
    '''更新小恐龙'''
    def update(self):
        if self.is_dead:
            self.image_idx = 4
            self.loadImage()
            return
        if self.is_jumping:
            self.movement[1] += self.gravity
            self.image_idx = 0
            self.loadImage()
            self.rect = self.rect.move(self.movement)
            if self.rect.bottom >= self.init_position[1]:
                self.rect.bottom = self.init_position[1]
                self.is_jumping = False
        elif self.is_ducking:
            if self.refresh_counter % self.refresh_rate == 0:
                self.refresh_counter = 0
                self.image_idx = 5 if self.image_idx == 6 else 6
                self.loadImage()
        else:
            if self.refresh_counter % self.refresh_rate == 0:
                self.refresh_counter = 0
                if self.image_idx == 1:
                    self.image_idx = 2
                elif self.image_idx == 2:
                    self.image_idx = 3
                else:
                    self.image_idx = 1
                self.loadImage()
        self.refresh_counter += 1

(此图其实为视频截图,实在没有找到上传视频的地方∑(っ°Д°;)っ )

(2)障碍物 obstacles.py:

该部分需要定义两个类:Cactus(仙人掌)和Ptera(飞龙),它们是恐龙奔跑的过程中会遇到的障碍物。

'''仙人掌'''
class Cactus(pygame.sprite.Sprite):
   def __init__(self, imagepath, position, size=(50, 50), **kwargs):
       # 初始化
       pygame.sprite.Sprite.__init__(self)
       # 导入图片
       self.image = pygame.image.load(imagepath)
       self.image = pygame.transform.scale(self.image, size)
       self.rect = self.image.get_rect()
       self.rect.bottom = position[1]  # 设置底部位置
       self.mask = pygame.mask.from_surface(self.image)
       # 定义一些必要的变量
       self.speed = -10
   '''画到屏幕上'''
   def draw(self, screen):
       screen.blit(self.image, self.rect)
   '''更新'''
   def update(self):
       self.rect = self.rect.move([self.speed, 0])
       if self.rect.right < 0:
           self.kill()


'''飞龙'''
class Ptera(pygame.sprite.Sprite):
   def __init__(self, imagepath, position, size=(46, 40), **kwargs):
       # 初始化
       pygame.sprite.Sprite.__init__(self)
       # 导入图片
       self.images = []
       image = pygame.image.load(imagepath)
       for i in range(2):
           self.images.append(pygame.transform.scale(image.subsurface((i*92, 0), (92, 81)), size))
       self.image_idx = 0
       self.image = self.images[self.image_idx]
       self.rect = self.image.get_rect()
       self.rect.left, self.rect.centery = position
       self.mask = pygame.mask.from_surface(self.image)
       # 定义一些必要的变量
       self.speed = -10
       self.refresh_rate = 10
       self.refresh_counter = 0
   '''画到屏幕上'''
   def draw(self, screen):
       screen.blit(self.image, self.rect)
   '''更新'''
   def update(self):
       if self.refresh_counter % self.refresh_rate == 0:
           self.refresh_counter = 0
           self.image_idx = (self.image_idx + 1) % len(self.images)
           self.loadImage()
       self.rect = self.rect.move([self.speed, 0])
       if self.rect.right < 0:
           self.kill()
       self.refresh_counter += 1
   '''载入当前状态的图片'''
   def loadImage(self):
       self.image = self.images[self.image_idx]
       rect = self.image.get_rect()
       rect.left, rect.top = self.rect.left, self.rect.top
       self.rect = rect
       self.mask = pygame.mask.from_surface(self.image)

(3)场景 scene.py:

类定义地板、云和记分板这些游戏场景元素和使用方法。

'''地板'''
class Ground(pygame.sprite.Sprite):
  def __init__(self, imagepath, position, **kwargs):
      # 初始化
      pygame.sprite.Sprite.__init__(self)
      # 导入图片
      self.image_0 = pygame.image.load(imagepath)
      self.rect_0 = self.image_0.get_rect()
      self.rect_0.left, self.rect_0.bottom = position
      self.image_1 = pygame.image.load(imagepath)
      self.rect_1 = self.image_1.get_rect()
      self.rect_1.left, self.rect_1.bottom = self.rect_0.right, self.rect_0.bottom
      # 定义一些必要的参数
      self.speed = -10
      
  '''更新地板'''
  def update(self):
      self.rect_0.left += self.speed
      self.rect_1.left += self.speed
      if self.rect_0.right < 0:
          self.rect_0.left = self.rect_1.right
      if self.rect_1.right < 0:
          self.rect_1.left = self.rect_0.right

  '''将地板画到屏幕'''
  def draw(self, screen):
      screen.blit(self.image_0, self.rect_0)
      screen.blit(self.image_1, self.rect_1)


'''云'''
class Cloud(pygame.sprite.Sprite):
  def __init__(self, imagepath, position, **kwargs):
      # 初始化
      pygame.sprite.Sprite.__init__(self)
      # 导入图片
      self.image = pygame.image.load(imagepath)
      self.rect = self.image.get_rect()
      self.rect.left, self.rect.top = position
      # 定义一些必要的参数
      self.speed = -1
      
  '''将云画到屏幕上'''
  def draw(self, screen):
      screen.blit(self.image, self.rect)

  '''更新云'''
  def update(self):
      self.rect = self.rect.move([self.speed, 0])
      if self.rect.right < 0:
          self.kill()


'''记分板'''
class Scoreboard(pygame.sprite.Sprite):
  def __init__(self, imagepath, position, size=(11, 13), is_highest=False, bg_color=None, **kwargs):
      # 初始化
      pygame.sprite.Sprite.__init__(self)
      # 导入图片
      self.images = []
      image = pygame.image.load(imagepath)
      for i in range(12):
          self.images.append(pygame.transform.scale(image.subsurface((i*20, 0), (20, 24)), size)
      if is_highest:
          self.image = pygame.Surface((size[0]*8, size[1]))
      else:
          self.image = pygame.Surface((size[0]*5, size[1]))
      self.rect = self.image.get_rect()
      self.rect.left, self.rect.top = position
      # 一些必要的变量
      self.is_highest = is_highest
      self.bg_color = bg_color
      self.score = '00000'
      
  '''设置得分'''
  def set(self, score):
      self.score = str(score).zfill(5)

  '''画到屏幕上'''
  def draw(self, screen):
      self.image.fill(self.bg_color)
      for idx, digital in enumerate(list(self.score)):
          digital_image = self.images[int(digital)]
          if self.is_highest:
              self.image.blit(digital_image, ((idx+3)*digital_image.get_rect().width, 0))
          else:
              self.image.blit(digital_image, (idx*digital_image.get_rect().width, 0))
      if self.is_highest:
          self.image.blit(self.images[-2], (0, 0))
          self.image.blit(self.images[-1], (digital_image.get_rect().width, 0))
      screen.blit(self.image, self.rect)

【5】游戏开始和结束界面

(1)设置一个简单的游戏开始界面的交互逻辑:

初始化游戏元素、在一个游戏循环中处理事件、更新游戏元素、渲染游戏画面、刷新屏幕、控制帧率。

'''
游戏开始界面
'''
import sys
import pygame
from modules.sprites.dinosaur import Dinosaur

def GameStartInterface(screen, sounds, cfg):
   # 初始化游戏元素
   dino = Dinosaur(cfg.IMAGE_PATHS['dino']) # 创建恐龙对象
   ground = pygame.image.load(cfg.IMAGE_PATHS['ground']).subsurface((0, 0), (83, 19)) # 加载并裁剪地面图像
   rect = ground.get_rect() 
   rect.left, rect.bottom = cfg.SCREENSIZE[0] / 20, cfg.SCREENSIZE[1] # 设置地面位置
   clock = pygame.time.Clock() # 创建时钟对象
   press_flag = False # 按键标志初始化为False
   
   while True:
       # 处理事件
       for event in pygame.event.get():
           if event.type == pygame.QUIT:
               pygame.quit()  # 退出游戏
               sys.exit()
           elif event.type == pygame.KEYDOWN:
               if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
                   press_flag = True
                   dino.jump(sounds) # 触发恐龙跳跃动作
       
       # 更新游戏元素
       dino.update() # 更新恐龙的状态和位置
       
       # 清空屏幕并绘制游戏元素
       screen.fill(cfg.BACKGROUND_COLOR) # 填充背景颜色
       screen.blit(ground, rect) # 绘制地面
       dino.draw(screen) # 绘制恐龙
       pygame.display.update() # 刷新屏幕
       
       # 控制帧率
       clock.tick(cfg.FPS) # 控制游戏帧率
       
       # 检查跳跃动作完成并按下空格键时返回True,表示游戏开始
       if (not dino.is_jumping) and press_flag:
           return True

(2)游戏结束界面逻辑:

加载并缩放重新开始图像和游戏结束图像。
在一个无限循环中,检测事件,并根据事件类型做出相应的响应。

  • 如果事件类型为QUIT(退出游戏),则退出游戏。
  • 如果事件类型为KEYDOWN(按下键盘按键),并且按下的是空格键或上箭头键,则返回True,表示重新开始游戏。
  • 如果事件类型为MOUSEBUTTONDOWN(鼠标点击),则检查鼠标位置是否在重新开始图像上,如果是,则返回True,表示重新开始游戏。

在循环中,将重新开始图像和游戏结束图像绘制到屏幕上,并刷新屏幕。
控制帧率,使游戏运行更顺畅。

'''
定义游戏结束界面
'''
import sys
import pygame

'''游戏结束界面'''
def GameEndInterface(screen, cfg):
   # 加载并缩放重新开始图像
   replay_image = pygame.image.load(cfg.IMAGE_PATHS['replay'])
   replay_image = pygame.transform.scale(replay_image, (35, 31))
   replay_image_rect = replay_image.get_rect()
   replay_image_rect.centerx = cfg.SCREENSIZE[0] / 2
   replay_image_rect.top = cfg.SCREENSIZE[1] * 0.52
   
   # 加载并缩放游戏结束图像
   gameover_image = pygame.image.load(cfg.IMAGE_PATHS['gameover'])
   gameover_image = pygame.transform.scale(gameover_image, (190, 11))
   gameover_image_rect = gameover_image.get_rect()
   gameover_image_rect.centerx = cfg.SCREENSIZE[0] / 2
   gameover_image_rect.centery = cfg.SCREENSIZE[1] * 0.35
   
   clock = pygame.time.Clock() # 创建时钟对象
   
   while True:
       for event in pygame.event.get():
           if event.type == pygame.QUIT:
               pygame.quit()
               sys.exit()
           elif event.type == pygame.KEYDOWN:
               if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
                   return True
           elif event.type == pygame.MOUSEBUTTONDOWN:
               mouse_pos = pygame.mouse.get_pos()
               if replay_image_rect.collidepoint(mouse_pos):  # 当鼠标点击在重新开始图像上时,返回True
                   return True
       
       # 绘制重新开始图像和游戏结束图像
       screen.blit(replay_image, replay_image_rect)
       screen.blit(gameover_image, gameover_image_rect)
       pygame.display.update() # 刷新屏幕
       clock.tick(cfg.FPS) # 控制帧率

3.小游戏运行的截图

(视频也提交啦)

4.实验过程中遇到的问题和解决过程

  • 问题1:pygame安装包一直显示没有安装,在终端中pip install pygame没解决。
  • 问题1解决方案:在CSDN中查明了原因,在项目中用anaconda解释器来安装pygame安装包。
  • 问题2:小恐龙快跑游戏代码较多,但是分类逻辑比较简单。
  • 问题2解决方案:在Python新建一个项目,分成几部分让整个游戏代码既简洁而且便于修改。
  • 问题3:游戏只是跳跳,少了玩游戏的沉浸感。
  • 问题3解决方案:上网添加一些音乐,使之更像是小游戏,同时可以陶冶情操。
  • 问题4:资源文件路径错误
  • 问题4解决方案:检查资源文件路径是否正确,并确保程序能够正确访问这些资源文件,后来发现是路径错误。

其他(感悟、思考等)

【1】本次实验感想体会

实验四是自己选择感兴趣的、有成就感的来自己实验,感觉最近学习的劲儿没得到开发,同时临近期末考试,学业压力也陆陆续续上来了,所以就想编写一个小游戏来玩。总的来说代码编写涉及了使用Python和Pygame库来实现游戏功能,包括小恐龙的奔跑、跳跃、躲避障碍物等。在编写小恐龙游戏代码的过程中,我学到了一些基础的游戏开发功能,了解了Pygame库,对游戏循环、角色控制、碰撞等等理解更深,同时中间虽然断断续续出现了代码多、程序实现困难、资源难找等问题,但是最后当它们都迎刃而解的时刻,我真真正正体会到了创造游戏的乐趣还有成就感。
总的来说,通过这个实验,我不仅提升了编程技能,还收获了无尽的乐趣和成就感。这段经历让我更加坚信,编程的世界无限精彩,我愿意不断探索、挑战自我,在代码的世界里创造出更多的奇迹。

【2】课程感想体会、意见及建议

1.感想体会:OWO “结课快乐!!!”

选了王老师的Python课程,真真正正在课堂的实践中明白了——“人生苦短,我用Python!”的内在含义!王老师讲的真的超级好超级好,一开始拿到零基础的书时发现还挺厚的,就以为Python会难学,后来把书读进去就觉得书其实还挺简洁的呢。但是王老师的课堂上的PPT还有word文档的总结更是精华中的精华,王老师讲解的也非常生动形象、言简但意义深!参加Python课程真的让我受益匪浅啊!学着学着,突然就豁然开朗了,感觉自己的大脑被开启了新的功能。学Python不仅让我掌握了新的技能,还让我懂得了问题分析和逻辑思维的重要性。解决问题不再那么困难,编写代码也变得不是一直在抓耳挠腮。而且背单词真的很有益处!
“那些看似波澜不惊的日复一日,终将在某一天,让我们看到坚持的意义。”最后超级感谢王老师,感谢Python课程给我带来的成长和启示,我会一直朝着我的目标前进,永不停步!

2.意见及建议 😃

前期提问时小问题可以多一点点,既可以活跃课堂还可以复习复习嘿~
可以增设Python的小组合作,增强沟通合作能力,更灵活地来运用学到的知识。

参考资料

posted @ 2025-06-03 19:36  无名星星眼  阅读(68)  评论(0)    收藏  举报