【Dison夏令营 Day 16】如何使用 Python 中的 PyGame 制作俄罗斯方块游戏

俄罗斯方块(Tetris)是一款经典的益智游戏,游戏的目的是将落下的几何图形片(称为 “俄罗斯方块”)排列起来,填满水平线,不留空隙。当一条线被完全填满时,它就被清除了,玩家就能获得分数。随着四角棋的下落速度加快,游戏的挑战性也逐渐增加,及时排列四角棋也变得更加困难。

在这里插入图片描述

在本教程中,我们将指导您使用 PyGame 逐步创建一个简单的俄罗斯方块游戏。我们将介绍以下内容:

  • 设置开发环境并安装 Pygame
  • 创建游戏窗口并定义俄罗斯方块棋子
  • 实现俄罗斯方块和俄罗斯方块类以管理游戏逻辑
  • 处理用户输入和游戏事件
  • 在屏幕上绘制游戏状态、分数和游戏结束信息
  • 执行主游戏循环

在本教程结束时,您将拥有一个功能齐全的俄罗斯方块游戏,并可以进行游戏和自定义。这个项目还将帮助您了解使用 Python 和 Pygame 开发游戏的基础知识,并为创建其他类型的游戏打下基础。下面是它的外观:

在这里插入图片描述

入门

安装好 Python 后,打开终端或命令提示符,输入以下命令安装 Pygame 库:

$ pip install pygame

创建游戏窗口

现在我们的开发环境已经准备就绪,让我们开始创建游戏窗口并定义四面体形状。

首先,我们需要导入俄罗斯方块游戏所需的模块。在 Python 脚本中添加以下几行:

import sys
import pygame
import random

要使用 Pygame 库,我们需要对其进行初始化。在 import 语句后添加以下一行:

pygame.init()

定义屏幕尺寸、颜色和四角棋形状

接下来,我们需要为游戏定义一些常量,如屏幕尺寸、网格大小、颜色和四角棋的形状。在脚本中添加以下几行:

# Screen dimensions
WIDTH, HEIGHT = 800, 600
GRID_SIZE = 25# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
COLORS = [RED, BLUE, GREEN]# Tetromino shapes
SHAPES = [[['.....','.....','.....','OOOO.','.....'],['.....','..O..','..O..','..O..','..O..']],[['.....','.....','..O..','.OOO.','.....'],['.....','..O..','.OO..','..O..','.....'],['.....','.....','.OOO.','..O..','.....'],['.....','..O..','..OO.','..O..','.....']],[['.....','.....','..OO.','.OO..','.....'],['.....','.....','.OO..','..OO.','.....'],['.....','.O...','.OO..','..O..','.....'],['.....','..O..','.OO..','.O...','.....']],[['.....','..O..','..O.','..OO.','.....'],['.....','...O.','.OOO.','.....','.....'],['.....','.OO..','..O..','..O..','.....'],['.....','.....','.OOO.','.O...','.....']],
]

在这里,我们定义了游戏窗口的宽度和高度、四角棋的网格大小以及游戏使用的颜色(白色、黑色和红色)。SHAPES 列表包含以字符串表示的四面体形状,您可以随意添加/编辑。您还可以随意调整颜色和网格大小。

实现 Tetromino 和 Tetris 类以管理游戏逻辑

现在,我们已经定义了游戏窗口和俄罗斯方块形状,让我们创建两个类来管理游戏逻辑:Tetromino 类和 Tetris 方块类。

创建 Tetromino 类

Tetromino 类将表示单个四面体,并具有位置、形状、颜色和旋转属性。在脚本中添加以下代码:

class Tetromino:def __init__(self, x, y, shape):self.x = xself.y = yself.shape = shapeself.color = random.choice(COLORS) # You can choose different colors for each shapeself.rotation = 0

创建 Tetris 类

俄罗斯方块类将处理主要的游戏逻辑。它将包含用于创建新棋子、检查走棋是否有效、清线、锁定棋子、更新游戏状态和绘制游戏的方法。在脚本中添加以下代码:

class Tetris:def __init__(self, width, height):self.width = widthself.height = heightself.grid = [[0 for _ in range(width)] for _ in range(height)]self.current_piece = self.new_piece()self.game_over = Falseself.score = 0  # Add score attribute

让我们来制作一个新的 Tetromino 棋子:

    def new_piece(self):# Choose a random shapeshape = random.choice(SHAPES)# Return a new Tetromino objectreturn Tetromino(self.width // 2, 0, shape)

