【游戏制作】使用Python创建一个完整的2048游戏项目

news2024/11/24 21:00:45

 

目录

项目运行展示

项目概述

项目目标

项目结构

安装依赖

代码实现

1. 导入库

2. 创建 Game2048 类

 3. 设置UI界面

 4. 加载二维码图片

5. 创建菜单 

6. 游戏逻辑和功能 

 7. 运行应用

总结


创建一个完整的2048游戏项目

项目运行展示

项目概述

在这个项目中,我们将创建一个2048游戏的桌面应用程序。这个游戏是一个流行的数学游戏,玩家通过合并相同的数字块来达到2048。我们将使用 ttkbootstrap 库为应用程序添加现代化的外观,并且通过 tkinterPIL 实现游戏的功能和界面。

项目目标
  • 实现2048游戏的逻辑和UI
  • 添加历史记录功能
  • 实现主题和窗口大小的动态修改
  • 加载和显示二维码图片
  • 添加游戏开始和结束的逻辑
项目结构
  1. 主程序文件: game2048.py — 包含游戏逻辑和界面实现。
  2. 资源文件: 1.gif — 二维码图片资源。
安装依赖

确保你已经安装了以下Python库:

  • tkinter (Python的标准库,通常默认安装)
  • ttkbootstrap (用于增强tkinter的UI)
  • Pillow (用于处理图像)

可以通过以下命令安装缺失的依赖:

pip install ttkbootstrap pillow
代码实现
1. 导入库
import tkinter as tk
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import Menu, Toplevel, messagebox, simpledialog
import random
import datetime
from PIL import Image, ImageTk
2. 创建 Game2048
class Game2048(ttk.Window):
    def __init__(self):
        super().__init__(title="2048 Game", themename="superhero")
        self.grid()
        self.cells = [[None for _ in range(4)] for _ in range(4)]
        self.history = []
        self.setup_ui()
        self.create_menu()
        self.start_game()
 3. 设置UI界面
    def setup_ui(self):
        self.title("2048 Game")
        self.geometry("800x600")
        self.resizable(False, False)

        self.main_grid = ttk.Frame(self, style='secondary.TFrame')
        self.main_grid.grid(row=0, column=0, padx=(10, 10), pady=(10, 10))

        for i in range(4):
            row = []
            for j in range(4):
                cell_frame = ttk.Frame(self.main_grid, width=100, height=100, style='primary.TFrame')
                cell_frame.grid(row=i, column=j, padx=5, pady=5)
                cell_number = ttk.Label(self.main_grid, text="", style='primary.Inverse.TLabel', font=("Helvetica", 24, "bold"))
                cell_number.grid(row=i, column=j)
                cell_data = {"frame": cell_frame, "number": cell_number}
                row.append(cell_data)
            self.cells[i] = row

        self.score_label = ttk.Label(self, text="Score: 0", style='info.TLabel', font=("Helvetica", 16))
        self.score_label.grid(row=1, column=0, columnspan=4, pady=(0, 10))

        # 加载二维码图片
        self.load_qr_code()

        self.bind_keys()
 4. 加载二维码图片
    def load_qr_code(self):
        image = Image.open("1.gif")  # 替换为你的二维码图片路径
        image = image.resize((150, 150), Image.ANTIALIAS)
        self.qr_code_image = ImageTk.PhotoImage(image)

        self.qr_code_label = ttk.Label(self, image=self.qr_code_image)
        self.qr_code_label.grid(row=0, column=1, padx=(10, 10), pady=(10, 10))

        self.qr_code_text = ttk.Label(self, text="B站优秀稳妥的小光", style='info.TLabel', font=("Helvetica", 16))
        self.qr_code_text.grid(row=0, column=1, pady=(170, 10))
5. 创建菜单 
    def create_menu(self):
        menubar = Menu(self)

        # 历史记录菜单
        history_menu = Menu(menubar, tearoff=0)
        history_menu.add_command(label="查看历史分数", command=self.show_history)
        menubar.add_cascade(label="历史记录", menu=history_menu)

        # 查看菜单
        view_menu = Menu(menubar, tearoff=0)
        view_menu.add_command(label="查看日期", command=self.show_date)
        view_menu.add_command(label="查看开发者", command=self.show_developer)
        menubar.add_cascade(label="查看", menu=view_menu)

        # 修改菜单
        edit_menu = Menu(menubar, tearoff=0)

        # 修改主题子菜单
        theme_menu = Menu(edit_menu, tearoff=0)
        style = ttk.Style()
        theme_names = style.theme_names()
        for theme_name in theme_names:
            theme_menu.add_command(label=theme_name, command=lambda t=theme_name: self.change_theme(t))
        edit_menu.add_cascade(label="修改主题", menu=theme_menu)

        # 修改窗口大小功能
        edit_menu.add_command(label="修改窗口大小", command=self.change_window_size)
        menubar.add_cascade(label="修改", menu=edit_menu)

        self.config(menu=menubar)
