unknown 6 months ago
parent 4680e98f91
commit bdd1068a04

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

@ -2,27 +2,28 @@ import math, pygame, sys,copy,random
import pygame.gfxdraw import pygame.gfxdraw
from pygame.locals import * from pygame.locals import *
# 定义游戏的常量
FPS = 120 FPS = 120 #帧率
WINDOWWIDTH = 640 WINDOWWIDTH = 640 #窗口宽度
WINDOWHEIGHT = 480 WINDOWHEIGHT = 480 # 窗口高度
TEXTHEIGHT = 20 TEXTHEIGHT = 20 # 文本高度
BUBBLERADIUS = 20 BUBBLERADIUS = 20 # 泡泡半径
BUBBLEWIDTH = BUBBLERADIUS * 2 BUBBLEWIDTH = BUBBLERADIUS * 2 # 泡泡宽度
BUBBLELAYERS = 5 BUBBLELAYERS = 5 # 泡泡层数
BUBBLEYADJUST = 5 BUBBLEYADJUST = 5 # 泡泡垂直调整
STARTX = WINDOWWIDTH / 2 STARTX = WINDOWWIDTH / 2 # 开始 X 坐标
STARTY = WINDOWHEIGHT - 27 STARTY = WINDOWHEIGHT - 27 # 开始 Y 坐标
ARRAYWIDTH = 16 ARRAYWIDTH = 16 # 数组宽度
ARRAYHEIGHT = 14 ARRAYHEIGHT = 14 # 数组高度
# 定义左右移动的常量
RIGHT = 'right' RIGHT = 'right'
LEFT = 'left' LEFT = 'left'
BLANK = '.' BLANK = '.' # 空白符号
## COLORS ## ## COLORS ##
# 定义颜色常量
#RGB #RGB
# 每个元组代表一种颜色,格式为 (红, 绿, 蓝)
GRAY = (100, 100, 100) GRAY = (100, 100, 100)
NAVYBLUE = (60, 60, 100) NAVYBLUE = (60, 60, 100)
WHITE = (255, 255, 255) WHITE = (255, 255, 255)
@ -36,15 +37,16 @@ CYAN = (0, 255, 255)
BLACK = (0, 0, 0) BLACK = (0, 0, 0)
COMBLUE = (233, 232, 255) COMBLUE = (233, 232, 255)
BGCOLOR = WHITE BGCOLOR = WHITE #背景颜色
COLORLIST = [RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN] COLORLIST = [RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN] #泡泡颜色列表
# 定义泡泡类继承自pygame.sprite.Sprite
class Bubble(pygame.sprite.Sprite): class Bubble(pygame.sprite.Sprite):
def __init__(self, color, row=0, column=0): def __init__(self, color, row=0, column=0):
pygame.sprite.Sprite.__init__(self) pygame.sprite.Sprite.__init__(self)
# 初始化泡泡属性
self.rect = pygame.Rect(0, 0, 30, 30) self.rect = pygame.Rect(0, 0, 30, 30) #创建了一个表示气泡的矩形区域,初始位置在(0, 0)宽和高都是30像素。
self.rect.centerx = STARTX self.rect.centerx = STARTX
self.rect.centery = STARTY self.rect.centery = STARTY
self.speed = 10 self.speed = 10
@ -54,8 +56,10 @@ class Bubble(pygame.sprite.Sprite):
self.row = row self.row = row
self.column = column self.column = column
# 更新泡泡位置的方法
def update(self): def update(self):
global xmove, ymove
if self.angle == 90: if self.angle == 90:
xmove = 0 xmove = 0
ymove = self.speed * -1 ymove = self.speed * -1
@ -69,53 +73,68 @@ class Bubble(pygame.sprite.Sprite):
self.rect.x += xmove self.rect.x += xmove
self.rect.y += ymove self.rect.y += ymove
# 绘制泡泡的方法
def draw(self): def draw(self):
pygame.gfxdraw.filled_circle(DISPLAYSURF, self.rect.centerx, self.rect.centery, self.radius, self.color) pygame.gfxdraw.filled_circle(DISPLAYSURF, self.rect.centerx, self.rect.centery, self.radius, self.color)
pygame.gfxdraw.aacircle(DISPLAYSURF, self.rect.centerx, self.rect.centery, self.radius, GRAY) pygame.gfxdraw.aacircle(DISPLAYSURF, self.rect.centerx, self.rect.centery, self.radius, GRAY)
# 计算X轴移动距离的方法
def xcalculate(self, angle): def xcalculate(self, angle):
radians = math.radians(angle) radians = math.radians(angle)
xmove = math.cos(radians) * (self.speed) xmove = math.cos(radians) * (self.speed)
return xmove return xmove
# 计算Y轴移动距离的方法
def ycalculate(self, angle): def ycalculate(self, angle):
radians = math.radians(angle) radians = math.radians(angle)
ymove = math.sin(radians) * (self.speed) * -1 ymove = math.sin(radians) * (self.speed) * -1
return ymove return ymove
# 定义箭头类继承自pygame.sprite.Sprite
class Arrow(pygame.sprite.Sprite): class Arrow(pygame.sprite.Sprite):
# 初始化箭头属性
def __init__(self): def __init__(self):
"""
初始化箭头对象
该方法对箭头对象进行初始化包括加载箭头图像设置初始角度确定箭头在屏幕上的初始位置
"""
# 调用父类pygame.sprite.Sprite的初始化方法
pygame.sprite.Sprite.__init__(self) pygame.sprite.Sprite.__init__(self)
self.angle = 90 self.angle = 90 # 将箭头的初始角度设置为90度指向正上方
# 加载箭头图像并进行透明处理
arrowImage = pygame.image.load('Arrow.png') arrowImage = pygame.image.load('Arrow.png')
arrowImage.convert_alpha() arrowImage.convert_alpha()
# 获取箭头图像的矩形区域
arrowRect = arrowImage.get_rect() arrowRect = arrowImage.get_rect()
self.image = arrowImage self.image = arrowImage # 将处理后的图像赋值给箭头对象的image属性
self.transformImage = self.image self.transformImage = self.image # 初始化transformImage为箭头的初始图像
self.rect = arrowRect self.rect = arrowRect # 将图像的矩形区域赋值给箭头对象的rect属性
# 设置箭头在屏幕上的初始位置
self.rect.centerx = STARTX self.rect.centerx = STARTX
self.rect.centery = STARTY self.rect.centery = STARTY
# 更新箭头方向的方法
def update(self, direction): def update(self, direction):
if direction == LEFT and self.angle < 180: if direction == LEFT and self.angle < 176:
self.angle += 2 self.angle += 2 # 如果按下左箭头键且当前角度小于180度则增加角度
elif direction == RIGHT and self.angle > 0: elif direction == RIGHT and self.angle > 4:
self.angle -= 2 self.angle -= 2 # 如果按下右箭头键且当前角度大于0度则减少角度
self.transformImage = pygame.transform.rotate(self.image, self.angle) self.transformImage = pygame.transform.rotate(self.image, self.angle)
self.rect = self.transformImage.get_rect() self.rect = self.transformImage.get_rect()
self.rect.centerx = STARTX self.rect.centerx = STARTX # 保持箭头在水平中心位置
self.rect.centery = STARTY self.rect.centery = STARTY # 保持箭头在垂直起始位置
# 绘制箭头的方法
def draw(self): def draw(self):
DISPLAYSURF.blit(self.transformImage, self.rect) DISPLAYSURF.blit(self.transformImage, self.rect)
# 定义分数类
class Score(object): class Score(object):
def __init__(self): def __init__(self):
self.total = 0 self.total = 0
@ -125,50 +144,60 @@ class Score(object):
self.rect.left = 5 self.rect.left = 5
self.rect.bottom = WINDOWHEIGHT - 5 self.rect.bottom = WINDOWHEIGHT - 5
# 更新分数的方法
def update(self, deleteList): def update(self, deleteList):
self.total += ((len(deleteList)) * 10) self.total += ((len(deleteList)) * 10)
self.render = self.font.render('Score: ' + str(self.total), True, BLACK, WHITE) self.render = self.font.render('Score: ' + str(self.total), True, BLACK, WHITE)
# 绘制分数的方法
def draw(self): def draw(self):
DISPLAYSURF.blit(self.render, self.rect) DISPLAYSURF.blit(self.render, self.rect)
# 主函数
def main(): def main():
global FPSCLOCK, DISPLAYSURF, DISPLAYRECT, MAINFONT
pygame.init()
FPSCLOCK = pygame.time.Clock()
pygame.display.set_caption('泡泡天堂小游戏')
MAINFONT = pygame.font.SysFont('Helvetica', TEXTHEIGHT)
DISPLAYSURF, DISPLAYRECT = makeDisplay()
while True: global FPSCLOCK, DISPLAYSURF, DISPLAYRECT, MAINFONT # 引用全局变量
score, winorlose = runGame()
endScreen(score, winorlose)
pygame.init() # 初始化Pygame
FPSCLOCK = pygame.time.Clock() # 创建一个时钟对象,用于控制游戏帧率
pygame.display.set_caption('泡泡天堂小游戏') # 设置游戏窗口标题
MAINFONT = pygame.font.SysFont('Helvetica', TEXTHEIGHT) # 设置游戏使用的默认字体
DISPLAYSURF, DISPLAYRECT = makeDisplay() # 创建游戏显示的表面和矩形
while True: # 进入游戏主循环
score, winorlose = runGame() # 运行游戏,返回得分和游戏结果
endScreen(score, winorlose) # 显示游戏结束画面
# 运行游戏的函数
def runGame(): def runGame():
musicList = ['知更鸟 _ HOYO-MiX _ Chevy - 使一颗心免于哀伤.ogg', '知更鸟 _ HOYO-MiX _ Chevy - 希望有羽毛和翅膀.ogg', '知更鸟 _ HOYO-MiX _ Chevy - 在银河中孤独摇摆.ogg']
# 初始化音乐列表
musicList = ['知更鸟 _ HOYO-MiX _ Chevy - 使一颗心免于哀伤.ogg', '知更鸟 _ HOYO-MiX _ Chevy - 希望有羽毛和翅膀.ogg',
'知更鸟 _ HOYO-MiX _ Chevy - 在银河中孤独摇摆.ogg']
pygame.mixer.music.load(musicList[0]) pygame.mixer.music.load(musicList[0])
pygame.mixer.music.play() pygame.mixer.music.play()
track = 0 track = 0 # 音乐曲目索引
# 初始化游戏颜色列表和游戏颜色数组
gameColorList = copy.deepcopy(COLORLIST) gameColorList = copy.deepcopy(COLORLIST)
direction = None direction = None # 玩家控制的方向
launchBubble = False launchBubble = False # 是否发射气泡
newBubble = None newBubble = None # 将要发射或正在移动的气泡
# 初始化箭头、游戏面板(气泡数组)和得分
arrow = Arrow() arrow = Arrow()
bubbleArray = makeBlankBoard() bubbleArray = makeBlankBoard()
setBubbles(bubbleArray, gameColorList) setBubbles(bubbleArray, gameColorList)
nextBubble = Bubble(gameColorList[0]) # 下一个要发射的气泡
nextBubble = Bubble(gameColorList[0])
nextBubble.rect.right = WINDOWWIDTH - 5 nextBubble.rect.right = WINDOWWIDTH - 5
nextBubble.rect.bottom = WINDOWHEIGHT - 5 nextBubble.rect.bottom = WINDOWHEIGHT - 5
score = Score() score = Score()
while True: while True:
DISPLAYSURF.fill(BGCOLOR) DISPLAYSURF.fill(BGCOLOR) # 填充游戏背景
# 处理事件:退出、按键等
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == QUIT: if event.type == QUIT:
terminate() terminate()
@ -186,6 +215,7 @@ def runGame():
elif event.key == K_ESCAPE: elif event.key == K_ESCAPE:
terminate() terminate()
# 如果按下发射气泡的按键
if launchBubble == True: if launchBubble == True:
if newBubble == None: if newBubble == None:
newBubble = Bubble(nextBubble.color) newBubble = Bubble(nextBubble.color)
@ -194,13 +224,16 @@ def runGame():
newBubble.update() newBubble.update()
newBubble.draw() newBubble.draw()
# 反转气泡下落方向
if newBubble.rect.right >= WINDOWWIDTH - 5: if newBubble.rect.right >= WINDOWWIDTH - 5:
newBubble.angle = 180 - newBubble.angle newBubble.angle = 180 - newBubble.angle
elif newBubble.rect.left <= 5: elif newBubble.rect.left <= 5:
newBubble.angle = 180 - newBubble.angle newBubble.angle = 180 - newBubble.angle
# 处理气泡发射和消除逻辑
launchBubble, newBubble, score = stopBubble(bubbleArray, newBubble, launchBubble, score) launchBubble, newBubble, score = stopBubble(bubbleArray, newBubble, launchBubble, score)
# 检查游戏是否结束
finalBubbleList = [] finalBubbleList = []
for row in range(len(bubbleArray)): for row in range(len(bubbleArray)):
for column in range(len(bubbleArray[0])): for column in range(len(bubbleArray[0])):
@ -209,29 +242,34 @@ def runGame():
if bubbleArray[row][column].rect.bottom > (WINDOWHEIGHT - arrow.rect.height - 10): if bubbleArray[row][column].rect.bottom > (WINDOWHEIGHT - arrow.rect.height - 10):
return score.total, 'lose' return score.total, 'lose'
# 游戏胜利条件检查
if len(finalBubbleList) < 1: if len(finalBubbleList) < 1:
return score.total, 'win' return score.total, 'win'
# 更新游戏颜色列表并随机排序
gameColorList = updateColorList(bubbleArray) gameColorList = updateColorList(bubbleArray)
random.shuffle(gameColorList) random.shuffle(gameColorList)
# 重置下一个要发射的气泡
if launchBubble == False: if launchBubble == False:
nextBubble = Bubble(gameColorList[0]) nextBubble = Bubble(gameColorList[0])
nextBubble.rect.right = WINDOWWIDTH - 5 nextBubble.rect.right = WINDOWWIDTH - 5
nextBubble.rect.bottom = WINDOWHEIGHT - 5 nextBubble.rect.bottom = WINDOWHEIGHT - 5
# 绘制游戏元素
nextBubble.draw() nextBubble.draw()
if launchBubble == True: if launchBubble == True:
coverNextBubble() coverNextBubble() # 遮挡下一个气泡
arrow.update(direction) arrow.update(direction) # 更新箭头方向
arrow.draw() arrow.draw() # 绘制箭头
setArrayPos(bubbleArray) setArrayPos(bubbleArray) # 更新气泡数组位置
drawBubbleArray(bubbleArray) drawBubbleArray(bubbleArray) # 绘制气泡数组
score.draw() score.draw() # 绘制得分
# 切换音乐
if pygame.mixer.music.get_busy() == False: if pygame.mixer.music.get_busy() == False:
if track == len(musicList) - 1: if track == len(musicList) - 1:
track = 0 track = 0
@ -242,101 +280,149 @@ def runGame():
pygame.mixer.music.play() pygame.mixer.music.play()
pygame.display.update() pygame.display.update()
FPSCLOCK.tick(FPS) FPSCLOCK.tick(FPS) # 控制游戏帧率
# 创建空白游戏板的函数
def makeBlankBoard(): def makeBlankBoard():
array = []
array = [] # 初始化一个空的一维列表,用于存放棋盘的每一行
# 循环创建ARRAYHEIGHT行
for row in range(ARRAYHEIGHT): for row in range(ARRAYHEIGHT):
column = [] column = [] # 初始化一个空的一维列表,用于存放当前行的列
# 循环创建ARRAYWIDTH列每列都初始化为BLANK
for i in range(ARRAYWIDTH): for i in range(ARRAYWIDTH):
column.append(BLANK) column.append(BLANK)
array.append(column)
return array array.append(column) # 将当前行的列添加到棋盘数组中
return array # 返回创建好的空棋盘
# 在游戏板上设置泡泡的函数
def setBubbles(array, gameColorList): def setBubbles(array, gameColorList):
for row in range(BUBBLELAYERS):
for column in range(len(array[row])):
random.shuffle(gameColorList)
newBubble = Bubble(gameColorList[0], row, column)
array[row][column] = newBubble
setArrayPos(array) for row in range(BUBBLELAYERS): # 遍历气泡层数
for column in range(len(array[row])): # 遍历每一层的气泡列数
random.shuffle(gameColorList) # 随机重洗颜色列表
newBubble = Bubble(gameColorList[0], row, column) # 创建新的气泡对象
array[row][column] = newBubble # 将新的气泡对象设置到对应的位置
setArrayPos(array) # 更新气泡数组的位置信息
def setArrayPos(array): # 设置游戏板上泡泡位置的函数def setArrayPos(array):
# 初始化元素位置
for row in range(ARRAYHEIGHT): for row in range(ARRAYHEIGHT):
for column in range(len(array[row])): for column in range(len(array[row])):
if array[row][column] != BLANK: if array[row][column] != BLANK:
array[row][column].rect.x = (BUBBLEWIDTH * column) + 5 array[row][column].rect.x = (BUBBLEWIDTH * column) + 5
array[row][column].rect.y = (BUBBLEWIDTH * row) + 5 array[row][column].rect.y = (BUBBLEWIDTH * row) + 5
# 调整奇数行元素的 x 坐标
for row in range(1, ARRAYHEIGHT, 2): for row in range(1, ARRAYHEIGHT, 2):
for column in range(len(array[row])): for column in range(len(array[row])):
if array[row][column] != BLANK: if array[row][column] != BLANK:
array[row][column].rect.x += BUBBLERADIUS array[row][column].rect.x += BUBBLERADIUS
# 调整所有行元素的 y 坐标
for row in range(1, ARRAYHEIGHT): for row in range(1, ARRAYHEIGHT):
for column in range(len(array[row])): for column in range(len(array[row])):
if array[row][column] != BLANK: if array[row][column] != BLANK:
array[row][column].rect.y -= (BUBBLEYADJUST * row) array[row][column].rect.y -= (BUBBLEYADJUST * row)
# 删除多余气泡
deleteExtraBubbles(array) deleteExtraBubbles(array)
#设置游戏板上泡泡位置的函数
def setArrayPos(array):
def deleteExtraBubbles(array): # 初始化元素位置
for row in range(ARRAYHEIGHT): for row in range(ARRAYHEIGHT):
for column in range(len(array[row])): for column in range(len(array[row])):
if array[row][column] != BLANK: if array[row][column] != BLANK:
array[row][column].rect.x = (BUBBLEWIDTH * column) + 5
array[row][column].rect.y = (BUBBLEWIDTH * row) + 5
# 调整奇数行元素的 x 坐标
for row in range(1, ARRAYHEIGHT, 2):
for column in range(len(array[row])):
if array[row][column] != BLANK:
array[row][column].rect.x += BUBBLERADIUS
# 调整所有行元素的 y 坐标
for row in range(1, ARRAYHEIGHT):
for column in range(len(array[row])):
if array[row][column] != BLANK:
array[row][column].rect.y -= (BUBBLEYADJUST * row)
# 删除多余气泡
deleteExtraBubbles(array)
#(删除超出游戏区域的泡泡)
def deleteExtraBubbles(array):
for row in range(ARRAYHEIGHT): # 遍历每一行
for column in range(len(array[row])): # 遍历当前行的每个元素
# 如果当前元素不为空
if array[row][column] != BLANK:
# 如果气泡的右边界超出窗口宽度
if array[row][column].rect.right > WINDOWWIDTH: if array[row][column].rect.right > WINDOWWIDTH:
# 将该气泡设置为空
array[row][column] = BLANK array[row][column] = BLANK
# 更新颜色列表的函数
def updateColorList(bubbleArray): def updateColorList(bubbleArray):
newColorList = [] newColorList = []
# 遍历气泡数组,将非空气泡的颜色添加到新颜色列表中
for row in range(len(bubbleArray)): for row in range(len(bubbleArray)):
for column in range(len(bubbleArray[0])): for column in range(len(bubbleArray[0])):
if bubbleArray[row][column] != BLANK: if bubbleArray[row][column] != BLANK:
newColorList.append(bubbleArray[row][column].color) newColorList.append(bubbleArray[row][column].color)
colorSet = set(newColorList) colorSet = set(newColorList) # 使用集合去重
# 如果集合为空,说明气泡数组中没有非空气泡,返回包含白色的列表
if len(colorSet) < 1: if len(colorSet) < 1:
colorList = [] colorList = []
colorList.append(WHITE) colorList.append(WHITE)
return colorList return colorList
else: else:
return list(colorSet) # 返回去重后的颜色列表
return list(colorSet)
#(检查孤立泡泡)
def checkForFloaters(bubbleArray): def checkForFloaters(bubbleArray):
# 遍历数组第一行找出非空列的索引存储到bubbleList中
bubbleList = [column for column in range(len(bubbleArray[0])) bubbleList = [column for column in range(len(bubbleArray[0]))
if bubbleArray[0][column] != BLANK] if bubbleArray[0][column] != BLANK]
newBubbleList = [] newBubbleList = []
# 筛选出bubbleList中需要处理的列即数值间隔大于1的列
for i in range(len(bubbleList)): for i in range(len(bubbleList)):
if i == 0: if i == 0:
newBubbleList.append(bubbleList[i]) newBubbleList.append(bubbleList[i])
elif bubbleList[i] > bubbleList[i - 1] + 1: elif bubbleList[i] > bubbleList[i - 1] + 1:
newBubbleList.append(bubbleList[i]) newBubbleList.append(bubbleList[i])
# 深拷贝bubbleArray以用于后续操作避免修改原数组
copyOfBoard = copy.deepcopy(bubbleArray) copyOfBoard = copy.deepcopy(bubbleArray)
# 清空原数组中的所有元素,准备进行浮选物处理
for row in range(len(bubbleArray)): for row in range(len(bubbleArray)):
for column in range(len(bubbleArray[0])): for column in range(len(bubbleArray[0])):
bubbleArray[row][column] = BLANK bubbleArray[row][column] = BLANK
# 对需要处理的列调用popFloaters函数进行浮选物处理
for column in newBubbleList: for column in newBubbleList:
popFloaters(bubbleArray, copyOfBoard, column) popFloaters(bubbleArray, copyOfBoard, column)
def popFloaters(bubbleArray, copyOfBoard, column, row=0): def popFloaters(bubbleArray, copyOfBoard, column, row=0):
if (row < 0 or row > (len(bubbleArray) - 1) if (row < 0 or row > (len(bubbleArray) - 1)
or column < 0 or column > (len(bubbleArray[0]) - 1)): or column < 0 or column > (len(bubbleArray[0]) - 1)):
@ -373,24 +459,33 @@ def popFloaters(bubbleArray, copyOfBoard, column, row=0):
popFloaters(bubbleArray, copyOfBoard, column + 1, row - 1) popFloaters(bubbleArray, copyOfBoard, column + 1, row - 1)
# 这个函数处理泡泡停止时的逻辑,包括判断泡泡是否到达了发射的终点,以及是否与其它泡泡发生碰撞。
def stopBubble(bubbleArray, newBubble, launchBubble, score): def stopBubble(bubbleArray, newBubble, launchBubble, score):
deleteList = []
popSound = pygame.mixer.Sound('popcork.ogg')
global newRow, newColumn
deleteList = [] # 用于存储需要消除的气泡位置
popSound = pygame.mixer.Sound('popcork.ogg') # 播放气泡消除音效
# 遍历气泡数组,检查新气泡与现有气泡的碰撞
for row in range(len(bubbleArray)): for row in range(len(bubbleArray)):
for column in range(len(bubbleArray[row])): for column in range(len(bubbleArray[row])):
# 如果当前位置有气泡,并且有新气泡即将落下
if (bubbleArray[row][column] != BLANK and newBubble != None): if (bubbleArray[row][column] != BLANK and newBubble != None):
# 检查新气泡是否与当前气泡碰撞,或者是否已经越界
if (pygame.sprite.collide_rect(newBubble, bubbleArray[row][column])) or newBubble.rect.top < 0: if (pygame.sprite.collide_rect(newBubble, bubbleArray[row][column])) or newBubble.rect.top < 0:
# 如果新气泡越界,则把它添加到上方
if newBubble.rect.top < 0: if newBubble.rect.top < 0:
newRow, newColumn = addBubbleToTop(bubbleArray, newBubble) newRow, newColumn = addBubbleToTop(bubbleArray, newBubble)
# 检查新气泡与当前气泡的中心是否在同一垂直线上
elif newBubble.rect.centery >= bubbleArray[row][column].rect.centery: elif newBubble.rect.centery >= bubbleArray[row][column].rect.centery:
# 向上或向下移动新气泡,并考虑奇偶行的规则
if newBubble.rect.centerx >= bubbleArray[row][column].rect.centerx: if newBubble.rect.centerx >= bubbleArray[row][column].rect.centerx:
if row == 0 or (row) % 2 == 0: if row == 0 or (row) % 2 == 0:
newRow = row + 1 newRow = row + 1
newColumn = column newColumn = column
# 如果目标位置已有气泡,则向上移动一行
if bubbleArray[newRow][newColumn] != BLANK: if bubbleArray[newRow][newColumn] != BLANK:
newRow = newRow - 1 newRow = newRow - 1
bubbleArray[newRow][newColumn] = copy.copy(newBubble) bubbleArray[newRow][newColumn] = copy.copy(newBubble)
@ -406,6 +501,7 @@ def stopBubble(bubbleArray, newBubble, launchBubble, score):
bubbleArray[newRow][newColumn].row = newRow bubbleArray[newRow][newColumn].row = newRow
bubbleArray[newRow][newColumn].column = newColumn bubbleArray[newRow][newColumn].column = newColumn
# 向左或向右移动新气泡,并考虑奇偶行的规则
elif newBubble.rect.centerx < bubbleArray[row][column].rect.centerx: elif newBubble.rect.centerx < bubbleArray[row][column].rect.centerx:
if row == 0 or row % 2 == 0: if row == 0 or row % 2 == 0:
newRow = row + 1 newRow = row + 1
@ -426,8 +522,9 @@ def stopBubble(bubbleArray, newBubble, launchBubble, score):
bubbleArray[newRow][newColumn].row = newRow bubbleArray[newRow][newColumn].row = newRow
bubbleArray[newRow][newColumn].column = newColumn bubbleArray[newRow][newColumn].column = newColumn
# 检查新气泡与当前气泡的中心是否在同一水平线上
elif newBubble.rect.centery < bubbleArray[row][column].rect.centery: elif newBubble.rect.centery < bubbleArray[row][column].rect.centery:
# 向上或向下移动新气泡,并考虑奇偶行的规则
if newBubble.rect.centerx >= bubbleArray[row][column].rect.centerx: if newBubble.rect.centerx >= bubbleArray[row][column].rect.centerx:
if row == 0 or row % 2 == 0: if row == 0 or row % 2 == 0:
newRow = row - 1 newRow = row - 1
@ -446,6 +543,7 @@ def stopBubble(bubbleArray, newBubble, launchBubble, score):
bubbleArray[newRow][newColumn].row = newRow bubbleArray[newRow][newColumn].row = newRow
bubbleArray[newRow][newColumn].column = newColumn bubbleArray[newRow][newColumn].column = newColumn
# 向左或向右移动新气泡,并考虑奇偶行的规则
elif newBubble.rect.centerx <= bubbleArray[row][column].rect.centerx: elif newBubble.rect.centerx <= bubbleArray[row][column].rect.centerx:
if row == 0 or row % 2 == 0: if row == 0 or row % 2 == 0:
newRow = row - 1 newRow = row - 1
@ -465,8 +563,10 @@ def stopBubble(bubbleArray, newBubble, launchBubble, score):
bubbleArray[newRow][newColumn].row = newRow bubbleArray[newRow][newColumn].row = newRow
bubbleArray[newRow][newColumn].column = newColumn bubbleArray[newRow][newColumn].column = newColumn
# 消除选中的气泡,并处理连消和得分
popBubbles(bubbleArray, newRow, newColumn, newBubble.color, deleteList) popBubbles(bubbleArray, newRow, newColumn, newBubble.color, deleteList)
# 如果消除的气泡数量达到3个或以上播放音效、更新布局和得分
if len(deleteList) >= 3: if len(deleteList) >= 3:
for pos in deleteList: for pos in deleteList:
popSound.play() popSound.play()
@ -477,54 +577,68 @@ def stopBubble(bubbleArray, newBubble, launchBubble, score):
score.update(deleteList) score.update(deleteList)
# 更新发射状态和新气泡为None
launchBubble = False launchBubble = False
newBubble = None newBubble = None
return launchBubble, newBubble, score return launchBubble, newBubble, score
def addBubbleToTop(bubbleArray, bubble): def addBubbleToTop(bubbleArray, bubble):
# 获取气泡中心的x坐标并计算气泡左侧边界的x坐标
posx = bubble.rect.centerx posx = bubble.rect.centerx
leftSidex = posx - BUBBLERADIUS leftSidex = posx - BUBBLERADIUS
# 根据气泡左侧边界的位置计算其所在的列
columnDivision = math.modf(float(leftSidex) / float(BUBBLEWIDTH)) columnDivision = math.modf(float(leftSidex) / float(BUBBLEWIDTH))
column = int(columnDivision[1]) column = int(columnDivision[1])
# 判断气泡应该添加到当前列还是下一列
if columnDivision[0] < 0.5: if columnDivision[0] < 0.5:
bubbleArray[0][column] = copy.copy(bubble) bubbleArray[0][column] = copy.copy(bubble)
else: else:
column += 1 column += 1
bubbleArray[0][column] = copy.copy(bubble) bubbleArray[0][column] = copy.copy(bubble)
# 设置行索引为0因为气泡被添加到数组顶部
row = 0 row = 0
return row, column return row, column
#这个函数递归地查找并消除连接的同色泡泡。
def popBubbles(bubbleArray, row, column, color, deleteList): def popBubbles(bubbleArray, row, column, color, deleteList):
# 检查索引是否越界
if row < 0 or column < 0 or row > (len(bubbleArray) - 1) or column > (len(bubbleArray[0]) - 1): if row < 0 or column < 0 or row > (len(bubbleArray) - 1) or column > (len(bubbleArray[0]) - 1):
return return
# 检查当前位置是否为空或颜色不匹配
elif bubbleArray[row][column] == BLANK: elif bubbleArray[row][column] == BLANK:
return return
elif bubbleArray[row][column].color != color: elif bubbleArray[row][column].color != color:
return return
# 如果气泡颜色匹配,但已在删除列表中,则不处理
for bubble in deleteList: for bubble in deleteList:
if bubbleArray[bubble[0]][bubble[1]] == bubbleArray[row][column]: if bubbleArray[bubble[0]][bubble[1]] == bubbleArray[row][column]:
return return
# 将当前气泡加入删除列表
deleteList.append((row, column)) deleteList.append((row, column))
# 递归消除相邻的气泡
# 处理顶部行或底部行的逻辑
if row == 0: if row == 0:
popBubbles(bubbleArray, row, column - 1, color, deleteList) popBubbles(bubbleArray, row, column - 1, color, deleteList)
popBubbles(bubbleArray, row, column + 1, color, deleteList) popBubbles(bubbleArray, row, column + 1, color, deleteList)
popBubbles(bubbleArray, row + 1, column, color, deleteList) popBubbles(bubbleArray, row + 1, column, color, deleteList)
popBubbles(bubbleArray, row + 1, column - 1, color, deleteList) popBubbles(bubbleArray, row + 1, column - 1, color, deleteList)
# 处理中间行的逻辑,奇数行和偶数行处理方式略有不同
elif row % 2 == 0: elif row % 2 == 0:
popBubbles(bubbleArray, row + 1, column, color, deleteList) popBubbles(bubbleArray, row + 1, column, color, deleteList)
popBubbles(bubbleArray, row + 1, column - 1, color, deleteList) popBubbles(bubbleArray, row + 1, column - 1, color, deleteList)
popBubbles(bubbleArray, row - 1, column, color, deleteList) popBubbles(bubbleArray, row - 1, column, color, deleteList)
@ -541,6 +655,7 @@ def popBubbles(bubbleArray, row, column, color, deleteList):
popBubbles(bubbleArray, row, column - 1, color, deleteList) popBubbles(bubbleArray, row, column - 1, color, deleteList)
def drawBubbleArray(array): def drawBubbleArray(array):
for row in range(ARRAYHEIGHT): for row in range(ARRAYHEIGHT):
for column in range(len(array[row])): for column in range(len(array[row])):
@ -549,48 +664,64 @@ def drawBubbleArray(array):
def makeDisplay(): def makeDisplay():
# 创建显示表面并获取其矩形区域
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
DISPLAYRECT = DISPLAYSURF.get_rect() DISPLAYRECT = DISPLAYSURF.get_rect()
# 填充显示表面的背景色
DISPLAYSURF.fill(BGCOLOR) DISPLAYSURF.fill(BGCOLOR)
# 转换显示表面的格式以优化性能
DISPLAYSURF.convert() DISPLAYSURF.convert()
# 更新显示内容
pygame.display.update() pygame.display.update()
return DISPLAYSURF, DISPLAYRECT return DISPLAYSURF, DISPLAYRECT
# 退出游戏的函数
def terminate(): def terminate():
pygame.quit() pygame.quit()
sys.exit() sys.exit()
# 遮盖下一个泡泡的函数
def coverNextBubble(): def coverNextBubble():
# 初始化一个白色矩形,位置在窗口的右下角
whiteRect = pygame.Rect(0, 0, BUBBLEWIDTH, BUBBLEWIDTH) whiteRect = pygame.Rect(0, 0, BUBBLEWIDTH, BUBBLEWIDTH)
whiteRect.bottom = WINDOWHEIGHT whiteRect.bottom = WINDOWHEIGHT
whiteRect.right = WINDOWWIDTH whiteRect.right = WINDOWWIDTH
# 在显示表面绘制矩形
pygame.draw.rect(DISPLAYSURF, BGCOLOR, whiteRect) pygame.draw.rect(DISPLAYSURF, BGCOLOR, whiteRect)
# 游戏结束屏幕的函数
def endScreen(score, winorlose): def endScreen(score, winorlose):
# 初始化游戏结束信息的字体和内容
endFont = pygame.font.SysFont('Helvetica', 20) endFont = pygame.font.SysFont('Helvetica', 20)
endMessage1 = endFont.render('You ' + winorlose + '! Your Score is ' + str(score) + '. Press Enter to Play Again.', endMessage1 = endFont.render('You ' + winorlose + '! Your Score is ' + str(score) + '. Press Enter to Play Again.',
True, BLACK, BGCOLOR) True, BLACK, BGCOLOR)
endMessage1Rect = endMessage1.get_rect() endMessage1Rect = endMessage1.get_rect()
endMessage1Rect.center = DISPLAYRECT.center endMessage1Rect.center = DISPLAYRECT.center # 将结束信息居中显示
# 清空显示屏幕并绘制结束信息
DISPLAYSURF.fill(BGCOLOR) DISPLAYSURF.fill(BGCOLOR)
DISPLAYSURF.blit(endMessage1, endMessage1Rect) DISPLAYSURF.blit(endMessage1, endMessage1Rect)
pygame.display.update() pygame.display.update()
# 等待玩家按键选择重新开始或退出游戏
while True: while True:
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == QUIT: if event.type == QUIT: # 如果检测到退出事件,则终止游戏
terminate() terminate()
elif event.type == KEYUP: elif event.type == KEYUP: # 如果检测到按键事件
if event.key == K_RETURN: if event.key == K_RETURN: # 如果玩家按下回车键,则返回主游戏循环
return return
elif event.key == K_ESCAPE: elif event.key == K_ESCAPE: # 如果玩家按下Esc键则终止游戏
terminate() terminate()
if __name__ == '__main__': if __name__ == '__main__':
main() main()
Loading…
Cancel
Save