在这节课中,我们将对比Scratch,在Scratch中制作一款小游戏,看看如何在Python中通过编程来实现。

游戏背景

在Scratch中,我们选择了"blue sky"这个背景。

image-20200702142550496

在Python中,我们将这个背景图片保存成一张图片,大小为480x360像素,放在一个images目录中,然后写以下代码:

import pgzrun

WIDTH=480
HEIGHT=360

def draw():
    screen.blit('bg', (0, 0))

pgzrun.go()

运行这段代码,可以看到会出现一个窗口如下:

image-20200702143127057

游戏角色:小鸟

在Scratch中,我们上传几张小鸟的图片,做成一个角色,这个角色有4个不同的造型:

image-20200702143424487

然后写代码让bird角色一开始出现在(-50, 0)的位置

image-20200702143714442

在Python项目里,我们将这4张图片放在images目录下:

images
  |
  |-- bg.png
  |-- bird0.png
  |-- bird1.png
  |-- bird2.png
  |-- birddead.png

我们需要写代码来创建这个角色,并且指定在(190, 180)的位置

因为Python中(x, y)坐标位置是以左上角为(0, 0)点的,所以这里换算成就是(190, 180)对应Scratch中的(-50, 0),大家可以思考一下是如何换算的。
import pgzrun

WIDTH=480
HEIGHT=360

bird = Actor('bird0', (190, 180))

def draw():
    screen.blit('bg', (0, 0))
    bird.draw()

pgzrun.go()
image-20200702144216488

游戏角色:柱子

在Scratch中,我们可以设置2个角色,分别是上面的柱子和下面的柱子

image-20200702144425696

我们可以写如下的代码让柱子不断的从最右边往左边移动,等到了最左边的时候,再从最右边出现再往左移动,并且每次出现的上下位置是随机生成的。

image-20200702145734537

上面柱子代码下面柱子代码

image-20200702145744428
image-20200702145754964

在Python中,我们也需要设置两个柱子的角色:

import pgzrun

WIDTH=480
HEIGHT=360

bird = Actor('bird0', (190, 180))

pipe_top = Actor('top', (480, -120))
pipe_bottom = Actor('bottom', (480, 480))

def draw():
    screen.blit('bg', (0, 0))
    bird.draw()
    pipe_top.draw()
    pipe_bottom.draw()

pgzrun.go()

如果我们要实现柱子不停止的从左边往右边移动,我们需要做一个自定义函数,并且在update()方法中不停的调用它。

def reset_pipes():
    y = random.randint(-100, 100)
    pipe_top.pos = (WIDTH, y - 120)
    pipe_bottom.pos = (WIDTH, y + 480)


def update_pipes():
    pipe_top.left -= 5
    pipe_bottom.left -= 5
    if pipe_top.right < 0:
        reset_pipes()


def update():
    update_pipes()
image-20200702151414520

控制小鸟

在Scratch中,我们让小鸟自由落体,当我们按下鼠标左键时,小鸟会往上飞起来。

image-20200702152311906

在Python代码中,我们也需要实现类似的代码,我们自定义一个函数来控制小鸟。

bird = Actor('bird0', (190, 180))
bird.gravity = 0

def on_mouse_down():
    bird.gravity = -5


def update_bird():
    bird.gravity += 0.3
    bird.y += bird.gravity


def update():
    update_pipes()
    update_bird()
image-20200702153852583

在Scratch中,我们在小鸟上升时换成造型1,下降时换成造型2

image-20200702154107949

在Python,我们也可以这样做:

def update_bird():
    bird.gravity += 0.3
    bird.y += bird.gravity
    if bird.gravity < 0:
        bird.image = 'bird2'
    else:
        bird.image = 'bird1'

撞击事件

在Scratch中,我们可以在小鸟的代码中判断是否碰到了柱子,或者碰到了地面,如果碰到了游戏就结束

image-20200702155102354

那么在Python中我们也可以同样来设置

bird.dead = 0

