python小游戏- 打乒乓球PyPong(python,pygame)

打乒乓球小游戏(python、pygame)

目录

前提:

一、开发环境

二、游戏说明

三、代码实现

ⅰ、准备乒乓球和球拍,创建实例

ⅱ、控制球拍

ⅲ、记录分数并用pygame.font显示

①、创建字体对象

②、重绘分数

③、跟踪分数

④、跟踪还有几条命

⑤、游戏结束

未添加声音代码:

ⅳ 给PyPong添加声音

①、每次球碰到球拍时要增加一个声音:

②、其他声音

代码:

③、存在问题——让声音只播放一次

④、添加背景音乐

最终代码:

前提:

将学到的内容集中在一起(包括动画精灵、碰撞检测和事件),建立一个简单的”球拍与球”游戏,类似于 Pong。

一、开发环境

二、游戏说明

  • 一个来回反弹的球;
  • 一个打球的球拍;
  • 一种控制球拍的方法;
  • 一种记录分数并在窗口上显示分数的方法;
  • 一种确定有几条”命”的方法 ——你有几次机会。

python小游戏- 打乒乓球PyPong(python,pygame)

三、代码实现

ⅰ、准备乒乓球和球拍,创建实例

球:

python小游戏- 打乒乓球PyPong(python,pygame)
class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]

myBall = MyBallClass('wackyball.bmp', [50, 50], ball_speed)
ballGroup = pygame.sprite.Group(myBall)

球拍:

只是使用一个简单的矩形,

class MyPaddleClass(pygame.sprite.Sprite):
    def __init__(self, location):
        pygame.sprite.Sprite.__init__(self)
        image_surface = pygame.surface.Surface([100,20])  #为球拍创建表面
        image_surface.fill([0, 0, 0])                     #黑色
        self.image = image_surface.convert()              #将表面转成一个图像
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

paddle = MyPaddleClass([270, 400])

ⅱ、控制球拍

  • *球拍只能左右移动,不能上下移动,让球拍的x位置,和鼠标移动,让鼠标控制球拍——MOUSEMOTION 事件(球拍会自动限制在窗口的边界以内)
elif event.type == pygame.MOUSEMOTION:
            paddle.rect.centerx = event.pos[0]  #event.pos[0]鼠标位置
  • *球拍和球的碰撞
 if pygame.sprite.spritecollide(paddle, ballGroup, False):
       myBall.speed[1] = -myBall.speed[1]

球拍拍球:

import sys, pygame
from random import *
from pygame.locals import *

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]

class MyPaddleClass(pygame.sprite.Sprite):
    def __init__(self, location):
        pygame.sprite.Sprite.__init__(self)
        image_surface = pygame.surface.Surface([100,20])  #为球拍创建表面
        image_surface.fill([0, 0, 0])                     #黑色
        self.image = image_surface.convert()              #将表面转成一个图像
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

pygame.init()
#设置窗口大小和颜色
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()
ball_speed = [10, 5]

myBall = MyBallClass('wackyball.bmp', [50, 50], ball_speed)
ballGroup = pygame.sprite.Group(myBall)

paddle = MyPaddleClass([270, 400])

running = True

while running:
    clock.tick(30)
    screen.fill([255, 255, 255])
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEMOTION:
            paddle.rect.centerx = event.pos[0]

    if pygame.sprite.spritecollide(paddle, ballGroup, False):
       myBall.speed[1] = -myBall.speed[1]

    myBall.move()
    screen.blit(myBall.image, myBall.rect)
    screen.blit(paddle.image, paddle.rect)
    pygame.display.flip()
pygame.quit()

ⅲ、记录分数并用pygame.font显示

  • 还有几条命,给每个玩家3条命
  • 得了几分,球碰到窗口顶边给1分。

显示分数——用pygame.font模块来显示文本

  • font 对象,告诉 Pygame 你想要的字体样式和大小。
  • 渲染文本,向字体对象传入一个字符串,(此处的字符串,是玩家的分数,在这里需要把整数换成string的格式)它会返回一个绘制有这个文本的新的表面。
  • 把这个表面块移到显示表面。

python小游戏- 打乒乓球PyPong(python,pygame)

①、创建字体对象

score_font = pygame.font.Font(None, 50)                    #创建字体对象
score_surf = score_font.render(str(score), 1, (0, 0, 0))   #渲染文本到表面
score_pos = [10, 10]                                       #文本位置

②、重绘分数

    screen.blit(score_surf, score_pos)     #重绘分数

③、跟踪分数

在球的类中,用球的 move() 方法检测了球什么时候碰到窗口的顶边(来完成反弹),这是就可以在此添加分数。

def move(self):
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]
            score = score + 1
            score_surf = score_font.render(str(score), 1, (0, 0, 0))

