【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…

uni-app基本的数据绑定v-bind,v-for,v-on:click

v-bind动态绑定属性 1.在data中定义了一个属性img&#xff0c;是图片路径&#xff0c;把这个图片路径绑定到image中用于展示&#xff0c;利用v-bind进行渲染 <image v-bind:src"img"></image>还可以缩写成 <image :src"img"></ima…

HarmonyOS入门-状态管理

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

18-else

## 八.else --- 循环可以和else配合使用,else下方缩进的代码指的是当循环正常结束之后要执行的代码. ### 8.1while...else --- 需求:女朋友生气了,要惩罚:连续说5遍媳妇我错了,如果道歉正常完毕女朋友就原谅我了,这个程序该怎么写? python i 1 while i < 5: pri…

C语言中常用的排序

一. 冒泡排序 对相邻两个元素的值进行两两比较&#xff0c;若发现逆序则交换&#xff0c;使值较大的元素逐渐从前移向后部&#xff0c;就如水底下的气泡一样逐渐向上冒。 void bubbleSort(int arr[], int n) {for (int i 0; i < n - 1; i) {for (int j 0; j < n - i …

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();…

audit审计超详细介绍,常见审计规则示例,与syslog、secure对比

Audit&#xff08;审计&#xff09;介绍 Audit&#xff08;审计&#xff09;在Linux系统中&#xff0c;特别是CentOS中&#xff0c;是一个用于监控和记录系统上各种操作的技术手段。Audit的主要功能是为系统管理员提供一个跟踪系统上与安全相关信息的方法。根据预配置的规则&a…

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

解决springboot的跨域冲突

前言 赶时间的可以直接加入地下的配置文件&#xff0c;就可解决问题。上面从概念讲起。 概念 在Web开发中&#xff0c;浏览器出于安全考虑&#xff0c;默认不允许从一个源加载页面的同时通过XMLHttpRequest发起对不同源的请求。例如&#xff0c;一个运行在http://example.co…

视觉巡线小车——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…

微前端--qiankun(3)

微前端–qiankun(3) 微前端的运行原理 监听路由变化匹配子应用加载子应用渲染子应用 监听路由变化 window.onhashchange 和window.addEventListener(popstate,() > {})等等&#xff0c;下篇文章我写个 匹配子应用 const currentApp apps.find(app > window.locati…

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

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