0
点赞
收藏
分享

微信扫一扫

90.pygame游戏-玩个球(play the ball)最终版


文章目录

  • ​​游戏部分截图​​
  • ​​游戏操作说明​​
  • ​​代码​​
  • ​​所有图片素材​​
  • ​​音乐素材​​
  • ​​下载链接​​

游戏部分截图

90.pygame游戏-玩个球(play the ball)最终版_游戏



游戏操作说明

1.鼠标上下左右晃动,在摩擦板中摩擦,会使得灰色求变绿色
2.上下左右(W,S,A,D)四个键可控制浅绿色的小球
3.将绿色小球移动到背景的黑洞上,覆盖黑色球
4.绿色球到黑洞位置时按下空格键,若听到音效声音,则覆盖成功
5.直至五个球全部归位,游戏胜利,自动结束游戏;倘若开始游戏伴随的音乐(一首歌)放完,五个球还没有全部覆盖黑洞,则游戏失败,将播放嘲讽的声乐。

代码

一个模块版本
main.py

import pygame
import sys # 退出需要
import traceback
from pygame.locals import * # 把pygame的常量名导进去
from random import * # 随机生成数需要


class Ball(pygame.sprite.Sprite): # 球类,继承自Spirte类
def __init__(self, grayball_image, greenball_image, position, speed, bg_size, target):
pygame.sprite.Sprite.__init__(self) # 初始化动画精灵

# 使用 .convert_alpha() 可以转换像素格式,提高 blit 的速度
self.grayball_image = pygame.image.load(grayball_image).convert_alpha() # 加载灰球图片
self.greenball_image = pygame.image.load(greenball_image).convert_alpha() # 加载绿球图片
self.rect = self.grayball_image.get_rect() # 获取小球位置
# 将小球放在指定位置
self.rect.left, self.rect.top = position # position赋值给小球的左边和上边
# choice() 方法返回一个列表,元组或字符串的随机项。
self.side = [choice([-1, 1]), choice([-1, 1])] # 移动小球方向
self.speed = speed # 移动速度
self.collide = False # 默认未碰撞
self.target = target # 为每一个小球设定一个不同的目标
# 5、小球应该添加一个 control 属性,用于记录当前的状态(绿色 -> 玩家控制 or 灰色 -> 随机移动)
self.control = False
self.width, self.height = bg_size[0], bg_size[1] # 窗口的宽高
self.radius = self.rect.width / 2 # 增加半径属性

def move(self): # 球的移动方法
if self.control: # 为真
self.rect = self.rect.move(self.speed) # 移动后的矩形位置
else: # 为假
self.rect = self.rect.move(self.side[0] * self.speed[0],
self.side[1] * self.speed[1]) # 移动小球矩形位置

""""
如果小球的左侧出了边界,那么将小球左侧的位置改为右侧的边界
这样便实现了从左边进入,右边出来的效果
"""
if self.rect.right <= 0: # 小球右边界<0,即小球出左边
self.rect.left = self.width # 从右边进来

elif self.rect.left >= self.width: # 小球左边界>窗口宽度,即小球出右边
self.rect.right = 0 # 从左边进来

elif self.rect.bottom <= 0: # 小球下边界<0,即小球出上边
self.rect.top = self.height # 从下边出来

elif self.rect.top >= self.height: # 小球上边界>窗口高度
self.rect.bottom = 0 # 从上边出来

# 3、为小球添加一个 check() 方法,用于判断鼠标在1秒钟内产生的事件数量是否匹配此目标;
def check(self, motion):
if self.target < motion < self.target + 5:
return True
else:
return False


class Glass(pygame.sprite.Sprite): # 摩擦板类
def __init__(self, glass_image, mouse_image, bg_size): # 这两行代码跟前面的一样
pygame.sprite.Sprite.__init__(self) # 初始化动画精灵

self.glass_image = pygame.image.load(glass_image).convert_alpha() # 加载摩擦板图像
self.glass_rect = self.glass_image.get_rect() # 获取摩擦板的矩形位置
# 摩擦板矩形为左边和上边界,水平位置在中心,垂直位置在下边
self.glass_rect.left, self.glass_rect.top = \
(bg_size[0] - self.glass_rect.width) // 2, \
bg_size[1] - self.glass_rect.height

self.mouse_image = pygame.image.load(mouse_image).convert_alpha() # 加载手图像
self.mouse_rect = self.mouse_image.get_rect() # 获取手的矩形位置
# 手的左边和上边界 = 摩擦板的左边和上边界, 相当于初始化位置
self.mouse_rect.left, self.mouse_rect.top = \
self.glass_rect.left, self.glass_rect.top
pygame.mouse.set_visible(False) # 鼠标不可见


def main(): # 主函数,把一群东西封装起来了
pygame.init() # 初始化

grayball_image = "gray_ball.png" # 球图像
greenball_image = "green_ball.png" # 球图像
bg_image = "background.png" # 背景图像
glass_image = "glass.png" # 摩擦板图像
mouse_image = "hand.png" # 摩擦的手的图像

running = True # 初始化running为True