注意:
当球碰到边界顶边时,应该加分数值时会报错!!

python小游戏- 打乒乓球PyPong(python,pygame)
解决方法:
这个问题是命名空间的问题,。尽管确实有一个名为 score 的变量,但是此刻试图从 MyBallClass类的 move() 方法中使用这个变量。这个类在寻找一个名为score 的局部变量,而这个局部变量并不存在。 应该定义为调用全局变量
参考:https://blog.csdn.net/qq_41070511/article/details/115670004
修改如下。
def move(self):
        global score, score_font, score_surf
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]
            score = score + 1
            score_surf = score_font.render(str(score), 1, (0, 0, 0))

这时可以看见分数在不停增加!

④、跟踪还有几条命

跟踪目前有几条命,目前给3条命,如果漏接球,就会从窗口底部掉下。

这个要放在重绘分数之后(分数刷新在重新赋予生命)

if myBall.rect.top >=screen.get_rect().bottom:
        lives = lives - 1
        pygame.time.delay(2000)
        myBall.rect.topleft = [50, 50]

这是运行效果,小球没有接到会重新从[50, 50],重新落下。

⑤、游戏结束

当玩家丢掉最后一条命时要显示一个”游戏结束”的消息。

  • 包含消息
  • 玩家的最后分数
 if myBall.rect.top >=screen.get_rect().bottom:
        lives = lives - 1
        if lives == 0:
            final_text1 = "Game Over"
            final_text2 = "Your final score is : " + str(score)
            ft1_font = pygame.font.Font(None, 70)
            ft1_surf = ft1_font.render(final_text1, 1, (0, 0, 0))
            ft2_font = pygame.font.Font(None, 50)
            ft2_surf = ft2_font.render(final_text2, 1, (0, 0, 0))
            screen.blit(ft1_surf, [screen.get_width()/2 - ft1_surf.get_width()/2, 100])
            screen.blit(ft2_surf, [screen.get_width()/2 - ft2_surf.get_width()/2, 100])
            pygame.display.flip()
            done = True
        else:
            pygame.time.delay(2000)
            myBall.rect.topleft = [(screen.get_rect().width) - 40 * lives, 20]

未添加声音代码:

import sys, pygame
from random import *
from pygame.locals import *

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        global score, score_font, score_surf
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]
            score = score + 1
            score_surf = score_font.render(str(score), 1, (0, 0, 0))

class MyPaddleClass(pygame.sprite.Sprite):
    def __init__(self, location):
        pygame.sprite.Sprite.__init__(self)
        image_surface = pygame.surface.Surface([100,20])  #为球拍创建表面
        image_surface.fill([0, 0, 0])                     #黑色
        self.image = image_surface.convert()              #将表面转成一个图像
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

pygame.init()
#设置窗口大小和颜色
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()
ball_speed = [10, 5]

score = 0
lives = 3
score_font = pygame.font.Font(None, 50)                    #创建字体对象
score_surf = score_font.render(str(score), 1, (0, 0, 0))   #渲染文本到表面
score_pos = [10, 10]                                       #文本位置

myBall = MyBallClass('wackyball.bmp', [50, 50], ball_speed)
ballGroup = pygame.sprite.Group(myBall)

paddle = MyPaddleClass([270, 400])
done = False

running = True

while running:
    clock.tick(30)
    screen.fill([255, 255, 255])
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEMOTION:
            paddle.rect.centerx = event.pos[0]

    if pygame.sprite.spritecollide(paddle, ballGroup, False):
       myBall.speed[1] = -myBall.speed[1]

    myBall.move()
    if not done:
        screen.blit(myBall.image, myBall.rect)
        screen.blit(paddle.image, paddle.rect)
        screen.blit(score_surf, score_pos)     #重绘分数

        for i in range(lives):
            width = screen.get_width()
            screen.blit(myBall.image, [width - 40 * i, 20])

        pygame.display.flip()

    if myBall.rect.top >=screen.get_rect().bottom:
        lives = lives - 1
        if lives == 0:
            final_text1 = "Game Over"
            final_text2 = "Your final score is : " + str(score)
            ft1_font = pygame.font.Font(None, 70)
            ft1_surf = ft1_font.render(final_text1, 1, (0, 0, 0))
            ft2_font = pygame.font.Font(None, 50)
            ft2_surf = ft2_font.render(final_text2, 1, (0, 0, 0))
            screen.blit(ft1_surf, [screen.get_width()/2 - ft1_surf.get_width()/2, 100])
            screen.blit(ft2_surf, [screen.get_width()/2 - ft2_surf.get_width()/2, 100])
            pygame.display.flip()
            done = True
        else:
            pygame.time.delay(2000)
            myBall.rect.topleft = [(screen.get_rect().width) - 40 * lives, 20]

pygame.quit()

ⅳ 给PyPong添加声音

