【Dison夏令营 Day 30】如何用 Python 创建平台游戏(下篇)

几十年来,平台游戏一直是深受玩家喜爱的游戏类型,它提供了令人兴奋的挑战和令人怀念的游戏玩法。在本教程中,我们将指导您使用 Python 中的 PyGame 库构建自己的平台游戏。

在这里插入图片描述
无论您是希望深入游戏开发的初学者,还是希望探索 Pygame 的资深程序员,本教程都将为您提供实现平台游戏创意所需的知识和技能。

在本教程中,我们将介绍平台游戏的基本组成部分,包括:

  • 安装和设置
  • 添加基本游戏组件
  • 游戏循环
  • 游戏世界
    • 世界设置
    • 添加世界功能
    • 移动和处理碰撞
    • 处理世界陷阱
    • 更新世界变化
  • 世界组件:瓦块、目标和陷阱
  • 添加玩家
    • 玩家动画
    • 添加玩家能力
    • 识别玩家活动
    • 更新玩家
  • 应用游戏目标
    • 添加游戏指标
    • 游戏检查
  • 总结

我们将指导您逐步完成整个过程,并解释每个功能背后的代码和概念。

本教程结束时,您将拥有一个可以自豪地与他人分享的游戏,并可以根据自己的喜好进一步定制。话不多说,让我们开始吧。

书接上回

添加玩家

现在我们的游戏世界已经有了玩家角色可以交互的对象,我们可以开始在游戏中添加玩家角色了。在 player.py 中创建一个名为 Player 的新类,它是 pygame.sprite.Sprite 的子类,代表游戏世界中的玩家角色:

# player.py
import pygame
from support import import_spriteclass Player(pygame.sprite.Sprite):def __init__(self, pos):super().__init__()self._import_character_assets()self.frame_index = 0self.animation_speed = 0.15self.image = self.animations["idle"][self.frame_index]self.rect = self.image.get_rect(topleft=pos)self.mask = pygame.mask.from_surface(self.image)# player movementself.direction = pygame.math.Vector2(0, 0)self.speed = 5self.jump_move = -16# player statusself.life = 5self.game_over = Falseself.win = Falseself.status = "idle"self.facing_right = Trueself.on_ground = Falseself.on_ceiling = Falseself.on_left = Falseself.on_right = False# gets all the image needed for animating specific player actiondef _import_character_assets(self):character_path = "assets/player/"self.animations = {"idle": [], "walk": [],"jump": [], "fall": [], "lose": [], "win": []}for animation in self.animations.keys():full_path = character_path + animationself.animations[animation] = import_sprite(full_path)

在__init__()方法中;_import_character_assets 方法被调用,以根据动画类型从不同的目录中导入并存储播放器动画的精灵图像。frame_index 属性初始化为 0,表示动画的当前帧。animation_speed 属性设置为 0.15,表示每个动画帧变化之间的时间间隔。self.image 属性将根据 frame_index 从动画字典中的 "idle "动画中分配初始图像。通过 get_rect(),rect 属性被设置为与图像相邻的矩形,topleft 参数被设置为提供的位置。使用 pygame.mask.from_surface 创建遮罩属性,为玩家定义像素级碰撞检测。

播放器类还为播放器的移动和状态定义了各种属性。direction 属性是一个 pygame.math.Vector2 对象,代表玩家的移动方向。speed 属性设置为 5,表示玩家的移动速度。jump_move 属性设置为 -16,表示玩家跳跃时的垂直移动。life 属性设置为 5,表示玩家的剩余生命值或健康值。game_over 属性初始设置为 “false”,表示游戏是否结束。win 属性初始也设置为 “false”,表示玩家是否取得了胜利。状态属性设置为 “空闲”,表示玩家当前的动画状态。facing_right 属性初始设置为 True,表示玩家朝右。on_ground、on_ceiling、on_left 和 on_right 属性初始设置为 False,分别代表玩家与地面、天花板、左侧和右侧的接触。

玩家动画

对于玩家正在进行的每项活动,无论是行走、跳跃还是简单的站立,我们都会为玩家的每项活动或动作制作大量动画。就像我们在陷阱类中为刀片制作动画一样,我们也将使用类似的逻辑为游戏中的玩家角色制作动画:

# player.py# animates the player actionsdef _animate(self):animation = self.animations[self.status]# loop over frame indexself.frame_index += self.animation_speedif self.frame_index >= len(animation):self.frame_index = 0image = animation[int(self.frame_index)]image = pygame.transform.scale(image, (35, 50))if self.facing_right:self.image = imageelse:flipped_image = pygame.transform.flip(image, True, False)self.image = flipped_image# set the rectif self.on_ground and self.on_right:self.rect = self.image.get_rect(bottomright = self.rect.bottomright)elif self.on_ground and self.on_left:self.rect = self.image.get_rect(bottomleft = self.rect.bottomleft)elif self.on_ground:self.rect = self.image.get_rect(midbottom = self.rect.midbottom)elif self.on_ceiling and self.on_right:self.rect = self.image.get_rect(topright = self.rect.topright)elif self.on_ceiling and self.on_left:self.rect = self.image.get_rect(bottomleft = self.rect.topleft)elif self.on_ceiling:self.rect = self.image.get_rect(midtop = self.rect.midtop)

_animate()方法负责通过循环播放当前动画的帧数来制作玩家角色的动画。首先,该方法使用 self.status 从动画字典中获取与玩家当前状态相对应的动画。接下来,frame_index 会以 self.animation_speed 递增,self.animation_speed 表示动画帧的变化速度。如果 frame_index 超过了动画帧的长度,它就会被重置为 0,从而循环回到第一帧。然后,根据 self.frame_index 的整数值从动画中获取当前帧图像。使用 pygame.transform.scale() 将图像缩放为 (35, 50) 大小。根据播放器的 facing_right 属性,如果播放器朝右,则直接将图像分配给 self.image。否则,如果玩家朝左,则使用 pygame.transform.flip() 水平翻转图像,并将其赋值给 self.image。

随后的代码块会根据玩家的当前状态设置其 rect 属性。玩家矩形(self.rect)的位置和方向会根据玩家是在地面还是天花板上,是在左侧还是右侧进行调整。具体的矩形分配会根据玩家的 on_ground、on_ceiling、on_left 和 on_right 属性组合而变化。

增加玩家能力

在游戏中,玩家应该会向左或向右行走和跳跃。让我们为移动和跳跃添加另外两个函数,命名为 _get_input() 和 _jump()。

# player.py# checks if the player is moving towards left or right or not movingdef _get_input(self, player_event):if player_event != False:if player_event == "right":self.direction.x = 1self.facing_right = Trueelif player_event == "left":self.direction.x = -1self.facing_right = Falseelse:self.direction.x = 0def _jump(self):self.direction.y = self.jump_move

_get_input()方法以 player_event 为参数,它代表来自玩家的输入事件或动作。如果 player_event 不是 False(意味着发生了输入事件),那么如果 player_event 等于 “right”,它就会将玩家方向向量的 x 分量设为 1,表示向右移动。此外,它还会将 facing_right 属性设置为 True,以表示玩家正朝右移动。

如果 player_event 等于 “left”(左),则会将玩家方向向量的 x 分量设置为-1,表示向左移动。它还会将 facing_right 属性设置为 “False”(假),以表示玩家朝左移动。如果 player_event 为 “false”(无输入事件),那么播放器方向向量的 x 分量将被设置为 0,表示没有水平移动。

_jump()方法负责启动玩家的跳跃。它将播放器方向向量的 y 分量设置为 self.jump_move 的值,表示播放器跳跃时的垂直运动。

识别玩家活动

# player.py# identifies player actiondef _get_status(self):if self.direction.y < 0:self.status = "jump"elif self.direction.y > 1:self.status = "fall"elif self.direction.x != 0:self.status = "walk"else:self.status = "idle"

_get_status()函数通过查看玩家精灵在方向属性中的矢量,查看其 x 坐标和 y 坐标的变化,从而为不同的玩家动作确定合适的动画。如果 self.direction.y 小于 0,说明玩家正在跳跃,因此我们会将 self.status 设置为 “跳跃”。反之亦然,如果 self.direction.y 大于 1,意味着玩家正在下落。如果 self.direction.x 不为 0,意味着玩家正在移动,因此我们会将 self.status 设置为 “walk”。最后,如果上述条件都不为真,我们将把 self.status 设置为 “空闲”,作为没有检测到玩家动作时的默认动画。

更新玩家

# player.py# update the player's statedef update(self, player_event):self._get_status()if self.life > 0 and not self.game_over:if player_event == "space" and self.on_ground:self._jump()else:self._get_input(player_event)elif self.game_over and self.win:self.direction.x = 0self.status = "win"else:self.direction.x = 0self.status = "lose"self._animate()

