摘要
Python 是一种跨平台的、开源的、免费的、解释型的高级编程语言。它具有丰富的、强大的库,能够把其他语言制作的各种模块很轻松地联结在一起,所以Python 常被称为“胶水”语言。Python 语言近几年发展势头迅猛,应用领域也非常广泛,在Web 编程、图形处理、黑客编程、大数据处理、网络爬虫、科学计算和游戏编程等领域都能找到Python 的应用。Python 语言的研究和发明主要是为了便于学习和应用,因此Python 语言是开源的,并且语法非常简单、容易编写和理解。本文通过对2048小游戏的设计与分析,掌握Python 语言在游戏开发领域的优势。
1 引言
当今社会是一个信息社会,一个知识经济的年代。自从世界上第一台计算机ENIAC于1946年问世到现在,计算机业飞速发展。随着以全球信息网络普及和全球信息共享为标志的“全球信息网络革命”的蓬勃兴起,世界已然进入在计算机信息管理领域的激烈竞争的时代,计算机,自然而然的变成了人们生活中必不可少的一部分。
过去,人们只要是借助电影,电视,音乐等方式来娱乐。而今天,以游戏为代表的电子娱乐正成为主流娱乐方式。因为CPU以及显卡等设备的高速发展,为人们开发出更加炫目多彩的游戏提供了可能。时代的发展,社会的进步,科学技术正以日新月异的速度飞速的向前发展。计算机技术的发展更是迅速而且广泛。可以说,计算机已经涉及到现代绝大部分行业。目前纷繁复杂的游戏软件比比皆是,无论在线的网路游戏还是桌面游戏,二维的还是三维立体空间的,多由单机版游戏孕育而来。学习简单的单机版游戏的制作,有利于初学者了解到游戏制作的理念。目前不论是在国内还是世界范围内,游戏产业都如雨后的春笋,蓬勃发展,越来越多更具娱乐性的游戏产品被开发出来。
为此,本文提出了基于Python语言开发的2048小游戏开发。根据游戏的运行流程及游戏元素的嵌入,将开发分为7个模块:创建游戏窗口及背景、数字块的创建、数字块的移动、游戏达成的提示、游戏失败的提示、游戏的重新开始、游戏分值的显示。
2 2048小游戏开发总体方案设计
2.1 游戏开发资源
目前互联网发展迅速,随之发展了各种强大的编程语言和实时电子游戏研发模块,比如Turtle模块,Turtle库是Python内置的图形化模块,属于标准库之一。由于Python的开源性和语言的流行,使得Python语言日趋成熟,在游戏的编程中提供强大的资源结构。按照游戏工业市场的飞机游戏开发需求,分析游戏的基本功能,在此基础上增加游戏的各类功能模块完善游戏。本设计所用到的编程语言是Python,版本是Python3.8,开发工具为Pycharm,根据现有资源,调用Turtle包,对游戏进行开发、运行及测试。游戏程序编辑、编译、调试、发布所有过程都是基于PC机平台运行。
2.2 游戏开发总体方案
游戏规则很简单,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出“2048”这个数字方块。
游戏实现的功能如下:创建游戏窗口及背景、数字块的随机出现、数字块的移动、游戏成功失败提醒、游戏的重新开始、游戏分值的显示。软件程序为本设计的最核心的部分,每一个代码块都构成了设计的整体,因此,先由每个小功能入手,分别实现该设计的程序功能,然后封装,调用,在程序的主体中调用封装好的代码块,从而运行整个程序的整体。软件开发结构如图1所示,程序上为面向对象编程,大体上可分成数字块类,窗口显示类、游戏类3大类,再在主程序中继承实例化以及嵌套。

图1 2048小游戏开发结构图
3 2048小游戏程序详细设计
3.1 程序主函数
程序main函数主要进行定义和继承的相关操作,实现成员函数的定义和成员属性的定义,继承相关函数并添加相关的游戏特性。游戏运行整体流程图如图2所示。游戏运行中判断优先级别,层层嵌套功能模块,检测各项功能和监听游戏的相关事件,譬如监听玩家键盘输入和历史最高分数读取等等,最后运行整体程序。