①、每次球碰到球拍时要增加一个声音:

hit_paddle= pygame.mixer.Sound("hit_paddle.wav")
hit_paddle.set_volume(0.50)

#当球碰到球拍时添加!播放声音。
if pygame.sprite.spritecollide(paddle, ballGroup, False):
     myBall.speed[1] = -myBall.speed[1]
     hit_paddle.play()

②、其他声音

  • 球碰到两边的墙时;
  • 球碰到顶边而且玩家得分时;
  • 玩家漏球,球碰到底边时;
  • 新的一条命开始时;
  • 游戏结束时。
#其他声音
splat = pygame.mixer.Sound("splat.wav")
splat.set_volume(0.6)
hit_wall = pygame.mixer.Sound("hit_wall.wav")
hit_wall.set_volume(0.40)
get_point = pygame.mixer.Sound("get_point.wav")
get_point.set_volume(0.2)
new_lift = pygame.mixer.Sound("new_lift.wav")
new_lift.set_volume(0.40)
game_over = pygame.mixer.Sound("game_over.wav")
game_over.set_volume(0.40)

玩家漏球,球碰到底边时;

漏球声音
if myBall.rect.top >=screen.get_rect().bottom:
        splat.play()                              #漏球声音
        lives = lives - 1

球碰到顶边而且玩家得分时 和球碰到两边的墙时

在反向时还可以播放声音
在顶部这里让球反弹,并为玩家加 1 分。

 def move(self):
        global score, score_font, score_surf
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]
            hit_wall.play()                        #换方向播声音

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]
            score = score + 1
            score_surf = score_font.render(str(score), 1, (0, 0, 0))
            get_point.play()                           #得分声音

新的一条命开始时;

 else:
            pygame.time.delay(1000)
            new_life.play()

            myBall.rect.topleft = [50, 50]
            screen.blit(myBall.image, myBall.rect)
            pygame.display.flip()
            pygame.time.delay(1000)

游戏结束时。

 if lives == 0:
            game_over.play()

③、存在问题——让声音只播放一次

python小游戏- 打乒乓球PyPong(python,pygame)

播 放 game_over声 音和 splat 声 音 的 代 码 放 在 主 while 循 环 中,Pygame 窗口关闭前它们是不会停止的,所以只要 while 循环在运行,声音就会反复播放!需要增加一些代码来确保它只会播放一次。
通过 done 变量来告诉我们游戏何时结束,且能够知道什么时候播放 game_over声音,以及什么时候显示最后的分数消息。

if myBall.rect.top >=screen.get_rect().bottom:
        if not done:
            splat.play()                              #漏球声音

        lives = lives - 1
        if lives == 0:
            if not done:
                game_over.play()

myBall.move(),在无限循环里一直运行。
解决方法:

  • 游戏结束时把球的速度设置为 [0,0] 来阻止球继续移动。
  • 查看球是否在窗口底边以下,如果是,就不再播放 hit_wall 声音。
  • 检查 done 变量,如果游戏已经结束就不再播放 hit_wall 声音。
def move(self):
        global score, score_font, score_surf
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > width:
            self.speed[0] = -self.speed[0]
            if not done:
                hit_wall.play()                        #换方向播声音

        if self.rect.top < 0:
            self.speed[1] = -self.speed[1]
            score = score + 1
            score_surf = score_font.render(str(score), 1, (0, 0, 0))
            if not done:
                get_point.play()                           #得分声音

④、添加背景音乐

pygame.mixer.music.load("bg_music.mp3")
pygame.mixer.music.set_volume(0.3)
pygame.mixer.music.play(-1)

在音乐要停下来的时候,渐渐淡出:

pygame.mixer.music.fadeout(2000)

最终代码:

import sys, pygame
from random import *
from pygame.locals import *

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        global score, score_font, score_surf
        self.rect = self.rect.move(self.speed)
        if self.rect.left < 0 or self.rect.right > screen.get_width():
            self.speed[0] = -self.speed[0]
            if not done:
                hit_wall.play()                        #换方向播声音

        if self.rect.top =screen.get_rect().bottom:
        if not done:
            splat.play()                              #漏球声音

        lives = lives - 1
        if lives

链接:https://pan.baidu.com/s/1azvZOoeDgYdnJc2gzNX4ZQ
提取码:3v5r
复制这段内容后打开百度网盘手机App,操作更方便哦

视频链接:https://www.bilibili.com/video/BV1kK4y1o76X?p=1&share_medium=iphone&share_plat=ios&share_source=QQ&share_tag=s_i×tamp=1623896465&unique_k=Aiqqof

Original: https://blog.csdn.net/qq_41070511/article/details/115937668
Author: 噗噗bug
Title: python小游戏- 打乒乓球PyPong(python,pygame)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/780657/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球