Python谷歌小恐龙(持续更新,未完结)

前言

  • 第一次写博客,可能有些写得不太好的地方,欢迎各位看官踊跃提意见和建议。
  • 我写这篇博客的出发点是在于用简单明了的代码去和大家分享我写代码的过程,希望对大家有所帮助。
  • 如果大家有需求的话也可联系我,我也可以接一些课设之类的小项目。+v:Ts_liyun
  • 此外本文也是我本人学习的一个过程,其中有些参考文章会在文中或者文末列出。

首先我们想达到最终的效果是这样的。
谷歌浏览器无法浏览时出现的小恐龙跳跃游戏
想试玩的话,谷歌浏览器可以直接输入网址打开:chrome://dino
其余浏览器可以用这个网址:https://dino.zone/zh-cn/

如果大家对这个游戏感兴趣并且想通过自己的双手编写出来的话那我们就继续往下看吧。同时也推荐看这篇文章并且想学的朋友注意观察前后代码的区别。由于这个游戏我是自己慢慢想的(没有参考任何小恐龙跳跃游戏的代码),我也会在里面加入一些我自己的想法,因此可能我的思路并不适合每一个人,但我也依然希望你能从中学到一些有用的东西。

那么废话不多说我们开始吧。

正文

接下来我将按照步骤一步步来展示我编写这个游戏的过程。
文章中我将采用先将结果用图片显示再解释代码的形式为大家叙述。
此外,推荐在看本文之前应掌握Python这门语言的一些基本的语法,以及对Pygame这个库有一些初步的了解,我本人推荐看这篇博客:Python游戏编程(Pygame)

创建窗口

既然要写一个游戏,那我们肯定需要一个窗口显示。
首先通过Pygame内置的函数创建出一个窗口。

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 734, 286  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口

while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

关于窗口框的大小我是根据小恐龙背景的图片的大小设计的。

添加静态背景图

接下来我们将背景导入。

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 734, 286  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口

background = pygame.image.load('D:/project/Python/PDL_Python/pygame/dragon/picture/background1.png')  # 加载图片
backgroundrect = background.get_rect()  # 获取矩形区域

while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

    screen.blit(background, backgroundrect)  # 将图片画到窗口上

    pygame.display.flip()  # 更新全部显示

可以点击此处,从网盘中获取这个小游戏的相关图片。提取码:88iw
这里导入的是background1这张图片,你也可以导入background2,取决于你的心情。记得更换代码中的图片路径,上述代码中是我电脑中的直接地址。

添加静态小恐龙

接着我们让主角小恐龙登场。

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 734, 286  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口

background = pygame.image.load('D:/project/Python/PDL_Python/pygame/dragon/picture/background1.png')  # 加载图片
backgroundrect = background.get_rect()  # 获取矩形区域

dragon = pygame.image.load('D:/project/Python/PDL_Python/pygame/dragon/picture/dragon1.png')
dragonrect = dragon.get_rect()
dragonrect = dragonrect.move(50,210)


while True:  # 死循环确保窗口一直显示
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

    screen.blit(background, backgroundrect)  # 将图片画到窗口上
    screen.blit(dragon, dragonrect)

    pygame.display.flip()  # 更新全部显示

导入图片时我们会发现小恐龙是在“天上”的,因此我们需要使用move函数将其移动到“地上”。

让小恐龙动起来

在这里插入图片描述
刚刚我们插入图片后发现小恐龙是在地上不动的,那么接下来我们就尝试让这个小恐龙运动起来。如果我们玩过这个游戏的话我们会发现小恐龙运动可拆分为两个步骤,第一部分是让小恐龙原地踏步,第二步则是让背景往左移。我们先完成第一部分:

import pygame
import sys

pygame.init()  # 初始化pygame
size = width, height = 734, 286  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
clock = pygame.time.Clock()

background = pygame.image.load('D:/project/Python/PDL_Python/pygame/dragon/picture/background1.png')  # 加载图片
backgroundrect = background.get_rect()  # 获取矩形区域

dragon1 = pygame.image.load('D:/project/Python/PDL_Python/pygame/dragon/picture/dragon1.png')
dragon2 = pygame.image.load('D:/project/Python/PDL_Python/pygame/dragon/picture/dragon2.png')
dragonrect = dragon1.get_rect()
dragonrect = dragonrect.move(50,210)