3.2 游戏窗口创建功能模块
在游戏窗口实例中,分成两个部分,一个是游戏标题、当前分数、和最大分数,另一个是16个方块。游戏标题、当前分数、最大分数通过计算其各个位置的中心坐标再进行进行背景图的填充。16分方块在设计时需要确定每个方格的中心坐标,再定义一个列表allpos来存储每个16个方块的坐标,再通过循环把每个16个方块的坐标进行填充。
3.3 数字块的随机出现
在游戏刚开始或有游戏方块移动是,都会在空闲的方格中出现2或4数字方块。主要原理是在初始化16个方块时先把每个方块的默认值设置为0,在创建一个block_list列表,判断值为0的加入block_list列表中,再从中随机挑选一个元素,把值设置为2或4。
3.4 数字块的移动
通过监听键盘的上下左右键调用相关数字块移动函数。对相同数字块碰撞进行相加。
3.5 游戏成功失败提醒
游戏成功失败提醒主要是judge方法通过判断数字方块是否还有位置可移动来判断游戏是否失败,当全局变量score达到2048也回提醒玩家游戏成功。
3.6 游戏分值的显示
游戏分值主要是当相同数字块碰撞时,全局变量score会进行增加,并将score在窗口进行回写,当score大于最大分数时,会将score写入score.txt文件。
4 实现代码
4.1 主程序
主程序主要时创建主窗口,注册游戏所需相关图片,allpos列表是设置16个小方块的中心坐标,读取score.txt文件中最高分数的数值,进行游戏的初始化,对键盘上下左右键进行监听,调用相关函数。
1. if __name__ == '__main__':
2. ms = turtle.Screen()
3. ms.setup(430, 630)
4. ms.bgcolor('gray')
5. ms.title('2048')
6. ms.tracer(0)
7. ms.register_shape('bg.gif')
8. ms.register_shape('title.gif')
9. ms.register_shape('score.gif')
10. ms.register_shape('top_score.gif')
11. block_dic = {}
12. allpos = [(-150, 50), (-50, 50), (50, 50), (150, 50),
13. (-150, -50), (-50, -50), (50, -50), (150, -50),
14. (-150, -150), (-50, -150), (50, -150), (150, -150),
15. (-150, -250), (-50, -250), (50, -250), (150, -250)]
16. flag_win = True
17. flag_win_lose_text = True
18. score = 0
19. with open('.\\score.txt', 'r') as f:
20. top_score = int(f.read())
21. show_score_text = BackGround()
22. win_lose_text = BackGround()
23. game = Game()
24. game.init()
25. game.grow()
26.
27. ms.listen()
28. ms.onkey(game.move_up, 'Up')
29. ms.onkey(game.move_down, 'Down')
30. ms.onkey(game.move_left, 'Left')
31. ms.onkey(game.move_right, 'Right')
32. ms.onkey(win_lose_text.win_lose_clear, 'Return')
33. ms.onkey(game.restart, 'space')
34. ms.mainloop()
4.2 BackGround类
BackGround主要绘制游戏窗口框架和游戏成功失败提示,draw_block方法主要是对16个方块进行背景填充,窗口分割线的绘画,标题图、当前分数、最高分数图片填充。judge方法是游戏失败成功的判断。win_lose_clear方法是当玩家玩到2048分或游戏失败,按提示操作后清楚提示文字。show_score显示当前分数,如果当前分数大于最大分数则写入score.txt文件。
1. class BackGround(turtle.Turtle): # 定义一个类,用来画除了数字方块之外的图形
2. def __init__(self):
3. super().__init__()
4. self.penup()
5. self.ht()
6.
7. def draw_block(self):
8. self.shape('bg.gif') # 画出背景方块
9. for i in allpos:
10. self.goto(i)
11. self.stamp()
12. self.color('white', 'white') # 画出其他背景
13. self.goto(-215, 120)
14. self.begin_fill()
15. self.goto(215, 120)
16. self.goto(215, 110)
17. self.goto(-215, 110)
18. self.end_fill()
19. self.shape('title.gif')
20. self.goto(-125, 210)
21. self.stamp()
22. self.shape('score.gif')
23. self.goto(125, 245)
24. self.stamp()
25. self.shape('top_score.gif')
26. self.goto(125, 170)
27. self.stamp()
28.
29. def judge(self): # 游戏失败及达成2048的提示文字
30. global flag_win, flag_win_lose_text
31. self.color('blue')
32. judge = 0 # 判断是否还有位置可以移动
33. for i in block_dic.values():
34. for j in block_dic.values():
35. if i.num == 0 or i.num == j.num and i.distance(j) == 100:
36. judge += 1
37. if judge == 0: # 无位置可移动,游戏失败
38. self.write(' GAME OVER\n重新开始请按空格键', align='center', font=('黑体', 30, 'bold'))
39. flag_win_lose_text = False
40. if flag_win is True: # 此条件让2048达成的判断只能进行一次
41. for k in block_dic.values():
42. if k.num == 2048: # 游戏达成
43. flag_win = False
44. self.write(' 达成2048\n继续游戏请按回车键', align='center', font=('黑体', 30, 'bold'))
45. flag_win_lose_text = False
46.
47. def win_lose_clear(self): # 游戏失败及达成2048提示文字clear
48. global flag_win_lose_text
49. self.clear()
50. flag_win_lose_text = True
51.
52. def show_score(self): # 分值的显示
53. global score, top_score
54. if score > top_score:
55. top_score = score
56. with open('.\\score.txt', 'w') as f:
57. f.write(f'{top_score}')
58. self.color('white')
59. self.goto(125, 210)
60. self.clear()
61. self.write(f'{score}', align='center', font=('Arial', 20, 'bold'))
62. self.goto(125, 135)
63. self.write(f'{top_score}', align='center', font=('Arial', 20, 'bold'))
4.3 Block类
Block在初始化时,将每个方块的值设置为0。draw方法是为方块进行值的绘画,dic_draw字典为每个不同数字设置不同的背景颜色。
1. class Block(turtle.Turtle): # 数字方块类
2. def __init__(self):
3. super().__init__()
4. self.ht()
5. self.penup()
6. self.num = 0
7.
8. def draw(self):
9. self.clear()
10. dic_draw = {2: '#eee6db', 4: '#efe0cd', 8: '#f5af7b',
11. 16: '#fb9660', 32: '#f57d5a', 64: '#f95c3d',
12. 128: '#eccc75', 256: '#eece61', 512: '#efc853',
13. 1024: '#ebc53c', 2048: '#eec430', 4096: '#aeb879',
14. 8192: '#aab767', 16384: '#a6b74f'}
15. if self.num > 0: # 数字大于0,画出方块
16. self.color(f'{dic_draw[self.num]}') # 选择颜色
17. self.begin_fill()
18. self.goto(self.xcor()+48, self.ycor()+48)
19. self.goto(self.xcor()-96, self.ycor())
20. self.goto(self.xcor(), self.ycor()-96)
21. self.goto(self.xcor()+96, self.ycor())
22. self.goto(self.xcor(), self.ycor()+96)
23. self.end_fill()
24. self.goto(self.xcor()-48, self.ycor()-68)
25. if self.num > 4: # 按照数字选择数字的颜色
26. self.color('white')
27. else:
28. self.color('#6d6058')
29. self.write(f'{self.num}', align='center', font=('Arial', 27, 'bold'))
30. self.goto(self.xcor(), self.ycor()+20)
4.4 Game类
Game类主要是对游戏进行初始化、方块的随机出现、方块的移动、游戏重新开始。init方法就是对游戏进行初始化操作,如背景图的填充和16个方块的初始化。restart方法是游戏重新开始,把游戏恢复到初始状态。grow从数值为0的方块中挑选一个方块设置为2或4。move_up、move_down、move_left、move_rigth方法为玩家每次按上下左右调用的方法,move_up、move_down按列把16个方块切成4列,move_left、move_rigth按行把16放开切成4行。Move方法主要时对方块操作后数字的回写,list_oper为正在对数字放开的操作。
1. class Game():
2. def init(self):
3. back = BackGround() # 实例画出游戏的背景
4. back.draw_block()
5. for i in allpos: # 画出16个海龟对应16个数字块
6. block = Block()
7. block.goto(i)
8. block_dic[i] = block
9.
10. def restart(self): # 重开游戏的方法
11. global score, flag_win_lose_text
12. score = 0
13. for i in block_dic.values():
14. i.num = 0
15. i.clear()
16. win_lose_text.clear()
17. game.grow()
18. flag_win_lose_text = True # 此flag为游戏达成或失败出现提示语后的判断,要提示语clear后才能继续move
19.
20. def grow(self): # 随机出现一个2或4的数字块
21. block_list = []
22. for i in allpos:
23. if block_dic[i].num == 0:
24. block_list.append(block_dic[i]) # 挑出空白方块的海龟
25. turtle_choice = random.choice(block_list) # 随机选中其中一个海龟
26. turtle_choice.num = random.choice([2, 2, 2, 2, 2, 4]) # 赋属性num=2/4
27. turtle_choice.draw()
28. win_lose_text.judge()
29. show_score_text.show_score()
30. ms.update()
31.
32. def move_up(self):
33. allpos1 = allpos[::4] # 切片为四列
34. allpos2 = allpos[1::4]
35. allpos3 = allpos[2::4]
36. allpos4 = allpos[3::4]
37. self.move_move(allpos1, allpos2, allpos3, allpos4)
38.
39. def move_down(self):
40. allpos1 = allpos[-4::-4]
41. allpos2 = allpos[-3::-4]
42. allpos3 = allpos[-2::-4]
43. allpos4 = allpos[-1::-4]
44. self.move_move(allpos1, allpos2, allpos3, allpos4)
45.
46. def move_left(self):
47. allpos1 = allpos[:4]
48. allpos2 = allpos[4:8]
49. allpos3 = allpos[8:12]
50. allpos4 = allpos[12:16]
51. self.move_move(allpos1, allpos2, allpos3, allpos4)
52.
53. def move_right(self):
54. allpos1 = allpos[-1:-5:-1]
55. allpos2 = allpos[-5:-9:-1]
56. allpos3 = allpos[-9:-13:-1]
57. allpos4 = allpos[-13:-17:-1]
58. self.move_move(allpos1, allpos2, allpos3, allpos4)
59.
60. def move_move(self, allpos1, allpos2, allpos3, allpos4):
61. if flag_win_lose_text is True:
62. count1 = self.move(allpos1) # 四列或四行依次移动
63. count2 = self.move(allpos2)
64. count3 = self.move(allpos3)
65. count4 = self.move(allpos4)
66. if count1 or count2 or count3 or count4: # 判断是否有方块移动,有才能继续出现新的数字块
67. self.grow()
68.
69. def move(self, pos_list):
70. num_list = [] # 为某一列或行的数字块海龟的坐标
71. for i in pos_list:
72. num_list.append(block_dic[i].num) # 把这些海龟的NUM形成list
73. new_num_list, count = self.list_oper(num_list) # 只是list_oper的方法形成新的list
74. for j in range(len(new_num_list)): # 把新的list依次赋值给对应的海龟.num属性并调用draw()方法
75. block_dic[pos_list[j]].num = new_num_list[j]
76. block_dic[pos_list[j]].draw()
77. return count
78.
79. def list_oper(self, num_list): # num_list的操作,假设其为【2,0,2,2】
80. global score
81. count = True
82. temp = []
83. new_temp = []
84. for j in num_list:
85. if j != 0:
86. temp.append(j) # temp=[2,2,2]
87. flag = True
88. for k in range(len(temp)):
89. if flag:
90. if k < len(temp)-1 and temp[k] == temp[k+1]:
91. new_temp.append(temp[k]*2)
92. flag = False
93. score += temp[k]
94. else:
95. new_temp.append(temp[k]) # new_temp=[4,2]
96. else:
97. flag = True
98. for m in range(len(num_list)-len(new_temp)):
99. new_temp.append(0) # new_temp=[4,2,0,0]
100. if new_temp == num_list:
101. count = False # 此变量判断num_list没有变化,数字块无移动
102. return(new_temp, count)
5 总结和展望
本文围绕面向对象的编程思想,基于Python开发2048小游戏,包括创建游戏窗口及背景、数字块的随机出现、数字块的移动、游戏成功失败提醒、游戏的重新开始、游戏分值的显示,并且利用继承的技巧优化了代码。模块以对象划分,有界面模块、数字块模块、游戏模块; 难点在于数字块的移动,判断相同数字块发生碰撞的算法设计。整个软件按照预期目标大致实现了2048小游戏。整个游戏还存在一些不足。比如,如何在多人联网下进行游戏分值排行傍,及时分享自己的战绩等,都需要进一步研究。
参考文献:
[1]耿颖. 使用Python 语言的GUI 可视化编程设计 [J]. 单片机与嵌入式系统应用
[2]黑马程序员. Python 快速编程入门[M]. 北京: 人民邮电出版社, 2018.
[3]刘长龙.python高效开发实战[M] .北京:电子工业出版社,2019.
1046

被折叠的 条评论
为什么被折叠?



