文章目录

  • ​​将摩擦板和鼠标加入代码中​​
  • ​​摩擦控制球​​
  • ​​参考博客​​


将摩擦板和鼠标加入代码中

素材:

89.摩擦摩擦_pygame

89.摩擦摩擦_ide_02

代码:

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


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

# 使用 .convert_alpha() 可以转换像素格式,提高 blit 的速度
self.image = pygame.image.load(image).convert_alpha() # 加载小球图片
self.rect = self.image.get_rect() # 获取小球位置
# 将小球放在指定位置
self.rect.left, self.rect.top = position # 小球的左边和上边
self.speed = speed
self.width, self.height = bg_size[0], bg_size[1] # 窗口的宽高
self.radius = self.rect.width / 2 # 增加半径属性

def move(self):
self.rect = self.rect.move(self.speed) # 移动小球矩形位置

# 如果小球的左侧出了边界,那么将小球左侧的位置改为右侧的边界
# 这样便实现了从左边进入,右边出来的效果
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 # 从上边出来


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() # 初始化

ball_image = "gray_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.play() # 播放背景音乐

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

# 背景音乐会贯穿游戏的始终,背景音乐完整播放一次我们视为游戏的时间,
# 因此我们需要想办法让游戏在背景音乐停止时结束,我们应该有留意到:
# 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() # 加载背景图片

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

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

# 在创建小球这里必须进行一下碰撞检测
"""
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) # 实例化摩擦板

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

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

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

"""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() # 移动小球
screen.blit(each.image, each.rect) # 更新小球位置

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

if pygame.sprite.spritecollide(each, group, False, pygame.sprite.collide_circle): # 把自己和别的球进行碰撞检测
each.speed[0] = -each.speed[0] # 碰撞后方向移动
each.speed[1] = -each.speed[1]

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

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


if __name__ == "__main__": # 运行
main()

效果图:

89.摩擦摩擦_python_03





摩擦控制球

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


# 球类继承自Spirte类
class Ball(pygame.sprite.Sprite):
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 # 小球的左边和上边
self.speed = speed
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):
self.rect = self.rect.move(self.speed) # 移动小球矩形位置

# 如果小球的左侧出了边界,那么将小球左侧的位置改为右侧的边界
# 这样便实现了从左边进入,右边出来的效果
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.play() # 播放背景音乐

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

# 背景音乐会贯穿游戏的始终,背景音乐完整播放一次我们视为游戏的时间,
# 因此我们需要想办法让游戏在背景音乐停止时结束,我们应该有留意到:
# 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() # 加载背景图片

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

# 创建五个小球
for i in range(5):
# 位置随机,速度随机
# position = (小球的左边,上边)
position = randint(0, width - 100), randint(0, height - 100) # 随机生成位置
speed = [randint(-10, 10), randint(-10, 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)

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

while running: # 主循环
for event in pygame.event.get(): # 遍历事件
if event.type == 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

"""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.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.speed[0] = -each.speed[0] # 碰撞后方向移动
each.speed[1] = -each.speed[1]

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

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


if __name__ == "__main__": # 运行
main()

效果:

89.摩擦摩擦_游戏开发_04