update() 方法首先调用 _get_status() 方法,根据播放器的当前状态更新播放器的状态。

如果玩家的生命值大于 0 且游戏尚未结束,则会根据 player_event 输入评估进一步的操作。如果 player_event 为 “space”(表示跳跃输入),且玩家当前在地面上,则会调用 _jump() 方法启动跳跃。如果 player_event 不是 “space”,或者玩家不在地面上,则会调用 _get_input() 方法来处理输入,并相应地更新玩家的移动。

如果游戏结束且玩家获胜(game_over 为 True,win 为 True),玩家的水平移动会被设置为 0,玩家的状态会被设置为 “win”。如果游戏结束且玩家输了(game_over 为 True,win 为 False),则玩家的水平移动将设为 0,状态设为 “输”。调用 _animate() 方法可更新玩家的动画。

应用游戏目标

对于我们需要的最后一个游戏类,请在 game.py 中创建另一个类并命名为 Game。它负责跟踪游戏的当前状态、游戏是否结束以及玩家是赢了还是输了:

# game.py
import pygame
from settings import HEIGHT, WIDTHpygame.font.init()class Game:def __init__(self, screen):self.screen = screenself.font = pygame.font.SysFont("impact", 70)self.message_color = pygame.Color("darkorange")

添加游戏指示器

我们将在 Game 类中添加几个函数,它们可以帮助用户识别游戏的最新状态。

让我们先创建一个简单的函数,用于在游戏屏幕上显示玩家的剩余生命或健康状况:

# game.pydef show_life(self, player):life_size = 30img_path = "assets/life/life.png"life_image = pygame.image.load(img_path)life_image = pygame.transform.scale(life_image, (life_size, life_size))# life_rect = life_image.get_rect(topleft = pos)indent = 0for life in range(player.life):indent += life_sizeself.screen.blit(life_image, (indent, life_size))

在 show_life() 方法中,life_size 变量被设置为 30,表示生命指示图像的大小。生命图像(“assets/life/life.png”)使用 pygame.image.load() 加载,并按 life_size 缩放,然后存储在 life_image 变量中。

名为 indent 的变量初始化为 0,该变量代表屏幕上显示每个生命指示器的水平位置。根据存储在 player.life 中的剩余生命值执行循环。

在循环的每次迭代中,缩进值都会按 life_size 递增,以确保每个生命值都显示在前一个生命值的旁边。使用 screen.blit() 方法将 life_image 显示在屏幕上,其中 life_image 是要显示的图像,而 (indent, life_size) 坐标代表生命指示器的位置。

我们还要添加一些函数,用于根据游戏状态返回信息。在 Game 类中创建 _game_lose() 和 _game_win() 方法:

# game.py# if player ran out of life or fell below the platformdef _game_lose(self, player):player.game_over = Truemessage = self.font.render('You Lose...', True, self.message_color)self.screen.blit(message,(WIDTH // 3 + 70, 70))# if player reach the goaldef _game_win(self, player):player.game_over = Trueplayer.win = Truemessage = self.font.render('You Win!!', True, self.message_color)self.screen.blit(message,(WIDTH // 3, 70))

游戏检查

让我们再创建一个分析当前游戏状态的函数。在 Game 类中创建另一个方法,并将其命名为 game_state() 方法:

# game.py# checks if the game is over or not, and if win or losedef game_state(self, player, goal):if player.life <= 0 or player.rect.y >= HEIGHT:self._game_lose(player)elif player.rect.colliderect(goal.rect):self._game_win(player)

game_state() 方法有两个参数:player 代表玩家对象,goal 代表游戏中的目标对象。

如果玩家的剩余生命值(player.life)小于或等于 0,或者玩家的垂直位置(player.rect.y)大于或等于屏幕高度(HEIGHT)(当玩家跌落到障碍物下方时,此声明为真),则表示游戏结束,玩家输了。在这种情况下,将调用 _game_lose() 方法来处理游戏结束状态。

如果玩家的矩形(player.rect)与目标的矩形(goal.rect)相撞,则表示玩家已到达目标并赢得了游戏。在这种情况下,将调用 _game_win() 方法来处理游戏结束状态。如果上述条件都不满足,表明游戏仍在进行中,game_state() 方法不会做任何操作。

