1. 初始化,画边框和格子
首先就是初始化一个tkinter的对象,建立画布,在这里将会使用一个矩阵来对边框进行区分,墙体和内部空间将会赋予不同的颜色
high_num = 20 # 纵向的格子数量
length_num = 12 # 横向的格子数量
size = 30 # 每个格子的size
margin = 2 # 边缘大小
bottom = high_num - 2 # 底部位置
score = 0 # 分数
A = np.full((high_num, length_num), 0) # 矩阵
# 初始化
def init():
global A
# 墙体赋值
for i in range(0, high_num):
A[i][0] = -1
A[i][length_num - 1] = -1
for i in range(0, length_num):
A[0][i] = -1
A[high_num - 1][i] = -1
# 画方块
for i in range(0, high_num):
for j in range(0, length_num):
if A[i][j] == 0:
canvas.create_rectangle(j * size + margin, i * size + margin, (j + 1) * size - margin,
(i + 1) * size - margin,
fill="grey")
elif A[i][j] == -1:
canvas.create_rectangle(j * size + margin, i * size + margin, (j + 1) * size - margin,
(i + 1) * size - margin,
fill="black")
2. 画坦克
第二步就是画坦克,初始化一个坦克的位置,设置不同的颜色
tank_location = [[bottom, 4], [bottom, 5], [bottom, 6], [bottom - 1, 5]]
# 画坦克
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="red")
3. 画方块
第三步是画方块,方块从内部空间的上面开始出现,且随机出现,在这里,首先是初始化一个空白的二维列表,接着定义一个函数get_random_list,这个函数可以返回一行的格子生成情况,有格子就是1,没有格子就是0,然后对这个二维列表进行操作,删除最后一行,并将返回的数据插入到第一行,就从存储上实现了对方块的存储。注意,这里在画方块的时候,对最后一行的方块不进行画画,因为最后一行是用来判断是否游戏结束的,而如果画在界面上的话,就会和坦克有重叠。
block_list = [[0] * (length_num - 2)] * (high_num - 3)
# 获取随机列表
def get_random_list(length, threshold):
random_list = [1 if random.randint(1, 10) >= threshold else 0 for i in range(0, length)]
return random_list
# 创建方块
def create_block():
global block_list
del block_list[len(block_list) - 1]
r = get_random_list(10, 6)
block_list.insert(0, r)
# 画方块
for i in range(0, len(block_list) - 1):
for j in range(0, len(block_list[0])):
num = block_list[i][j]
x = i + 1
y = j + 1
if num == 1:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="yellow")
elif num == 0:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
4. 动画化
接着就可以试一下动画效果了,调用tkinter的after功能,并对界面进行update,就可以查看方块的动画情况了
root.update()
canvas.after(1000, create_block)
5. 绑定键盘事件
对坦克进行移动和射击
移动为左右移动,绑定的是键盘的左右方向键
# 移动
def move(event):
global tank_location
if event.keysym == 'Left':
if tank_location[0][1] >= 1:
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
tank_location = [[i[0], i[1] - 1] for i in tank_location]
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="red")
if event.keysym == 'Right':
if tank_location[2][1] <= 10:
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
tank_location = [[i[0], i[1] + 1] for i in tank_location]
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="red")
root.update()
# 事件绑定
canvas.focus_set() # 聚焦
canvas.bind("<KeyPress-Left>", move)
canvas.bind("<KeyPress-Right>", move)
对于射击,这里绑定的是空格键,射击的时候,将会倒序遍历block_list,将对应列的为1的格子设置为0,并更改颜色,然后跳出循环,这样就实现了射击这个动作了
# 射击
def shoot(event):
global block_list, score
row = tank_location[1][1] - 1
for i in range(len(block_list) - 2, -1, -1):
if block_list[i][row] == 1:
block_list[i][row] = 0
score += 1
break
# 画方块
for i in range(0, len(block_list) - 1):
for j in range(0, len(block_list[0])):
num = block_list[i][j]
x = i + 1
y = j + 1
if num == 1:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="yellow")
elif num == 0:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
canvas.update()
canvas.bind("<space>", shoot)
6. 判断游戏结束
最后一步就是判断游戏是否结束了,如果说block_list的最后一行有不为0的值,就是表示方块已经到达坦克这一行了,游戏结束
# 判断游戏结束
def if_end():
if max(block_list[-1]) == 1:
return True
else:
return False
完整代码
from tkinter import *
from tkinter import messagebox
import numpy as np
import random
high_num = 20
length_num = 12
size = 30
margin = 2
bottom = high_num - 2
score = 0
A = np.full((high_num, length_num), 0) # 矩阵
tank_location = [[bottom, 4], [bottom, 5], [bottom, 6], [bottom - 1, 5]]
block_list = [[0] * (length_num - 2)] * (high_num - 3)
# 初始化
def init():
global A
# 墙体赋值
for i in range(0, high_num):
A[i][0] = -1
A[i][length_num - 1] = -1
for i in range(0, length_num):
A[0][i] = -1
A[high_num - 1][i] = -1
# 画方块
for i in range(0, high_num):
for j in range(0, length_num):
if A[i][j] == 0:
canvas.create_rectangle(j * size + margin, i * size + margin, (j + 1) * size - margin,
(i + 1) * size - margin,
fill="grey")
elif A[i][j] == -1:
canvas.create_rectangle(j * size + margin, i * size + margin, (j + 1) * size - margin,
(i + 1) * size - margin,
fill="black")
# 画坦克
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="red")
create_block()
# 获取随机列表
def get_random_list(length, threshold):
random_list = [1 if random.randint(1, 10) >= threshold else 0 for i in range(0, length)]
return random_list
# 判断游戏结束
def if_end():
if max(block_list[-1]) == 1:
return True
else:
return False
# 创建方块
def create_block():
global block_list
root.update()
if if_end():
messagebox.showinfo('游戏结束', '你的分数是:' + str(score))
return
del block_list[len(block_list) - 1]
r = get_random_list(10, 6)
block_list.insert(0, r)
# 画方块
for i in range(0, len(block_list) - 1):
for j in range(0, len(block_list[0])):
num = block_list[i][j]
x = i + 1
y = j + 1
if num == 1:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="yellow")
elif num == 0:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
canvas.after(1000, create_block)
# 射击
def shoot(event):
global block_list, score
row = tank_location[1][1] - 1
for i in range(len(block_list) - 2, -1, -1):
if block_list[i][row] == 1:
block_list[i][row] = 0
score += 1
break
# 画方块
for i in range(0, len(block_list) - 1):
for j in range(0, len(block_list[0])):
num = block_list[i][j]
x = i + 1
y = j + 1
if num == 1:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="yellow")
elif num == 0:
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
canvas.update()
# 移动
def move(event):
global tank_location
if event.keysym == 'Left':
if tank_location[0][1] >= 1:
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
tank_location = [[i[0], i[1] - 1] for i in tank_location]
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="red")
if event.keysym == 'Right':
if tank_location[2][1] <= 10:
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="grey")
tank_location = [[i[0], i[1] + 1] for i in tank_location]
for i in tank_location:
x = i[0]
y = i[1]
canvas.create_rectangle(y * size + margin, x * size + margin, (y + 1) * size - margin,
(x + 1) * size - margin, fill="red")
root.update()
if __name__ == '__main__':
root = Tk()
root.title("打方块")
canvas = Canvas(root, width=size * length_num, height=size * high_num, background='lightcyan')
canvas.pack()
# 事件绑定
canvas.focus_set() # 聚焦
canvas.bind("<KeyPress-Left>", move)
canvas.bind("<KeyPress-Right>", move)
canvas.bind("<space>", shoot)
init()
mainloop()