1、2048游戏设计与实现课题名称:2048游戏开发与测试院系:电气学院专业:电气工程及其自动化班级:电气48小组成员:赵红阳 朱正昊 陶站平一 、 摘 要在 生 活 节 奏 不 断 加 快 的 现 代 社 会 , 轻 松 的 益 智 游 戏 对 缓 解 生 活 压力 , 调 节 情 绪 具 有 重 要 的 意 义 。 2048 是 比 较 流 行 的 一 款 数 字 游 戏 。原 版 2048 首 先 在 GitHub 上 发 布 , 原 作 者 是 Gabriele Cirulli, 是 基 于 1024 和 小 3 传 奇 的 玩 法 开 发 而 成 的 新 型 数 字 游 戏 。 而 游
2、戏 设计 初 衷 是 一 款 益 智 类 的 游 戏 , 其 特 点 在 于 轻 松 , 简 单 , 因 此 , 开 发 要求 做 到 各 项 功 能 要 完 备 、 操 作 要 简 便 、 易 学 易 用 。本 文 采 用 c#语 言 开 发 了 2048 小 游 戏 , 通 过 windows 控 制 台 应 用程 序 实 现 了 2048 的 基 本 运 行 , 而 后 进 过 图 形 界 面 的 处 理 , 以 不 同 的数 字 西 安 市 不 同 的 颜 色 , 并 拥 有 了 成 绩 记 录 , 成 绩 截 图 的 各 项 功 能 。本 着 简 单 , 易 于 操 作 的 原 则
3、和 缓 解 生 活 压 力 、 降 低 生 活 节 奏 的 初 衷 ,本 小 组 在 游 戏 界 面 中 添 加 了 帮 助 菜 单 和 各 类 提 示 , 让 游 戏 的 用 户 界 面更 加 人 性 化 。二 、 关 键 词2048 c# 休 闲 小 游 戏一 、 游 戏 开 发 环 境 . 41 开 发 工 具 .42 应 用 环 境 .6二 、 游 戏 需 求 分 析 . 61. 需 求 分 析 62. 可 行 性 分 析 6三 、 程 序 概 要 设 计 . 7四 、 程 序 详 细 设 计 . 81. 游 戏 主 界 面 82. 游 戏 结 束 界 面 183. 新 纪 录 界 面
4、 194. 主 要 功 能 代 码 22五 、 游 戏 测 试 . 321 测 试 的 意 义 .322 测 试 过 程 . 323 测 试 内 容 .334 测 试 结 果 .33一 、 游 戏 开 发 环 境1 开 发 工 具C#(读 做 “C sharp“)暂 时 没 有 中 文 译 名 , 专 业 人 士 一 般 读 “Csharp“, 现 在 很 多 非 专 业 一 般 读 “C井 “。C#是 一 种 安 全 的 、 稳 定 的 、 简 单 的 、 优 雅 的 , 由 C 和 C+衍 生 出来 的 面 向 对 象 的 编 程 语 言 。 它 在 继 承 C和 C+强 大 功 能 的
5、同 时 去 掉 了一 些 它 们 的 复 杂 特 性 ( 例 如 没 有 宏 和 模 版 , 不 允 许 多 重 继 承 ) 。 C#综合 了 VB 简 单 的 可 视 化 操 作 和 C+的 高 运 行 效 率 , 以 其 强 大 的 操 作 能力 、 优 雅 的 语 法 风 格 、 创 新 的 语 言 特 性 和 便 捷 的 面 向 组 件 编 程 的 支 持成 为 .NET 开 发 的 首 选 语 言 。并 且 C#成 为 ECMA与 ISO标 准 规 范 。 C#看 似 基 于 C+写 成 , 但 又 融入 其 它 语 言 如 Pascal、 Java、 VB等 。Microsoft在
6、 正 式 的 场 合 把 C#描 述 为 一 种 简 单 、 现 代 、 面 向 对 象 、类 型 非 常 安 全 、 派 生 于 C和 C+的 编 程 语 言 。 大 多 数 独 立 的 评 论 员 对其 说 法 是 “ 派 生 于 C、 C+和 Java” 。 这 种 描 述 在 技 术 上 是 非 常 准 确 的 ,但 没 有 涉 及 到 该 语 言 的 真 正 优 点 。 从 语 法 上 看 , C#非 常 类 似 于 C 和Java, 许 多 关 键 字 都 是 相 同 的 , C#也 使 用 类 似 于 C 和 C+的 块 结 构 ,并 用 括 号 ()来 标 识 代 码 块 ,
7、用 分 号 分 隔 各 行 语 句 。 对 C#代 码 的 第一 印 象 是 它 非 常 类 似 于 C 和 Java 代 码 。 但 在 这 些 表 面 上 的 类 似 性 后面 , C#学 习 起 来 要 比 C+容 易 得 多 , 但 比 Java 难 一 些 。 其 设 计 与 现代 开 发 工 具 的 适 应 性 要 比 其 他 语 言 更 高 , 它 同 时 具 有 Visual Basic的 易 用 性 、 高 性 能 以 及 C+的 低 级 内 存 访 问 性 。 #包 括 以 下 一 些 特 性 : 完 全 支 持 类 和 面 向 对 象 编 程 , 包 括 接 口 和 继
8、承 、 虚 函 数 和 运 算符 重 载 的 处 理 。 定 义 完 整 、 一 致 的 基 本 类 型 集 。 对 自 动 生 成 XML 文 档 说 明 的 内 存 。 自 动 清 理 动 态 分 配 的 内 存 。 可 以 用 用 户 定 义 的 特 性 来 标 记 类 或 方 法 对 .NET基 类 库 的 完 全 访 问 权 , 并 易 于 访 问 Windows API。 可 以 使 用 指 针 和 直 接 内 存 访 问 , 但 C#语 言 可 以 在 没 有 它 们 的条 件 下 访 问 内 存 。 以 VB的 风 格 支 持 属 性 和 事 件 。 改 变 编 译 器 选 项
9、 , 可 以 把 程 序 编 译 为 可 执 行 文 件 或 .NET 组 件库 , 该 组 件 库 可 以 用 与 ActiveX控 件 (COM组 件 )相 同 的 方 式 由其 他 代 码 调 用 。 C#可 以 用 于 编 写 ASP.NET动 态 Web页 面 和 XML Web 服 务 。2 应 用 环 境操 作 系 统 : Windows 7/8/8.1应 用 软 件 : Microsoft Visual Studio 2012/2013二 、 游 戏 需 求 分 析1. 需 求 分 析现 代 社 会 对 休 闲 小 游 戏 的 需 求 是 : 提 高 游 戏 的 操 作 可 行
10、 性 , 降 低游 戏 的 操 作 难 度 , 降 低 游 戏 的 上 手 难 度 , 降 低 游 戏 的 竞 争 需 求 , 对 使用 设 备 的 要 求 趋 于 简 单 化 和 多 样 化 , 游 戏 界 面 更 加 人 性 化 , 功 能 更 加贴 合 使 用 。2. 可 行 性 分 析1 技 术 可 行 性根 据 游 戏 设 计 的 要 求 , 可 以 通 过 c#进 行 源 代 码 的 编 辑 , 通 过windows 界 面 进 行 用 户 界 面 的 编 辑 和 优 化 , 结 合 时 间 和 目 前 学 习 水 平等 各 项 因 素 , 项 目 所 要 求 功 能 和 性 能
11、完 全 可 以 实 现 。2 运 行 可 行 性游 戏 基 本 要 求 是 .net framework4.0 及 以 上 , 在 大 部 分 的 用 户 设 备上 可 以 实 现 , 并 且 游 戏 运 行 对 硬 件 几 乎 无 要 求 , 项 目 运 行 可 以 得 到 保证 。3 可 行 性 综 合 分 析综 合 以 上 两 点 , 项 目 开 发 可 以 得 到 技 术 和 运 行 的 保 证 , 证 明 项 目可 行 。三 、 程 序 概 要 设 计 游 戏 启 动检 测 是 否 为 第 一 次 启 动 打 开 帮 助 对 话 框启 动 游 戏 界 面键盘控制方块移动 游戏运行 打
12、开帮助 各项功能实现 退出游戏各 功 能 键 EscF1游戏结束 重 启 退 出四 、 程 序 详 细 设 计1. 游 戏 主 界 面截 图 如 下 :其 功 能 代 码 如 下 :usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Runtime.Serialization;usingSy
13、stem.Runtime.Serialization.Formatters.Binary;usingSystem.IO;namespace_2048publicpartialclassForm1:FormpublicForm1()InitializeComponent();Class1c;_2048messageBoxmes=new_2048messageBox();Bitmapbit=newBitmap(400,400);privatevoidForm1_Load(objectsender,EventArgse)if(File.Exists(“D:2048记 录“)/监 测 是 否 有 存
14、档ToLoad();else/如 果 没 有 存 档 , 生 成 新 的 游 戏 。_2048messageBoxmes1=new_2048messageBox();mes1.a=“提 示“;mes1.b=“检 测 到 您 是 第 一 次 打 开 , 可 按F1打 开 帮 助 。rn游 戏 为 无限 模 式 , 直 到GameOver才 会 终 止 。“;mes1.StartPosition=FormStartPosition.CenterScreen;mes1.ShowDialog();c=newClass1();c.Reset();mes.a=“提 示“;/生 成 帮 助 菜 单mes.b
15、=“F2:窗 口 总 在 最 前rnF3:解 锁/锁 定 窗 口rnF4:隐 藏 任 务 栏 图 标rnF5:重 新 开 始rnF6:截 图 并 保 存rnShife+: 调 整 透 明 度rn: 控 制 方 块 移 动rnESC:退出“;drow();Num_pictureBox.Refresh();/窗 口 加 载 前 的 操 作privatevoidForm1_KeyDown(objectsender,KeyEventArgse)switch(e.KeyCode)caseKeys.Up:if(e.Modifiers=Keys.Shift)this.Opacity-=0.1;elsec.U
16、p();if(c.change)c.Add();break;caseKeys.Down:if(e.Modifiers=Keys.Shift)this.Opacity+=0.1;elsec.Down();if(c.change)c.Add();break;caseKeys.Left:c.Left();if(c.change)c.Add();break;caseKeys.Right:c.Right();if(c.change)c.Add();break;caseKeys.F1:mes.ShowDialog();break;caseKeys.F2:this.TopMost=!this.TopMost
17、;break;caseKeys.F3:if(this.FormBorderStyle=FormBorderStyle.FixedToolWindow)this.FormBorderStyle=FormBorderStyle.None;elsethis.FormBorderStyle=FormBorderStyle.FixedToolWindow;break;caseKeys.F4:this.ShowInTaskbar=!this.ShowInTaskbar;break;caseKeys.F5:c=newClass1();c.Reset();Num_pictureBox.Refresh();br
18、eak;caseKeys.F6:_2048Screen();_2048messageBoxmes2=new_2048messageBox();mes2.a=“保 存 成 功“;mes2.b=“保 存 在“+Directory.GetCurrentDirectory()+“成 绩 截图.bmp“;mes2.ShowDialog();break;caseKeys.Escape:this.Close();break;drow();Num_pictureBox.Refresh();grade.Text=c.grade.ToString();if(c.die)gameOver();/捕 捉 键 盘 按
19、下 的 键 , 做 出 相 应 操 作privatevoiddisplay(intm,Pointdian)Graphicsgra=Graphics.FromImage(bit);switch(m)case0:gra.FillRectangle(newSolidBrush(Color.BurlyWood),dian.X,dian.Y,90,90);break;case2:gra.FillRectangle(newSolidBrush(Color.LightSalmon),dian.X,dian.Y,90,90);break;case4:gra.FillRectangle(newSolidBrus
20、h(Color.Peru),dian.X,dian.Y,90,90);break;case8:gra.FillRectangle(newSolidBrush(Color.Chocolate),dian.X,dian.Y,90,90);break;case16:gra.FillRectangle(newSolidBrush(Color.Gray),dian.X,dian.Y,90,90);break;case32:gra.FillRectangle(newSolidBrush(Color.DarkSeaGreen),dian.X,dian.Y,90,90);break;case64:gra.Fi
21、llRectangle(newSolidBrush(Color.Gold),dian.X,dian.Y,90,90);break;case128:gra.FillRectangle(newSolidBrush(Color.HotPink),dian.X,dian.Y,90,90);break;case256:gra.FillRectangle(newSolidBrush(Color.DarkOrange),dian.X,dian.Y,90,90);break;case512:gra.FillRectangle(newSolidBrush(Color.LightPink),dian.X,dian
22、.Y,90,90);break;case1024:gra.FillRectangle(newSolidBrush(Color.DarkRed),dian.X,dian.Y,90,90);break;case2048:gra.FillRectangle(newSolidBrush(Color.Red),dian.X,dian.Y,90,90);break;switch(m)case2:case4:case8:gra.DrawString(m.ToString(),newFont(“黑 体“,40.5f,FontStyle.Bold),newSolidBrush(Color.White),dian
23、.X+22,dian.Y+17);break;case16:case32:case64:gra.DrawString(m.ToString(),newFont(“黑 体“,40.5f,FontStyle.Bold),newSolidBrush(Color.White),dian.X+8,dian.Y+17);break;case128:case256:case512:gra.DrawString(m.ToString(),newFont(“黑 体“,35.5f,FontStyle.Bold),newSolidBrush(Color.White),dian.X+0,dian.Y+20);brea
24、k;case1024:case2048:case4096:case8192:gra.DrawString(m.ToString(),newFont(“黑 体“,30.5f,FontStyle.Bold),newSolidBrush(Color.White),dian.X-4,dian.Y+23);break;/画 出 一 个 方 块 和 方 块 上 的 数 字privatevoiddrow()for(intx=1;xbestGrade)bestGrade=grade;/记 录 最 好 成 绩grade=0;/成 绩 归 零Add();Add();/为 新 游 戏 增 加 两 个 方 块publ
25、icvoidAdd()/增 加 新 方 块intx=ra.Next(1,5);inty=ra.Next(1,5);/随 机 选 定 位 置if(ix,y=0)if(ra.Next(1,101)=90)ix,y=4;/有10%的 几 率 刷 新 出 方 块4elseix,y=2;/有90%的 几 率 刷 新 出 方 块2quantity+;/增 加 一 个 新 方 块 后 计 数 器 加1Die();/判 断 游 戏 是 否 已 经 死 局elseAdd();/如 果 随 机 选 定 的 位 置 不 能 添 加 新的 放 开 , 则 重 新 调 用 该 方 法#region上 下 左 右非 零
26、元 素 处 理 上 下 左 右 处 理 时 采 用 了 先 处 理0元 素 , 再 处 理 非0元素 的 方 法publicvoidDown()change=false;down();/处 理 零 方 块 , 其 他 方 法 同for(intx=1;x=4;x+)if(ix,4=ix,3ix,3=ix,2*2;ix,2=0;ix,1=0;grade+=ix,4+ix,3;elseix,4*=2;ix,3=ix,2;ix,2=ix,1;ix,1=0;grade+=ix,4;change=true;elseif(ix,3=ix,2ix,2=ix,1;ix,1=0;change=true;grade
27、+=ix,3;elseif(ix,2=ix,1ix,1=0;change=true;grade+=ix,2;GetQuantity();publicvoidUp()change=false;up();for(intx=1;x=4;x+)if(ix,1=ix,2ix,2=ix,3*2;ix,3=0;ix,4=0;grade+=ix,1+ix,2;elseix,1*=2;ix,2=ix,3;ix,3=ix,4;ix,4=0;grade+=ix,1;change=true;elseif(ix,2=ix,3ix,3=ix,4;ix,4=0;change=true;grade+=ix,2;elseif(
28、ix,3=ix,4ix,4=0;change=true;grade+=ix,3;GetQuantity();publicvoidLeft()change=false;left();for(inty=1;y=4;y+)if(i1,y=i2,yi2,y=i3,y;i3,y=0;i4,y=0;grade+=i1,y+i2,y;elsei1,y*=2;i2,y=i3,y;i3,y=i4,y;i4,y=0;grade+=i1,y;change=true;elseif(i2,y=i3,yi3,y=i4,y;i4,y=0;change=true;grade+=i2,y;elseif(i3,y=i4,yi4,
29、y=0;change=true;grade+=i3,y;GetQuantity();publicvoidRight()change=false;right();for(inty=1;y=4;y+)if(i4,y=i3,yi3,y=i2,y;i2,y=0;i1,y=0;grade+=i4,y+i3,y;elsei4,y*=2;i3,y=i2,y;i2,y=i1,y;i1,y=0;grade+=i4,y;change=true;elseif(i3,y=i2,yi2,y=i1,y;i1,y=0;change=true;grade+=i3,y;elseif(i2,y=i1,yi1,y=0;change
30、=true;grade+=i2,y;GetQuantity();privatevoiddown()/先 将 方 块 移 到 同 一 边,其 他 方 法 同for(intx=1;x=4;x+)if(ix,4=0ix,3=ix,2;ix,2=ix,1;ix,1=0;change=true;down();elseif(ix,3=0ix,2=ix,1;ix,1=0;change=true;down();elseif(ix,2=0ix,1=0;change=true;privatevoidup()for(intx=1;x=4;x+)if(ix,1=0ix,2=ix,3;ix,3=ix,4;ix,4=0;
31、change=true;up();elseif(ix,2=0ix,3=ix,4;ix,4=0;change=true;up();elseif(ix,3=0ix,4=0;change=true;privatevoidleft()for(inty=1;y=4;y+)if(i1,y=0i2,y=i3,y;i3,y=i4,y;i4,y=0;change=true;left();elseif(i2,y=0i3,y=i4,y;i4,y=0;change=true;left();elseif(i3,y=0i4,y=0;change=true;privatevoidright()for(inty=1;y=4;
32、y+)if(i4,y=0i3,y=i2,y;i2,y=i1,y;i1,y=0;change=true;right();elseif(i3,y=0i2,y=i1,y;i1,y=0;change=true;right();elseif(i2,y=0i1,y=0;change=true;#endregionprivatevoidGetQuantity()/获 得 当 前 游 戏 中 的 方 块 数 目intcount=0;/初 始 化 计 数 器for(intx=1;x=4;x+)for(inty=1;y=4;y+)if(ix,y!=0)count+;/逐 块 检 索 , 每 检 索 到 一 个 方
33、 块 计数 器 加1quantity=count;/记 录 当 前 方 块 数 目privatevoidDie()/判 断 当 前 是 否 死 局intcount=0;/初 始 化 计 数 器if(quantity=16)/若 游 戏 中 方 块 数 达 到16个 , 则开 始 判 断 是 否 死 局for(intx=1;x=3;x+=2)for(inty=1;y=3;y+=2)if(!GetEqual(x,y)count+;for(intx=2;x=4;x+=2)for(inty=2;y=4;y+=2)if(!GetEqual(x,y)count+;/选 取 了 所 有 方 块 中 互 不 相 邻 的 八块 , 判 断 是 否 可 加if(count=8)die=true;/若 计 数 器 达 到8, 则 说 明 所 有 临近 方 块 均 不 可 加 , 游 戏 死 局privateboolGetEqual(intx,inty)/判 断 方 块 是 否 与 周 围 方 块 相 等( 是 否 可 加 )if(ix,y=ix-1,y)returntrue;elseif(ix,y=ix+1,y)