嗨喽~小伙伴们,大家早上好,中午好,晚上好呀,

通过前两章对Pygame的学习,我们了解了它的基本使用,附上链接:

1. Python不能做游戏?一小时做出一个游戏!

2. Python不能做游戏?Pygame中的对象你了解吗?

现在,我们就开始真正动手写一个游戏。

这个游戏名字为:ink spill,中文名:墨水溢出。这是Python中一个非常典型的游戏,我们首先来看看游戏长什么样子以及应该怎么玩:

小伙伴们看完后,应该差不多明白这个游戏的玩法了。

现在,让我们站在“设计者”的角度来考虑,这个游戏应该怎么去制作。

一般说来,游戏制作要考虑三个方面的内容:

  • 游戏道具 (图片,音效等)
  • 逻辑控制 (游戏状态的逻辑控制)
  • UI设计 (游戏界面的设计)

游戏道具 ,主要通过两种方式获得:一是加载图片,二是用代码直接绘制。

本游戏中,需要用到的图片有以下几个:

inkspilllogo.png​​

inkspillresetbutton.png

inkspillsettings.png

inkspillsettingsbutton.png

inkspillspot.png

其余的,咱均用代码直接绘制。

分析一下游戏主界面:

它主要由以下几个部分组成:

  • 界面正中央的大格子
  • 界面左边的生命“计”
  • 界面正下方的六个不同颜色的调色板
  • 界面右下方的“重新游戏”按钮和“设置”按钮

在编写游戏之前,我们考虑一个问题:如何设计游戏的难度?

大伙首先想到的肯定是,控制小格子的数量,数量越多,难度越大:

除此之外,关于游戏难度,咱还可以创建一个 boxesToChange 变量,随机将某个小格子的周围格子变成与之同色,这样的格子数用boxesToChange来描述,这样,“简单难度”就将boxesToChange的值设大一点(使得同色的越多),“困难难度”就将boxesToChange的值设小一点(使得同色的越少)(或者直接设为0)。

前面几章说过,一个游戏会有各种各样的游戏状态,比如角色的血量,武器类型等。首先,让我们思考一下,在这个游戏中,需要哪些变量来存储哪些游戏状态(先自己想一想......)。

不知道小伙伴们能想到多少个游戏状态,答案在下面的代码中:


# 根据设置界面,有不同的整个格子尺寸、小格子数量和生命# 小格子大小
SMALL_BOX_SIZE = 60  # 大小以像素为单位
MEDIUM_BOX_SIZE = 20
LARGE_BOX_SIZE = 11# 整个格子的大小
SMALL_BOARD_SIZE = 6  # 大小以一个小格子为单位
MEDIUM_BOARD_SIZE = 17
LARGE_BOARD_SIZE = 30# 最多几次操作(生命)
SMALL_MAX_LIFE = 10
MEDIUM_MAX_LIFE = 30
LARGE_MAX_LIFE = 64FPS = 30
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480
boxSize = MEDIUM_BOX_SIZE
PALETTE_GAP_SIZE = 10  # 调色板间隔大小
PALETTE_SIZE = 45
EASY = 0  # 难度:简单
MEDIUM = 1  # 难度:中等
HARD = 2  # 难度:困难difficulty = MEDIUM  # 游戏以难度“中等”模式开始
maxLife = MEDIUM_MAX_LIFE
boardWidth = MEDIUM_BOARD_SIZE
boardHeight = MEDIUM_BOARD_SIZE#            R    G    B
WHITE = (255, 255, 255)
DARKGRAY = (70, 70, 70)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
PURPLE = (255, 0, 255)# 每个方案中的第一种颜色是背景色,接下来的六种是调色板颜色。
COLOR_SCHEMES = (((150, 200, 255), RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE),((0, 155, 104), (97, 215, 164), (228, 0, 69), (0, 125, 50), (204, 246, 0), (148, 0, 45),(241, 109, 149)),((195, 179, 0), (255, 239, 115), (255, 226, 0), (147, 3, 167), (24, 38, 176), (166, 147, 0),(197, 97, 211)),((85, 0, 0), (155, 39, 102), (0, 201, 13), (255, 118, 0), (206, 0, 113), (0, 130, 9), (255, 180, 115)),((191, 159, 64), (183, 182, 208), (4, 31, 183), (167, 184, 45), (122, 128, 212), (37, 204, 7),(88, 155, 213)),((200, 33, 205), (116, 252, 185), (68, 56, 56), (52, 238, 83), (23, 149, 195), (222, 157, 227),(212, 86, 185)))
# 对颜色的处理
for i in range(len(COLOR_SCHEMES)):assert len(COLOR_SCHEMES[i]) == 7, '颜色方案 %s 没有7种颜色!.' % (i)
# 背景色,调色板设置默认色
bgColor = COLOR_SCHEMES[0][0]
paletteColors = COLOR_SCHEMES[0][1:]

你会看到,记录游戏状态,用到了非常多的变量。依据变量的名称,咱可以很容易推出这个变量的作用是什么。实际上,之后的游戏逻辑控制,就是在更改这些变量的值。

接着,我们来考虑编写整个游戏框架。

接下来编写的代码会非常之多,请小伙伴们仔细体会每个函数的具体作用,这样才能更好的理解整个游戏。

​​​​​​​框架编写如下:


def main():# 需要用到函数之外的变量global FPS_CLOCK, DISPLAY_SURF, LOGO_IMAGE, SPOT_IMAGE, SETTINGS_IMAGE, SETTINGS_BUTTON_IMAGE, RESET_BUTTON_IMAGE# 初始化pygame.init()# 控制帧率FPS_CLOCK = pygame.time.Clock()# 创建窗口DISPLAY_SURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))# 加载图片LOGO_IMAGE = pygame.image.load('inkspilllogo.png')SPOT_IMAGE = pygame.image.load('inkspillspot.png')SETTINGS_IMAGE = pygame.image.load('inkspillsettings.png')SETTINGS_BUTTON_IMAGE = pygame.image.load('inkspillsettingsbutton.png')RESET_BUTTON_IMAGE = pygame.image.load('inkspillresetbutton.png')# 设置窗口标题pygame.display.set_caption('墨水溢出')# 生成界面mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)life = maxLife# 记录上次点击界面下方调色板的颜色lastPaletteClicked = Nonewhile True:  # 主游戏循环paletteClicked = NoneresetGame = False# 画屏幕DISPLAY_SURF.fill(bgColor)# 加载图标和相关按钮drawLogoAndButtons()# 加载正中央的大格子并随机初始化每个小格子的颜色drawBoard(mainBoard)# 加载左侧的"生命计"drawLifeMeter(life)# 加载屏幕底部的六个调色板drawPalettes()# 判断玩家是否想要退出游戏checkForQuit()