def update_bird():
    if bird.dead == 0:
        bird.gravity += 0.3
        bird.y += bird.gravity
        if bird.gravity < 0:
            bird.image = 'bird2'
        else:
            bird.image = 'bird1'

        if bird.colliderect(pipe_top) or bird.colliderect(pipe_bottom) or bird.y > 350:
            bird.dead = 1
            bird.image = 'birddead'


def update():
    if bird.dead == 1:
        return 
    update_pipes()
    update_bird()
image-20200702155845985

加入音效

为了让游戏更有意思,我们让小鸟飞起来时发出声音

image-20200702160353496

设置一个得分变量,在柱子重新从右边出现时,加一分,并发出得分音效

image-20200702160518580

同样我们在Python中也项目sounds目录下放入这两个声音文件

└─ sounds/
    │── jump.wav
    └── coin.wav

然后在代码中使用它们:

def update_pipes():
    pipe_top.left -= 3
    pipe_bottom.left -= 3
    if pipe_top.right < 0:
        sounds.coin.play()
        reset_pipes()
        bird.score += 1


def on_mouse_down():
    sounds.jump.play()
    bird.gravity = -5

最后,我们将得分显示在左上角:

def draw():
    screen.blit('bg', (0, 0))
    bird.draw()
    pipe_top.draw()
    pipe_bottom.draw()
    screen.draw.text(
        str(bird.score),
        color='red',
        midtop=(20, 10),
        fontsize=30
    )
image-20200702162016207

最终代码

为了让游戏操作更加友好,一开始时会显示一个“开始游戏”的按钮,按下这个按钮才开始玩游戏,当游戏结束之后这个按钮会再次出现。

image-20200702165415578
import pgzrun
import random

WIDTH = 480
HEIGHT = 360

TITLE = 'Flappy Bird'

bird = Actor('bird0', (100, 180))
bird.gravity = 0
bird.dead = 0
bird.score = 0

pipe_top = Actor('top', (WIDTH, -120))
pipe_bottom = Actor('bottom', (WIDTH, 480))

start = Actor('start', (WIDTH / 2, HEIGHT / 2))
start.running = False


def reset_pipes():
    y = random.randint(-100, 100)
    pipe_top.pos = (WIDTH, y - 120)
    pipe_bottom.pos = (WIDTH, y + 480)


def update_pipes():
    pipe_top.left -= 3
    pipe_bottom.left -= 3
    if pipe_top.right < 0:
        sounds.coin.play()
        reset_pipes()
        bird.score += 1


def on_mouse_down(pos, button):
    if start.collidepoint(pos) and start.running == False:
        start.running = True
        bird.dead = 0
        bird.score = 0
        reset_pipes()

    if start.running:
        sounds.jump.play()
        bird.gravity = -5


def update_bird():
    if bird.dead == 0:
        bird.gravity += 0.2
        bird.y += bird.gravity
        if bird.gravity < 0:
            bird.image = 'bird2'
        else:
            bird.image = 'bird1'

        if bird.colliderect(pipe_top) or bird.colliderect(pipe_bottom) or bird.y > 350:
            bird.dead = 1
            start.running = False
            bird.image = 'birddead'


def update():
    if start.running:
        if bird.dead == 1:
            return
        update_pipes()
        update_bird()


def draw():
    screen.blit('bg', (0, 0))
    if start.running:
        bird.draw()
        pipe_top.draw()
        pipe_bottom.draw()
        screen.draw.text(
            str(bird.score),
            color='red',
            midtop=(20, 10),
            fontsize=30
        )
    else:
        start.draw()
        bird.draw()
        pipe_top.draw()
        pipe_bottom.draw()


pgzrun.go()

Python游戏使用了pygame zero框架,可以使用Mu编辑器直接便可以直接开发,本游戏所用图片、声音资源以及Scratch和Python源代码可以从这里下载:链接:https://pan.baidu.com/s/1ABxyp8UGsMp9S8oAE-aFVg  密码:3cl1

本文参考:https://pygame-zero.readthedocs.io/en/stable/from-scratch.html