文章目录
Pygame实战(一):随机抽位置
一、 概述
1、 简介
在学完Pygame基础后,大家是不是非常想做一些小程序出来玩呢?
最近,别人问我,可不可以做一个随机选人的程序,即根据随机选出一个位置来,以做到选人的功能!这让我想起了以前做的一个贪吃蛇的小游戏(后面有时间再出教程),其中食物的出现就是随机的,这让我答应了那个同学的要求!那我们就开始来写吧!
2、 设计思路
首先,我们需要有一个设计的思路:
-
设置配置文件,通过配置文件来设置参数
由于使用者不是程序员,那么,我们就肯定要使用友好的方式来让程序可以尽量按照使用者的想法来运行
这里,我们选择的配置文件是
yaml
文件 -
界面设计
把界面分成两块,即显示区和操作区
这里使用
other_width
这个参数来控制操作区的大小- 显示区绘制网格
- 操作区显示文字
-
随机方块
-
程序打包
由于这个设计思路是第一次写,可能写的不是很好!
3、 成果展示
二、 开始编程
1、 配置文件
创建一个config.yml
,然后写入:
width_num: 10 # 有多少个横排
height_num: 8 # 有多少个竖排
width: 800 # 宽度
height: 600 # 高度
other_w: 250 # 操作界面的宽度
other_h: 600 # 操作界面的高度
timer: 400 # 一次抽取的时间,单位为ms
fps: 40 # 设置界面的帧数
background: background=(41, 45, 62) # 设置背景颜色
font: "config/STSONG.TTF" # 设置字体
margin: 4 # 设置边框与文字的边距
store: "config/data.json" # 设置数据存储路径,防止程序的重启,造成程序数据的丢失
同时,将我们的字体文件一起移入config
文件夹中
2、 程序界面
由于这个是一个文档,不是很好展示。
2.1 读取配置
import sys
import pygame
import yaml
from pathlib import Path
from random import randint
import json
background: tuple = None # 背景颜色变量
with open("config/config.yml", "r", encoding="utf-8") as f: # 读取配置文件
config_data = yaml.load(f, Loader=yaml.FullLoader) # 加载配置
exec(config_data["background"]) # 使用反射机制读取背景颜色
2.2 工具类
这个工具类是后面需要使用的,写在外面增加代码的可读性
class Tools:
"""工具类"""
@staticmethod
def is_inrect(point, rect_tup):
"""判断是否在矩形内部"""
point_x, point_y = point
rect_tup_x, rect_tup_y, rect_tup_w, rect_tup_h = rect_tup
if point_x > rect_tup_x and point_x < rect_tup_x + rect_tup_w: # 如果横坐标在里面
if point_y > rect_tup_y and point_y < rect_tup_y + rect_tup_h: # 并且纵坐标在里面
return True # 返回真
return False # 返回假
@staticmethod
def save(data):
"""保存数据文件"""
p: Path = config_data["store"]
with open(p, "w", encoding="utf-8") as f:
json.dump(data, f)
@staticmethod
def load():
"""读取数据文件"""
p: Path = Path(config_data["store"])
if p.exists():
"如果文件存在"
with open(p, "r", encoding="utf-8") as f:
data = json.load(f)
return data
else:
return {
"selected": []}
2.3 显示区
class MainWindow:
def __init__(self) -> None:
self.selected = [(i[0], i[1]) for i in Tools.load()["selected"]] # 设置已经抽到过的点
self.is_start = False # 标记是否开始选人
self.pos = () # 存放当前坐标的元组
self.init() # 初始化配置
self.init_data() # 初始化数据
# 创建一个定时器事件
self.RANDOM_POS = pygame.USEREVENT + 1
self.draw_line(False) # 画线
def init(self) -> None:
pygame.init() # 初始化程序
w, h = config_data["width"] + config_data["other_w"], config_data["height"] # 设置界面的高度和宽度
self.screen = pygame.display.set_mode(size=(w, h)) # 设置屏幕的大小
pygame.display.set_caption("随机选人") # 设置标题
self.clock = pygame.time.Clock() # 设置一个时钟
def init_data(self) -> None:
self.w_t, self.h_t = config_data["width"] // 200, config_data["height"] // 200 # 距离底端和侧边的距离
self.total_w = config_data["width"] - 2 * self.w_t # 求出显示随机图片区域的宽度
self.total_h = config_data["height"] - 2 * self.h_t # 设置显示区域的高度
self.count_w, self.count_h = config_data["width_num"], config_data["height_num"] # 获取多少行,多少列
self.space_w, self.space_h = self.total_w // self.count_w, self.total_h // self.count_h # 求出每一个矩形的宽度和高度
def draw_line(self, is_flush=True) -> None:
"""is_flush参数,指定需不需要刷新随机坐标,因为在一开始显示界面以及在清空缓存时,其是不需要刷新坐标的"""
self.screen.fill(background) # 同时起到刷新界面的作用
self.setButton(is_flush) # 这里是创建操作区的函数,在后面来编写,先用来占位
line_width = 1 # 设置边框的线宽
for i in range(self.count_w + 1):
# 画竖线
pos_start = (i * self.space_w + self.w_t, self.h_t + line_width * 2)
pos_end = (i * self.space_w + self.w_t, self.total_h - self.h_t + 3 + line_width *