代码中有许多函数如

        generateRandomBoard(),

        我们还未实现,下面我们来实现这些函数:

一. generateRandomBoard() :

产生游戏主窗口-----中央的整个大格子:


def generateRandomBoard(width, height, difficulty=MEDIUM):# 为整个大格子中的每个小格子创建具有随机颜色的数据结构。board = []for x in range(width):column = []for y in range(height):column.append(random.randint(0, len(paletteColors) - 1))board.append(column)# 通过将一些小格子设置为与相邻格子相同的颜色,使同色整个大格子更容易。# 确定要更改的小格子数。if difficulty == EASY:if boxSize == SMALL_BOX_SIZE:boxesToChange = 100else:boxesToChange = 1500elif difficulty == MEDIUM:if boxSize == SMALL_BOX_SIZE:boxesToChange = 5else:boxesToChange = 200else:boxesToChange = 0# 挂邻居格子的颜色:for i in range(boxesToChange):# 随机选择要复制其颜色的框x = random.randint(1, width - 2)y = random.randint(1, height - 2)# 随机选择要更改的邻居格子direction = random.randint(0, 3)if direction == 0:  # 左,下board[x - 1][y] = board[x][y]board[x][y - 1] = board[x][y]elif direction == 1:  # 右,上board[x + 1][y] = board[x][y]board[x][y + 1] = board[x][y]elif direction == 2:  # 左,下board[x][y - 1] = board[x][y]board[x + 1][y] = board[x][y]else:  # 左,上board[x][y + 1] = board[x][y]board[x - 1][y] = board[x][y]return board

二. drawLogoAndButtons() :

给界面加上部分按钮和图标:

def drawLogoAndButtons():# 绘制墨水溢出徽标、设置和重置按钮。# bait()函数用于将图片加载到DISPALY_SURF这个Surface对象上DISPLAY_SURF.blit(LOGO_IMAGE, (WINDOW_WIDTH - LOGO_IMAGE.get_width(), 0))DISPLAY_SURF.blit(SETTINGS_BUTTON_IMAGE,(WINDOW_WIDTH - SETTINGS_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height()))DISPLAY_SURF.blit(RESET_BUTTON_IMAGE, (WINDOW_WIDTH - RESET_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height() - RESET_BUTTON_IMAGE.get_height()))

代码中使用了大量坐标运算来控制图片的位置,请小伙伴们细细体会。

三. drawBoard(mainBoard) :

加载界面正中央的大格子并随机初始化每个小格子的颜色:

def drawBoard(board, transparency=255):  # 透明度设置默认为255# 彩色方块将绘制到临时曲面,然后绘制到DISPLAY_SURF曲面。这样我们就可以在DISPLAY_SURF的顶部绘制具有透明度的正方形了。tempSurf = pygame.Surface(DISPLAY_SURF.get_size())  # 获取窗口尺寸tempSurf = tempSurf.convert_alpha()   # 支持透明tempSurf.fill((0, 0, 0, 0))   # 先全部处理为黑色for x in range(boardWidth):for y in range(boardHeight):# 获取每个小格子左上角的坐标left, top = leftTopPixelCoordOfBox(x, y)r, g, b = paletteColors[board[x][y]]pygame.draw.rect(tempSurf, (r, g, b, transparency), (left, top, boxSize, boxSize))left, top = leftTopPixelCoordOfBox(0, 0)# 为防止边缘的小格子颜色与窗口背景色相同,在整个大格子外面包一层黑色细线,厚度为1pxpygame.draw.rect(tempSurf, BLACK, (left - 1, top - 1, boxSize * boardWidth + 1, boxSize * boardHeight + 1), 1)DISPLAY_SURF.blit(tempSurf, (0, 0))

代码中调用了leftTopPixelCoordOfBox(x,y),实现如下:

def leftTopPixelCoordOfBox(boxx, boxy):# 返回某个小格子最左上方像素的x和y。# 注意整个大格子位于窗口的正中央x_margin = int((WINDOW_WIDTH - (boardWidth * boxSize)) / 2)  # x_margin 为整个大格子最左边与窗口最左边的间距y_margin = int((WINDOW_HEIGHT - (boardHeight * boxSize)) / 2)  # y_margin 为整个大格子最上边与窗口最上边的间距return boxx * boxSize + x_margin, boxy * boxSize + y_margin

四. drawLifeMeter(life) :

绘制游戏界面左边的生命“计”并进行简单的生命“逻辑计算”:

def drawLifeMeter(currentLife):# '生命计' 竖直放置,与上下边缘各相距20pxlifeBoxSize = int((WINDOW_HEIGHT - 40) / maxLife)# 绘制"生命计"的背景色,'生命计'的左上角位于坐标(20,20),宽20px,高20 + (maxLife * lifeBoxSize) pxpygame.draw.rect(DISPLAY_SURF, bgColor, (20, 20, 20, 20 + (maxLife * lifeBoxSize)))for i in range(maxLife):if currentLife >= (maxLife - i):  # 画一个实心的红色方框pygame.draw.rect(DISPLAY_SURF, RED, (20, 20 + (i * lifeBoxSize), 20, lifeBoxSize))# 加1px白色的边框pygame.draw.rect(DISPLAY_SURF, WHITE, (20, 20 + (i * lifeBoxSize), 20, lifeBoxSize), 1)

在图形的位置定位上,我们用了大量的坐标运算,请小伙伴们细细体会。

五. drawPalettes() :

给界面添上正下方的六个调色板并进行简单的逻辑控制:

def drawPalettes():# 在屏幕底部绘制六个调色板numColors = len(paletteColors)x_margin = int((WINDOW_WIDTH - ((PALETTE_SIZE * numColors) + (PALETTE_GAP_SIZE * (numColors - 1)))) / 2)for i in range(numColors):left = x_margin + (i * PALETTE_SIZE) + (i * PALETTE_GAP_SIZE)top = WINDOW_HEIGHT - PALETTE_SIZE - 10pygame.draw.rect(DISPLAY_SURF, paletteColors[i], (left, top, PALETTE_SIZE, PALETTE_SIZE))# 为了美观,在格子外2px再加2px厚度的对应颜色的区域pygame.draw.rect(DISPLAY_SURF, bgColor, (left + 2, top + 2, PALETTE_SIZE - 4, PALETTE_SIZE - 4), 2)

六.  checkForQuit()

玩家想要退出游戏时的处理:

def checkForQuit():# 如果存在任何退出事件,则终止程序for event in pygame.event.get(QUIT):  # 获取所有退出事件pygame.quit()  # 如果存在任何退出事件,则终止sys.exit()for event in pygame.event.get(KEYUP):  # 获取所有KEYUP(按键按下)事件if event.key == K_ESCAPE:pygame.quit()  # 如果KEYUP(按键按下)事件是针对Esc键的,则终止sys.exit()pygame.event.post(event)  # 将其他KEYUP(按键按下)事件对象放回原处

接着,我们来考虑游戏的主要逻辑控制。

由于我们并未创建按钮,所以当“鼠标点击”这个事件发生时,我们尝试着获取其点击的位置坐标(利用Event对象的 pos 属性:mousex, mousey = event.pos),将这个坐标与界面上某个图标的位置区域比较(使用pygame.Rest.collidepoint(mousex, mousey)函数),如果在这个区域内,就说明玩家想要点击该图标来实现对应的功能(如鼠标点击“reset”图标表示玩家想重新开始游戏),我们编写代码做出响应即可。基于这样的思想,咱可以将main()函数补充完整:

def main():global FPS_CLOCK, DISPLAY_SURF, LOGO_IMAGE, SPOT_IMAGE, SETTINGS_IMAGE, SETTINGS_BUTTON_IMAGE, RESET_BUTTON_IMAGEpygame.init()FPS_CLOCK = pygame.time.Clock()DISPLAY_SURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))# 加载图片LOGO_IMAGE = pygame.image.load('inkspilllogo.png')SPOT_IMAGE = pygame.image.load('inkspillspot.png')SETTINGS_IMAGE = pygame.image.load('inkspillsettings.png')SETTINGS_BUTTON_IMAGE = pygame.image.load('inkspillsettingsbutton.png')RESET_BUTTON_IMAGE = pygame.image.load('inkspillresetbutton.png')# 设置窗口标题pygame.display.set_caption('墨水溢出')mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)life = maxLifelastPaletteClicked = Nonewhile True:  # 主游戏循环paletteClicked = NoneresetGame = False# 画屏幕DISPLAY_SURF.fill(bgColor)# 加载图标和相关按钮drawLogoAndButtons()# 加载正中央的大格子并随机初始化每个小格子的颜色drawBoard(mainBoard)# 加载左侧的"生命计"drawLifeMeter(life)# 加载屏幕底部的六个调色板drawPalettes()# 判断玩家是否想要退出游戏checkForQuit()for event in pygame.event.get():  # 事件处理循环if event.type == MOUSEBUTTONUP:  # 如果事件是鼠标点击mousex, mousey = event.pos   # 获取鼠标点击的坐标# 如果点击的是"SETTINGS"字样处if pygame.Rect(WINDOW_WIDTH - SETTINGS_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height(),SETTINGS_BUTTON_IMAGE.get_width(),SETTINGS_BUTTON_IMAGE.get_height()).collidepoint(mousex, mousey):# 就展示设置界面resetGame = showSettingsScreen()   # showSettingsScreen() 待实现# 如果点击的是"RESET"字样处elif pygame.Rect(WINDOW_WIDTH - RESET_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height() - RESET_BUTTON_IMAGE.get_height(),RESET_BUTTON_IMAGE.get_width(),RESET_BUTTON_IMAGE.get_height()).collidepoint(mousex, mousey):# 就重新开始游戏resetGame = Trueelse:# 检查是否点击了调色板按钮,如果点击了,返回六个调色板中点击的那一个颜色的索引paletteClicked = getColorOfPaletteAt(mousex, mousey)  # getColorOfPaletteAt()待实现if paletteClicked is not None and paletteClicked != lastPaletteClicked:# 单击的调色板按钮与上次单击的调色板按钮不同,防止鼠标意外单击同一调色板两次lastPaletteClicked = paletteClicked# 对大格子填充颜色,floodAnimation()待实现floodAnimation(mainBoard, paletteClicked)# 点击一次,"生命"减少1life -= 1resetGame = Falseif hasWon(mainBoard):  # 如果赢了,hasWon()待实现for i in range(4):  # 成功的界面效果:闪烁边框4次flashBorderAnimation(WHITE, mainBoard)   # flashBorderAnimation()待实现# "闪光"结束后,重新开始游戏resetGame = True# 暂停2s后再开始游戏pygame.time.wait(2000)elif life == 0:# 生命降为零,玩家失败drawLifeMeter(0)# 更新界面pygame.display.update()# 等待0.4spygame.time.wait(400)# 失败的结束效果:用黑色"闪光"4次for i in range(4):flashBorderAnimation(BLACK, mainBoard)。 # flashBorderAnimation()待实现resetGame = True# 暂停2s后开始重新游戏pygame.time.wait(2000)if resetGame:# 重新开始游戏mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)life = maxLifelastPaletteClicked = None# 更新界面pygame.display.update()# 控制帧率FPS_CLOCK.tick(FPS)

上述主要逻辑控制代码中,还有部分函数未实现:

showSettingsScreen() :展示“设置”界面并提供相应逻辑控制:

def showSettingsScreen():# 获取全局变量global difficulty, boxSize, boardWidth, boardHeight, maxLife, paletteColors, bgColor# 此函数中的像素坐标是通过将inkspillsettings.png图像加载到图形编辑器中并从中读取像素坐标获得的origDifficulty = difficultyorigBoxSize = boxSizescreenNeedsRedraw = Truewhile True:if screenNeedsRedraw:DISPLAY_SURF.fill(bgColor)# 加载"设置"图片DISPLAY_SURF.blit(SETTINGS_IMAGE, (0, 0))# 将"墨迹"图片标记放在选定的颜色左边if difficulty == EASY:DISPLAY_SURF.blit(SPOT_IMAGE, (30, 4))if difficulty == MEDIUM:DISPLAY_SURF.blit(SPOT_IMAGE, (8, 41))if difficulty == HARD:DISPLAY_SURF.blit(SPOT_IMAGE, (30, 76))# 将墨迹标记放置在选定尺寸旁边if boxSize == SMALL_BOX_SIZE:DISPLAY_SURF.blit(SPOT_IMAGE, (22, 150))if boxSize == MEDIUM_BOX_SIZE:DISPLAY_SURF.blit(SPOT_IMAGE, (11, 185))if boxSize == LARGE_BOX_SIZE:DISPLAY_SURF.blit(SPOT_IMAGE, (24, 220))# 加载设置界面右边的颜色选择框for i in range(len(COLOR_SCHEMES)):drawColorSchemeBoxes(500, i * 60 + 30, i)  # 待实现# 更新界面pygame.display.update()screenNeedsRedraw = False  # 默认情况下,不重新绘制屏幕# 事件处理循环for event in pygame.event.get():if event.type == QUIT:pygame.quit()sys.exit()elif event.type == KEYUP:if event.key == K_ESCAPE:# 设置屏幕上的Esc键返回游戏return not (origDifficulty == difficulty and origBoxSize == boxSize)elif event.type == MOUSEBUTTONUP:screenNeedsRedraw = True  # 屏幕应该重新绘制mousex, mousey = event.pos  # 鼠标点击的坐标# 检查难度按钮上是否有咔嗒声if pygame.Rect(74, 16, 111, 30).collidepoint(mousex, mousey):difficulty = EASYelif pygame.Rect(53, 50, 104, 29).collidepoint(mousex, mousey):difficulty = MEDIUMelif pygame.Rect(72, 85, 65, 31).collidepoint(mousex, mousey):difficulty = HARD# 检查尺寸按钮上是否有点击elif pygame.Rect(63, 156, 84, 31).collidepoint(mousex, mousey):# 小板尺寸设置:boxSize = SMALL_BOX_SIZEboardWidth = SMALL_BOARD_SIZEboardHeight = SMALL_BOARD_SIZEmaxLife = SMALL_MAX_LIFEelif pygame.Rect(52, 192, 106, 32).collidepoint(mousex, mousey):# 中板尺寸设置:boxSize = MEDIUM_BOX_SIZEboardWidth = MEDIUM_BOARD_SIZEboardHeight = MEDIUM_BOARD_SIZEmaxLife = MEDIUM_MAX_LIFEelif pygame.Rect(67, 228, 58, 37).collidepoint(mousex, mousey):# 大板尺寸设置:boxSize = LARGE_BOX_SIZEboardWidth = LARGE_BOARD_SIZEboardHeight = LARGE_BOARD_SIZEmaxLife = LARGE_MAX_LIFEelif pygame.Rect(178, 418, 215, 34).collidepoint(mousex, mousey):# 点击“Back To Game”按钮return not (origDifficulty == difficulty and origBoxSize == boxSize)for i in range(len(COLOR_SCHEMES)):# 单击颜色方案按钮if pygame.Rect(500, 30 + i * 60, MEDIUM_BOX_SIZE * 3, MEDIUM_BOX_SIZE * 2).collidepoint(mousex,mousey):bgColor = COLOR_SCHEMES[i][0]paletteColors = COLOR_SCHEMES[i][1:]

上述代码中调用了 drawColorSchemeBoxes():实现如下:

def drawColorSchemeBoxes(x, y, schemeNum):# 绘制“设置”屏幕上显示的颜色方案框for boxy in range(2):for boxx in range(3):pygame.draw.rect(DISPLAY_SURF, COLOR_SCHEMES[schemeNum][3 * boxy + boxx + 1],(x + MEDIUM_BOX_SIZE * boxx, y + MEDIUM_BOX_SIZE * boxy, MEDIUM_BOX_SIZE, MEDIUM_BOX_SIZE))if paletteColors == COLOR_SCHEMES[schemeNum][1:]:# 将"墨迹"图片放置在所选配色方案旁边DISPLAY_SURF.blit(SPOT_IMAGE, (x - 50, y))

getColorOfPaletteAt(mousex, mousey) :获取被点击的调色板颜色的索引:

def getColorOfPaletteAt(x, y):# 返回x和y参数覆盖的调色板颜色的索引numColors = len(paletteColors)xmargin = int((WINDOW_WIDTH - ((PALETTE_SIZE * numColors) + (PALETTE_GAP_SIZE * (numColors - 1)))) / 2)# 调色板底端距窗口底端10pxtop = WINDOW_HEIGHT - PALETTE_SIZE - 10for i in range(numColors):# 六个调色板左上角的坐标:(left,top)left = xmargin + (i * PALETTE_SIZE) + (i * PALETTE_GAP_SIZE)r = pygame.Rect(left, top, PALETTE_SIZE, PALETTE_SIZE)# 找出鼠标单击区域是否在任何调色板内if r.collidepoint(x, y):return i  # 如果在,则返回所点击的调色板的序号# 如果x和y不在任何调色板上,则返回Nonereturn None

hasWon(): 判断玩家是否胜利,实现如下:

def hasWon(board):# 如果整个棋盘颜色相同,则表示玩家获胜for x in range(boardWidth):for y in range(boardHeight):# 只要发现一个颜色与左上角的颜色不同,玩家还没有赢if board[x][y] != board[0][0]:return Falsereturn True

floodAnimation(mainBoard, paletteClicked):用paletteClicked对应的颜色填充mainBoard(中央的大格子):

def floodAnimation(board, paletteClicked, animationSpeed=25):origBoard = copy.deepcopy(board)  # 深拷贝整个大格子# 从左上角处的格子开始同色填充,floodFill()待实现floodFill(board, board[0][0], paletteClicked, 0, 0)for transparency in range(0, 255, animationSpeed):# “新”大格子在大格子上慢慢变得不透明drawBoard(origBoard)# 更新透明度drawBoard(board, transparency)# 更新界面pygame.display.update()# 控制帧率FPS_CLOCK.tick(FPS)

floodFill() :填充算法,实现如下:

def floodFill(board, oldColor, newColor, x, y):# 洪水填充算法if oldColor == newColor or board[x][y] != oldColor:# 如果左上角的颜色和点击颜色没有相邻,直接返回returnboard[x][y] = newColor  # 更改当前格子的颜色# 对任何相邻格子进行递归调用:if x > 0:floodFill(board, oldColor, newColor, x - 1, y)if x < boardWidth - 1:floodFill(board, oldColor, newColor, x + 1, y)if y > 0:floodFill(board, oldColor, newColor, x, y - 1)if y < boardHeight - 1:floodFill(board, oldColor, newColor, x, y + 1)

flashBorderAnimation(Color, mainBoard):游戏胜利或失败的结束画面:

def flashBorderAnimation(color, board, animationSpeed=30):# "闪光"效果结束后,需要回到原来(游戏刚结束)的界面,此处先保存原来的界面origSurf = DISPLAY_SURF.copy()flashSurf = pygame.Surface(DISPLAY_SURF.get_size())flashSurf = flashSurf.convert_alpha()# 实现"闪光"效果for start, end, step in ((0, 256, 1), (255, 0, -1)):# 外循环的第一次迭代将内循环的透明度设置为从0到255,第二次迭代将透明度设置为从255到0。这就是“闪光”。for transparency in range(start, end, animationSpeed * step):DISPLAY_SURF.blit(origSurf, (0, 0))r, g, b = colorflashSurf.fill((r, g, b, transparency))DISPLAY_SURF.blit(flashSurf, (0, 0))drawBoard(board)  # 在透明层的顶部绘制板# 更新界面pygame.display.update()# 控制帧率FPS_CLOCK.tick(FPS)# 绘制原来(游戏刚结束)的界面DISPLAY_SURF.blit(origSurf, (0, 0))

......我猜,小伙伴们可能已经懵了......但是做游戏,考虑的东西会非常之多,也许咱只有好好的理解每一个细节,才能真正做出好的游戏。

最后,附上游戏完整代码:


import random, sys, copy, pygame
from pygame.locals import *  # 将所有的 Pygame 常量导入# 根据设置界面,有不同的大格子尺寸、小格子数量和寿命# 小格子大小
SMALL_BOX_SIZE = 60  # 大小以像素为单位
MEDIUM_BOX_SIZE = 20
LARGE_BOX_SIZE = 11# 整个格子的大小
SMALL_BOARD_SIZE = 6  # 大小以一个小格子为单位
MEDIUM_BOARD_SIZE = 17
LARGE_BOARD_SIZE = 30# 最多几次操作(生命)
SMALL_MAX_LIFE = 10
MEDIUM_MAX_LIFE = 30
LARGE_MAX_LIFE = 64FPS = 30
WINDOW_WIDTH = 640
WINDOW_HEIGHT = 480
boxSize = MEDIUM_BOX_SIZE
PALETTE_GAP_SIZE = 10  # 调色板间隔大小
PALETTE_SIZE = 45
EASY = 0  # 难度:简单
MEDIUM = 1  # 难度:中等
HARD = 2  # 难度:困难difficulty = MEDIUM  # 游戏以难度“中等”模式开始
maxLife = MEDIUM_MAX_LIFE
boardWidth = MEDIUM_BOARD_SIZE
boardHeight = MEDIUM_BOARD_SIZE#            R    G    B
WHITE = (255, 255, 255)
DARKGRAY = (70, 70, 70)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
PURPLE = (255, 0, 255)# 每个方案中的第一种颜色是背景色,接下来的六种是调色板颜色。
COLOR_SCHEMES = (((150, 200, 255), RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE),((0, 155, 104), (97, 215, 164), (228, 0, 69), (0, 125, 50), (204, 246, 0), (148, 0, 45),(241, 109, 149)),((195, 179, 0), (255, 239, 115), (255, 226, 0), (147, 3, 167), (24, 38, 176), (166, 147, 0),(197, 97, 211)),((85, 0, 0), (155, 39, 102), (0, 201, 13), (255, 118, 0), (206, 0, 113), (0, 130, 9), (255, 180, 115)),((191, 159, 64), (183, 182, 208), (4, 31, 183), (167, 184, 45), (122, 128, 212), (37, 204, 7),(88, 155, 213)),((200, 33, 205), (116, 252, 185), (68, 56, 56), (52, 238, 83), (23, 149, 195), (222, 157, 227),(212, 86, 185)))
# 对颜色的处理
for i in range(len(COLOR_SCHEMES)):assert len(COLOR_SCHEMES[i]) == 7, '颜色方案 %s 没有7种颜色!.' % (i)
# 背景色,调色板设置默认色
bgColor = COLOR_SCHEMES[0][0]
paletteColors = COLOR_SCHEMES[0][1:]def main():global FPS_CLOCK, DISPLAY_SURF, LOGO_IMAGE, SPOT_IMAGE, SETTINGS_IMAGE, SETTINGS_BUTTON_IMAGE, RESET_BUTTON_IMAGEpygame.init()FPS_CLOCK = pygame.time.Clock()DISPLAY_SURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))# 加载图片LOGO_IMAGE = pygame.image.load('inkspilllogo.png')SPOT_IMAGE = pygame.image.load('inkspillspot.png')SETTINGS_IMAGE = pygame.image.load('inkspillsettings.png')SETTINGS_BUTTON_IMAGE = pygame.image.load('inkspillsettingsbutton.png')RESET_BUTTON_IMAGE = pygame.image.load('inkspillresetbutton.png')# 设置窗口标题pygame.display.set_caption('墨水溢出')mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)life = maxLifelastPaletteClicked = Nonewhile True:  # 主游戏循环paletteClicked = NoneresetGame = False# 画屏幕DISPLAY_SURF.fill(bgColor)# 加载图标和相关按钮drawLogoAndButtons()# 加载正中央的大格子并随机初始化每个小格子的颜色drawBoard(mainBoard)# 加载左侧的"生命计"drawLifeMeter(life)# 加载屏幕底部的六个调色板drawPalettes()# 判断玩家是否想要退出游戏checkForQuit()for event in pygame.event.get():  # 事件处理循环if event.type == MOUSEBUTTONUP:  # 如果事件是鼠标点击mousex, mousey = event.pos   # 获取鼠标点击的坐标# 如果点击的是"SETTINGS"字样处if pygame.Rect(WINDOW_WIDTH - SETTINGS_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height(),SETTINGS_BUTTON_IMAGE.get_width(),SETTINGS_BUTTON_IMAGE.get_height()).collidepoint(mousex, mousey):# 就展示设置界面resetGame = showSettingsScreen()# 如果点击的是"RESET"字样处elif pygame.Rect(WINDOW_WIDTH - RESET_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height() - RESET_BUTTON_IMAGE.get_height(),RESET_BUTTON_IMAGE.get_width(),RESET_BUTTON_IMAGE.get_height()).collidepoint(mousex, mousey):# 就重新开始游戏resetGame = Trueelse:# 检查是否点击了调色板按钮paletteClicked = getColorOfPaletteAt(mousex, mousey)if paletteClicked is not None and paletteClicked != lastPaletteClicked:# 单击的调色板按钮与上次单击的调色板按钮不同,防止播放器意外单击同一调色板两次lastPaletteClicked = paletteClicked# 填充颜色floodAnimation(mainBoard, paletteClicked)# 点击一次,"生命"减少1life -= 1resetGame = Falseif hasWon(mainBoard):  # 如果赢了for i in range(4):  # 成功的界面效果:闪烁边框4次flashBorderAnimation(WHITE, mainBoard)# "闪光"结束后,重新开始游戏resetGame = True# 暂停2s后再开始游戏pygame.time.wait(2000)elif life == 0:# 生命降为零,玩家失败drawLifeMeter(0)# 更新界面pygame.display.update()# 等待0.4spygame.time.wait(400)# 失败的结束效果:用黑色"闪光"4次for i in range(4):flashBorderAnimation(BLACK, mainBoard)resetGame = True# 暂停2s后开始重新游戏pygame.time.wait(2000)if resetGame:# 重新开始游戏mainBoard = generateRandomBoard(boardWidth, boardHeight, difficulty)life = maxLifelastPaletteClicked = None# 更新界面pygame.display.update()# 控制帧率FPS_CLOCK.tick(FPS)def checkForQuit():# 如果存在任何退出事件,则终止程序for event in pygame.event.get(QUIT):  # 获取所有退出事件pygame.quit()  # 如果存在任何退出事件,则终止sys.exit()for event in pygame.event.get(KEYUP):  # 获取所有KEYUP(按键按下)事件if event.key == K_ESCAPE:pygame.quit()  # 如果KEYUP(按键按下)事件是针对Esc键的,则终止sys.exit()pygame.event.post(event)  # 将其他KEYUP(按键按下)事件对象放回原处def hasWon(board):# 如果整个棋盘颜色相同,则表示玩家获胜for x in range(boardWidth):for y in range(boardHeight):# 只要发现一个颜色与左上角的颜色不同,玩家还没有赢if board[x][y] != board[0][0]:return Falsereturn Truedef showSettingsScreen():# 获取全局变量global difficulty, boxSize, boardWidth, boardHeight, maxLife, paletteColors, bgColor# 此函数中的像素坐标是通过将inkspillsettings.png图像加载到图形编辑器中并从中读取像素坐标获得的origDifficulty = difficultyorigBoxSize = boxSizescreenNeedsRedraw = Truewhile True:if screenNeedsRedraw:DISPLAY_SURF.fill(bgColor)# 加载"设置"图片DISPLAY_SURF.blit(SETTINGS_IMAGE, (0, 0))# 将"墨迹"图片标记放在选定的颜色左边if difficulty == EASY:DISPLAY_SURF.blit(SPOT_IMAGE, (30, 4))if difficulty == MEDIUM:DISPLAY_SURF.blit(SPOT_IMAGE, (8, 41))if difficulty == HARD:DISPLAY_SURF.blit(SPOT_IMAGE, (30, 76))# 将墨迹标记放置在选定尺寸旁边if boxSize == SMALL_BOX_SIZE:DISPLAY_SURF.blit(SPOT_IMAGE, (22, 150))if boxSize == MEDIUM_BOX_SIZE:DISPLAY_SURF.blit(SPOT_IMAGE, (11, 185))if boxSize == LARGE_BOX_SIZE:DISPLAY_SURF.blit(SPOT_IMAGE, (24, 220))# 加载设置界面右边的颜色选择框for i in range(len(COLOR_SCHEMES)):drawColorSchemeBoxes(500, i * 60 + 30, i)# 更新界面pygame.display.update()screenNeedsRedraw = False  # 默认情况下,不重新绘制屏幕# 事件处理循环for event in pygame.event.get():if event.type == QUIT:pygame.quit()sys.exit()elif event.type == KEYUP:if event.key == K_ESCAPE:# 设置屏幕上的Esc键返回游戏return not (origDifficulty == difficulty and origBoxSize == boxSize)elif event.type == MOUSEBUTTONUP:screenNeedsRedraw = True  # 屏幕应该重新绘制mousex, mousey = event.pos  # 鼠标点击的坐标# 检查难度按钮上是否有咔嗒声if pygame.Rect(74, 16, 111, 30).collidepoint(mousex, mousey):difficulty = EASYelif pygame.Rect(53, 50, 104, 29).collidepoint(mousex, mousey):difficulty = MEDIUMelif pygame.Rect(72, 85, 65, 31).collidepoint(mousex, mousey):difficulty = HARD# 检查尺寸按钮上是否有点击elif pygame.Rect(63, 156, 84, 31).collidepoint(mousex, mousey):# 小板尺寸设置:boxSize = SMALL_BOX_SIZEboardWidth = SMALL_BOARD_SIZEboardHeight = SMALL_BOARD_SIZEmaxLife = SMALL_MAX_LIFEelif pygame.Rect(52, 192, 106, 32).collidepoint(mousex, mousey):# 中板尺寸设置:boxSize = MEDIUM_BOX_SIZEboardWidth = MEDIUM_BOARD_SIZEboardHeight = MEDIUM_BOARD_SIZEmaxLife = MEDIUM_MAX_LIFEelif pygame.Rect(67, 228, 58, 37).collidepoint(mousex, mousey):# 大板尺寸设置:boxSize = LARGE_BOX_SIZEboardWidth = LARGE_BOARD_SIZEboardHeight = LARGE_BOARD_SIZEmaxLife = LARGE_MAX_LIFEelif pygame.Rect(178, 418, 215, 34).collidepoint(mousex, mousey):# 点击“Back To Game”按钮return not (origDifficulty == difficulty and origBoxSize == boxSize)for i in range(len(COLOR_SCHEMES)):# 单击颜色方案按钮if pygame.Rect(500, 30 + i * 60, MEDIUM_BOX_SIZE * 3, MEDIUM_BOX_SIZE * 2).collidepoint(mousex,mousey):bgColor = COLOR_SCHEMES[i][0]paletteColors = COLOR_SCHEMES[i][1:]def drawColorSchemeBoxes(x, y, schemeNum):# 绘制“设置”屏幕上显示的颜色方案框for boxy in range(2):for boxx in range(3):pygame.draw.rect(DISPLAY_SURF, COLOR_SCHEMES[schemeNum][3 * boxy + boxx + 1],(x + MEDIUM_BOX_SIZE * boxx, y + MEDIUM_BOX_SIZE * boxy, MEDIUM_BOX_SIZE, MEDIUM_BOX_SIZE))if paletteColors == COLOR_SCHEMES[schemeNum][1:]:# 将"墨迹"图片放置在所选配色方案旁边DISPLAY_SURF.blit(SPOT_IMAGE, (x - 50, y))def flashBorderAnimation(color, board, animationSpeed=30):# "闪光"效果结束后,需要回到原来(游戏刚结束)的界面,此处先保存原来的界面origSurf = DISPLAY_SURF.copy()flashSurf = pygame.Surface(DISPLAY_SURF.get_size())flashSurf = flashSurf.convert_alpha()# 实现"闪光"效果for start, end, step in ((0, 256, 1), (255, 0, -1)):# 外循环的第一次迭代将内循环的透明度设置为从0到255,第二次迭代将透明度设置为从255到0。这就是“闪光”。for transparency in range(start, end, animationSpeed * step):DISPLAY_SURF.blit(origSurf, (0, 0))r, g, b = colorflashSurf.fill((r, g, b, transparency))DISPLAY_SURF.blit(flashSurf, (0, 0))drawBoard(board)  # 在透明层的顶部绘制板# 更新界面pygame.display.update()# 控制帧率FPS_CLOCK.tick(FPS)# 绘制原来(游戏刚结束)的界面DISPLAY_SURF.blit(origSurf, (0, 0))def floodAnimation(board, paletteClicked, animationSpeed=25):origBoard = copy.deepcopy(board)  # 深拷贝整个大格子# 从左上角处的格子开始同色填充floodFill(board, board[0][0], paletteClicked, 0, 0)for transparency in range(0, 255, animationSpeed):# “新”大格子在大格子上慢慢变得不透明drawBoard(origBoard)# 更新透明度drawBoard(board, transparency)# 更新界面pygame.display.update()# 控制帧率FPS_CLOCK.tick(FPS)def generateRandomBoard(width, height, difficulty=MEDIUM):# 为整个大格子中的每个小格子创建具有随机颜色的数据结构。board = []for x in range(width):column = []for y in range(height):column.append(random.randint(0, len(paletteColors) - 1))board.append(column)# 通过将一些小格子设置为与相邻格子相同的颜色,使解决整个大格子更容易。# 确定要更改的小格子数。if difficulty == EASY:if boxSize == SMALL_BOX_SIZE:boxesToChange = 100else:boxesToChange = 1500elif difficulty == MEDIUM:if boxSize == SMALL_BOX_SIZE:boxesToChange = 5else:boxesToChange = 200else:boxesToChange = 0# 挂邻居格子的颜色:for i in range(boxesToChange):# 随机选择要复制其颜色的框x = random.randint(1, width - 2)y = random.randint(1, height - 2)# 随机选择要更改的邻居格子direction = random.randint(0, 3)if direction == 0:  # 左,下board[x - 1][y] = board[x][y]board[x][y - 1] = board[x][y]elif direction == 1:  # 右,上board[x + 1][y] = board[x][y]board[x][y + 1] = board[x][y]elif direction == 2:  # 左,下board[x][y - 1] = board[x][y]board[x + 1][y] = board[x][y]else:  # 左,上board[x][y + 1] = board[x][y]board[x - 1][y] = board[x][y]return boarddef drawLogoAndButtons():# 绘制墨水溢出徽标、设置和重置按钮。DISPLAY_SURF.blit(LOGO_IMAGE, (WINDOW_WIDTH - LOGO_IMAGE.get_width(), 0))DISPLAY_SURF.blit(SETTINGS_BUTTON_IMAGE,(WINDOW_WIDTH - SETTINGS_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height()))DISPLAY_SURF.blit(RESET_BUTTON_IMAGE, (WINDOW_WIDTH - RESET_BUTTON_IMAGE.get_width(),WINDOW_HEIGHT - SETTINGS_BUTTON_IMAGE.get_height() - RESET_BUTTON_IMAGE.get_height()))def drawBoard(board, transparency=255):  # 透明度设置默认为255# 彩色方块将绘制到临时曲面,然后绘制到DISPLAY_SURF曲面。这样我们就可以在DISPLAY_SURF的顶部绘制具有透明度的正方形了。tempSurf = pygame.Surface(DISPLAY_SURF.get_size())  # 获取窗口尺寸tempSurf = tempSurf.convert_alpha()   # 支持透明tempSurf.fill((0, 0, 0, 0))   # 先全部处理为黑色for x in range(boardWidth):for y in range(boardHeight):left, top = leftTopPixelCoordOfBox(x, y)r, g, b = paletteColors[board[x][y]]pygame.draw.rect(tempSurf, (r, g, b, transparency), (left, top, boxSize, boxSize))left, top = leftTopPixelCoordOfBox(0, 0)# 为防止边缘的小格子颜色与窗口背景色相同,在整个大格子外面包一层黑色细线,厚度为1pxpygame.draw.rect(tempSurf, BLACK, (left - 1, top - 1, boxSize * boardWidth + 1, boxSize * boardHeight + 1), 1)DISPLAY_SURF.blit(tempSurf, (0, 0))def drawPalettes():# 在屏幕底部绘制六个调色板numColors = len(paletteColors)x_margin = int((WINDOW_WIDTH - ((PALETTE_SIZE * numColors) + (PALETTE_GAP_SIZE * (numColors - 1)))) / 2)for i in range(numColors):left = x_margin + (i * PALETTE_SIZE) + (i * PALETTE_GAP_SIZE)top = WINDOW_HEIGHT - PALETTE_SIZE - 10pygame.draw.rect(DISPLAY_SURF, paletteColors[i], (left, top, PALETTE_SIZE, PALETTE_SIZE))# 为了美观,在格子外2px再加2px厚度的对应颜色的区域pygame.draw.rect(DISPLAY_SURF, bgColor, (left + 2, top + 2, PALETTE_SIZE - 4, PALETTE_SIZE - 4), 2)def drawLifeMeter(currentLife):# '生命计' 竖直放置,与上下边缘各相距20pxlifeBoxSize = int((WINDOW_HEIGHT - 40) / maxLife)# 绘制"生命计"的背景色,'生命计'的左上角位于坐标(20,20),宽20px,高20 + (maxLife * lifeBoxSize) pxpygame.draw.rect(DISPLAY_SURF, bgColor, (20, 20, 20, 20 + (maxLife * lifeBoxSize)))for i in range(maxLife):if currentLife >= (maxLife - i):  # 画一个实心的红色方框pygame.draw.rect(DISPLAY_SURF, RED, (20, 20 + (i * lifeBoxSize), 20, lifeBoxSize))# 加1px白色的边框pygame.draw.rect(DISPLAY_SURF, WHITE, (20, 20 + (i * lifeBoxSize), 20, lifeBoxSize), 1)def getColorOfPaletteAt(x, y):# 返回x和y参数覆盖的调色板颜色的索引numColors = len(paletteColors)xmargin = int((WINDOW_WIDTH - ((PALETTE_SIZE * numColors) + (PALETTE_GAP_SIZE * (numColors - 1)))) / 2)# 调色板底端距窗口底端10pxtop = WINDOW_HEIGHT - PALETTE_SIZE - 10for i in range(numColors):# 六个调色板左上角的坐标:(left,top)left = xmargin + (i * PALETTE_SIZE) + (i * PALETTE_GAP_SIZE)r = pygame.Rect(left, top, PALETTE_SIZE, PALETTE_SIZE)# 找出鼠标单击区域是否在任何调色板内if r.collidepoint(x, y):return i  # 如果在,则返回所点击的调色板的序号# 如果x和y不在任何调色板上,则返回Nonereturn Nonedef floodFill(board, oldColor, newColor, x, y):# 洪水填充算法if oldColor == newColor or board[x][y] != oldColor:# 如果左上角的颜色和点击颜色没有相邻,直接返回returnboard[x][y] = newColor  # 更改当前格子的颜色# 对任何相邻格子进行递归调用:if x > 0:floodFill(board, oldColor, newColor, x - 1, y)if x < boardWidth - 1:floodFill(board, oldColor, newColor, x + 1, y)if y > 0:floodFill(board, oldColor, newColor, x, y - 1)if y < boardHeight - 1:floodFill(board, oldColor, newColor, x, y + 1)def leftTopPixelCoordOfBox(boxx, boxy):# 返回某个小格子最左上方像素的x和y。# 注意整个大格子位于窗口的正中央x_margin = int((WINDOW_WIDTH - (boardWidth * boxSize)) / 2)  # x_margin 为整个大格子最左边与窗口最左边的间距y_margin = int((WINDOW_HEIGHT - (boardHeight * boxSize)) / 2)  # y_margin 为整个大格子最上边与窗口最上边的间距return boxx * boxSize + x_margin, boxy * boxSize + y_marginif __name__ == '__main__':main()