现在,我们已经完成了平台游戏的编码工作。要测试我们的游戏,请打开终端,进入 "Platformer-Game "文件夹。进入目录后,输入 python main.py 运行游戏。下面是游戏的一些快照:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论

最后,本教程介绍了如何使用 Python 的 Pygame 库创建一款平台游戏。我们探索了游戏的不同组成部分,包括玩家角色、世界对象、动画、碰撞和游戏状态。通过本教程,您已经学会了如何从零开始开发一个基本的平台游戏,理解了一些关键概念,如精灵处理、输入处理、重力、滚动和输赢条件。

利用从本教程中学到的知识,您可以通过添加新功能、新关卡或新机制来进一步增强和定制您的平台游戏。Pygame 为游戏开发提供了一个多功能框架,让您尽情释放创造力,打造引人入胜的游戏体验。您可以随意探索 Pygame 的其他功能,如音效、关卡设计或敌人 AI,从而将您的游戏提升到一个新的水平。希望本教程对您使用 Pygame 创建平台游戏的旅程有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49030.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【OpenCV C++20 学习笔记】基本图像容器——Mat

【OpenCV C20 学习笔记】基本图像容器——Mat 概述Mat内部结构引用计数机制颜色数据格式 显式创建Mat对象使用cv::Mat::Mat构造函数矩阵的数据项 使用数组进行初始化的构造函数cv::Mat::create函数MATLAB风格的初始化小型矩阵通过复制创建Mat对象 Mat对象的输出其他普通数据项的…