# 添加背景音乐
pygame.mixer.music.load("bg_music.ogg") # 加载背景音乐
pygame.mixer.music.set_volume(0.2) # 设置音量
pygame.mixer.music.play() # 播放背景音乐

# 添加音效
loser_sound = pygame.mixer.Sound("fail.ogg") # 失败的时候的声音
loser_sound.set_volume(0.2)
laugh_sound = pygame.mixer.Sound("laugh.ogg") # 嘲笑的声音
laugh_sound.set_volume(0.2)
winner_sound = pygame.mixer.Sound("win.ogg") # 成功的时候的声音
winner_sound.set_volume(0.2)
hole_sound = pygame.mixer.Sound("hole.ogg")
hole_sound.set_volume(0.2)

""""
# 背景音乐会贯穿游戏的始终,背景音乐完整播放一次我们视为游戏的时间,
# 因此我们需要想办法让游戏在背景音乐停止时结束,我们应该有留意到:
# music 模块有一个 set_endevent() 方法,该方法的作用就是在音乐播放完时
# 发送一条事件消息,发送什么消息是我们自定义的,USEREVENT 就是自定义消息,
# Pygame 给我们预定了很多事件,像我们熟悉的 键盘事件、鼠标事件等。这些预定义
# 的事件都有一个标记符,例如:MOUSEBUTTONDOWN 、KEYDOWN等。这些都是
# 一些数字的等值定义,其实在内部,2 就表示鼠标按下,但是人类难以记住,所以定义为
# MOUSEBUTTONDOWN。
# USEREVENT 就是数字24,24以上就是我们可以自定义的事件,我们可以像这样自定义事件:
# MY_EVENT = USEREVENT。
# MY_EVENT_1 = USEREVENT + 1........
"""

# 音乐播放完时游戏结束
GAMEOVER = USEREVENT
pygame.mixer.music.set_endevent(GAMEOVER)

# 根据背景图片指定游戏界面尺寸
bg_size = width, height = 1024, 681 # 窗口尺寸
screen = pygame.display.set_mode(bg_size) # 绘制窗口
pygame.display.set_caption("小游戏") # 窗口名

background = pygame.image.load(bg_image).convert_alpha() # 加载背景图片

# 黑洞范围(x1, x2, y1, y2)
hole = [(115, 121, 197, 203), (223, 229, 388, 394), (501, 507, 318, 324),
(696, 702, 190, 196), (904, 910, 417, 423)]

msgs = []
balls = [] # 用来存放小球对象的列表
group = pygame.sprite.Group() # 这里的group在碰撞检测需要

# 创建五个小球,位置随机,速度随机
for i in range(5):
# position = (小球的左边,上边)
position = randint(0, width - 100), randint(0, height - 100) # 随机生成位置
speed = [randint(1, 10), randint(1, 10)] # 随机生成速度
"""四个参数ball_image, position, speed, bg_size 前面都设置了"""
ball = Ball(grayball_image, greenball_image, position, speed, bg_size, 5 * (i+1)) # 实例化小球

"""
spritecollide(sprite, group, dokill, collided = None)
第一个参数 sprite 是指定被检测的精灵;(就是我们写的里面的 item)
第二个参数 group 是指定一个组(就是我们写的里面的 target 列表),它是 sprite 的组,因此要使用 sprite.Group() 来生成;
第三个参数 dokill 是设置是否从组中删除检测到碰撞的精灵,设置为True,则删除;
第四个参数 collided 是指定一个回调函数,用于定制特殊的检测方法,如果第四个参数忽略的话,默认是检测精灵之间的 rect 属性。
"""
# 在创建小球这里必须进行一下碰撞检测
while pygame.sprite.spritecollide(ball, group, False, pygame.sprite.collide_circle):
# 小球 group 不删除 圆形属性
# 随机生成的小球碰撞了就再次随机生成位置
ball.rect.left, ball.rect.top = randint(0, width - 100), randint(0, height - 100)

balls.append(ball) # 列表用append
group.add(ball) # 集合用add

glass = Glass(glass_image, mouse_image, bg_size) # 实例化摩擦板

# 2、创建一个motion 变量来记录每一秒钟产生事件数量
motion = 0

# 4.1、添加一个自定义事件,每一秒钟触发一次
MYTIMER = USEREVENT + 1 # 自定义事件的知识点可以查看上一节课的末尾注解
pygame.time.set_timer(MYTIMER, 1000)

pygame.key.set_repeat(100, 100)

clock = pygame.time.Clock() # 设置帧率需要

while running: # 主循环
for event in pygame.event.get(): # 遍历事件
if event.type == QUIT: # ×掉窗口
pygame.quit()
sys.exit() # 退出游戏

elif event.type == GAMEOVER: # 判断事件是否为我们自定义的GAMEOVER事件
loser_sound.play() # 失败的声音播放
pygame.time.delay(2000) # 暂停2秒
laugh_sound.play() # 嘲笑的声音播放
running = False # 退出循环了

