2048小游戏成品源码
2048小游戏,可以自选背景颜色,方框颜色,音乐播放。
还可以展示当前玩家的排名,动态排名,及历史玩家的排名。
前期需求:
使用pygame加载目录音乐。MP3文件:
def music_play():import pygame as py# 初始化py.mixer.init()# 文件加载py.mixer.music.load(r'.\test.mp3')# 播放 第一个是播放值 -1代表循环播放, 第二个参数代表开始播放的时间py.mixer.music.play(-1, 10)
看下运行后的效果图:
=========参数设置:
=========背景设置:
=========方块设置:
==========源码分享:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author : Codeooo
# @Time : 2022/04/13"""2048游戏本模块已完整实现2048游戏的算法及分数的计算算法
本游戏的界面采用python 标准库 tkinter 来实现
此界面的布局采用tkinter中的grid布局
"""import copy
import random # 导入随机模块random,主要用于随机生成新的数字及数字摆方位置
import math # 导入数学模块,用来计算分数# _map_data 绑定一个 4 x 4 列表,此列表为2048游戏地图,初始值如下:
from tkinter.colorchooser import askcolor_map_data = [[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 0, 0]
]score_list = [] # 分数列表# -------------------------以下为2048游戏的基本算法---------------------------def reset():'''重新设置游戏数据,将地图恢复为初始状态,并加入两个数据 2 作用初始状态'''_map_data[:] = [] # _map_data.clear()_map_data.append([0, 0, 0, 0])_map_data.append([0, 0, 0, 0])_map_data.append([0, 0, 0, 0])_map_data.append([0, 0, 0, 0])# 在空白地图上填充两个2fill2()fill2()def get_space_count():"""获取没有数字的方格的数量,如果数量为0则说有无法填充新数据,游戏即将结束"""count = 0for r in _map_data:count += r.count(0)return countdef get_score():'''获取游戏的分数,得分规则是每次有两个数加在一起则生成相应的分数。如 2 和 2 合并后得4分, 8 和 8 分并后得 16分.根据一个大于2的数字就可以知道他共合并了多少次,可以直接算出分数:如:4 一定由两个2合并,得4分8 一定由两个4合并,则计:8 + 4 + 4 得32分... 以此类推'''score = 0for r in _map_data:for c in r:score += 0 if c < 4 else c * int((math.log(c, 2) - 1.0))return score # 导入数学模块def fill2():'''填充2到空位置,如果填度成功返回True,如果已满,则返回False'''blank_count = get_space_count() # 得到地图上空白位置的个数if 0 == blank_count:return False# 生成随机位置, 如,当只有四个空时,则生成0~3的数,代表自左至右,自上而下的空位置pos = random.randrange(0, blank_count)offset = 0for row in _map_data: # row为行rowfor col in range(4): # col 为列,columnif 0 == row[col]:if offset == pos:# 把2填充到第row行,第col列的位置,返回Truerow[col] = 2return Trueoffset += 1def is_gameover():"""判断游戏是否结束,如果结束返回True,否是返回False"""for r in _map_data:# 如果水平方向还有0,则游戏没有结束if r.count(0):return False# 水平方向如果有两个相邻的元素相同,应当是可以合并的,则游戏没有结束for i in range(3):if r[i] == r[i + 1]:return Falsefor c in range(4):# 竖直方向如果有两个相邻的元素相同,应当可以合并的,则游戏没有结束for r in range(3):if _map_data[r][c] == _map_data[r + 1][c]:return False# 以上都没有,则游戏结束return True# 以下是2048游戏的基本算法,此算法是在达内的美女老师"贾琳倩"提供算法上改进而来
# 此种算法不是最优算法,但我认为这是目前最容易理解的算法def _left_move_number(line):'''左移一行数字,如果有数据移动则返回True,否则返回False:如: line = [0, 2, 0, 8] 即表达如下一行:+---+---+---+---+| 0 | 2 | 0 | 8 | <----向左移动+---+---+---+---+此行数据需要左移三次:第一次左移结果:+---+---+---+---+| 2 | 0 | 8 | 0 |+---+---+---+---+第二次左移结果:+---+---+---+---+| 2 | 8 | 0 | 0 |+---+---+---+---+第三次左移结果:+---+---+---+---+| 2 | 8 | 0 | 0 | # 因为最左则为2,所以8不动+---+---+---+---+最终结果: line = [4, 8, 0, 0]'''moveflag = False # 是否移动的标识,先假设没有移动for _ in range(3): # 重复执行下面算法三次for i in range(3): # i为索引if 0 == line[i]: # 此处有空位,右侧相邻数字向左侧移动,右侧填空白moveflag = Trueline[i] = line[i + 1]line[i + 1] = 0return moveflagdef _left_marge_number(line):'''向左侧进行相同单元格合并,合并结果放在左侧,右侧补零如: line = [2, 2, 4, 4] 即表达如下一行:+---+---+---+---+| 2 | 2 | 4 | 4 |+---+---+---+---+全并后的结果为:+---+---+---+---+| 4 | 0 | 8 | 0 |+---+---+---+---+最终结果: line = [4, 8, 8, 0]'''moveflag = Falsefor i in range(3):if line[i] == line[i + 1]:moveflag = Trueline[i] *= 2 # 左侧翻倍line[i + 1] = 0 # 右侧归零return moveflagdef _left_move_aline(line):'''左移一行数据,如果有数据移动则返回True,否则返回False:如: line = [2, 0, 2, 8] 即表达如下一行:+---+---+---+---+| 2 | | 2 | 8 | <----向左移动+---+---+---+---+左移算法分为三步:1. 将所有数字向左移动来填补左侧空格,即:+---+---+---+---+| 2 | 2 | 8 | |+---+---+---+---+2. 判断是否发生碰幢,如果两个相临且相等的数值则说明有碰撞需要合并,合并结果靠左,右则填充空格 +---+---+---+---+| 4 | | 8 | |+---+---+---+---+3. 再重复第一步,将所有数字向左移动来填补左侧空格,即:+---+---+---+---+| 4 | 8 | | |+---+---+---+---+最终结果: line = [4, 8, 0, 0]'''moveflag = Falseif _left_move_number(line):moveflag = Trueif _left_marge_number(line):moveflag = Trueif _left_move_number(line):moveflag = Truereturn moveflagdef left():"""游戏左键按下时或向左滑动屏幕时的算法"""moveflag = False # moveflag 是否成功移动数字标志位,如果有移动则为真值,原地图不变则为假值# 将第一行都向左移动.如果有移动就返回Truefor line in _map_data:if _left_move_aline(line):moveflag = Truereturn moveflagdef right():"""游戏右键按下时或向右滑动屏幕时的算法选将屏幕进行左右对调,对调后,原来的向右滑动即为现在的向左滑动滑动完毕后,再次左右对调回来"""# 左右对调for r in _map_data:r.reverse()moveflag = left() # 向左滑动# 再次左右对调for r in _map_data:r.reverse()return moveflagdef up():"""游戏上键按下时或向上滑动屏幕时的算法先把每一列都自上而下放入一个列表中line中,然后执行向滑动,滑动完成后再将新位置摆回到原来的一列中"""moveflag = Falseline = [0, 0, 0, 0] # 先初始化一行,准备放入数据for col in range(4): # 先取出每一列# 把一列中的每一行数入放入到line中for row in range(4):line[row] = _map_data[row][col]# 将当前列进行上移,即line 左移if (_left_move_aline(line)):moveflag = True# 把左移后的 line中的数据填充回原来的一列for row in range(4):_map_data[row][col] = line[row]return moveflagdef down():"""游戏下键按下时或向下滑动屏幕时的算法选将屏幕进行上下对调,对调后,原来的向下滑动即为现在的向上滑动滑动完毕后,再次上下对调回来"""_map_data.reverse()moveflag = up() # 上滑_map_data.reverse()return moveflagdef music_play():import pygame as py# 初始化py.mixer.init()# 文件加载py.mixer.music.load(r'.\test.mp3')# 播放 第一个是播放值 -1代表循环播放, 第二个参数代表开始播放的时间py.mixer.music.play(-1, 10)# -------------------------以下为2048游戏的操作界面---------------------------from tkinter import *
from tkinter import messageboxdef set_score(score):score_list.append(score)def record_score(score):_grade_list = copy.copy(score_list)_grade_list.append(score)grade_list = list(set(_grade_list))grade_list.sort(reverse=True)for i in range(len(grade_list)):# 对比取出数据与待查找数据if grade_list[i] == score:# 查找成功,返回当前下标值return i + 1# 查找完所有数据,仍未找到# 查找失败,返回非法下标值return -1def on_key_down(event):'键盘按下处理函数'keysym = event.keysymif keysym in keymap:if keymap[keysym](): # 如果有数字移动fill2() # 填充一个新的2update_ui()if is_gameover():set_score(get_score())mb = messagebox.askyesno(title="gameOver", message="游戏结束!\n是否退出游戏!")if mb:root.quit()else:reset()update_ui()def update_ui():'''刷新界面函数根据计算出的f地图数据,更新各个Label的设置'''for r in range(4):for c in range(len(_map_data[0])):number = _map_data[r][c] # 设置数字label = map_labels[r][c] # 选中Lable控件label['text'] = str(number) if number else ''label['bg'] = mapcolor[number][0]label['foreground'] = mapcolor[number][1]label_score['text'] = str(get_score()) # 重设置分数label_ranking['text'] = str(record_score(get_score())) # 重设置排名# 以下排名按钮
def history_game():history_list = list(set(score_list))history_list.sort(reverse=True)message_data = ""for i in range(len(history_list)):message_data += f"第{i + 1}名:分数为{history_list[i]}\n"if not message_data:message_data = "暂无排名"messagebox.showwarning(title='历史排名', message=message_data)# 以下设置重新开始按钮
def reset_game():set_score(get_score())reset()update_ui()label_ranking['text'] = '0' # 重设置排名if __name__ == '__main__':# 初始化音乐music_play()reset() # 先重新设置游戏数据root = Tk() # 创建tkinter窗口root.title('2048-by@Codeooo') # 设置标题文字screen_width = root.winfo_screenwidth() # 获得屏幕宽度screen_height = root.winfo_screenheight() # 获得屏幕高度root.geometry('%dx%d+%d+%d' % (440, 490, (screen_width - 440) / 2, (screen_height - 490) / 2))root.resizable(width=False, height=False) # 固定宽和高game_bg_color = "#bbada0" # 背景色# 设置游戏中每个数据对应色块的颜色mapcolor = {0: ("#cdc1b4", "#776e65"),2: ("#eee4da", "#776e65"),4: ("#ede0c8", "#f9f6f2"),8: ("#f2b179", "#f9f6f2"),16: ("#f59563", "#f9f6f2"),32: ("#f67c5f", "#f9f6f2"),64: ("#f65e3b", "#f9f6f2"),128: ("#edcf72", "#f9f6f2"),256: ("#edcc61", "#f9f6f2"),512: ("#e4c02a", "#f9f6f2"),1024: ("#e2ba13", "#f9f6f2"),2048: ("#ecc400", "#f9f6f2"),4096: ("#ae84a8", "#f9f6f2"),8192: ("#b06ca8", "#f9f6f2"),# ----其它颜色都与8192相同---------2 ** 14: ("#b06ca8", "#f9f6f2"),2 ** 15: ("#b06ca8", "#f9f6f2"),2 ** 16: ("#b06ca8", "#f9f6f2"),2 ** 17: ("#b06ca8", "#f9f6f2"),2 ** 18: ("#b06ca8", "#f9f6f2"),2 ** 19: ("#b06ca8", "#f9f6f2"),2 ** 20: ("#b06ca8", "#f9f6f2"),}isParams = messagebox.askyesno(title="设置参数", message="是否进行设置游戏参数")if isParams:# 设置背景颜色def chooseColor(detail_color, title):color = askcolor(color=detail_color, title=title)return color[1]game_bg_color = chooseColor("#bbada0", '选择背景色')if not game_bg_color:game_bg_color = "#bbada0"block_color = chooseColor("#cdc1b4", '选择方块色')if not block_color:block_color = "#cdc1b4"mapcolor[0] = (block_color, block_color)else:messagebox.showwarning(title='start', message="开始游戏")# 以下是键盘映射keymap = {'a': left,'d': right,'w': up,'s': down,'Left': left,'Right': right,'Up': up,'Down': down,}frame = Frame(root, bg=game_bg_color)frame.grid(sticky=N + E + W + S)# 设置焦点能接收按键事件frame.focus_set()frame.bind("<Key>", on_key_down)# 初始化图形界面# 创建4x4的数字块map_labels = [] # 游戏各方块的lable Widgetfor r in range(4):row = []for c in range(len(_map_data[0])):value = _map_data[r][c]text = str(value) if value else ''label = Label(frame, text=text, width=4, height=2,font=("黑体", 30, "bold"))label.grid(row=r, column=c, padx=5, pady=5, sticky=N + E + W + S)row.append(label)map_labels.append(row)# 设置显示分数的Lablelabel = Label(frame, text='分数', font=("黑体", 30, "bold"),bg="#bbada0", fg="#eee4da")label.grid(row=4, column=0, padx=5, pady=5)label_score = Label(frame, text='0', font=("黑体", 30, "bold"),bg="#bbada0", fg="#ffffff")label_score.grid(row=4, columnspan=1, column=1, padx=5, pady=5)ranking = Label(frame, text='排名', font=("黑体", 30, "bold"),bg="#bbada0", fg="#eee4da")ranking.grid(row=4, column=2, padx=5, pady=5)label_ranking = Label(frame, text='0', font=("黑体", 30, "bold"),bg="#bbada0", fg="#ffffff")label_ranking.grid(row=4, columnspan=3, column=3, padx=5, pady=5)history_button = Button(frame, text='排名记录', font=("黑体", 16, "bold"),bg="#8f7a66", fg="#f9f6f2", command=history_game)history_button.grid(row=5, column=0, padx=5, pady=5)restart_button = Button(frame, text='重新开始', font=("黑体", 16, "bold"),bg="#8f7a66", fg="#f9f6f2", command=reset_game)restart_button.grid(row=5, column=3, padx=5, pady=5)update_ui() # 更新界面label_ranking['text'] = '0' # 重设置排名root.mainloop() # 进入tkinter主事件循环
2048小游戏成品源码相关推荐
- java实现2048小游戏(源码+注释)
实现文件 APP.java import javax.swing.*;public class APP {public static void main(String[] args) {new MyF ...
- 星益小游戏平台源码 内置80多个在线小游戏
简介: 星益小游戏平台源码是一款星益在线小游戏可的网站源码,本程序由小星合集整理制作,共计80个小游戏. 内置了80个在线小游戏,直接就能玩耍,上传到空间用! 本程序大部分都是自适应,但是使用电脑端体 ...
- python小游戏-16行代码实现3D撞球小游戏!-源码下载
python小游戏-16行代码实现3D撞球小游戏!-源码下载 所属网站分类: 资源下载 > python小游戏 作者:搞笑 链接: http://www.pythonheidong.com/bl ...
- 微信网页小游戏网站源码带后台+可后台添加游戏+推荐到微信
微信网页小游戏网站源码带后台,淘宝上卖的很火的源码,免费公开!
- 遥控汽车网页小游戏html源码
这是一个网页小游戏源代码 你可以开着小汽车在整个地图中旅行 可撞墙.可鸣笛.自己发现吧 无聊时可以用它打消下无聊的时间 首页注释挺详细的,可自行修改 运行不成功注意文件引用的路径 路径 路径 快来下载 ...
- flash高科技php网站源码下载,Flash小游戏PHP源码
项目包里有两种版本, 第一种是:UTF-8 PHP版本 第二种是:UTF-8 伪静态版本(如果空间支持,强烈建议使用此版本,对搜索引擎友好) 开源项目:flash游戏源码,小游戏PHP源码,休闲fla ...
- java 猫 游戏,crazycat 围住神经猫-小游戏-Java源码 联合开发网 - pudn.com
crazycat 所属分类:Java编程 开发工具:Java 文件大小:1373KB 下载次数:1 上传日期:2019-01-19 21:03:14 上 传 者:lynnhl 说明: 围住神经猫-小 ...
- 2023 俄罗斯方块网页小游戏HTML源码
手机和电脑自适应都可以玩,试玩了一下源码没问题,也没有加密,想试玩的可以下载源码搭建耍耍 2023 俄罗斯方块网页小游戏HTML源码
- html实现扫雷小游戏(附源码)
文章目录 实现功能 1.扫雷设计 1.1 主界面 1.2 扫雷难度 1.3 附带功能 2.效果和源码 2.1 动态效果 2.2 源代码 源码下载 作者:xcLeigh 文章地址:https://blo ...
- Java五子棋小游戏(源码及效果图)
巩固Java基础时写的小Demo,源码如下: package javagobang;import java.io.BufferedReader; import java.io.InputStreamR ...
最新文章
- 删除同域名所有cookies_淘宝自动登录2.0,新增Cookies序列化
- Extending_and_embedding_php翻译
- matplotlib 中文_详解Matplotlib中文字符显示问题
- unity实现图片轮播效果_Unity3D实现列表拖拽轮播分页滚动功能
- 支付宝芝麻分多少算正常?分高有什么好处?
- 你不是编程挺厉害的吗?这都做不出来 | 硕士写给自己:努力应该适可而止
- python的基础_毫无基础的人如何入门 Python ?
- 广数系统加工中心编程_数控铣和加工中心编程
- 互联网晚报 | 12月10日 星期五 | B站月均活跃UP主达270万人;宝马电动车总销量破百万;苹果市值逼近3万亿美元...
- linux mysql 挂马_解决数据库被挂马最快方法
- Effective+Java+中文版
- Pycharm下载与安装教程
- 利用opencv-python 进行图像的不规则裁剪
- 算法设计——基姆拉尔森计算公式:计算几月几号是星期几
- 移动端1px边框实现
- MOS管寄生电容是如何形成的?
- 哔哩哔哩查看视频av号
- RDSDRDSPolarDBPolarDB-X的区别
- 2022年全球市场国内和国际物流服务总体规模、主要企业、主要地区、产品和应用细分研究报告
- 谈谈我2013上半年在公司内部培训的经历
热门文章
- 【Visual Assist X】VAssistX的安装和使用
- 计算机机房需求调查表,机房建设需求调查表.doc
- Batch Normalization(BN层)详解
- 国内首款性能最稳定ISO 14443B身份证读卡器芯片FSV9523国产替代MFRC523 国产NFC芯片 不缺货 性价比高 可提供软硬件DEMO
- vue2.0 海报生成器、二维码生成器
- 远程控制安卓手机教程
- 威纶触摸屏和台达b2伺服通讯,含程序案例资料
- zec挖矿(zcash挖矿)鱼池跟蚂蚁矿池的比较到底哪个好?哪个收益高? (二)
- dbf转成excel_DBF文件转换成excel工具(DbfToExcel)
- python数据导出excel_Python方法将DBF文件导出到Excel代码示例