6. 游戏逻辑和功能 
    def start_game(self):
        self.matrix = [[0] * 4 for _ in range(4)]
        self.score = 0
        self.add_new_tile()
        self.add_new_tile()
        self.update_ui()

    def add_new_tile(self):
        empty_cells = [(i, j) for i in range(4) for j in range(4) if self.matrix[i][j] == 0]
        if empty_cells:
            i, j = random.choice(empty_cells)
            self.matrix[i][j] = 2 if random.random() < 0.9 else 4

    def update_ui(self):
        for i in range(4):
            for j in range(4):
                cell_value = self.matrix[i][j]
                if cell_value == 0:
                    self.cells[i][j]["frame"].configure(style='primary.TFrame')
                    self.cells[i][j]["number"].configure(text="")
                else:
                    self.cells[i][j]["frame"].configure(style=f'TFrame')
                    self.cells[i][j]["number"].configure(text=str(cell_value), font=("Helvetica", 24, "bold"))
        self.score_label.configure(text=f"Score: {self.score}")
        self.update_idletasks()

    def move_up(self, event):
        self.move_tiles(0, -1)
        self.merge_tiles(0, -1)
        self.move_tiles(0, -1)
        self.add_new_tile()
        self.update_ui()
        self.check_game_over()

    def move_down(self, event):
        self.move_tiles(0, 1)
        self.merge_tiles(0, 1)
        self.move_tiles(0, 1)
        self.add_new_tile()
        self.update_ui()
        self.check_game_over()

    def move_left(self, event):
        self.move_tiles(-1, 0)
        self.merge_tiles(-1, 0)
        self.move_tiles(-1, 0)
        self.add_new_tile()
        self.update_ui()
        self.check_game_over()

    def move_right(self, event):
        self.move_tiles(1, 0)
        self.merge_tiles(1, 0)
        self.move_tiles(1, 0)
        self.add_new_tile()
        self.update_ui()
        self.check_game_over()

    def move_tiles(self, x, y):
        def move(x, y, i, j):
            if self.matrix[i][j] != 0:
                ni, nj = i + x, j + y
                while 0 <= ni < 4 and 0 <= nj < 4 and self.matrix[ni][nj] == 0:
                    self.matrix[ni][nj] = self.matrix[i][j]
                    self.matrix[i][j] = 0
                    i, j = ni, nj
                    ni, nj = i + x, j + y

        for i in range(4):
            for j in range(4):
                if x == -1:
                    move(x, y, i, j)
                if x == 1:
                    move(x, y, 3 - i, j)
                if y == -1:
                    move(x, y, j, i)
                if y == 1:
                    move(x, y, j, 3 - i)

    def merge_tiles(self, x, y):
        def merge(x, y, i, j):
            ni, nj = i + x, j + y
            if 0 <= ni < 4 and 0 <= nj < 4 and self.matrix[i][j] == self.matrix[ni][nj] and self.matrix[i][j] != 0:
                self.matrix[ni][nj] *= 2
                self.matrix[i][j] = 0
                self.score += self.matrix[ni][nj]

        for i in range(4):
            for j in range(4):
                if x == -1:
                    merge(x, y, i, j)
                if x == 1:
                    merge(x, y, 3 - i, j)
                if y == -1:
                    merge(x, y, j, i)
                if y == 1:
                    merge(x, y, j, 3 - i)

    def show_history(self):
        history_window = Toplevel(self)
        history_window.title("历史分数")
        history_window.geometry("320x420")

        history_text = tk.Text(history_window, wrap="word")
        history_text.pack(expand=1, fill="both")

        for record in self.history:
            history_text.insert("end", record + "\n")

    def show_date(self):
        current_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        messagebox.showinfo("当前日期和时间", current_date)

    def show_developer(self):
        messagebox.showinfo("开发者信息", "开发者: B站 优秀稳妥的小光")

    def check_game_over(self):
        if not any(0 in row for row in self.matrix) and not self.can_merge():
            self.history.append(f"Score: {self.score}")
            messagebox.showinfo("Game Over", f"Game Over! Your Score: {self.score}")
            self.start_game()

    def can_merge(self):
        for i in range(4):
            for j in range(4):
                if j < 3 and self.matrix[i][j] == self.matrix[i][j + 1]:
                    return True
                if i < 3 and self.matrix[i][j] == self.matrix[i + 1][j]:
                    return True
        return False
 7. 运行应用