# 4.2、 调用每个小球的 check() 检测 motion 的值是否匹配某一个小球的目标,
# 并将motion重新初始化,以便记录下1秒鼠标事件数量
elif event.type == MYTIMER:
if motion:
for each in group:
if each.check(motion):
each.speed = [0, 0]
each.control = True
motion = 0

# 需要计算一下motion
elif event.type == MOUSEMOTION: # 鼠标事件
motion += 1

elif event.type == KEYDOWN: # 键按下
if event.key == K_w: # 按下w键
for each in group: # 上移
if each.control:
each.speed[1] -= 1

if event.key == K_s: # 按下s键
for each in group: # 下移
if each.control:
each.speed[1] += 1

if event.key == K_a: # 按下a键
for each in group: # 左移
if each.control:
each.speed[0] -= 1

if event.key == K_d: # 按下d键
for each in group: # 右移
if each.control:
each.speed[0] += 1

if event.key == K_SPACE: # 按下空格键
for each in group:
if each.control:
for i in hole:
if i[0] <= each.rect.left <= i[1] and \
i[2] <= each.rect.top <= i[3]:
hole_sound.play()
each.speed = [0, 0] # 固定该小球
group.remove(each) # 不会被撞到
# 下面两行语句就是完成该小球第一个绘制,
# 然后其它小球就在该小球上边了
temp = balls.pop(balls.index(each)) # 先从temp 中弹出
balls.insert(0, temp) # 然后插入到第一个的位置,就会第一个画了
hole.remove(i) # 把这个黑洞去掉
if not hole: # 所有洞补完,游戏结束
pygame.mixer.music.stop() # 停止背景音乐
winner_sound.play() # 播放胜利音效
pygame.time.delay(3000) # 播放音效需要时间,延迟3秒
msg = pygame.image.load("win.png").convert_alpha()
msg_pos = (width - msg.get_width()) // 2, \
(height - msg.get_height()) // 2
msgs.append((msg, msg_pos))
# 播放音效
laugh_sound.play()

"""blit:第一个参数为一个Surface对象,第二个为左上角位置。画完以后得用update更新,否则画面一片漆黑。"""
# 更新图像的位置,这里是更新背景图像的位置
screen.blit(background, (0, 0))
screen.blit(glass.glass_image, glass.glass_rect) # 更新摩擦板位置

glass.mouse_rect.left, glass.mouse_rect.top = pygame.mouse.get_pos() # 获得鼠标当前位置
if glass.mouse_rect.left < glass.glass_rect.left: # 鼠标左边<摩擦板左边,即从左边出去了
glass.mouse_rect.left = glass.glass_rect.left # 让鼠标手保持在左边界
if glass.mouse_rect.left > glass.glass_rect.right - glass.mouse_rect.width:
glass.mouse_rect.left = glass.glass_rect.right - glass.mouse_rect.width
if glass.mouse_rect.top < glass.glass_rect.top:
glass.mouse_rect.top = glass.glass_rect.top
if glass.mouse_rect.top > glass.glass_rect.bottom - glass.mouse_rect.height:
glass.mouse_rect.top = glass.glass_rect.bottom - glass.mouse_rect.height

screen.blit(glass.mouse_image, glass.mouse_rect) # 更新手位置

for each in balls: # 遍历小球
each.move() # 移动小球
if each.collide:
each.speed = [randint(1, 10), randint(1, 10)] # 随机生成速度
each.collide = False
if each.control:
screen.blit(each.greenball_image, each.rect)
else:
screen.blit(each.grayball_image, each.rect) # 更新小球位置

for each in group:
group.remove(each) # 把自身拿出来

if pygame.sprite.spritecollide(each, group, False, pygame.sprite.collide_circle): # 把自己和别的球进行碰撞检测
each.side[0] = -each.side[0]
each.side[1] = -each.side[1]
each.collide = True
if each.control:
each.side[0] = -1
each.side[1] = -1
each.control = False

group.add(each) # 还要把自己放进去

# 打印消息
for msg in msgs:
screen.blit(msg[0], msg[1])

pygame.display.flip() # 刷新界面
# 数越大越快
clock.tick(30)


if __name__ == "__main__": # 运行
try:
main()
except SystemExit: # 这是按下 × 的异常,直接忽略
pass
except:
traceback.print_exc()
pygame.quit()
input()


所有图片素材

1.背景(background.png)

90.pygame游戏-玩个球(play the ball)最终版_pygame_02


2.摩擦板(grass.png)    3.胜利显示的图片(win.png)

90.pygame游戏-玩个球(play the ball)最终版_ide_03

90.pygame游戏-玩个球(play the ball)最终版_ide_04

4.灰球(gray_ball.png)  5.绿球 (green_ball.png)  6.摩擦板内的摩擦手(hand.png)

90.pygame游戏-玩个球(play the ball)最终版_游戏_05

90.pygame游戏-玩个球(play the ball)最终版_python_06

90.pygame游戏-玩个球(play the ball)最终版_python_07




音乐素材

以下的 .ogg文件 音乐素材这里发不了,请在评论区自留邮箱,看到发你邮箱

90.pygame游戏-玩个球(play the ball)最终版_ide_08

举报

相关推荐

0 条评论