喜欢的小伙伴们点个赞鼓励支持一下吧~

Python不能做游戏?游戏实战之-----《ink spill》(附游戏完整源码)相关推荐

  1. [智慧农业]Python基于改进YOLOv5的猕猴桃叶病害检测系统(完整源码&数据集&视频教程)

    1.背景 现如今由于农作物病虫害的多样性和复杂性,在特定的条件下其很容易在大范围内发生,导致农产品产量急剧下降.因此,预防和监测农作物病虫害已成为农业生产活动中的重要环节.当前,耕地面积逐渐减少,世界 ...

  2. Tkinter模块GUI界面化编程实战(六)——超级游戏盒子(含超详解及完整源码、完整程序免费下载链接)

    [上期回顾:Tkinter模块GUI界面化编程实战(五)--大鱼吃小鱼游戏] 这篇博客介绍了如何用Python Tkinter模块编写一个界面化的超级游戏盒子,在博客下面有完整的源码,源码中有详细的注 ...

  3. 纯JavaScript入门级小游戏:兔子抢金币(附演示地址+源码)

    Hello,大家好,我是兔哥,我又来分享好玩的入门级项目啦. 今天给大家带来的是一个纯JavaScript入门级小游戏:兔子抢金币,规则非常简单,控制屏幕上的兔子去接天上掉下来的金币,接满20个就可以 ...

  4. Python基于改进FCN&VGG的高分辨率遥感图像分割(完整源码&数据集&视频教程)

    1.高分辨率遥感图像分割效果展示: 2.数据集简介: 首先介绍一下数据,我们这次采用的数据集是CCF大数据比赛提供的数据(2015年中国南方某城市的高清遥感图像),这是一个小数据集,里面包含了5张带标 ...

  5. java制作管理系统视频_阶段1:手把手快速做一个Java swing mysql学生信息管理系统附带完整源码及视频开发教程【猿来入此自营】...

    <p> <span style="color:#666666;font-family:"font-size:16px;background-color:#FFFF ...

  6. java swing课程表设计_阶段2:手把手快速做一个Java swing mysql学生选课系统附带完整源码及视频开发教程【猿来入此自营】...

    <p> <span style="font-family:微软雅黑;font-size:16px;color:#666666;background:#FFFFFF;line ...

  7. 【多人在线游戏架构实战-基于C++的分布式游戏编程】开篇

    学习一门语言很久了,却从来没有用它做过项目,刚学的时候用它来写过一个黑白通讯录,后来又常常用它来刷题.会了Java以后,刷题也不愿意去用这门语言了,没错它就是C++,一把锋利的瑞士军刀.这个国庆节期间 ...

  8. Python贪吃蛇小游戏_完整源码免费分享

    文章目录 Python 贪吃蛇小游戏 1. 导包 2. 配置初始化参数 3. 主函数及运行主体 4. 画食物的函数 5. 画贪吃蛇的函数 6. 画网格的函数(非必选,觉得多余的可以忽略此项) 7. 操 ...

  9. 【Python游戏】Python各大游戏合集(3):飞翔的小鸟、俄罗斯方块、24点小游戏、吃豆豆小游、扫雷 | 附带源码

    相关文件 关注小编,私信小编领取哟! 当然别忘了一件三连哟~~ 公众号:Python日志 可以关注小编公众号,会不定时的发布一下Python小技巧,还有很多资源可以免费领取哟!! 源码领取:加Pyth ...

