提到开心消消乐这款小游戏,相信大家都不陌生,其曾在 2015 年获得过玩家最喜爱的移动单机游戏奖,受欢迎程度可见一斑,本文我们使用 Python 来做个简单的消消乐小游戏。

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:1097524789

实现

消消乐的构成主要包括三部分:游戏主体、计分器、计时器,下面来看一下具体实现。

先来看一下游戏所需 Python 库。

import os
import sys
import time
import pygame
import random

定义一些常量,比如:窗口宽高、网格行列数等,代码如下:

WIDTH = 400
HEIGHT = 400
NUMGRID = 8
GRIDSIZE = 36
XMARGIN = (WIDTH - GRIDSIZE * NUMGRID) // 2
YMARGIN = (HEIGHT - GRIDSIZE * NUMGRID) // 2
ROOTDIR = os.getcwd()
FPS = 30

接着创建一个主窗口,代码如下:

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('消消乐')

看一下效果:

再接着在窗口中画一个 8 x 8 的网格,代码如下:

screen.fill((255, 255, 220))
# 游戏界面的网格绘制
def drawGrids(self):
for x in range(NUMGRID):
for y in range(NUMGRID):
rect = pygame.Rect((XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE, GRIDSIZE, GRIDSIZE))
self.drawBlock(rect, color=(255, 165, 0), size=1
# 画矩形 block 框
def drawBlock(self, block, color=(255, 0, 0), size=2):
pygame.draw.rect(self.screen, color, block, size)

看一下效果:

再接着在网格中随机放入各种拼图块,代码如下:

while True:
self.all_gems = []
self.gems_group = pygame.sprite.Group()
for x in range(NUMGRID):
self.all_gems.append([])
for y in range(NUMGRID):
gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+x*GRIDSIZE, YMARGIN+y*GRIDSIZE-NUMGRID*GRIDSIZE], downlen=NUMGRID*GRIDSIZE)
self.all_gems[x].append(gem)
self.gems_group.add(gem)
if self.isMatch()[0] == 0:
break

看一下效果:

再接着加入计分器和计时器,代码如下:

# 显示得分
def drawScore(self):
score_render = self.font.render('分数:'+str(self.score), 1, (85, 65, 0))
rect = score_render.get_rect()
rect.left, rect.top = (55, 15)
self.screen.blit(score_render, rect)
# 显示加分
def drawAddScore(self, add_score):
score_render = self.font.render('+'+str(add_score), 1, (255, 100, 100))
rect = score_render.get_rect()
rect.left, rect.top = (250, 250)
self.screen.blit(score_render, rect)
# 显示剩余时间
def showRemainingTime(self):
remaining_time_render = self.font.render('倒计时: %ss' % str(self.remaining_time), 1, (85, 65, 0))
rect = remaining_time_render.get_rect()
rect.left, rect.top = (WIDTH-190, 15)
self.screen.blit(remaining_time_render, rect)

看一下效果:

当设置的游戏时间用尽时,我们可以生成一些提示信息,代码如下:

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP and event.key == pygame.K_r:
flag = True
if flag:
break
screen.fill((255, 255, 220))
text0 = '最终得分: %s' % score
text1 = '按 R 键重新开始'
y = 140
for idx, text in enumerate([text0, text1]):
text_render = font.render(text, 1, (85, 65, 0))
rect = text_render.get_rect()
if idx == 0:
rect.left, rect.top = (100, y)
elif idx == 1:
rect.left, rect.top = (100, y)
y += 60
screen.blit(text_render, rect)
pygame.display.update()

看一下效果:

说完了游戏图形化界面相关的部分,我们再看一下游戏的主要处理逻辑。

我们通过鼠标来操纵拼图块,因此程序需要检查有无拼图块被选中,代码实现如下:

def checkSelected(self, position):
for x in range(NUMGRID):
for y in range(NUMGRID):
if self.getGemByPos(x, y).rect.collidepoint(*position):
return [x, y]
return None

我们需要将鼠标连续选择的拼图块进行位置交换,代码实现如下:

def swapGem(self, gem1_pos, gem2_pos):
margin = gem1_pos[0] - gem2_pos[0] + gem1_pos[1] - gem2_pos[1]
if abs(margin) != 1:
return False
gem1 = self.getGemByPos(*gem1_pos)
gem2 = self.getGemByPos(*gem2_pos)
if gem1_pos[0] - gem2_pos[0] == 1:
gem1.direction = 'left'
gem2.direction = 'right'
elif gem1_pos[0] - gem2_pos[0] == -1:
gem2.direction = 'left'
gem1.direction = 'right'
elif gem1_pos[1] - gem2_pos[1] == 1:
gem1.direction = 'up'
gem2.direction = 'down'
elif gem1_pos[1] - gem2_pos[1] == -1:
gem2.direction = 'up'
gem1.direction = 'down'
gem1.target_x = gem2.rect.left
gem1.target_y = gem2.rect.top
gem1.fixed = False
gem2.target_x = gem1.rect.left
gem2.target_y = gem1.rect.top
gem2.fixed = False
self.all_gems[gem2_pos[0]][gem2_pos[1]] = gem1
self.all_gems[gem1_pos[0]][gem1_pos[1]] = gem2
return True

每一次交换拼图块时,我们需要判断是否有连续一样的三个及以上拼图块,代码实现如下:

def isMatch(self):
for x in range(NUMGRID):
for y in range(NUMGRID):
if x + 2 < NUMGRID:
if self.getGemByPos(x, y).type == self.getGemByPos(x+1, y).type == self.getGemByPos(x+2, y).type:
return [1, x, y]
if y + 2 < NUMGRID:
if self.getGemByPos(x, y).type == self.getGemByPos(x, y+1).type == self.getGemByPos(x, y+2).type:
return [2, x, y]
return [0, x, y]

当出现三个及以上拼图块时,需要将这些拼图块消除,代码实现如下:

def removeMatched(self, res_match):
if res_match[0] > 0:
self.generateNewGems(res_match)
self.score += self.reward
return self.reward
return 0

将匹配的拼图块消除之后,我们还需要随机生成新的拼图块,代码实现如下:

def generateNewGems(self, res_match):
if res_match[0] == 1:
start = res_match[2]
while start > -2:
for each in [res_match[1], res_match[1]+1, res_match[1]+2]:
gem = self.getGemByPos(*[each, start])
if start == res_match[2]:
self.gems_group.remove(gem)
self.all_gems[each][start] = None
elif start >= 0:
gem.target_y += GRIDSIZE
gem.fixed = False
gem.direction = 'down'
self.all_gems[each][start+1] = gem
else:
gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+each*GRIDSIZE, YMARGIN-GRIDSIZE], downlen=GRIDSIZE)
self.gems_group.add(gem)
self.all_gems[each][start+1] = gem
start -= 1
elif res_match[0] == 2:
start = res_match[2]
while start > -4:
if start == res_match[2]:
for each in range(0, 3):
gem = self.getGemByPos(*[res_match[1], start+each])
self.gems_group.remove(gem)
self.all_gems[res_match[1]][start+each] = None
elif start >= 0:
gem = self.getGemByPos(*[res_match[1], start])
gem.target_y += GRIDSIZE * 3
gem.fixed = False
gem.direction = 'down'
self.all_gems[res_match[1]][start+3] = gem
else:
gem = Puzzle(img_path=random.choice(self.gem_imgs), size=(GRIDSIZE, GRIDSIZE), position=[XMARGIN+res_match[1]*GRIDSIZE, YMARGIN+start*GRIDSIZE], downlen=GRIDSIZE*3)
self.gems_group.add(gem)
self.all_gems[res_match[1]][start+3] = gem
start -= 1

之后反复执行这个过程,直至耗尽游戏时间,游戏结束。

最后,我们动态看一下游戏效果。

总结

本文我们使用 Python 实现了一个简单的消消乐游戏,有兴趣的可以对游戏做进一步扩展,比如增加关卡等。