77.WEB渗透测试-信息收集-框架组件识别利用(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;76.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;16&#xff09; java&#xff…

HarmonyOS入门-状态管理

View(UI)&#xff1a;UI渲染&#xff0c;指将build方法内的UI描述和Builder装饰的方法内的UI描述映射到界面。 State&#xff1a;状态&#xff0c;指驱动UI更新的数据。用户通过触发组件的事件方法&#xff0c;改变状态数据。状态数据的改变&#xff0c;引起UI的重新渲染。 装…

C# Nmodbus,EasyModbusTCP读写操作

Nmodbus读写 两个Button控件分别为 读取和写入 分别使用控件的点击方法 ①引用第三方《NModbus4》2.1.0版本 全局 public SerialPort port new SerialPort("COM2", 9600, Parity.None, 8, (StopBits)1); ModbusSerialMaster master; public Form1() port.Open();…

UWA Gears正式上线,助力移动平台性能优化

亲爱的开发者朋友们&#xff0c; 我们非常激动地向大家宣布&#xff0c;UWA最新的无SDK性能分析工具 - UWA Gears&#xff0c;现已正式发布&#xff01;无论您使用的是哪种开发引擎&#xff0c;这款工具都能轻松应对&#xff0c;为您的项目保驾护航。更令人心动的是&#xff0c…

后台管理系统登录安全和权限要求

一、前言 几乎所有的系统都有后台管理系统&#xff0c;后台登录需要账号和密码&#xff0c;后台管理员权限需要有控制。所有管理员的操作都应该有操作日志。 二、存在的问题 现在很多系统只需要账号和密码就能登录&#xff0c;有的还是简单账号和简单密码&#xff0c;就是弱口…

虚拟机之ip配置,ssh连接到虚拟机

右边是我的虚拟机&#xff0c;左边是我使用vscode来连接&#xff08;终端也可以。然后注意vscode配置后点一下刷新&#xff0c;不会自动刷新的QA&#xff09;&#xff08;吐槽一下&#xff0c;虚拟机都不能复制内容呢&#xff0c;确实仿真&#xff0c;centos仿真就是因为没有图…

二手车小程序

本文来自&#xff1a;FastAdmin二手车小程序 - 源码1688 一款基于ThinkPHPFastAdmin开发的原生微信小程序二手车管理系统。 前端小程序码&#xff1a; 后台演示地址&#xff1a; https://facars.site100.cn/OHNYSKzuba.php/carswxsys/sysinit?refaddtabs

视觉巡线小车——STM32+OpenMV(四)

目录 前言 一、整体控制思路 二、代码实现 1.主函数 2.定时器回调函数 总结 前言 通过以上三篇文章已将基本条件实现&#xff0c;本文将结合以上内容&#xff0c;进行综合控制&#xff0c;实现小车的视觉巡线功能。 系列文章请查看&#xff1a;视觉巡线小车——STM32OpenMV系列…

【轨物方案】电表红外抄表物联网装置

对于光伏运维工程师来说&#xff0c;电表抄表是一件并不陌生的工作&#xff0c;不过很多并网电表的RS485通讯接口一般都被占用了&#xff0c;并且电表的外壳也被铅封起来。在这种情况下电站通常采用人工抄表的方式采集电量数据&#xff0c;这种方式费时费力&#xff0c;对电站运…

京东科技集团将在香港发行与港元1:1挂钩的加密货币稳定币

据京东科技集团旗下公司京东币链科技(香港)官网信息&#xff0c;京东稳定币是一种基于公链并与港元(HKD) 1:1挂钩的稳定币&#xff0c;将在公共区块链上发行&#xff0c;其储备由高度流动且可信的资产组成&#xff0c;这些资产安全存放于持牌金融机构的独立账户中&#xff0c;通…

【OpenCV C++20 学习笔记】扫描图片数据

扫描图片数据 应用情景图像数据扫描的难点颜色空间缩减&#xff08;color space reduction&#xff09;查询表 扫描算法计算查询表统计运算时长连续内存3种扫描方法C风格的扫描方法迭代器方法坐标方法LUT方法 算法效率对比结论 应用情景 图像数据扫描的难点 在上一篇文章《基…

OAK-FFC 分体式相机使用入门介绍

概述 OAK FFC 主控板和多种可选配镜头模组非常适合灵活的搭建您的3D人工智能产品原型。由于镜头是分体式的&#xff0c;因此你可以根据需要测量的距离&#xff0c;自定义深度相机安装基线&#xff0c;并根据你的项目要求&#xff08;分辨率、快门类型、FPS、光学元件&#xff…

FPGA教程|零基础到实战的全方位指导

在数字化时代&#xff0c;FPGA&#xff08;现场可编程门阵列&#xff09;作为一种灵活的硬件编程平台&#xff0c;正逐渐成为电子工程师和计算机科学家必备的技能之一。无论你是电子专业的学生&#xff0c;还是职场中的工程师&#xff0c;掌握FPGA开发技术&#xff0c;都将为你…

前端与HTML

前端与HTML 什么是前端&#xff1f; 解决GUI人机交互问题跨终端&#xff08;PC/移动浏览器&#xff09;&#xff08;客户端小程序&#xff09;&#xff08;VR/AR等&#xff09;Web技术栈 前端工程师&#xff1a;利用web技术栈解决多端图形界面用户交互的工程师 前端技术栈 …

CDGA|数据治理:安全如何贯穿数据供给、流通、使用全过程

随着信息技术的飞速发展&#xff0c;数据已经成为企业运营、社会管理和经济发展的核心要素。然而&#xff0c;数据在带来巨大价值的同时&#xff0c;也伴随着诸多安全风险。因此&#xff0c;数据治理的重要性日益凸显&#xff0c;它不仅仅是对数据的简单管理&#xff0c;更是确…

rv1126物体检测 rkmedia、opencv……

整体码流流向&#xff1a; 因此代码也分为这几部分&#xff1a; VI&#xff1a;采集视频 配置视频采集信息 模型推理线程&#xff1a;获取VI码流、载入模型、进行模型推理、保存推理结果 画框线程&#xff1a;获取VI码流、获取推理结果、显示推理结果、输出码流到VENC VENC…

如何使用C#快速创建定时任务

原文链接&#xff1a;https://www.cnblogs.com/zhaotianff/p/17511040.html 使用Windows的计划任务功能可以创建定时任务。 使用schtasks.exe可以对计划任务进行管理&#xff0c;而不需要编写额外代码 这里掌握schtasks /CREATE 的几个核心参数就可以快速创建计划任务 /SC …

论文总结:A Survey on Evaluation of Large Language Models-鲁棒性相关内容

A Survey on Evaluation of Large Language Models 只取了鲁棒性相关的内容 LLMs&#xff1a;《A Survey on Evaluation of Large Language Models大型语言模型评估综述》理解智能本质(具备推理能力)、AI评估的重要性(识别当前算法的局限性设 3.2.1 Robustness鲁棒性&#xf…

Gitlab以及分支管理

一、概述 Git 是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;尤其是源代码的变化。它由 Linus Torvalds 于 2005 年开发&#xff0c;旨在帮助管理大型软件项目的开发过程。 二、Git 的功能特性 Git 是关注于文件数据整体的变化&#xff0c;直接会将文件…