flag = True
while True:  # 死循环确保窗口一直显示
    clock.tick(6)
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
            sys.exit()

    screen.blit(background, backgroundrect)  # 将图片画到窗口上
    if flag == True:
        screen.blit(dragon1, dragonrect)
    else:
        screen.blit(dragon2, dragonrect)
    flag = not flag

    pygame.display.flip()  # 更新全部显示

小恐龙原地踏步的原理是将两张图片在背景中循环播放。

程序小优化(增加小知识)

为了让下载的用户可以下载下来就使用,不需要下载代码后还需要更改地址等操作才能使用,因此特地更新一下代码。更新内容如下:

  1. 将注释更加完善。如果看不懂可以私信或者留言,我会持续改善。
  2. 使用OS库,读取文件当前目录,并合并成图片所在地址,这样读取图片时无需频繁更改路径,只需保证下载时整个文件夹保持一致就行。
    代码如下:
import pygame
import sys
import os

#获取当前文件的目录,方便在别的电脑运行时读取相应文件
Current_path = os.path.join(os.getcwd(), 'pygame', 'dragon', 'picture')
Current_path = Current_path.replace('\\', '/')

pygame.init()  # 初始化pygame
size = width, height = 734, 286  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
clock = pygame.time.Clock() #创建一个时间对象用于控制游戏运作的快慢

background = pygame.image.load(Current_path + '/background1.png')  # 加载图片
backgroundrect = background.get_rect()  # 获取矩形区域

dragon1 = pygame.image.load(Current_path + '/dragon1.png')
dragon2 = pygame.image.load(Current_path + '/dragon2.png')
dragonrect = dragon1.get_rect()
dragonrect = dragonrect.move(50,210)    #将小恐龙移动到“地上”

flag = True #创建一个flag标志用于在循环中判断使用哪张图片
while True:  # 死循环确保窗口一直显示
    clock.tick(6)
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果程序发现单击关闭窗口按钮
            sys.exit()  #将窗口关闭

    screen.blit(background, backgroundrect)  # 将背景图片画到窗口上

    #根据flag标志确定显示的图片,这样可以造成小恐龙在跑的现象
    if flag == True:
        screen.blit(dragon1, dragonrect)
    else:
        screen.blit(dragon2, dragonrect)
    flag = not flag

    pygame.display.flip()  # 更新全部显示

背景动起来

在这里插入图片描述
小恐龙原地踏步在加上背景移动是不是就真正让小恐龙跑起来啦!
其实实现这一步的原理很简单,我用 Tkinter(Python自带的用户交互界面设计包)设计了一个动画演示。实际上就是两张背景在后面循环移动。
在这里插入图片描述
上面的图中,黑色框框代表我们游戏显示的画面,而红色和蓝色就分别是两个背景框,当我们让其“排着队”从程序窗口前滑过时就形成了背景运动的效果。
具体实现的方式是,我们去检测红色框的右边框,当其移出屏幕时,我们就让其瞬移到蓝色框后面,也就是将红色的左边框设置成和此时蓝色的左边框一致,可能有点绕,多看上面的动图就懂啦,当然,蓝色框我们也是如此操作。
下面代码改变内容为:

  1. 导入多一张背景图片以及设计多一个背景框
  2. 让背景实现循环移动(42-47行)
import pygame
import sys
import os

#获取当前文件的目录,方便在别的电脑运行时读取相应文件
Current_path = os.path.join(os.getcwd(), 'picture')
Current_path = Current_path.replace('\\', '/')

pygame.init()  # 初始化pygame
size = width, height = 734, 286  # 设置窗口大小
screen = pygame.display.set_mode(size)  # 显示窗口
clock = pygame.time.Clock() #创建一个时间对象用于控制游戏运作的快慢

background1 = pygame.image.load(Current_path + '/background1.png')  # 加载图片
background2 = pygame.image.load(Current_path + '/background2.png')  # 加载图片
backgroundrect1 = background1.get_rect()  # 获取矩形区域
backgroundrect2 = background2.get_rect()  # 获取矩形区域
backgroundrect2[0] = backgroundrect1.right

