|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 lzb1001 于 2022-8-8 16:33 编辑
import pygame
import sys
from pygame.locals import *
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)
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
#加多一个side表示速度的方向
self.side = [choice([-1, 1]), choice([-1, 1])]#第一个元素表示水平方向,第二个元素表示垂直方向,使用random 的choice() 方法随机选择-1和1
self.speed = speed
#加多一个属性表示是否碰撞了
self.collide = False
#1、为每个小球设定一个不同的目标;
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:
self.rect.left = self.width
elif self.rect.left >= self.width:
self.rect.right = 0
elif self.rect.bottom <= 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)#设置Pygame 光标不可见
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
#添加背景音乐
pygame.mixer.music.load('bg_music.ogg')
pygame.mixer.music.set_volume(0.2)#设置音量
pygame.mixer.music.play()#播放
#加载音效
winner_sound = pygame.mixer.Sound("winner.wav")
winner_sound.set_volume(0.2)
loser_sound = pygame.mixer.Sound("loser.wav")
loser_sound.set_volume(0.2)
laugh_sound = pygame.mixer.Sound("laugh.wav")
laugh_sound.set_volume(0.2)
hole_sound = pygame.mixer.Sound("hole.wav")
hole_sound.set_volume(0.2)
#背景音乐会贯穿游戏的始终,背景音乐完整播放一次我们视为游戏的时间,
#音乐播放完时,游戏结束
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("Play the ball - Python Demo")
background = pygame.image.load(bg_image).convert_alpha()
# 用来存放小球对象的列表
balls = []
group = pygame.sprite.Group()
# 创建五个小球
for i in range(5):
# 位置随机,速度随机
position = randint(0, width-100), randint(0, height-100)
#speed 初始化就只为正数了
speed = [randint(1, 10), randint(1, 10)]
ball = Ball(grayball_image, greenball_image, position, speed, bg_size, 5 * (i + 1)) #target 设为5-30,比较适中
while pygame.sprite.spritecollide(ball, group, False, pygame.sprite.collide_circle):#在创建小球这里必须进行一下碰撞检测
ball.rect.left, ball.rect.top = randint(0, width-100), randint(0, height-100)
balls.append(ball)
group.add(ball)
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:
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
#用户通过WSAD按键移动绿色小球,使用+= 和 -= 而不是 +1 或者 -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_a: #a,左
for each in group:
if each.control:
each.speed[0] -= 1
if event.key == K_s: #s,下
for each in group:
if each.control:
each.speed[1] += 1
if event.key == K_d: #d, 右
for each in group:
if each.control:
each.speed[0] += 1
#在默认我们是不能感受到加速度的感觉的,
#因为在默认情况下,无论你是简单的按一下按键或是按住按键不放,
#Pygame都只为你发送一个键盘按下的事件
#不过我们可以通过 key 模块的 set_repeat() 方法来设置是否重复响应按下某个按键
# pygame.key.set_repeat(delay, interval)
#--delay 参数制动第一次发送事件的延迟时间
#--interval 参数指定重复发送事件的时间间隔
#--如果不带任何参数,表示取消重复发送事件
#为了使小球获得加速度的快感,我们设置按键的重复间隔为100毫秒,在while 循环前面设置。
screen.blit(background, (0, 0))
screen.blit(glass.glass_image, glass.glass_rect)
#将小手光标画在Pygame 默认光标位置上
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.mouse_rect.bottom - glass.mouse_rect.height:
glass.mouse_rect.top = glass.mouse_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
#如果小球的 control 属性为 True,就画绿球
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: # 即if each.control == True:,若小球受控(即处于由玩家控制状态)---这样理解对吗???
each.side[0] = -1 # 无法理解!!!
each.side[1] = -1 # 无法理解!!!
each.control = False
group.add(each)#还要把自己放进去
pygame.display.flip()
clock.tick(30)
if __name__ == "__main__":
main()
------------------------------------------
Windows 10 专业版 | Python 3.7.6
------------------------------------------
【我的问题】
1、恕本人愚钝,对代码中红色部分不理解,恳请大神予以指点
小甲鱼教材和视频上不是都说:
将小球的移动给区分开处理:
(1)随机移动时(即小球处于失控状态)按照方向乘以速度(仅描述速度的大小即速率)的形式;
(2)而为了保留玩家操控小球是带加速度的特性,由玩家操控移动时(即小球处于受控状态)仍采用带方向描述的速度形式(也就是说仍保持原来带方向的speed)。
代码中:
if each.control: 也就是if each.control == True:,所以这行代码不是表示如果小球受控(即处于由玩家控制状态),则……?那应该按上面(2)的方法处理,为何下面又冒出:
each.side[0] = -1
each.side[1] = -1
上面这两行代码又是什么意思呢???
******************************
感谢大神不吝赐教,为新手解疑释惑。
赠人玫瑰,手有余香,好人一生平安! |
|