接下来,valid_move() 方法会检查棋子是否能移动到指定位置:

    def valid_move(self, piece, x, y, rotation):"""Check if the piece can move to the given position"""for i, row in enumerate(piece.shape[(piece.rotation + rotation) % len(piece.shape)]):for j, cell in enumerate(row):try:if cell == 'O' and (self.grid[piece.y + i + y][piece.x + j + x] != 0):return Falseexcept IndexError:return Falsereturn True

clear_lines() 方法会清除已满的行,并返回已清除的行数,以便我们稍后计算分数:

    def clear_lines(self):"""Clear the lines that are full and return the number of cleared lines"""lines_cleared = 0for i, row in enumerate(self.grid[:-1]):if all(cell != 0 for cell in row):lines_cleared += 1del self.grid[i]self.grid.insert(0, [0 for _ in range(self.width)])return lines_cleared

现在是锁定棋子的方法:

    def lock_piece(self, piece):"""Lock the piece in place and create a new piece"""for i, row in enumerate(piece.shape[piece.rotation % len(piece.shape)]):for j, cell in enumerate(row):if cell == 'O':self.grid[piece.y + i][piece.x + j] = piece.color# Clear the lines and update the scorelines_cleared = self.clear_lines()self.score += lines_cleared * 100  # Update the score based on the number of cleared lines# Create a new pieceself.current_piece = self.new_piece()# Check if the game is overif not self.valid_move(self.current_piece, 0, 0, 0):self.game_over = Truereturn lines_cleared

update() 函数将四叶草向下移动一格:

    def update(self):"""Move the tetromino down one cell"""if not self.game_over:if self.valid_move(self.current_piece, 0, 1, 0):self.current_piece.y += 1else:self.lock_piece(self.current_piece)

最后,我们制作了绘制游戏网格和当前棋子的方法:

    def draw(self, screen):"""Draw the grid and the current piece"""for y, row in enumerate(self.grid):for x, cell in enumerate(row):if cell:pygame.draw.rect(screen, cell, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))if self.current_piece:for i, row in enumerate(self.current_piece.shape[self.current_piece.rotation % len(self.current_piece.shape)]):for j, cell in enumerate(row):if cell == 'O':pygame.draw.rect(screen, self.current_piece.color, ((self.current_piece.x + j) * GRID_SIZE, (self.current_piece.y + i) * GRID_SIZE, GRID_SIZE - 1, GRID_SIZE - 1))

为在游戏中绘制文本创建辅助函数

既然我们已经创建了俄罗斯方块类,那么让我们来创建两个绘制文本的辅助函数,一个用于显示得分,另一个用于显示 “Game Over!”:

def draw_score(screen, score, x, y):"""Draw the score on the screen"""font = pygame.font.Font(None, 36)text = font.render(f"Score: {score}", True, WHITE)screen.blit(text, (x, y))def draw_game_over(screen, x, y):"""Draw the game over text on the screen"""font = pygame.font.Font(None, 48)text = font.render("Game Over", True, RED)screen.blit(text, (x, y))

这些函数需要四个参数(draw_game_over()需要三个):

  • screen:要绘制的 Pygame 表面。
  • score:当前游戏得分。
  • x:分数显示位置的 x 坐标。
  • y:分数显示位置的 y 坐标。

这些函数使用 pygame.font.Font(None, 36) 创建字体对象,使用 font.render() 方法渲染得分文本,然后使用 screen.blit() 将文本显示在屏幕上。

使游戏循环

在运行循环之前,我们首先初始化 Pygame,创建时钟对象,然后创建游戏屏幕和游戏,即俄罗斯方块对象:

def main():# Initialize pygamescreen = pygame.display.set_mode((WIDTH, HEIGHT))pygame.display.set_caption('Tetris')# Create a clock objectclock = pygame.time.Clock()# Create a Tetris objectgame = Tetris(WIDTH // GRID_SIZE, HEIGHT // GRID_SIZE)fall_time = 0fall_speed = 50  # You can adjust this value to change the falling speed, it's in milliseconds

您可以调整 fall_speed 来降低它(使其更快),或增加它使其更慢。