dragon1 = pygame.image.load(Current_path + '/dragon1.png')
dragon2 = pygame.image.load(Current_path + '/dragon2.png')
dragonrect = dragon1.get_rect()
dragonrect = dragonrect.move(50, 210)    #将小恐龙移动到“地上”

flag = True #创建一个flag标志用于在循环中判断使用哪张图片
while True:  # 死循环确保窗口一直显示
    clock.tick(6)
    for event in pygame.event.get():  # 遍历所有事件
        if event.type == pygame.QUIT:  # 如果程序发现单击关闭窗口按钮
            sys.exit()  #将窗口关闭

    screen.blit(background1, backgroundrect1)  # 将背景图片画到窗口上
    screen.blit(background2, backgroundrect2)

    #根据flag标志确定显示的图片,这样可以造成小恐龙在跑的现象
    if flag == True:
        screen.blit(dragon1, dragonrect)
    else:
        screen.blit(dragon2, dragonrect)
    flag = not flag

    backgroundrect1 = backgroundrect1.move(-10, 0)    #将背景向左移动
    backgroundrect2 = backgroundrect2.move(-10, 0)    #将背景向左移动
    if backgroundrect1.right < 0:   #判断第一个背景框如果移动到了窗口外面
        backgroundrect1[0] = backgroundrect2.right  #将第一个背景框移动到第二个背景框后面,形成循环
    if backgroundrect2.right < 0:   #和上面同理,最终实现的效果就是两个图片排着队从窗口前划过
        backgroundrect2[0] = backgroundrect1.right

    pygame.display.flip()  # 更新全部显示

小恐龙跳跃(代码大改,做好心理准备)

在做小恐龙跳跃的时候我遇到了一个难题,如何将小恐龙跳跃的速度和背景移动的速度剥离开来,如果我们玩过那个游戏的话,不难发现,随着分数的增加,背景的移动速度会越来越快,但是小恐龙的跳跃速度是不会发生改变的,我们之前小恐龙踏步的速度其实是和背景移动的速度一样的,都由全局游戏速度来控制,当背景移动越来越快,那么小恐龙跳的上下速度也会越来越快。因此我修改了大部分的代码,但我们逻辑始终没有变化,就是增加了定义类,这样更好的管理我们的代码,可以使得代码不在那么臃肿。
先上效果图:
在这里插入图片描述
现在的小恐龙已经能检测到按键(空格或者鼠标)按下就跳跃,并且现在地图会移动得越来越快。
更新的内容:

  1. 删除了没必要的库(之前添加的又删了,我真的是闲),直接通过间接寻址获取图片,就不需要再用OS库了。换了一种关掉游戏的循环方式,也不需要sys库啦。
  2. 删除掉了很多没有必要的全局变量,增加程序的可读性同时增强程序的规范化。
  3. 用类的方式分别定义地图与小恐龙,让其分别携带自身属性,方便以后添加代码。这涉及到了类的定义,如果不太懂的同学可以去看看别的python基础教程。其中每个类里有一些默认属性,以及update函数用于更新框的位置与显示图片。

代码很多地方都已经加上了注释,如果有不懂的可以留言或私信,我再补充详细一些。
代码如下:

import pygame

