python实现打砖块游戏

1. 前言

Brick Breaker,也叫打砖块游戏,是一种非常经典的街机游戏,相信很多人小时候都玩过这个游戏。在这篇文章中,我们将使用Python编写一个简单的打砖块游戏。

2. 游戏规则

打砖块游戏的规则非常简单,玩家需要操纵一个反弹板,用球去打破上方不断下来的砖块。当所有砖块都被打破后,游戏获胜。

2.1 游戏界面

首先,让我们来看一下我们需要实现的游戏界面。游戏界面如下:

```

╔══════════════════════════════════╗

║ ║

║ ║

║ ║

║ ║

║ ║

║ ║

║ ║

║ ║

║ ║

║ ║

╚══════════════════════════════════╝

```

我们需要维护一个二维数组表示游戏界面,每个元素的值表示相应位置上是否有砖块。同时,我们需要在左侧操纵一个反弹板,用来射出小球。

2.2 游戏流程

游戏流程如下:

1. 初始化游戏界面,生成起始的砖块布局;

2. 显示游戏界面;

3. 等待玩家按下空格键;

4. 每隔一定时间,更新球的位置;

5. 判断球的位置是否碰到砖块或者反弹板,如果碰到,改变球的运动方向;

6. 判断球是否越界,如果越界,游戏失败;

7. 判断所有砖块是否被打破,如果是,游戏胜利;

8. 重复步骤4-7,直到游戏胜利或失败。

3. 编码实现

3.1 初始化游戏界面

游戏界面使用一个NumPy数组来表示,每个元素的值为0或1,分别表示位置上没有砖块或有砖块。我们将使用Matplotlib来显示游戏界面。

下面是初始化游戏界面的代码:

import numpy as np

import matplotlib.pyplot as plt

# 定义屏幕大小

SCREEN_WIDTH = 10

SCREEN_HEIGHT = 10

# 定义砖块大小

BRICK_WIDTH = 2

BRICK_HEIGHT = 1

# 定义砖块间隔

BRICK_SPACE_X = 1

BRICK_SPACE_Y = 1

# 定义反弹板大小

PAD_WIDTH = 3

PAD_HEIGHT = 1

# 定义球大小

BALL_SIZE = 1

# 创建游戏界面

screen = np.zeros((SCREEN_HEIGHT, SCREEN_WIDTH))

# 随机生成砖块

