From 1111d5a131cbf8485147d2ea00db89641c0bb206 Mon Sep 17 00:00:00 2001 From: MuspiMerol Date: Wed, 9 Mar 2022 04:52:32 +0800 Subject: [PATCH 1/6] =?UTF-8?q?bug=20fix:=20=E5=8E=9F=E6=9C=AC=E7=9A=84ani?= =?UTF-8?q?mate=E7=9A=84=E5=8F=82=E6=95=B0=E6=98=AF=E6=B2=A1=E7=94=A8?= =?UTF-8?q?=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cpgzh/animation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpgzh/animation.py b/cpgzh/animation.py index 229d087..6a595f3 100755 --- a/cpgzh/animation.py +++ b/cpgzh/animation.py @@ -3,12 +3,12 @@ from pgzero.animation import animate as ani def animate(object, tween='linear', duration=1, on_finished=None, **targets): - ''' - 控制角色运动的功能,比如从一个地方运动到另外一个地方。\n + """ + 控制角色运动的功能,比如从一个地方运动到另外一个地方。\n object:你要运动的角色(必选)。\n pos:终点坐标(必选)。 tween:运动的方式,linear就是线性的意思,还有:accelerate、decelerate、accel_decel、end_elastic、start_elastic、both_elastic、bounce_end、bounce_start、bounce_start_end等参数可选,请大家自行尝试。\n duration:延迟的时间,单位为s。\n on_finished:结束后做的事。\n - ''' - ani(object, tween='linear', duration=1, on_finished=None, **targets) + """ + return ani(object, tween, duration, on_finished, **targets) -- Gitee From 5a1f011d9726f12845f374674d509c750e714bf2 Mon Sep 17 00:00:00 2001 From: MuspiMerol Date: Wed, 9 Mar 2022 05:06:14 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E5=8F=91=E7=8E=B0data.py=E6=98=AF=E7=9A=84?= =?UTF-8?q?load=E6=96=B9=E6=B3=95=E5=92=8C=E4=B8=80=E8=88=AC=E8=AE=A4?= =?UTF-8?q?=E4=B8=BA=E7=9A=84=E6=9C=89=E6=89=80=E5=8C=BA=E5=88=AB=20?= =?UTF-8?q?=E5=B0=86=E6=9D=A5=E5=BA=94=E8=AF=A5=E4=BF=AE=E6=94=B9=E6=88=90?= =?UTF-8?q?=E8=BF=94=E5=9B=9EData=E5=AE=9E=E4=BE=8B=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=88=96=E9=9D=99=E6=80=81=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +++- cpgzh/data.py | 30 ++++++++++++++++++------------ version.txt | 2 +- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 529c3af..e7a2d8c 100755 --- a/.gitignore +++ b/.gitignore @@ -114,4 +114,6 @@ dmypy.json # Pyre type checker .pyre/ -md-style \ No newline at end of file +md-style + +.idea \ No newline at end of file diff --git a/cpgzh/data.py b/cpgzh/data.py index 89bafc9..cfc4a61 100755 --- a/cpgzh/data.py +++ b/cpgzh/data.py @@ -4,27 +4,28 @@ import os class Data: - '数据存储类' + """数据存储类""" def __init__(self, data_path) -> None: - '数据类' - self.status = 0 # 游戏状态\ - self.time = 0 # 游戏持续时间 + """数据类""" + self.status = 0 # 游戏状态 + self.time = 0 # 游戏持续时间 TODO: 这个实例属性从没用过 self.score = 0 # 得分 self.start() self.data_path = data_path + self.__start = NotImplemented def start(self): - '启动' + """启动""" self.__start = time.time() return self.__start def get_time(self): - '获取游戏的持续时间' - return time.time()-self.__start + """获取游戏的持续时间""" + return time.time() - self.__start def save_data(self): - '保存数据' + """保存数据""" try: with open(self.data_path, 'wb') as f: pickle.dump(self, f) @@ -35,19 +36,24 @@ class Data: return 0 def load_data(self): - '加载数据' + """加载数据""" if os.path.isfile(self.data_path): with open(self.data_path, 'rb') as f: - self = pickle.load(f) + data: Data = pickle.load(f) + self.status = data.status + self.score = data.score + self.data_path = data.data_path + self.time = data.time + self.__start = data.__start # print(f'{self.data_path}加载成功!') return 1 else: # print(f'{self.data_path}加载失败!') - #self = Data(self.data_path) + # self = Data(self.data_path) return 0 def del_data(self): - '删除数据' + """删除数据""" try: os.remove(self.data_path) print(f'{self.data_path}删除成功') diff --git a/version.txt b/version.txt index 23e5f18..d3662a8 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.1.34 \ No newline at end of file +0.1.36 \ No newline at end of file -- Gitee From bffa1c1812fb1ae485faa1f9c9093392706f5dec Mon Sep 17 00:00:00 2001 From: MuspiMerol Date: Wed, 9 Mar 2022 05:54:30 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=B8=8D=E6=94=B9=E5=8F=98=E4=BB=BB?= =?UTF-8?q?=E4=BD=95API=E5=89=8D=E6=8F=90=E4=B8=8B=20=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E4=BA=86=E4=B8=80=E4=BA=9B=E4=BB=A3=E7=A0=81=E3=80=81=E6=94=B9?= =?UTF-8?q?=E4=BA=86=E5=B0=91=E9=87=8F=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cpgzh/actor.py | 97 +++++++++++++++++++++++++------------------------ cpgzh/getimg.py | 26 ++++++------- cpgzh/keys.py | 4 +- cpgzh/master.py | 58 +++++++++++++++-------------- cpgzh/mouse.py | 30 +++++++-------- cpgzh/runner.py | 2 +- 6 files changed, 110 insertions(+), 107 deletions(-) diff --git a/cpgzh/actor.py b/cpgzh/actor.py index 685ce7b..53977b3 100755 --- a/cpgzh/actor.py +++ b/cpgzh/actor.py @@ -12,10 +12,10 @@ from .mouse import mouse class Actor(Actor): - "角色" + """角色""" def __init__(self, image, pos=POS_TOPLEFT, anchor=ANCHOR_CENTER, **kwargs): - "新的角色类" + """新的角色类""" may_dir = os.path.join(loaders.root, "images", image) if os.path.isdir(image): self._images = self.__load_dir_images(image) @@ -40,25 +40,25 @@ class Actor(Actor): super().__init__(self._images[0], pos, anchor, **kwargs) def __load_gif(self, image): - "gif动画支持" + """gif动画支持""" if not os.path.isfile(image): image = os.path.join(loaders.root, "images", image) images = gif2png(image) return images def __load_dir_images(self, dirname): - "加载某个文件夹中的图片" + """加载某个文件夹中的图片""" if not os.path.isdir(dirname): dirname = os.path.join(loaders.root, "images", dirname) images = loadimgs(dirname) return images def distance_to(self, actor: Actor): - "计算到另一个角色的距离" + """计算到另一个角色的距离""" return math.dist(actor.pos, self.pos) def direction_to(self, actor): - "计算面向另一个角色的方向" + """计算面向另一个角色的方向""" dx = actor.x - self.x dy = self.y - actor.y @@ -69,7 +69,7 @@ class Actor(Actor): return 360 + angle def move_towards(self, actor, dist): - "朝另一个角色移动dist步" + """朝另一个角色移动dist步""" angle = math.radians(self.direction_to(actor)) dx = dist * math.cos(angle) dy = dist * math.sin(angle) @@ -77,12 +77,12 @@ class Actor(Actor): self.y -= dy def point_towards(self, actor): - "面向另一个角色" + """面向另一个角色""" print(self.direction_to(actor)) self.angle = self.direction_to(actor) def move_in_direction(self, dist): - "朝着当前方向移动dist步,不是角色角度" + """朝着当前方向移动dist步,不是角色角度""" angle = math.radians(self.direction) dx = dist * math.cos(angle) dy = dist * math.sin(angle) @@ -90,7 +90,7 @@ class Actor(Actor): self.y -= dy def move_forward(self, dist): - "演着角色角度移动dist步" + """演着角色角度移动dist步""" angle = math.radians(self.angle) dx = dist * math.cos(angle) dy = dist * math.sin(angle) @@ -98,7 +98,7 @@ class Actor(Actor): self.y -= dy def move_left(self, dist): - "朝当前角度的左边移动dist步" + """朝当前角度的左边移动dist步""" angle = math.radians(self.angle + 90) dx = dist * math.cos(angle) dy = dist * math.sin(angle) @@ -106,7 +106,7 @@ class Actor(Actor): self.y -= dy def move_right(self, dist): - "朝当前角度的右边移动dist步" + """朝当前角度的右边移动dist步""" angle = math.radians(self.angle - 90) dx = dist * math.cos(angle) dy = dist * math.sin(angle) @@ -114,7 +114,7 @@ class Actor(Actor): self.y -= dy def move_back(self, dist): - "倒退dist步" + """倒退dist步""" angle = math.radians(self.angle) dx = -dist * math.cos(angle) dy = -dist * math.sin(angle) @@ -123,18 +123,18 @@ class Actor(Actor): @property def images(self): - "设置造型列表" + """设置造型列表""" return self._images @images.setter def images(self, images): - "设置造型列表" + """设置造型列表""" self._images = images if len(self._images) != 0: self.image = self._images[0] def next_image(self): - "下一个造型" + """下一个造型""" if self.image in self._images: current = self._images.index(self.image) if current == len(self._images) - 1: @@ -145,7 +145,7 @@ class Actor(Actor): self.image = self._images[0] def toggle_animate(self): - "切换角色是否自动切换造型" + """切换角色是否自动切换造型""" if self.animate_fps == 0: self.animate_fps = 10 else: @@ -208,7 +208,7 @@ class Actor(Actor): self.tasks[task_count] = {self._task_id: after} def remove_taskById(self, id): - "根据id删掉任务" + """根据id删掉任务""" for i in self.tasks: if id in self.tasks[i]: del self.tasks[i][id] @@ -217,27 +217,27 @@ class Actor(Actor): @property def angle(self): - "设置角度" + """设置角度""" return self._angle @angle.setter def angle(self, angle): - "设置角度" + """设置角度""" self._angle = angle self._transform_surf() @property def scale(self): - "设置缩放" + """设置缩放""" return self._scale @scale.setter def scale(self, scale): - ''' + """ 设置缩放\n 设置一个小数将会同时修改x方向和y方向\n 设置一个(0.4,0.6)这样的元组,将会x方向缩放到0.4倍,y方向缩放到0.6倍 - ''' + """ if type(scale) == float or type(scale) == int: self._scale_x = self._scale_y = scale self._scale = scale @@ -250,41 +250,41 @@ class Actor(Actor): @property def flip_x(self): - "设置x方向翻转" + """设置x方向翻转""" return self._flip_x @flip_x.setter def flip_x(self, flip_x): - "设置x方向翻转" + """设置x方向翻转""" self._flip_x = flip_x self._transform_surf() @property def flip_y(self): - "设置x方向翻转" + """设置x方向翻转""" return self._flip_y @flip_y.setter def flip_y(self, flip_y): - "设置y方向翻转" + """设置y方向翻转""" self._flip_y = flip_y self._transform_surf() @property def image(self): - "设置造型" + """设置造型""" return self._image_name @image.setter def image(self, image): - "设置当前造型" + """设置当前造型""" self._image_name = image self._orig_surf = self._surf = loaders.images.load(image) self._update_pos() self._transform_surf() def _transform_surf(self): - "变换角色的缩放、翻转等" + """变换角色的缩放、翻转等""" self._surf = self._orig_surf p = self.pos @@ -311,7 +311,7 @@ class Actor(Actor): self._mask = None def collidepoint_pixel(self, x, y=0): - "检测碰撞到某个像素,像素级精确检测" + """检测碰撞到某个像素,像素级精确检测""" if isinstance(x, tuple): x, y = x if self._mask == None: @@ -329,9 +329,9 @@ class Actor(Actor): return self._mask.get_at((xoffset, yoffset)) def collide_pixel(self, actor): - "检测碰撞其他某个角色,返回重叠的坐标,如果没重叠就直接返回None,像素级精确检测" + """检测碰撞其他某个角色,返回重叠的坐标,如果没重叠就直接返回None,像素级精确检测""" for a in [self, actor]: - if a._mask == None: + if a._mask is None: a._mask = pygame.mask.from_surface(a._surf) xoffset = int(actor.left - self.left) @@ -340,18 +340,17 @@ class Actor(Actor): return self._mask.overlap(actor._mask, (xoffset, yoffset)) def collidelist_pixel(self, actors): - "检测碰撞角色列表,返回碰撞到的角色的索引,没碰到返回None,像素级精确检测" + """检测碰撞角色列表,返回碰撞到的角色的索引,没碰到返回None,像素级精确检测""" for i, actor in enumerate(actors): if self.collide_pixel(actor): return i - return None def collidelistall_pixel(self, actors): - "检测碰撞角色列表,返回值是碰撞到的角色,返回一个列表,如果列表为空说明没碰到,像素级精确检测" + """检测碰撞角色列表,返回值是碰撞到的角色,返回一个列表,如果列表为空说明没碰到,像素级精确检测""" return list(filter(self.collide_pixel, actors)) def obb_collidepoints(self, actors): - "检测多个角色碰撞,旋转了rect,使得rect贴合角色" + """检测多个角色碰撞,旋转了rect,使得rect贴合角色""" angle = math.radians(self._angle) costheta = math.cos(angle) sintheta = math.sin(angle) @@ -371,7 +370,7 @@ class Actor(Actor): return -1 def obb_collidepoint(self, x, y=0): - "检测碰撞一个点,旋转了rect,使得rect贴合角色" + """检测碰撞一个点,旋转了rect,使得rect贴合角色""" if isinstance(x, tuple): x, y = x angle = math.radians(self._angle) @@ -389,7 +388,7 @@ class Actor(Actor): return -half_width < rx < half_width and -half_height < ry < half_height def circle_collidepoints(self, radius, actors): - "检测碰撞一堆点,将角色变成圆形区域,适合于圆形角色的碰撞检测" + """检测碰撞一堆点,将角色变成圆形区域,适合于圆形角色的碰撞检测""" rSquare = radius ** 2 for i, actor in enumerate(actors): @@ -401,7 +400,7 @@ class Actor(Actor): return -1 def circle_collidepoint(self, radius, x, y=0): - "检测碰撞一个点,将角色变成圆形区域,适合于圆形角色的碰撞检测" + """检测碰撞一个点,将角色变成圆形区域,适合于圆形角色的碰撞检测""" if isinstance(x, tuple): x, y = x rSquare = radius ** 2 @@ -410,36 +409,38 @@ class Actor(Actor): return dSquare < rSquare def draw(self): - "绘图" + """绘图""" if self.is_draw: game.screen.blit(self._surf, self.topleft) def get_rect(self): - "获取角色的rect" + """获取角色的rect""" return self._rect def show(self): - "显示角色" + """显示角色""" self.is_draw = 1 def hide(self): - "隐藏" + """隐藏""" self.is_draw = 0 def face_to(self, pos=None): - ''' + """ 面向一个对象\n pos参数不传递则面向鼠标\n pos传入一个坐标则面向这个坐标\n pos传入一个Actor则面向这个演员\n - ''' + """ if isinstance(pos, (list, tuple)): x, y = pos[0], pos[1] elif isinstance(pos, Actor): x, y = pos.pos - else: + elif pos is None: x, y = mouse.get_pos() + else: + raise NotImplementedError(pos) dx = x - self.x - dy = self.y-y + dy = self.y - y d = math.degrees(math.atan2(dy, dx)) self.angle = d diff --git a/cpgzh/getimg.py b/cpgzh/getimg.py index b1d8eb6..e04dc3c 100755 --- a/cpgzh/getimg.py +++ b/cpgzh/getimg.py @@ -5,33 +5,31 @@ from PIL import Image, ImageSequence def gif2png(image): - '将gif动画拆解成每一帧png的函数' - image_dir=os.path.dirname(image) - head,name=os.path.split(image) - name=name[:-4] - image_dir=os.path.join(image_dir,name) + """将gif动画拆解成每一帧png的函数""" + image_dir = os.path.dirname(image) + head, name = os.path.split(image) + name = name[:-4] + image_dir = os.path.join(image_dir, name) if not os.path.isdir(image_dir): os.makedirs(image_dir) - img=Image.open(image) + img = Image.open(image) # 创建读取每一帧的迭代器 - iter = ImageSequence.Iterator(img) - index=1 + iter_ = ImageSequence.Iterator(img) images=[] - for i in iter: - now_img=os.path.join(image_dir,f"{name}({index}).png") + for index, i in enumerate(iter_): + now_img = os.path.join(image_dir, f"{name}({index + 1}).png") i.save(now_img) images.append(now_img) - index+=1 return images def loadimgs(path): - '加载并排序图片' + """加载并排序图片""" if os.path.isdir(path): - new_lists=[] - files=os.listdir(path) + new_lists = [] + files = os.listdir(path) for file in files: if os.path.isfile(os.path.join(path,file)): if file.split(".")[-1] in ["png", "jpg", "jpeg", "gif", "bmp"]: diff --git a/cpgzh/keys.py b/cpgzh/keys.py index ba31def..d57ed68 100644 --- a/cpgzh/keys.py +++ b/cpgzh/keys.py @@ -1,7 +1,7 @@ from enum import IntEnum class keys(IntEnum): - '用于获取键盘按键的类' + """用于获取键盘按键的类""" AC_BACK = 1073742094 UNKNOWN = 0 BACKSPACE = 8 @@ -180,7 +180,7 @@ class keymods(IntEnum): from warnings import warn from pgzero.keyboard import Keyboard class Keyboard(Keyboard): - '重写获取按键函数' + """重写获取按键函数""" def __getitem__(self, k): if isinstance(k, str): warn( diff --git a/cpgzh/master.py b/cpgzh/master.py index 55abf35..56e0a1f 100755 --- a/cpgzh/master.py +++ b/cpgzh/master.py @@ -1,5 +1,4 @@ -import sys,os -from tkinter import simpledialog +import sys, os import guizero import pygame @@ -7,20 +6,21 @@ import pygame.draw from guizero import App from .data import Data + def round_xy(pos): - "四舍五入坐标" + """四舍五入坐标""" if isinstance(pos, tuple): x, y = pos - return (round(x), round(y)) + return round(x), round(y) else: return round(pos) class Master: - "管家类,负责一些管理类的功能" + """管家类,负责一些管理类的功能""" def __init__(self, data_path="data.dat") -> None: - "管家类,负责一些管理类的功能" + """管家类,负责一些管理类的功能""" self._fullscreen = False self.data = Data(data_path) self.load_data() @@ -30,44 +30,44 @@ class Master: @property def data_path(self): - "获取data_path" + """获取data_path""" return self.data.data_path @data_path.setter def data_path(self, path): - "设置data_path" + """设置data_path""" print(f"数据地址{path}") self.data.data_path = path def load_data(self): - "加载数据" + """加载数据""" self.data.load_data() def save_data(self): - "保存数据" + """保存数据""" self.data.save_data() def del_data(self): - "删除数据" + """删除数据""" self.data.del_data() def set_fullscreen(self) -> None: - "设置全屏" + """设置全屏""" self.mod.screen.surface = pygame.display.set_mode( (self.mod.WIDTH, self.mod.HEIGHT), pygame.FULLSCREEN ) self._fullscreen = True def set_windowed(self) -> None: - "设置窗口化" - os.environ['SDL_VIDEO_CENTERED'] = "1"# pygame设置窗口在中心,实测无效 + """设置窗口化""" + os.environ['SDL_VIDEO_CENTERED'] = "1" # pygame设置窗口在中心,实测无效 self.mod.screen.surface = pygame.display.set_mode( (self.mod.WIDTH, self.mod.HEIGHT) ) self._fullscreen = False def toggle_fullscreen(self) -> None: - "切换全屏和窗口化" + """切换全屏和窗口化""" if self._fullscreen: self.set_windowed() else: @@ -81,6 +81,7 @@ class Master: dtype=1输入整数\n dtype=2输入浮点数\n """ + from tkinter import simpledialog if dtype == 1: text = simpledialog.askinteger("输入整数", msg) elif dtype == 2: @@ -115,25 +116,28 @@ class Master: return path def select_dir(self, msg="请选择文件夹") -> str: - "选择一个文件夹" - dir = guizero.select_folder(msg) - self.data.temp = dir - return dir + """选择一个文件夹""" + dir_ = guizero.select_folder(msg) + self.data.temp = dir_ + return dir_ def yes_no(self, msg="是否?"): - "是否做某件事的选择框" + """是否做某件事的选择框""" yes_or_no = guizero.yesno("请选择", msg) self.data.temp = yes_or_no return yes_or_no - def msg(self, msg="这是提示信息"): - "提示信息" + @staticmethod + def msg(msg="这是提示信息"): + """提示信息""" guizero.info("提示", msg) - def warning(self, msg="这是警告信息"): - "警告信息" + @staticmethod + def warning(msg="这是警告信息"): + """警告信息""" guizero.warn("警告", msg) - def error(self, msg="这是错误信息"): - "错误信息" - guizero.error("错误", msg) \ No newline at end of file + @staticmethod + def error(msg="这是错误信息"): + """错误信息""" + guizero.error("错误", msg) diff --git a/cpgzh/mouse.py b/cpgzh/mouse.py index c733369..a1c6430 100755 --- a/cpgzh/mouse.py +++ b/cpgzh/mouse.py @@ -2,30 +2,30 @@ import pygame from pgzero.constants import mouse as mouse_keys -class Mouse(object): - '鼠标类' +class Mouse: + """鼠标类""" def __init__(self) -> None: - '鼠标类' + """鼠标类""" self.keys = mouse_keys - def get_pos(self): - '获取鼠标坐标' + @staticmethod + def get_pos(): + """获取鼠标坐标""" return pygame.mouse.get_pos() + @staticmethod def set_pos(x, y=None): - if y == None: - pos = x - else: - pos = (x, y) - pygame.mouse.set_pos(pos) - - def hide(self) -> None: - "隐藏鼠标" + pygame.mouse.set_pos(x, y) + + @staticmethod + def hide() -> None: + """隐藏鼠标""" pygame.mouse.set_visible(False) - def show(self) -> None: - "显示鼠标" + @staticmethod + def show() -> None: + """显示鼠标""" pygame.mouse.set_visible(True) diff --git a/cpgzh/runner.py b/cpgzh/runner.py index 8e593f9..c485d81 100755 --- a/cpgzh/runner.py +++ b/cpgzh/runner.py @@ -46,6 +46,6 @@ def go(): def get_screen(): - "返回当前游戏所在的屏幕" + """返回当前游戏所在的屏幕""" mod = sys.modules["__main__"] return mod.screen -- Gitee From 856864455f2f826910a6175864efd4a8f450096f Mon Sep 17 00:00:00 2001 From: MuspiMerol Date: Wed, 9 Mar 2022 19:41:04 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=B8=BB=E8=A6=81=E6=94=B9=E4=BA=86Data?= =?UTF-8?q?=E7=B1=BB=E7=9A=84load=5Fdata=E6=96=B9=E6=B3=95=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cpgzh/actor.py | 7 +++---- cpgzh/data.py | 45 +++++++++++++++++++++++++-------------------- cpgzh/master.py | 25 +++++++++++++++++-------- version.txt | 2 +- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/cpgzh/actor.py b/cpgzh/actor.py index 53977b3..b640bba 100755 --- a/cpgzh/actor.py +++ b/cpgzh/actor.py @@ -295,11 +295,10 @@ class Actor(Actor): int(size[1] * self._scale_y)) ) if self._flip_x or self._flip_y: - self._surf = pygame.transform.flip( - self._surf, self._flip_x, self._flip_y) + self._surf = pygame.transform.flip(self._surf, self._flip_x, self._flip_y) self._surf = pygame.transform.rotate(self._surf, self._angle) - # 应该改成用pygame.transform.rotozoom合并旋转和缩放操作 + # 应该改成用pygame.transform.rotozoom合并旋转和缩放操作,但是rotozoom只支持横竖统一的缩放率 self.width, self.height = self._surf.get_size() w, h = self._orig_surf.get_size() @@ -433,7 +432,7 @@ class Actor(Actor): pos传入一个Actor则面向这个演员\n """ if isinstance(pos, (list, tuple)): - x, y = pos[0], pos[1] + x, y = pos[:2] # 传入Rect也行 elif isinstance(pos, Actor): x, y = pos.pos elif pos is None: diff --git a/cpgzh/data.py b/cpgzh/data.py index cfc4a61..bed614d 100755 --- a/cpgzh/data.py +++ b/cpgzh/data.py @@ -6,14 +6,15 @@ import os class Data: """数据存储类""" - def __init__(self, data_path) -> None: + def __init__(self, data_path): """数据类""" + self.data_path = data_path + self.status = 0 # 游戏状态 - self.time = 0 # 游戏持续时间 TODO: 这个实例属性从没用过 self.score = 0 # 得分 + self.__start = 0 # 起始时间 + self.start() - self.data_path = data_path - self.__start = NotImplemented def start(self): """启动""" @@ -24,6 +25,10 @@ class Data: """获取游戏的持续时间""" return time.time() - self.__start + @property + def time(self): + return self.get_time() + def save_data(self): """保存数据""" try: @@ -35,22 +40,17 @@ class Data: print(f'{self.data_path}保存失败!') return 0 - def load_data(self): + @classmethod + def load_data(cls, path): """加载数据""" - if os.path.isfile(self.data_path): - with open(self.data_path, 'rb') as f: - data: Data = pickle.load(f) - self.status = data.status - self.score = data.score - self.data_path = data.data_path - self.time = data.time - self.__start = data.__start - # print(f'{self.data_path}加载成功!') - return 1 - else: - # print(f'{self.data_path}加载失败!') - # self = Data(self.data_path) - return 0 + try: + with open(path, 'rb') as f: + data = pickle.load(f) + assert isinstance(path, cls) + return data + except FileNotFoundError: + print(f'{path}不存在') + return cls(path) def del_data(self): """删除数据""" @@ -58,6 +58,11 @@ class Data: os.remove(self.data_path) print(f'{self.data_path}删除成功') return 1 - except: + except FileNotFoundError: print(f'{self.data_path}不存在') return 0 + + def __str__(self): + return f"" + + __repr__ = __str__ diff --git a/cpgzh/master.py b/cpgzh/master.py index 56e0a1f..a0fe967 100755 --- a/cpgzh/master.py +++ b/cpgzh/master.py @@ -19,11 +19,10 @@ def round_xy(pos): class Master: """管家类,负责一些管理类的功能""" - def __init__(self, data_path="data.dat") -> None: + def __init__(self, data_path="data.dat"): """管家类,负责一些管理类的功能""" self._fullscreen = False - self.data = Data(data_path) - self.load_data() + self.data: Data = Data.load_data(data_path) self.data.temp = "" self.app = App(visible=False) self.mod = sys.modules["__main__"] @@ -39,9 +38,9 @@ class Master: print(f"数据地址{path}") self.data.data_path = path - def load_data(self): + def load_data(self, new_path=None): """加载数据""" - self.data.load_data() + self.data = Data.load_data(new_path or self.data_path) def save_data(self): """保存数据""" @@ -51,14 +50,14 @@ class Master: """删除数据""" self.data.del_data() - def set_fullscreen(self) -> None: + def set_fullscreen(self): """设置全屏""" self.mod.screen.surface = pygame.display.set_mode( (self.mod.WIDTH, self.mod.HEIGHT), pygame.FULLSCREEN ) self._fullscreen = True - def set_windowed(self) -> None: + def set_windowed(self): """设置窗口化""" os.environ['SDL_VIDEO_CENTERED'] = "1" # pygame设置窗口在中心,实测无效 self.mod.screen.surface = pygame.display.set_mode( @@ -66,13 +65,23 @@ class Master: ) self._fullscreen = False - def toggle_fullscreen(self) -> None: + def toggle_fullscreen(self): """切换全屏和窗口化""" if self._fullscreen: self.set_windowed() else: self.set_fullscreen() + @property + def fullscreen(self): + return self._fullscreen + + @fullscreen.setter + def fullscreen(self, is_fullscreen): + if is_fullscreen is not self.fullscreen: + self.toggle_fullscreen() + + def input(self, msg="请输入数据:", dtype=0) -> str or int or float: """ 简单输入框\n diff --git a/version.txt b/version.txt index d3662a8..2cdd56e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.1.36 \ No newline at end of file +0.1.38 \ No newline at end of file -- Gitee From b5a7cbc6271f8f94ff41dcb17f4903fd35aca5b7 Mon Sep 17 00:00:00 2001 From: MuspiMerol Date: Thu, 10 Mar 2022 12:44:15 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E9=87=8D=E6=96=B0=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cpgzh/data.py | 4 ++-- cpgzh/example.py | 40 ++++++++++++++++++---------------------- cpgzh/runner.py | 36 ++++++++++++++++++++++++------------ 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/cpgzh/data.py b/cpgzh/data.py index bed614d..40adbbd 100755 --- a/cpgzh/data.py +++ b/cpgzh/data.py @@ -41,12 +41,12 @@ class Data: return 0 @classmethod - def load_data(cls, path): + def load_data(cls, path) -> "Data": """加载数据""" try: with open(path, 'rb') as f: data = pickle.load(f) - assert isinstance(path, cls) + assert isinstance(path, cls), type(data) return data except FileNotFoundError: print(f'{path}不存在') diff --git a/cpgzh/example.py b/cpgzh/example.py index ef47a37..d8eccc8 100755 --- a/cpgzh/example.py +++ b/cpgzh/example.py @@ -25,15 +25,6 @@ monv.flip_y = 1 master = Master() pen = Pen() -a = 10 -b = 12 -c = a -a = b -b = c - -a, b = b, a - - def flushImages(): "刷新造型列表" now = datetime.datetime.now() @@ -43,11 +34,7 @@ def flushImages(): def update(): "更新数据" - rc.animate() - jisi.run_tasks() # 执行计划任务 - monv.run_tasks() - jisi.animate() # 切换造型动画 - monv.animate() + master.run_tasks() # 面向鼠标 jisi.face_to() # 面向演员 @@ -92,14 +79,23 @@ def draw(): def on_mouse_down(pos, button): "当鼠标按下" - print(button) - if button == mouse.keys.LEFT: # 按下左键刷新造型列表 + print(button, pos) + # 按下左键刷新造型列表 + if button == mouse.keys.LEFT: jisi.images = jisi.images = [ f"大祭司_人偶-待机-{i:0>3}.png" for i in range(30)] - else: # 按下右键停止切换造型并延迟开启 + # 滚轮调节动画fps + elif button == mouse.keys.WHEEL_UP: + jisi.animate_fps += 3 + elif button == mouse.keys.WHEEL_DOWN: + jisi.animate_fps -= 3 + # 按下右键提问是否刷新造型 + else: yesOrNo = master.yes_no("是否切换造型?") if yesOrNo: - jisi.create_delay_tasks(flushImages, 5, 3) # 延迟5s重置造型列表,循环3次 + jisi.animate_fps = 10 + else: + jisi.animate_fps = 0 def on_mouse_move(pos): @@ -186,12 +182,12 @@ def on_key_down(key): # 显示角色 elif key == keys.W: monv.show() - # 切换5次造型后隐藏 + # 等待1s后隐藏 elif key == keys.X: - monv.create_delay_tasks(monv.next_image, 1, 5, monv.hide) - # 等待5s后显示 + master.create_delay_tasks(monv.hide, 1) + # 等待1s后显示 elif key == keys.Y: - monv.create_delay_tasks(monv.show, 5) + master.create_delay_tasks(monv.show, 1) elif key == keys.SPACE: # 按下空格键 print(key) diff --git a/cpgzh/runner.py b/cpgzh/runner.py index c485d81..147120d 100755 --- a/cpgzh/runner.py +++ b/cpgzh/runner.py @@ -1,16 +1,22 @@ import os import sys -from warnings import warn import pygame from pgzero.game import PGZeroGame from .keys import keyboard from pgzero.runner import prepare_mod +import time - - - +HEADER = '\033[1;95m' +OKBLUE = '\033[1;94m' +OKGREEN = '\033[1;92m' +OKRED = '\033[1;31m' +WARNING = '\033[1;93m' +FAIL = '\033[1;91m' +ENDL = '\033[0m' +BOLD = '\033[1m' +UNDERLINE = '\033[1;4m' mod = sys.modules["__main__"] @@ -22,27 +28,33 @@ try: os.environ['SDL_VIDEO_WINDOW_POS'] = f'{int((w-WIDTH)/2)},{int((h-HEIGHT)/2)}' except: os.environ['SDL_VIDEO_WINDOW_POS'] = '100,100' - -if not getattr(sys, '_pgzrun', None): - if not getattr(mod, '__file__', None): - raise ImportError( - "You are running from an interactive interpreter.\n" - "'import pgzrun' only works when you are running a Python file." - ) +finally: + now = time.localtime() + sec = time.time() % 60 + now = f'{now[0]}-{now[1]}-{now[2]} {now[3]}:{now[4]}:{sec:.2f} ' + print(f'{OKGREEN}{now}{ENDL}cpgzh模块加载成功,开始游戏加载主程序...') prepare_mod(mod) def go(): - """Run the __main__ module as a Pygame Zero script.""" + """启动游戏引擎""" if getattr(sys, '_pgzrun', None): return app = PGZeroGame(mod) app.keyboard = keyboard + now = time.localtime() + sec = time.time() % 60 + now = f'{now[0]}-{now[1]}-{now[2]} {now[3]}:{now[4]}:{sec:.2f} ' + print(f'{OKGREEN}{now}{ENDL}主程序加载成功,启动游戏...') try: app.mainloop() finally: pygame.display.quit() pygame.mixer.quit() + now = time.localtime() + sec = time.time() % 60 + now = f'{now[0]}-{now[1]}-{now[2]} {now[3]}:{now[4]}:{sec:.2f} ' + print(f'{OKGREEN}{now}{ENDL}游戏结束,谢谢使用。') def get_screen(): -- Gitee From e52f4c88473d26015d5be5ec661fb12e6f883a24 Mon Sep 17 00:00:00 2001 From: MuspiMerol Date: Thu, 10 Mar 2022 13:58:15 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86Task=E7=B1=BB?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E7=9A=84=E6=A0=87=E7=AD=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cpgzh/data.py | 2 +- cpgzh/master.py | 102 +++++++++++++++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/cpgzh/data.py b/cpgzh/data.py index 40adbbd..2f06c8c 100755 --- a/cpgzh/data.py +++ b/cpgzh/data.py @@ -46,7 +46,7 @@ class Data: try: with open(path, 'rb') as f: data = pickle.load(f) - assert isinstance(path, cls), type(data) + assert isinstance(data, cls), type(data) return data except FileNotFoundError: print(f'{path}不存在') diff --git a/cpgzh/master.py b/cpgzh/master.py index 255fb8a..715bafd 100755 --- a/cpgzh/master.py +++ b/cpgzh/master.py @@ -15,70 +15,76 @@ MAX_FPS = 120 def round_xy(pos): - "四舍五入坐标" + """四舍五入坐标""" if isinstance(pos, tuple): x, y = pos - return (round(x), round(y)) + return round(x), round(y) else: return round(pos) class Task: - '任务类' + """任务类""" - def __init__(self, id, time_count, func, args) -> None: - '任务类' - self.id = id + def __init__(self, id_, time_count, func, *args, init_hp=1, tags=None, **kwargs): + """任务类""" + self.id = id_ self.time_count = time_count self.__func = func self.__args = args - self.hp = 1 + self.hp = init_hp + self.tags = tags or {} + self.__kwargs = kwargs - def run(self): - '运行任务' - if int(time.time()*MAX_FPS) >= self.time_count: - self.__func(*self.__args) - self.hp = 0 + def run(self, async_=False): + """运行任务""" + if int(time.time() * MAX_FPS) >= self.time_count: + if async_: # 执行一些长时间任务时(比如保存转码GIF,读取游戏地图之类),不会阻塞主线程 + import threading + threading.Thread(target=self.__func, args=self.__args, kwargs=self.__kwargs).start() + else: + self.__func(*self.__args, **self.__kwargs) + self.hp -= 1 class Master: - "管家类,负责一些管理类的功能" + """管家类,负责一些管理类的功能""" def __init__(self, data_path="data.dat") -> None: - "管家类,负责一些管理类的功能" + """管家类,负责一些管理类的功能""" self._fullscreen = False - self.data: Data = Data.load_data(Data, data_path) + self.data: Data = Data.load_data(data_path) self.data.temp = "" self.app = App(visible=False) self.mod = sys.modules["__main__"] self._task_id = 0 - self.tasks = [] + self.tasks: list[Task] = [] @property def data_path(self): - "获取data_path" + """获取data_path""" return self.data.data_path @data_path.setter def data_path(self, path): - "设置data_path" + """设置data_path""" print(f"数据地址{path}") self.data.data_path = path def load_data(self, new_path=None): """加载数据""" - self.data: Data = Data.load_data(Data, new_path or self.data_path) + self.data: Data = Data.load_data(new_path or self.data_path) def save_data(self): - "保存数据" + """保存数据""" self.data.save_data() def del_data(self): - "删除数据" + """删除数据""" self.data.del_data() - def set_fullscreen(self) -> None: - "设置全屏" + def set_fullscreen(self): + """设置全屏""" self.mod.screen.surface = pygame.display.set_mode( (self.mod.WIDTH, self.mod.HEIGHT), pygame.FULLSCREEN ) @@ -108,7 +114,6 @@ class Master: if is_fullscreen is not self.fullscreen: self.toggle_fullscreen() - def input(self, msg="请输入数据:", dtype=0) -> str or int or float: """ 简单输入框\n @@ -119,14 +124,14 @@ class Master: """ if dtype == 1: text = guizero.askstring("输入整数", msg) - text = int(text) + ans = int(text) elif dtype == 2: - text = guizero.askstringt("输入小数", msg) - text = float(text) + text = guizero.askstring("输入小数", msg) + ans = float(text) else: - text = guizero.askstring("输入", msg) - self.data.temp = text - return text + ans = guizero.askstring("输入", msg) + self.data.temp = ans + return ans def select_file(self, msg="请选择文件", filetypes=[["All files", "*.*"]]) -> str: """ @@ -159,7 +164,7 @@ class Master: return dir_ def yes_no(self, msg="是否?"): - "是否做某件事的选择框" + """是否做某件事的选择框""" yes_or_no = guizero.yesno("请选择", msg) self.data.temp = yes_or_no return yes_or_no @@ -190,10 +195,11 @@ class Master: if task.hp: left_tasks.append(task) self.tasks = left_tasks + del left_tasks gc.collect() # 释放内存 - def create_delay_tasks(self, task, seconds=1, times=1, args=()): + def create_delay_tasks(self, task, seconds=1, times=1, *args, **kwargs): """ 创建任务队列并添加到角色的任务列表中。\n 延迟seconds秒执行task任务,times代表这个任务执行多少次。\n @@ -206,14 +212,38 @@ class Master: time_count = int(task_time * MAX_FPS) # 计算计数器走到哪一帧 self._task_id += 1 # 将任务加到任务队列 - now_task = Task(self._task_id, time_count, task, args) + now_task = Task(self._task_id, time_count, task, *args, **kwargs) self.tasks.append(now_task) - def remove_taskById(self, id): - "根据id删掉任务" + def remove_tasks_by_tag(self, tag): + """删除所有含有该标签的任务,类似抓违章""" + self.tasks = [task for task in self.tasks if tag not in task.tags] + gc.collect() + + def remain_tasks_by_tag(self, tag): + """只保留所有含有该标签的任务,类似免死金牌""" + self.tasks = [task for task in self.tasks if tag in task.tags] + gc.collect() + + def remove_tasks_by_tags(self, *tags): + """删除精确匹配该标签组合的任务,类似通缉令""" + tags = {tags} if len(tags) == 1 else set(tags) + self.tasks = [task for task in self.tasks if task.tags != tags] + gc.collect() + + def remain_tasks_by_tags(self, *tags): + """只保留精确匹配该标签组合的任务,暂时没想到用途""" + tags = {tags} if len(tags) == 1 else set(tags) + self.tasks = [task for task in self.tasks if task.tags == tags] + gc.collect() + + def remove_taskById(self, id_): + """根据id删掉任务""" + import warnings + warnings.warn("这个方法将来会变成按标签删除任务", DeprecationWarning) del_task = 0 for task in self.tasks: - if task.id == id: + if task.id == id_: del_task = task break del del_task -- Gitee