下面是游戏循环:

    while True:# Fill the screen with blackscreen.fill(BLACK) for event in pygame.event.get():# Check for the QUIT eventif event.type == pygame.QUIT:pygame.quit()sys.exit()# Check for the KEYDOWN eventif event.type == pygame.KEYDOWN:if event.key == pygame.K_LEFT:if game.valid_move(game.current_piece, -1, 0, 0):game.current_piece.x -= 1 # Move the piece to the leftif event.key == pygame.K_RIGHT:if game.valid_move(game.current_piece, 1, 0, 0):game.current_piece.x += 1 # Move the piece to the rightif event.key == pygame.K_DOWN:if game.valid_move(game.current_piece, 0, 1, 0):game.current_piece.y += 1 # Move the piece downif event.key == pygame.K_UP:if game.valid_move(game.current_piece, 0, 0, 1):game.current_piece.rotation += 1 # Rotate the pieceif event.key == pygame.K_SPACE:while game.valid_move(game.current_piece, 0, 1, 0):game.current_piece.y += 1 # Move the piece down until it hits the bottomgame.lock_piece(game.current_piece) # Lock the piece in place# Get the number of milliseconds since the last framedelta_time = clock.get_rawtime() # Add the delta time to the fall timefall_time += delta_time if fall_time >= fall_speed:# Move the piece downgame.update()# Reset the fall timefall_time = 0# Draw the score on the screendraw_score(screen, game.score, 10, 10)# Draw the grid and the current piecegame.draw(screen)if game.game_over:# Draw the "Game Over" messagedraw_game_over(screen, WIDTH // 2 - 100, HEIGHT // 2 - 30)  # Draw the "Game Over" message# You can add a "Press any key to restart" message here# Check for the KEYDOWN eventif event.type == pygame.KEYDOWN:# Create a new Tetris objectgame = Tetris(WIDTH // GRID_SIZE, HEIGHT // GRID_SIZE)# Update the displaypygame.display.flip()# Set the framerateclock.tick(60)

主游戏循环是一个 while 循环,不断执行以下步骤:

  1. 用黑色填充屏幕,清空屏幕。
  2. 处理 Pygame 事件,如退出游戏或处理移动和旋转俄罗斯方块棋子的键盘输入。
  3. 更新游戏状态,包括将当前棋子向下移动一行,并在棋子到达底部时将其锁定。
  4. 在屏幕上绘制当前分数、游戏网格和当前棋子。
  5. 如果游戏结束,显示 "游戏结束 "信息。
  6. 更新 Pygame 显示屏,并使用时钟对象控制帧频。

最后的话

就是这样!俄罗斯方块游戏的简单实现现在应该可以运行了。您可以运行脚本来玩游戏,并对游戏玩法、图形或控件进行任何所需的定制。

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

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

相关文章

操作系统——内存管理(面试准备)

虚拟内存 单片机没有操作系统,每次写完代码,都需要借助工具把程序烧录进去,这样程序才能跑起来。 另外,单片机的CPU是直接操作内存的物理地址。 在这种情况下,想在内存中同时运行两个程序是不可能的,如果第…

(CVPR-2024)SwiftBrush:具有变分分数蒸馏的单步文本到图像扩散模型

SwiftBrush:具有变分分数蒸馏的单步文本到图像扩散模型 Paper Title:SwiftBrush: One-Step Text-to-Image Diffusion Model with Variational Score Distillation Paper 是 VinAI Research 发表在 CVPR 24 的工作 Paper地址 Code:地址 Abstract 尽管文本…

Flutter-实现物理小球碰撞效果

效果 引言 在Flutter应用中实现物理动画效果,可以大大提升用户体验。本文将详细介绍如何在Flutter中创建一个模拟物理碰撞的动画小球界面,主要代码实现基于集成sensors_plus插件来获取设备的加速度传感器数据。 准备工作 在开始之前,请确保…

一文详解DDL同步及其应用场景

目录 一、什么是DDL? 二、什么是DDL同步? 三、DDL同步的痛点 1、缺少自动DDL同步机制 2、缺少DDL变更监测预警 四、解决方案 五、应用场景及案例 案例一 案例二 案例三 在现代数据管理中,数据库的结构变更频繁且不可避免,特别是在…

Kubelet 认证

当我们执行kubectl exec -it pod [podName] sh命令时,apiserver会向kubelet发起API请求。也就是说,kubelet会提供HTTP服务,而为了安全,kubelet必须提供HTTPS服务,且还要提供一定的认证与授权机制,防止任何知…

C语言 | Leecode C语言题解之第229题多数元素II