bricks = np.zeros((SCREEN_HEIGHT // (BRICK_HEIGHT + BRICK_SPACE_Y), SCREEN_WIDTH // (BRICK_WIDTH + BRICK_SPACE_X)))

for i in range(bricks.shape[0]):

for j in range(bricks.shape[1]):

if np.random.random() < 0.5:

bricks[i, j] = 1

# 在游戏界面中放置砖块

for i in range(bricks.shape[0]):

for j in range(bricks.shape[1]):

if bricks[i, j]:

y = i * (BRICK_HEIGHT + BRICK_SPACE_Y)

x = j * (BRICK_WIDTH + BRICK_SPACE_X)

screen[y:y+BRICK_HEIGHT, x:x+BRICK_WIDTH] = 1

# 初始化反弹板和球的位置

pad_x = SCREEN_WIDTH // 2 - PAD_WIDTH // 2

ball_x = pad_x + PAD_WIDTH // 2

ball_y = SCREEN_HEIGHT - PAD_HEIGHT - BALL_SIZE

ball_dir_x = 1

ball_dir_y = -1

# 显示游戏界面

plt.imshow(screen, cmap='gray')

我们使用几个常量来定义游戏界面和游戏元素的大小。我们随机生成一个砖块布局,并将其放置在游戏界面中。最后初始化反弹板和球的位置,并显示游戏界面。运行代码,我们将会看到以下游戏界面:

![游戏界面](https://s3.ax1x.com/2021/03/20/6BaHs0.png)

3.2 更新球的位置

下面是更新球的位置的代码:

# 定义帧率和速度

FPS = 60

SPEED = 0.5

# 定义游戏状态

GAME_STATE_RUNNING = 1

GAME_STATE_OVER = 2

# 初始化游戏状态

game_state = GAME_STATE_RUNNING

# 开始游戏循环

while game_state == GAME_STATE_RUNNING:

# 处理键盘事件

for event in plt.gcf().canvas.key_press_events:

if event.key == ' ':

ball_dir_x = 1 if ball_dir_x == 0 else 0

# 清空屏幕

plt.clf()

# 更新球的位置

ball_x += ball_dir_x * SPEED

ball_y += ball_dir_y * SPEED

# 显示球和反弹板

plt.fill([pad_x, pad_x+PAD_WIDTH, pad_x+PAD_WIDTH, pad_x], [0, 0, PAD_HEIGHT, PAD_HEIGHT], 'w')

plt.fill([ball_x, ball_x+BALL_SIZE, ball_x+BALL_SIZE, ball_x], [ball_y, ball_y, ball_y+BALL_SIZE, ball_y+BALL_SIZE], 'w')

# 显示砖块和边界

plt.imshow(screen, cmap='gray')

# 显示游戏界面

plt.axis('off')

plt.pause(1 / FPS)

plt.show()

我们定义了帧率和速度,以及游戏状态,然后在游戏循环中更新球的位置。当玩家按下空格键时,我们改变球的运动方向。我们使用Matplotlib来显示球和反弹板,并显示当前的游戏界面。

运行代码,我们将会看到球在游戏界面中移动。

3.3 碰撞检测

下面是碰撞检测的代码:

# 检测是否碰到反弹板

if ball_y + BALL_SIZE >= SCREEN_HEIGHT - PAD_HEIGHT and ball_y < SCREEN_HEIGHT - PAD_HEIGHT:

if ball_x + BALL_SIZE >= pad_x and ball_x <= pad_x + PAD_WIDTH:

ball_dir_y *= -1

# 检测是否碰到边界

if ball_x < 0 or ball_x + BALL_SIZE >= SCREEN_WIDTH:

ball_dir_x *= -1

if ball_y < 0:

ball_dir_y *= -1

# 检测是否碰到砖块

if ball_y < SCREEN_HEIGHT - (BRICK_HEIGHT + BRICK_SPACE_Y) * bricks.shape[0]:

i = (SCREEN_HEIGHT - ball_y - BALL_SIZE) // (BRICK_HEIGHT + BRICK_SPACE_Y)

j = ball_x // (BRICK_WIDTH + BRICK_SPACE_X)

if i >= 0 and i < bricks.shape[0] and j >= 0 and j < bricks.shape[1] and bricks[i, j]:

bricks[i, j] = 0

screen[(bricks.shape[0]-i-1)*(BRICK_HEIGHT+BRICK_SPACE_Y):(bricks.shape[0]-i)*(BRICK_HEIGHT+BRICK_SPACE_Y)-BRICK_SPACE_Y, j*(BRICK_WIDTH+BRICK_SPACE_X):(j+1)*(BRICK_WIDTH+BRICK_SPACE_X)-BRICK_SPACE_X] = 0

ball_dir_y *= -1

# 检查是否胜利

if np.sum(bricks) == 0:

game_state = GAME_STATE_WIN

在碰撞检测中,我们首先判断球是否碰到了反弹板,并将球的运动方向反转。然后检查球是否碰到了边界,如果碰到了边界,同样将球的运动方向反转。最后,检查球是否碰到了砖块。如果球与砖块相碰,将该砖块从界面中移除,并将球的运动方向反转。当所有砖块都被打破时,游戏胜利。

3.4 完整代码

下面是完整的代码:

import numpy as np

import matplotlib.pyplot as plt

# 定义屏幕大小

SCREEN_WIDTH = 10

SCREEN_HEIGHT = 10

# 定义砖块大小

BRICK_WIDTH = 2

BRICK_HEIGHT = 1

# 定义砖块间隔

BRICK_SPACE_X = 1

BRICK_SPACE_Y = 1

# 定义反弹板大小

PAD_WIDTH = 3

PAD_HEIGHT = 1

# 定义球大小

BALL_SIZE = 1

# 定义帧率和速度

FPS = 60

SPEED = 0.5

# 定义游戏状态

GAME_STATE_RUNNING = 1

GAME_STATE_WIN = 2

GAME_STATE_OVER = 3

# 创建游戏界面

screen = np.zeros((SCREEN_HEIGHT, SCREEN_WIDTH))

# 随机生成砖块

bricks = np.zeros((SCREEN_HEIGHT // (BRICK_HEIGHT + BRICK_SPACE_Y), SCREEN_WIDTH // (BRICK_WIDTH + BRICK_SPACE_X)))

for i in range(bricks.shape[0]):

for j in range(bricks.shape[1]):

if np.random.random() < 0.5:

bricks[i, j] = 1

# 在游戏界面中放置砖块

for i in range(bricks.shape[0]):

for j in range(bricks.shape[1]):

if bricks[i, j]:

y = i * (BRICK_HEIGHT + BRICK_SPACE_Y)

x = j * (BRICK_WIDTH + BRICK_SPACE_X)

screen[y:y+BRICK_HEIGHT, x:x+BRICK_WIDTH] = 1

# 初始化反弹板和球的位置

pad_x = SCREEN_WIDTH // 2 - PAD_WIDTH // 2

ball_x = pad_x + PAD_WIDTH // 2

ball_y = SCREEN_HEIGHT - PAD_HEIGHT - BALL_SIZE

ball_dir_x = 1

ball_dir_y = -1

# 初始化游戏状态

game_state = GAME_STATE_RUNNING

# 开始游戏循环

while game_state == GAME_STATE_RUNNING:

# 处理键盘事件

for event in plt.gcf().canvas.key_press_events:

if event.key == ' ':

ball_dir_x = 1 if ball_dir_x == 0 else 0

# 清空屏幕

plt.clf()

# 更新球的位置

ball_x += ball_dir_x * SPEED

ball_y += ball_dir_y * SPEED

# 检测是否碰到反弹板

if ball_y + BALL_SIZE >= SCREEN_HEIGHT - PAD_HEIGHT and ball_y < SCREEN_HEIGHT - PAD_HEIGHT:

if ball_x + BALL_SIZE >= pad_x and ball_x <= pad_x + PAD_WIDTH:

ball_dir_y *= -1

# 检测是否碰到边界

if ball_x < 0 or ball_x + BALL_SIZE >= SCREEN_WIDTH:

ball_dir_x *= -1

if ball_y < 0:

ball_dir_y *= -1

# 检测是否碰到砖块

if ball_y < SCREEN_HEIGHT - (BRICK_HEIGHT + BRICK_SPACE_Y) * bricks.shape[0]:

i = (SCREEN_HEIGHT - ball_y - BALL_SIZE) // (BRICK_HEIGHT + BRICK_SPACE_Y)

j = ball_x // (BRICK_WIDTH + BRICK_SPACE_X)

if i >= 0 and i < bricks.shape[0] and j >= 0 and j < bricks.shape[1] and bricks[i, j]:

bricks[i, j] = 0

screen[(bricks.shape[0]-i-1)*(BRICK_HEIGHT+BRICK_SPACE_Y):(bricks.shape[0]-i)*(BRICK_HEIGHT+BRICK_SPACE_Y)-BRICK_SPACE_Y, j*(BRICK_WIDTH+BRICK_SPACE_X):(j+1)*(BRICK_WIDTH+BRICK_SPACE_X)-BRICK_SPACE_X] = 0

ball_dir_y *= -1

# 检查是否胜利

if np.sum(bricks) == 0:

game_state = GAME_STATE_WIN

# 显示球和反弹板

plt.fill([pad_x, pad_x+PAD_WIDTH, pad_x+PAD_WIDTH, pad_x], [0, 0, PAD_HEIGHT, PAD_HEIGHT], 'w')

plt.fill([ball_x, ball_x+BALL_SIZE, ball_x+BALL_SIZE, ball_x], [ball_y, ball_y, ball_y+BALL_SIZE, ball_y+BALL_SIZE], 'w')

# 显示砖块和边界

plt.imshow(screen, cmap='gray')

# 显示游戏界面

plt.axis('off')

plt.pause(1 / FPS)

plt.show()

# 检查是否失败

if ball_y + BALL_SIZE >= SCREEN_HEIGHT:

game_state = GAME_STATE_OVER

# 显示游戏结束界面

plt.clf()

if game_state == GAME_STATE_WIN:

plt.text(0.5, 0.5, 'You win!', ha='center', va='center', fontsize=20)

elif game_state == GAME_STATE_OVER:

plt.text(0.5, 0.5, 'Game over!', ha='center', va='center', fontsize=20)

plt.axis('off')

plt.show()

我们将游戏状态和游戏界面显示的逻辑加入到游戏循环中,并在游戏结束时,显示相应的游戏结束界面。

4. 结论

在这篇文章中,我们使用Python编写了一个简单的打砖块游戏。我们通过Matplotlib来显示游戏界面,并使用NumPy数组来维护游戏状态。我们实现了游戏的规则和碰撞检测,使得玩家可以在游戏界面中与砖块和反弹板交互。这个游戏虽然简单,但是可以作为学习Matplotlib和NumPy的一个好例子。

后端开发标签