Python实现一笔画游戏
关于一笔画介绍可参见“HTML5实现一笔画游戏”https://blog.csdn.net/cnds123/article/details/136669088
在Python中,Tkinter是一个广泛使用的标准GUI库,我们将使用它来实现这个游戏。
先给出效果图:
连接线段时,必须按照一定的顺序来连接点。
两点间连线方法:从一个点按下鼠标左键拖动到释放。
源码如下:
import tkinter as tk
from math import sqrt
# 游戏关卡设置
levels = {
"easy": {
"points": [
{"id": 1, "x": 50, "y": 50},
{"id": 2, "x": 150, "y": 50},
{"id": 3, "x": 150, "y": 150},
{"id": 4, "x": 50, "y": 150}
],
"lines": [
{"start": 1, "end": 2},
{"start": 2, "end": 3},
{"start": 3, "end": 4},
{"start": 4, "end": 1},
{"start": 2, "end": 4}
]
},
"medium": {
"points": [
{"id": 1, "x": 50, "y": 100},
{"id": 2, "x": 150, "y": 100},
{"id": 3, "x": 250, "y": 100},
{"id": 4, "x": 100, "y": 200},
{"id": 5, "x": 200, "y": 200}
],
"lines": [
{"start": 1, "end": 2},
{"start": 2, "end": 3},
{"start": 1, "end": 4},
{"start": 2, "end": 5},
{"start": 3, "end": 5},
{"start": 4, "end": 5}
]
},
"hard": {
"points": [
{"id": 1, "x": 50, "y": 50},
{"id": 2, "x": 150, "y": 50},
{"id": 3, "x": 250, "y": 50},
{"id": 4, "x": 50, "y": 150},
{"id": 5, "x": 150, "y": 150},
{"id": 6, "x": 250, "y": 150},
{"id": 7, "x": 50, "y": 250},
{"id": 8, "x": 150, "y": 250},
{"id": 9, "x": 250, "y": 250}
],
"lines": [
{"start": 1, "end": 2},
{"start": 2, "end": 3},
{"start": 1, "end": 4},
#{"start": 2, "end": 5},
{"start": 3, "end": 6},
{"start": 4, "end": 5},
#{"start": 5, "end": 6},
{"start": 4, "end": 7},
{"start": 5, "end": 8},
{"start": 6, "end": 9},
{"start": 7, "end": 8},
{"start": 8, "end": 9}
]
}
}
class OneStrokeGame:
def __init__(self, master):
self.master = master
self.canvas = tk.Canvas(master, width=300, height=300, bg="white")
self.canvas.pack()
self.start_point = None
self.last_point_id = None
self.user_lines = []
# 添加难度选择按钮
self.easy_button = tk.Button(master, text="简单", command=lambda: self.start_game("easy"))
self.easy_button.pack(side="left")
self.medium_button = tk.Button(master, text="中等", command=lambda: self.start_game("medium"))
self.medium_button.pack(side="left")
self.hard_button = tk.Button(master, text="困难", command=lambda: self.start_game("hard"))
self.hard_button.pack(side="left")
self.preset_points = []
self.preset_lines = []
self.canvas.bind("<Button-1>", self.on_mouse_down)
self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)
def start_game(self, difficulty):
level = levels.get(difficulty)
if not level:
print("未知的难度级别")
return
self.preset_points = level["points"]
self.preset_lines = level["lines"]
self.user_lines = []
self.last_point_id = None
self.draw()
def on_mouse_down(self, event):
self.start_point = self.get_point_from_mouse_event(event.x, event.y)
def on_mouse_up(self, event):
end_point = self.get_point_from_mouse_event(event.x, event.y)
if self.start_point and end_point and self.start_point["id"] != end_point["id"]:
if self.last_point_id is None or self.last_point_id == self.start_point["id"]:
if self.is_preset_line(self.start_point["id"], end_point["id"]):
self.user_lines.append({"start": self.start_point, "end": end_point})
self.last_point_id = end_point["id"]
self.draw()
else:
print("不能绘制原图中不存在的线段。")
else:
print("必须按顺序连接点。")
def get_point_from_mouse_event(self, x, y):
for point in self.preset_points:
if sqrt((point["x"] - x) ** 2 + (point["y"] - y) ** 2) < 10:
return point
return None
def is_preset_line(self, start_id, end_id):
return any(line for line in self.preset_lines if (line["start"] == start_id and line["end"] == end_id) or (line["start"] == end_id and line["end"] == start_id))
def draw(self):
self.canvas.delete("all")
for line in self.preset_lines:
start = next(p for p in self.preset_points if p["id"] == line["start"])
end = next(p for p in self.preset_points if p["id"] == line["end"])
self.canvas.create_line(start["x"], start["y"], end["x"], end["y"], fill="black")
for line in self.user_lines:
self.canvas.create_line(line["start"]["x"], line["start"]["y"], line["end"]["x"], line["end"]["y"], fill="red")
for point in self.preset_points:
self.canvas.create_oval(point["x"] - 5, point["y"] - 5, point["x"] + 5, point["y"] + 5, fill="blue")
# 检查胜利条件
if self.check_win():
self.canvas.create_text(150, 150, text="恭喜,你完成了这个难度级别的游戏!", fill="green")
def check_win(self):
if len(self.user_lines) != len(self.preset_lines):
return False
# 创建一个用于比较的预设线段副本
preset_lines_copy = [line.copy() for line in self.preset_lines]
# 检查每个用户线段是否都能在预设线段副本中找到匹配项
for user_line in self.user_lines:
matching_line = None
for line in preset_lines_copy:
if ((line["start"] == user_line["start"]["id"] and line["end"] == user_line["end"]["id"]) or
(line["start"] == user_line["end"]["id"] and line["end"] == user_line["start"]["id"])):
matching_line = line
break
if matching_line:
preset_lines_copy.remove(matching_line)
else:
return False
return True
# 创建Tkinter窗口
root = tk.Tk()
root.title("一笔画游戏")
# 创建游戏实例
game = OneStrokeGame(root)
root.mainloop()
说明,定义不同难度的关卡数据:
const levels = {
"easy ":{
// 定义简单难度的点和线段
},
"medium": {
// 定义中等难度的点和线段
},
"hard": {
// 定义高难度的点和线段
}
};
这些点的 x 和 y 坐标是基于画布的尺寸和布局预设的。你可能需要根据你的具体实现调整这些坐标值,以确保点和线在你的游戏界面中正确显示。此外,这些关卡设计仅作为示例,你可以根据需要调整点和线的数量及布局,创造出更多不同难度的关卡。