最新文章

  1. SICP 1.21 1.22 1.23 1.24
  2. android 如何解决scrollTo无法执行
  3. 用Docker之后还需要OpenStack吗
  4. 第三方登录过程—OAuth2.0协议
  5. Android华容道之一步一步实现-2-图片分割
  6. OSI模型中的数据链路层和物理层的区分
  7. 谈谈java的线程池(创建、机制)
  8. 利剑无意之面试题(二)
  9. 加油python_力扣——gas station (加油站) python实现
  10. Centos7 安装python3.7.2
  11. 前端学习(1665):前端系列实战课程之自定义右键菜单
  12. APU(美国AMD公司研发的加速处理器)
  13. nginx 403 Forbidden
  14. 计算机网络各层设备故障及可行的解决方案
  15. 小微-你的专属聊天机器人
  16. execjs安装及相关问题解决
  17. 产品运营数据分析—SPSS数据分组案例
  18. 鸿蒙系统安装电视猫,免费资源丰富 如何让智能电视物尽其用
  19. java日志管理(slf4j+logback,tomcat)
  20. 18个提高效率的办公软件推荐,收好不谢

热门文章

  1. Linux 命令(75)—— uptime 命令
  2. Office Word 使用笔记
  3. word2vec 细节解析1
  4. 使用ip命令搭建基于隧道的虚拟专有网络
  5. java代码求IP和mac地址
  6. 跨域资源请求(除jsonp以外)的方法
  7. 不错的网络协议栈測试工具 — Packetdrill
  8. 设置UITableView的separatorInset值为UIEdgeInsetsZero,分隔线不最左端显示的问题
  9. Python之with语句
  10. HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)