if __name__ == "__main__":
    app = Game2048()
    app.mainloop()
总结

这个2048游戏项目展示了如何使用 tkinterttkbootstrap 创建一个具有现代化外观的桌面游戏应用程序。我们实现了基本的游戏逻辑、动态更新UI、以及附加的功能如历史记录、二维码显示和主题切换。通过这个项目,你可以深入了解如何使用Python创建复杂的图形用户界面,并且扩展到更多的功能和设计。

 交流扩列在主页加WX 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1952995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常用sql:删除表中重复的数据

在平常的开发工作中&#xff0c;我们可能经常需要对表进行操作。比如某些数据重复了&#xff0c;那么可能需要删除掉重复的数据&#xff0c;保证数据根据业务字段属性相同的数据只有一条&#xff0c;那么应该如何做呢&#xff1f; 1&#xff1a;新建表&#xff1a;用户详情表 …

for循环计算1~100之间3的倍数的数字之和

你要计算1~100之间的数字先得打印出来1~100之间的数字然后在判断是不是3的倍数然后在打印出数字&#xff0c;代码如下 #include<stdio.h> int main() {int i 0;for (i 1; i < 100; i){if (i % 3 0){printf("%d ", i);}}return 0; }

Intellij IDEA多模块分组 实现move to group

新版本idea&#xff0c;没有了move to group的功能&#xff0c;导致模块很多的时候不能分组。2018版本有。 这个分组是虚拟的&#xff0c;不会在磁盘中实际存在。 要实现这个功能&#xff0c;只需要改modules.xml即可。 步骤 1. 找到配置文件 .idea目录下的moudules.xml 2.…

GeoServer GIS 服务器(geoServer离线地图服务器搭建)

文章目录 引言I GeoServer 安装部署版本选择基于war包进行部署II geoServer配置2.1 geoServer新建工作区2.2 geoServer 新建数据源2.3 geoServer图层发布和图层编辑2.4 指定存储层的坐标系2.5 geoServer图层样式2.6 图层组的创建GIS基础知识GeoServerWMTSEPSGEPSG3857相关的数据…

Cadence学习笔记(十三)--设置边框与异形铺铜

直接导入板框用小眼睛可以看到所有的都是线的属性&#xff1a; 那么如何让它变成板框呢&#xff1f;这里先跳转到下图中的层&#xff1a; 将Z--CPOY这一层变成shape区&#xff1a; 之后用Z--copy: Z--COPY设置如下参数&#xff0c;铺铜内缩20mil: 之后选择长方形铺铜就可以了&…

快醒醒,别睡了!...讲《数据分析pandas库》了—/—<5>

一、 1、修改替换变量值 本质上是如何直接指定单元格的问题&#xff0c;只要能准确定位单元地址&#xff0c;就能够做到准确替换。 1.1 对应数值的替换 具体用法如下&#xff1a; replace方法&#xff1a; df.replace(to_replace None :将被替换的原数值&#xff0c;所有…

matlab6.5免安装版,解压即可用【亲测win10可用】

这个版本是咱第一次学matlab的时候用的处女版&#xff0c;如今看着这个界面依然恍如昨日。为甚要分享这种老掉牙古董matlab版本呢&#xff1f;原因在于一款老古董工具箱 —— geatbx。 这款工具箱采用了古老pcode的加密系统加密&#xff0c;而matlab的pcode加密经过几次迭代&a…

数据库开发:MySQL基础(二)

MySQL基础&#xff08;二&#xff09; 一、表的关联关系 在关系型数据库中&#xff0c;表之间可以通过关联关系进行连接和查询。关联关系是指两个或多个表之间的关系&#xff0c;通过共享相同的列或键来建立连接。常见的关联关系有三种类型&#xff1a;一对多关系&#xff0c;…