题目: 题解: /*** Note: The returned array must be malloced, assume caller calls free().*//*假定 num1,num2 为出现次数大于 nums.length / 3 的两个数。(最多出现两个)遍历 nums, 若出现 num1、num2…

《C语言程序设计 第4版》笔记和代码 第十一章 指针和数组

第十一章 指针和数组 11.1 指针和一维数组间的关系 1 由于数组名代表数组元素的连续存储空间的首地址,因此,数组元素既可以用下标法也可以用指针来引用。 例11.1见文末 2 p1与p在本质上是两个不同的操作,前者不改变当前指针的指向&#xf…

无人机之遥控器保养

一、使用存放 1、避免让遥控器受到强烈的震动或从高处跌落,以免影响内部结构的精度; 2、遥控器在使用完后,需要将天线收拢,避免折断,养成定期检查天线的习惯; 3、定期检查遥控器按键有无裂纹、畸变、松旷…

ISO/OIS的七层模型②

OSI模型是一个分层的模型,每一个部分称为一层,每一层扮演固定的角色,互不干扰。OSI有7层,从上到下分别是: 一,每层功能 7.应用层(Application layer ):应用层功能&#x…

如何从gitlab删除仓库

嗨,我是兰若姐姐。今天发现gitlab上有些仓库的代码没有用,是个多余的仓库,想要删掉,经过一番操作之后,成功的删除了,git上没有 多余的仓库,看着干净舒服很多,现在把删除的过程分享出…

基于ssm的图书管理系统的设计与实现

摘 要 在当今信息技术日新月异的时代背景下,图书管理领域正经历着深刻的变革,传统的管理模式已难以适应现代社会的快节奏和高要求,逐渐向数字化、智能化的方向演进。本论文聚焦于这一转变趋势,致力于设计并成功实现一个基于 SSM&…

U-net和U²-Net网络详解

目录 U-Net: Convolutional Networks for Biomedical Image Segmentation摘要U-net网络结构pixel-wise loss weight U-Net: Going Deeper with Nested U-Structure for Salient Object Detection摘要网络结构详解整体结构RSU-n结构RSU-4F结构saliency map fusion module -- 显著…

JavaFx+MySql学生管理系统

前言: 上个月学习了javafx和mysql数据库,于是写了一个学生管理系统,因为上个月在复习并且有一些事情,比较忙,所以没有更新博客了,这个项目页面虽然看着有点简陋了,但是大致内容还是比较简单的,于是现在跟大家分享一下我的学生管理系统,希望对这方面有兴趣的同学提供一些帮助 &a…

Vue 3 中创建一个动态的组件实例

本文将介绍如何在 Vue 3 中实现一个动态 Toast 组件实例。我们将创建一个简单的 Toast 组件,并使用一个动态创建实例的脚本来显示 Toast 消息。在 Vue 3 中创建动态组件实例有许多好处,这些好处主要体现在灵活性、性能、可维护性和用户体验等方面。 创建…

【JavaScript 算法】快速排序:高效的排序算法

🔥 个人主页:空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 快速排序(Quick Sort)是一种高效的排序算法,通过分治法将数组分为较小的子数组,递归地排序子数组。快速排序通常…

分享一个 .NET 通过监听器拦截 EF 消息写日志的详细例子

前言 EF 开发效率确实很高也很便捷,但当它发生错误时,也挺让人头疼的,为什么?因为 EF 就像是一个黑盒子,一切全被封装起来,出错的时候很难定位原因,如果能够知道并打印 EF 生成的 SQL 语句&…

记录些Redis题集(1)

为什么Redis要有淘汰机制? 淘汰机制的存在是必要的,因为Redis是一种基于内存的数据库,所有数据都存储在内存中。然而,内存资源是有限的。在Redis的配置文件redis.conf中,有一个关键的配置项: # maxmemory…

Go语言入门之Map详解

Go语言入门之Map详解 1.基础定义 map是一个无序的,k-v键值对格式的集合 (1)特点 类型特点:map为引用类型,所以在函数中更新value值会永久改变顺序特点:map的遍历是无序的,因为底层是哈希表&am…

零基础学python(二)

1. 字典 字典的创建 最常见的创建方式: d {"k1": "v1", "k2": "v2"} 再向字典中添加一对键值: d["k3"] "v3" 字典还可以用dict()创建,这种方式中,键是不加引…

【Unity2D 2022:UI】制作主菜单

一、创建主菜单游戏场景 1. 在Scenes文件夹中新建一个游戏场景Main Menu 2. 为场景添加背景 (1)创建画布Canvas (2)在Canvas中创建新的空游戏物体Main Menu (3)在Main Menu中新建一个图像游戏物体Backgrou…