用 Python 写个消消乐小游戏的更多相关文章

  1. 初学python写个自娱自乐的小游戏

    一.摘要 当编写完后的代码执行第一次后达到了目标的预期效果,内心有些许满足,但是当突发情况产生后,程序便不能正常运行,于是准备从简单的版本开始出发,综合考虑使用者的需求,和使用过程中会遇到的问题,一步 ...

  2. 用python写了一个猜年龄小游戏

    写一个猜年龄游戏: 需要实现用户登录的功能 初始用户登录信息为 {'hades': '13579','nick': '123','ruixing': 'a1','fanping': 'b2'} 登录时 ...

  3. python写的第一个简单小游戏-猜数字

    #Filename:game1.py guess=10 running=True while running: try: answer=int(raw_input('Guess what i thin ...

  4. 用Python写个开心消消乐小游戏

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 提到开心消消乐这款小游戏,相信大家都不陌生,其曾在 2015 年获得过玩家最喜爱的移动单机游戏奖,受 ...

  5. Python基础入门-实现猜数字小游戏

    今天呢,我们来通过前面学过的一些知识点来完成一个猜数字大小的游戏程序设计.那么呢,一般人写代码直接上来就干,没有分析,这样的做法是没有产出的,除非你是大牛,今天呢,我会把我学习编程的思路分享给大家,我 ...

  6. python 写一个生成大乐透号码的程序

    """ 写一个生成大乐透号码的程序 生成随机号码:大乐透分前区号码和后区号码, 前区号码是从01-35中无重复地取5个号码, 后区号码是从01-12中无重复地取2个号码, ...

  7. 一听就懂:用Python做一个超简单的小游戏

    写它会用到 while 循环random 模块if 语句输入输出函数

  8. 用python实现自动玩21点小游戏

    1. 背景 前段时间发现一个论坛上(https://npupt.com/blackjack.php)有21点小游戏. 这个21点小游戏的规则是每个人开局都会获得随机点数,如果觉得点数小,可以继续摸牌. ...

  9. python 基础(实例1——登陆小游戏)

    一个简单的登陆小游戏,输入用户名和密码,如果和user_passwd.txt中内容匹配,则打印“welcome to login...”,如果三次输入错误则将该用户列入黑名单,无法再用该用户名登陆. ...

随机推荐

  1. 数据可视化基础专题(九):Matplotlib 基础(一)坐标相关

    1.前言 图表要素如下图所示 # sphinx_gallery_thumbnail_number = 3 import matplotlib.pyplot as plt import numpy as ...

  2. 最大熵原理(The Maximum Entropy Principle)

    https://wanghuaishi.wordpress.com/2017/02/21/%E5%9B%BE%E8%A7%A3%E6%9C%80%E5%A4%A7%E7%86%B5%E5%8E%9F% ...

  3. 深度学习趣谈:什么是迁移学习?(附带Tensorflow代码实现)

    一.迁移学习的概念 什么是迁移学习呢?迁移学习可以由下面的这张图来表示: 这张图最左边表示了迁移学习也就是把已经训练好的模型和权重直接纳入到新的数据集当中进行训练,但是我们只改变之前模型的分类器(全连 ...

  4. 【软件安装】在 CentOS 7(Linux)上部署流媒体服务(Tengine、ffmpeg、Centos 7、nginx-http-flv-module、OBS)

    Centos7+Tengine+Nginx-http-flv-module+ffmpeg+OBS搭建流媒体服务器 一.需求和背景 视频直播是基于领先的内容接入.分发网络和大规模分布式实时转码技术打造的 ...

  5. MSF查找提权exp

    0x01:介绍 在拿到一个反弹shell后,下一步可以用metaspolit的内置模块Local Exploit SuggesterLocal-exploit-suggester的功能就如它的名字一样 ...

  6. Kubernetes的10个基本事实!你知道几个?k8s与Docker又有何不同?

    无论您是Kubernetes的新手还是只是想获得更多知识,这篇文章都会帮到您! Kubernetes是一个增长的趋势.近年来,K8s技术经历了从小型开源Google项目到Cloud Native Co ...

  7. UC 网盘:我又回来了

    普通用户不限速下载,免费 10GB 空间,支持离线下载 这个域名非常厉害,某里挑选域名果然是值得称赞的.直接使用手机号即可注册登录,默认赠送 10GB 空间.不过目前好像没看到有电脑客户端,电脑上下载 ...

  8. 高效C++:让自己习惯C++

    视C++为一个联邦语言 面向过程,面向对象,泛型编程,元编程,C++同时支持,强大而迷惑 C++语言可以分为如下4个部分: C,C语言相同 C with Class,包括封装.继承.多态... Tem ...

  9. 题解 洛谷 P3639 【[APIO2013]道路费用 】

    不难想到可以\(2^k\)去枚举\(k\)条新边的选择方案,然后加入原图中的边来使图连通,用当前方案的收益去更新答案,但是这样复杂度过不去. 可以先把\(k\)条新边都连上,然后再加入边权从小到大排序 ...

  10. phpMyAdmin历史漏洞复现

    简介 phpMyAdmin是一个非常受欢迎的基于web的MySQL数据库管理工具.它能够创建和删除数据库,创建/删除/修改表格,删除/编辑/新增字段,执行SQL脚本等 复现三个古老漏洞 phpMyAd ...