【机器学习】智驭未来:机器学习如何重塑制造业的转型与升级

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#x1f4d2;2. 机器学习重塑制造业生产流程&#x1f338;预测性维护&#xff1a;减少停机时间&#xff0c;提高设…

JavaScript(17)——事件监听

什么是事件&#xff1f; 事件是在编程时系统内发生的动作或发生的事情&#xff0c;比如用户在网页上单击一个按钮 什么是事件监听&#xff1f; 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立刻调用一个函数做出响应&#xff0c;也称为绑定事件或…

【Linux】进程IO|系统调用|open|write|文件描述符fd|封装|理解一切皆文件

目录 ​编辑 前言 系统调用 open 参数flags 参数mode write 追加方式 read close 文件描述符 打开多个文件并观察其文件描述符 C语言文件操作 理解一切皆文件 理解open操作 前言 各类语言的文件操作其实是对系统调用的封装 我们经常说&#xff0c;创建一个文件&a…

【 C++ 】 一文搞定——引用、内联、命名空间、缺省、重载

前言&#xff1a;这篇文章将带您了解C基础中的知识点——命名空间、引用、内联、缺省、重载 &#x1f618;我的主页&#xff1a;OMGmyhair-CSDN博客 一、命名空间namespace 1.可以嵌套定义&#xff0c;但是只能定义在全局 namespace ly {int student 1;int age 21;void Pr…

剑和沙盒 6 - 线程辱骂 – 使用线程名称进行攻击

强调&#xff1a; 进程注入是攻击者工具包中的重要技术之一。在下面的文章中 解释了如何滥用线程描述 API 来绕过端点保护产品。提出了一种新的注入技术&#xff1a;Thread Name-Calling&#xff0c;并给出了实施保护的相关建议。 介绍 进程注入是攻击者使用的重要技术之一 。…

Go-知识panic

Go-知识panic 1. 介绍2. 工作机制2.1 panic函数2.2 工作流程2.3 总结 3. 原理3.1 数据结构3.2 gopanic没有deferdefer函数处理嵌套defer 4. 总结 Go-知识error :https://blog.csdn.net/a18792721831/article/details/140430350 Go-知识defer : https://blog.csdn.net/a18792721…

单片机基于TXW8301的Wi-Fi Halow物联网控制

目前市面上基于2.4/5.8G wifi通讯信号干扰很频繁&#xff0c;基于Wi-Fi Halow的sub1g wifi既可以绕过干扰还可以达到公里级别控制&#xff0c;并且实现高清图传非常方便。 什么是Wi-Fi Halow&#xff1f;有何优势&#xff1f; 早在2016年3月&#xff0c;Wi-Fi联盟就针对物联网…

YOLO v8目标检测(二)—v8理论与模型推理

YOLO v8目标检测 数据增强 使用场景&#xff1a;在数据加载器加载数据的过程中会使用到数据增强的相关方法&#xff0c;来构造数据集。模型推理方法进行学习之前首先复习了解图像数据增强的相关方法和步骤。 其中在v8的源代码中 augment.py 的源代码文件。它包含了几个用于数据…

【python】python基于 Q-learning 算法的迷宫游戏(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

java项目数据库 mysql 迁移到 达梦

目录 一、下载安装达梦数据库 1、下载 2、解压 3、安装 二、迁移 三、更改SpringBoot 的 yml文件 1、达梦创建用户 2、修改yml 一、下载安装达梦数据库 1、下载 下载地址 https://eco.dameng.com/download/ 点击下载 开发版 (X86平台) , 然后选择操作系统并点击立…

重装win10系统,“我们无法创建新的分区 也找不到现有的分区”“我们无法更新系统保留的分区”

重装系统&#xff0c;最开始用这篇教程保留数据的重装系统教程&#xff01;&#xff08;win10系统&#xff09;_win10重装系统保留c盘数据-CSDN博客里win10官方的更新方法。想保留C盘以外的数据来重装系统 然后就会提示“我们无法更新系统保留的分区” 查到网上说这是因为MSR分…

python基础巩固

基本数据类型 可以用isinstance来判断 a111 isinstance(a,int) True数值运算&#xff1a; >>> 2 / 4 # 除法&#xff0c;得到一个浮点数 0.5 >>> 2 // 4 # 除法&#xff0c;得到一个整数 0 >>> 17 % 3 # 取余 2Python 字符串不能被改变。向一个…