【Python小游戏】使用tkinter制作打方块小游戏

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()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moyuweiqing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值