'''-------------------------------定义一个小恐龙的类-------------------------------'''
class Dragon:
    #实例化的时候需要输入创建的游戏窗口对象
    def __init__(self, Screen):
        #小恐龙的默认参数
        self.screen = Screen
        self.rectangle = pygame.Rect(50, 210, 40, 45)    #小恐龙的边框,预先设计好就不需要移动到地上
        self.status = True #两种状态对应两个图片
        #定义小恐龙的两种状态(读取图片放在列表里)
        self.StatusPicture = [
            pygame.image.load('./picture/dragon1.png'),
            pygame.image.load('./picture/dragon2.png')
        ]
        self.jump_speed = 0  #小恐龙的跳跃速度,当为正的时候上升,为负的时候下降
        self.alive = True    #生命状态
        self.jump_flag = False   #跳跃标志,判断小恐龙是否跳跃
        self.count = 0

    #更新小恐龙的状态
    def update(self):
        #如果当前没有检测到跳跃且小恐龙在地上,轮流显示图片
        if self.jump_flag == False and self.rectangle[1] == 210:
            if self.count % 15 == 0:    #控制小恐龙踏步速度
                self.status = not self.status
            #轮流显示图片,这样可以造成小恐龙在跑的现象
            if self.status:
                screen.blit(self.StatusPicture[0], self.rectangle)
            else:
                screen.blit(self.StatusPicture[1], self.rectangle)
            self.count += 1
            self.count %= 10000  #防止溢出

        #如果检测到按下跳跃并且小恐龙在地上那就判定为有效跳跃
        if self.jump_flag and self.rectangle[1] == 210:
            self.jump_speed = 15 #将上升速度调为15

        #如果小恐龙的跳跃速度不为0,或者当前在空中,说明正在跳跃周期
        if self.jump_speed != 0 or self.rectangle[1] != 210:
            self.rectangle[1] -= self.jump_speed   #将小恐龙框移动
            self.jump_speed -= 1 #将速度降低,效果为上升越来越慢,下降越来越快
            if self.rectangle[1] >= 210:    #防止将小恐龙移动到地下
                #落地后恢复默认值等待下次跳跃
                self.Y_axis = 210
                self.jump_speed = 0
                self.jump_flag = False
            #如果在空中那就显示两个图片,效果就是两个脚都伸直(没有太大意义)
            self.screen.blit(self.StatusPicture[0], self.rectangle)
            self.screen.blit(self.StatusPicture[1], self.rectangle)   

'''-------------------------------定义一个地图的类-------------------------------'''
class Map:
    #实例化的时候需要输入创建的游戏窗口对象
    def __init__(self, Screen):
        self.screen = Screen
        self.speed = 3  #初始速度(像素)
        self.background_1 = pygame.image.load('./picture/background1.png')  # 加载图片
        self.background_2 = pygame.image.load('./picture/background2.png')
        self.background_rectangle_1 = self.background_1.get_rect()    # 获取图片大小的矩形区域
        self.background_rectangle_2 = self.background_2.get_rect()
        self.background_rectangle_2[0] = self.background_rectangle_1.right

    def update(self):
        #移动框
        self.background_rectangle_1 = self.background_rectangle_1.move(-self.speed, 0)
        self.background_rectangle_2 = self.background_rectangle_2.move(-self.speed, 0)

        if self.background_rectangle_1.right < 0:   #判断第一个背景框如果移动到了窗口外面
            self.background_rectangle_1[0] = self.background_rectangle_2.right  #将第一个背景框移动到第二个背景框后面,形成循环
        if self.background_rectangle_2.right < 0:   #和上面同理,最终实现的效果就是两个图片排着队从窗口前划过
            self.background_rectangle_2[0] = self.background_rectangle_1.right

        #将图片放到框里面
        self.screen.blit(self.background_1, self.background_rectangle_1)
        self.screen.blit(self.background_2, self.background_rectangle_2)

#主程序
if __name__ == "__main__":
    "-------------------------------初始化部分-------------------------------"
    pygame.init()  # 初始化pygame
    pygame.display.set_caption('Dino')  #设置窗口标题
    screen = pygame.display.set_mode([734, 286])  # 创建并显示窗口,设置这个大小是因为一张背景图就是这么大
    clock = pygame.time.Clock() #创建一个时间对象用于控制游戏运作的快慢

    map = Map(screen)     #创建地图实例
    dragon = Dragon(screen)   #创建小恐龙实例
    score = 0   #设置初始分数

    "-------------------------------主循环部分-------------------------------"
    running = True
    while running:  # 死循环确保窗口一直显示
        clock.tick(60)      #越大越快
        for event in pygame.event.get():  # 遍历所有事件
            if event.type == pygame.QUIT:  # 如果程序发现单击关闭窗口按钮
                running = False
            if event.type == pygame.KEYDOWN or event.type == pygame.MOUSEBUTTONDOWN:
                dragon.jump_flag = True

        map.update()    #更新地图元素框的位置
        dragon.update()     #更新小恐龙元素框的位置

        #这部分暂时测试用 现在背景的移动速度和时间成正比
        score += 1
        if score % 100 == 0:
            map.speed += 0.5

        pygame.display.flip()  # 更新全部显示

    pygame.quit()

添加障碍物

未完待续
接下来还要填了坑有:
1、加入障碍物
2、加入分数以及让分数和背景运动速度成正相关

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