Compare commits
6 Commits
cc0420d8f4
...
ab01781d91
Author | SHA1 | Date | |
---|---|---|---|
ab01781d91 | |||
ec3cce88c2 | |||
eb5b1fadd5 | |||
b9275ae298 | |||
96fb0526f2 | |||
4b0eb2aa08 |
@ -2,8 +2,7 @@
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"rust-namer",
|
"rust-namer",
|
||||||
"miner"
|
"miner"]
|
||||||
]
|
|
||||||
|
|
||||||
# [miner.profile.release]
|
# [miner.profile.release]
|
||||||
# opt-level = 3
|
# opt-level = 3
|
||||||
|
5
maker-py/.gitignore
vendored
Normal file
5
maker-py/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
env
|
||||||
|
venv
|
||||||
|
|
||||||
|
*__pycache__*
|
||||||
|
|
75
maker-py/camera.py
Normal file
75
maker-py/camera.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
from typing import Tuple, Optional
|
||||||
|
|
||||||
|
# from pyglet.gl import gl
|
||||||
|
from pyglet.math import Mat4, Vec3
|
||||||
|
from pyglet.graphics import Group
|
||||||
|
|
||||||
|
|
||||||
|
class GroupCamera(Group):
|
||||||
|
"""
|
||||||
|
A camera by group
|
||||||
|
can be used by just added to your widget
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
window,
|
||||||
|
order: int = 0,
|
||||||
|
parent: Optional[Group] = None,
|
||||||
|
view_x: Optional[int] = 0,
|
||||||
|
view_y: Optional[int] = 0,
|
||||||
|
zoom: Optional[float] = 1.0,
|
||||||
|
min_zoom: Optional[float] = 1.0,
|
||||||
|
max_zoom: Optional[float] = 1.0,
|
||||||
|
):
|
||||||
|
super().__init__(order=order, parent=parent)
|
||||||
|
self._window = window
|
||||||
|
self._previous_view = None
|
||||||
|
|
||||||
|
self._view_x = view_x or 0
|
||||||
|
self._view_y = view_y or 0
|
||||||
|
self._zoom = zoom or 1.0
|
||||||
|
self.min_zoom = min_zoom or 1.0
|
||||||
|
self.max_zoom = max_zoom or 1.0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view_x(self) -> int:
|
||||||
|
return self._view_x
|
||||||
|
|
||||||
|
@view_x.setter
|
||||||
|
def view_x(self, value: int):
|
||||||
|
self._view_x = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def view_y(self) -> int:
|
||||||
|
return self._view_y
|
||||||
|
|
||||||
|
@view_y.setter
|
||||||
|
def view_y(self, value: int):
|
||||||
|
self._view_y = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def zoom(self) -> float:
|
||||||
|
return min(max(self._zoom, self.min_zoom), self.max_zoom)
|
||||||
|
|
||||||
|
@zoom.setter
|
||||||
|
def zoom(self, value: float):
|
||||||
|
self._zoom = value
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._view_x = 0
|
||||||
|
self._view_y = 0
|
||||||
|
self.zoom = 1
|
||||||
|
|
||||||
|
def set_state(self):
|
||||||
|
self._previous_view = self._window.view
|
||||||
|
|
||||||
|
view = Mat4.from_translation(Vec3(self._view_x, self._view_y, 0))
|
||||||
|
if self._zoom == 1.0:
|
||||||
|
self._window.view = view
|
||||||
|
else:
|
||||||
|
view = view.scale(Vec3(self._zoom, self._zoom, 1))
|
||||||
|
self._window.view = view
|
||||||
|
|
||||||
|
def unset_state(self):
|
||||||
|
self._window.view = self._previous_view
|
106
maker-py/control.py
Normal file
106
maker-py/control.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
from typing import Callable, Union, Tuple, Dict, TYPE_CHECKING, TypeVar, Optional
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pyglet.text import Label
|
||||||
|
from pyglet.window import Window
|
||||||
|
from pyglet.sprite import Sprite
|
||||||
|
from pyglet.shapes import ShapeBase
|
||||||
|
from pyglet.gui.widgets import WidgetBase
|
||||||
|
|
||||||
|
Repositionable = Union[ShapeBase, Label, Sprite, WidgetBase] # just for typing
|
||||||
|
else:
|
||||||
|
Window = TypeVar("Window") # for type checking
|
||||||
|
Repositionable = TypeVar("Repositionable") # for type checking
|
||||||
|
|
||||||
|
Num = Union[int, float]
|
||||||
|
|
||||||
|
PotitionTuple = Union[Tuple[Num, Num], Tuple[Num, Num, Num]]
|
||||||
|
|
||||||
|
CallBackFunc = Callable[[Repositionable, int, int, Window], None]
|
||||||
|
CalculateFunc = Callable[[Repositionable, int, int, Window], PotitionTuple]
|
||||||
|
|
||||||
|
CallBack = Union[CallBackFunc, CalculateFunc]
|
||||||
|
IndexType = Union[int, str]
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"RePositionFrame",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class RePositionFrame:
|
||||||
|
"""A Frame Like Object that allows for repositioning of widgets
|
||||||
|
you can give A function and A widget/shape to let it reposition itself
|
||||||
|
when the function is called
|
||||||
|
|
||||||
|
>>> import pyglet
|
||||||
|
>>> window = pyglet.window.Window(resizable=True)
|
||||||
|
>>> reposition_frame = pyglet.gui.frame.RePositionFrame(window)
|
||||||
|
>>> label = pyglet.text.Label("Hello World", x=0, y=0)
|
||||||
|
>>> b_label = pyglet.text.Label("Hello World with call back", x=0, y=0)
|
||||||
|
>>> def callback(obj, width, height, window):
|
||||||
|
>>> obj.x = width/3
|
||||||
|
>>> obj.y = height/3
|
||||||
|
>>> obj.text = f"Hello World with call back, width: {width}, height: {height}"
|
||||||
|
>>> reposition_frame.add_calculate_func(label, lambda obj, width, height, window: (width/2, height/2, 0))
|
||||||
|
>>> reposition_frame.add_callback_func(b_label, callback)
|
||||||
|
>>> @window.event
|
||||||
|
>>> def on_draw():
|
||||||
|
>>> window.clear()
|
||||||
|
>>> label.draw()
|
||||||
|
>>> b_label.draw()
|
||||||
|
>>> pyglet.app.run()
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, window):
|
||||||
|
window.push_handlers(self)
|
||||||
|
self.window = window
|
||||||
|
self.callback_dict: Dict[IndexType, Tuple[Repositionable, CallBackFunc]] = {}
|
||||||
|
self.calculate_dict: Dict[IndexType, Tuple[Repositionable, CalculateFunc]] = {}
|
||||||
|
|
||||||
|
def add_callback_func(
|
||||||
|
self, obj: Repositionable, func: CallBackFunc, index: Optional[IndexType] = None
|
||||||
|
) -> IndexType:
|
||||||
|
"""Add A callback function to the frame
|
||||||
|
|
||||||
|
:param obj: The object that will be repositioned
|
||||||
|
:param func: The function that will be called
|
||||||
|
:param index: The index of the object
|
||||||
|
"""
|
||||||
|
if index is None:
|
||||||
|
index = hash(obj)
|
||||||
|
self.callback_dict[index] = (obj, func)
|
||||||
|
return index
|
||||||
|
|
||||||
|
def add_calculate_func(
|
||||||
|
self,
|
||||||
|
obj: Repositionable,
|
||||||
|
func: CalculateFunc,
|
||||||
|
index: Optional[IndexType] = None,
|
||||||
|
) -> IndexType:
|
||||||
|
"""Add A calculate function to the frame
|
||||||
|
|
||||||
|
:param obj: The object that will be repositioned
|
||||||
|
:param func: The function that will be called
|
||||||
|
:param index: The index of the object
|
||||||
|
"""
|
||||||
|
if index is None:
|
||||||
|
index = hash(obj)
|
||||||
|
self.calculate_dict[index] = (obj, func)
|
||||||
|
return index
|
||||||
|
|
||||||
|
def remove_callback_func(self, index: IndexType):
|
||||||
|
if index in self.callback_dict:
|
||||||
|
self.callback_dict.pop(index)
|
||||||
|
|
||||||
|
def remove_calculate_func(self, index: IndexType):
|
||||||
|
if index in self.calculate_dict:
|
||||||
|
self.calculate_dict.pop(index)
|
||||||
|
|
||||||
|
def on_resize(self, width: int, height: int):
|
||||||
|
"""Call all the functions when the window is resized"""
|
||||||
|
for _, (obj, func) in self.callback_dict.items():
|
||||||
|
func(obj, width, height, self.window)
|
||||||
|
|
||||||
|
for _, (obj, func) in self.calculate_dict.items():
|
||||||
|
obj.position = func(obj, width, height, self.window) # type: ignore
|
317
maker-py/main.py
Normal file
317
maker-py/main.py
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
import pyglet
|
||||||
|
from pyglet.font import load as load_font
|
||||||
|
from pyglet.text import Label
|
||||||
|
from pyglet.gui import TextEntry
|
||||||
|
from pyglet.window import Window
|
||||||
|
from pyglet.gl import glClearColor
|
||||||
|
from pyglet.shapes import Rectangle
|
||||||
|
from pyglet.graphics import Batch, Group
|
||||||
|
|
||||||
|
from control import RePositionFrame
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
gray = (200, 200, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class NumStatus(IntEnum):
|
||||||
|
"""未被选中"""
|
||||||
|
|
||||||
|
wait = 8
|
||||||
|
|
||||||
|
# 血量
|
||||||
|
hp = 0
|
||||||
|
# 攻击
|
||||||
|
attack = 1
|
||||||
|
# 防御
|
||||||
|
defense = 2
|
||||||
|
# 速度
|
||||||
|
speed = 3
|
||||||
|
# 敏捷
|
||||||
|
agility = 4
|
||||||
|
# 魔法
|
||||||
|
magic = 5
|
||||||
|
# 抗性
|
||||||
|
resistance = 6
|
||||||
|
# 智慧
|
||||||
|
wisdom = 7
|
||||||
|
|
||||||
|
|
||||||
|
class NumWidget:
|
||||||
|
def __init__(self, num: int, batch: Batch, group: Group, x: int, y: int) -> None:
|
||||||
|
self._y = y
|
||||||
|
self._x = x
|
||||||
|
font = load_font("黑体", 15)
|
||||||
|
font_height = font.ascent - font.descent
|
||||||
|
self.label_group = Group(parent=group, order=20)
|
||||||
|
self.background_group = Group(parent=group, order=10)
|
||||||
|
self.label = Label(
|
||||||
|
x=x + 17,
|
||||||
|
y=y + 7,
|
||||||
|
color=(0, 0, 0, 255),
|
||||||
|
text=f"{num}",
|
||||||
|
font_name="黑体",
|
||||||
|
font_size=15,
|
||||||
|
width=35,
|
||||||
|
height=font_height + 4,
|
||||||
|
anchor_x="center",
|
||||||
|
batch=batch,
|
||||||
|
group=self.label_group,
|
||||||
|
)
|
||||||
|
self.background = Rectangle(
|
||||||
|
x=x,
|
||||||
|
y=y,
|
||||||
|
width=35,
|
||||||
|
height=font_height + 4,
|
||||||
|
color=gray,
|
||||||
|
batch=batch,
|
||||||
|
group=self.background_group,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self) -> int:
|
||||||
|
return int(self.label.text)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x(self) -> int:
|
||||||
|
return self._x
|
||||||
|
|
||||||
|
@x.setter
|
||||||
|
def x(self, value: int) -> None:
|
||||||
|
self._x = value
|
||||||
|
self.label.x = value + 17
|
||||||
|
self.background.x = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def y(self) -> int:
|
||||||
|
return self._y
|
||||||
|
|
||||||
|
@y.setter
|
||||||
|
def y(self, value: int) -> None:
|
||||||
|
self._y = value
|
||||||
|
self.label.y = value + 7
|
||||||
|
self.background.y = value
|
||||||
|
|
||||||
|
def aabb(self, x: int, y: int) -> bool:
|
||||||
|
# 判断是否在范围内
|
||||||
|
width = 35
|
||||||
|
height = 20
|
||||||
|
return self.x <= x <= self.x + width and self.y <= y <= self.y + height
|
||||||
|
|
||||||
|
|
||||||
|
def middle_widget(一: NumWidget, 二: NumWidget, 三: NumWidget) -> int:
|
||||||
|
"""返回中间值"""
|
||||||
|
a, b, c = 一.value, 二.value, 三.value
|
||||||
|
if a < b < c or c < b < a:
|
||||||
|
return b
|
||||||
|
if b < a < c or c < a < b:
|
||||||
|
return a
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(Window):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(
|
||||||
|
resizable=True,
|
||||||
|
width=800,
|
||||||
|
height=600,
|
||||||
|
caption="Maker",
|
||||||
|
vsync=True,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.main_batch = Batch()
|
||||||
|
self.main_group = Group()
|
||||||
|
self.main_frame = RePositionFrame(self)
|
||||||
|
|
||||||
|
self.name_info_displays = {}
|
||||||
|
self.init_name_dispaly()
|
||||||
|
self.init_name_diy()
|
||||||
|
|
||||||
|
def init_name_diy(self) -> None:
|
||||||
|
"""
|
||||||
|
初始化 名字自定义
|
||||||
|
"""
|
||||||
|
# 0-255
|
||||||
|
self.num_dict = {}
|
||||||
|
self.num_batch = Batch()
|
||||||
|
self.num_group = Group(parent=self.main_group, order=10)
|
||||||
|
# 从大到小
|
||||||
|
num_group = Group(parent=self.num_group, order=10)
|
||||||
|
for i in range(256):
|
||||||
|
num_name = NumWidget(
|
||||||
|
num=i, batch=self.num_batch, group=num_group, x=40, y=50
|
||||||
|
)
|
||||||
|
self.num_dict[i] = num_name
|
||||||
|
self.num_hints = []
|
||||||
|
# 每个部分的取值提示
|
||||||
|
font = load_font("黑体", 15)
|
||||||
|
font_height = font.ascent - font.descent
|
||||||
|
num_hint_group = Group(parent=self.main_group, order=20)
|
||||||
|
# hp: 3~6 len = 4
|
||||||
|
# 要覆盖住 4 个数字
|
||||||
|
self.num_hints.append(
|
||||||
|
Rectangle(
|
||||||
|
x=40 - 3,
|
||||||
|
y=self.height - (173 + 30 * 6),
|
||||||
|
width=41,
|
||||||
|
height=(font_height + 4 + 5) * 4,
|
||||||
|
# 浅蓝色背景
|
||||||
|
color=(0, 0, 255, 100),
|
||||||
|
batch=self.num_batch,
|
||||||
|
group=num_hint_group,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# 剩下 7 个, 每个都是中间
|
||||||
|
for x in range(1, 8):
|
||||||
|
self.num_hints.append(
|
||||||
|
Rectangle(
|
||||||
|
x=40 - 3 + (65 * x),
|
||||||
|
y=self.height - (173 + 30),
|
||||||
|
width=41,
|
||||||
|
height=font_height + 4 + 5,
|
||||||
|
# 浅蓝色背景
|
||||||
|
color=(0, 0, 255, 100),
|
||||||
|
batch=self.num_batch,
|
||||||
|
group=num_hint_group,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 0-9 sorted
|
||||||
|
# 取前9个拿到血量这边
|
||||||
|
# index 3~6 之和 + 154 = 血量
|
||||||
|
# index 10~12 中值 + 36 = 攻击
|
||||||
|
# index 13~15 中值 + 36 = 防御
|
||||||
|
# index 16~18 中值 + 36 = 速度
|
||||||
|
# index 19~21 中值 + 36 = 敏捷
|
||||||
|
# index 22~24 中值 + 36 = 魔法
|
||||||
|
# index 25~27 中值 + 36 = 抗性
|
||||||
|
# index 28~30 中值 + 36 = 智慧
|
||||||
|
self.display_dict: dict[NumStatus, list[NumWidget]] = {
|
||||||
|
NumStatus.hp: [self.num_dict[i] for i in range(0, 10)],
|
||||||
|
NumStatus.attack: [self.num_dict[i] for i in range(10, 13)],
|
||||||
|
NumStatus.defense: [self.num_dict[i] for i in range(13, 16)],
|
||||||
|
NumStatus.speed: [self.num_dict[i] for i in range(16, 19)],
|
||||||
|
NumStatus.agility: [self.num_dict[i] for i in range(19, 22)],
|
||||||
|
NumStatus.magic: [self.num_dict[i] for i in range(22, 25)],
|
||||||
|
NumStatus.resistance: [self.num_dict[i] for i in range(25, 28)],
|
||||||
|
NumStatus.wisdom: [self.num_dict[i] for i in range(28, 31)],
|
||||||
|
NumStatus.wait: [self.num_dict[i] for i in range(31, 256)],
|
||||||
|
}
|
||||||
|
self.update_num_display()
|
||||||
|
|
||||||
|
def update_num_display(self) -> None:
|
||||||
|
# sort hp
|
||||||
|
self.display_dict[NumStatus.hp].sort(key=lambda x: x.value)
|
||||||
|
# sort wait
|
||||||
|
self.display_dict[NumStatus.wait].sort(key=lambda x: x.value)
|
||||||
|
|
||||||
|
for status, widgets in self.display_dict.items():
|
||||||
|
num_count = 0
|
||||||
|
for widget in widgets:
|
||||||
|
widget.x = 40 + (65 * status.value)
|
||||||
|
widget.y = self.height - (170 + 30 * num_count)
|
||||||
|
num_count += 1
|
||||||
|
# 计算数据
|
||||||
|
hp = sum(widget.value for widget in self.display_dict[NumStatus.hp][3:6]) + 154
|
||||||
|
attack = middle_widget(*self.display_dict[NumStatus.attack]) + 36
|
||||||
|
defense = middle_widget(*self.display_dict[NumStatus.defense]) + 36
|
||||||
|
speed = middle_widget(*self.display_dict[NumStatus.speed]) + 36
|
||||||
|
agility = middle_widget(*self.display_dict[NumStatus.agility]) + 36
|
||||||
|
magic = middle_widget(*self.display_dict[NumStatus.magic]) + 36
|
||||||
|
resistance = middle_widget(*self.display_dict[NumStatus.resistance]) + 36
|
||||||
|
wisdom = middle_widget(*self.display_dict[NumStatus.wisdom]) + 36
|
||||||
|
gather = sum(
|
||||||
|
(int(hp / 3), attack, defense, speed, agility, magic, resistance, wisdom)
|
||||||
|
)
|
||||||
|
self.name_info_displays[
|
||||||
|
"label"
|
||||||
|
].text = f"HP|{hp} 攻|{attack} 防|{defense} 速|{speed} 敏|{agility} 魔|{magic} 抗|{resistance} 智|{wisdom} 八围:{gather}"
|
||||||
|
# 更新提示框
|
||||||
|
# hp 提示框是固定的
|
||||||
|
self.num_hints[0].y = self.height - (173 + 30 * 6)
|
||||||
|
# 剩下的需要先判断那个是中间的
|
||||||
|
for i in range(1, 8):
|
||||||
|
data = sorted(enumerate(x.value for x in self.display_dict[NumStatus(i)]))
|
||||||
|
middle_index = data[1][0]
|
||||||
|
self.num_hints[i].y = self.height - (173 + 30 * middle_index)
|
||||||
|
|
||||||
|
def init_name_dispaly(self) -> None:
|
||||||
|
"""
|
||||||
|
初始化 名字显示 这块内容
|
||||||
|
"""
|
||||||
|
name_group = Group(parent=self.main_group)
|
||||||
|
self.name_info_displays["group"] = name_group
|
||||||
|
|
||||||
|
font = load_font("黑体", 20)
|
||||||
|
font_height = font.ascent - font.descent
|
||||||
|
name_rec = Rectangle(
|
||||||
|
x=20,
|
||||||
|
y=self.height - 135,
|
||||||
|
width=600, # 在 callback 中定义
|
||||||
|
height=font_height,
|
||||||
|
# 颜色: 灰色
|
||||||
|
color=gray,
|
||||||
|
batch=self.main_batch,
|
||||||
|
group=name_group,
|
||||||
|
)
|
||||||
|
name_info_label = Label(
|
||||||
|
x=25,
|
||||||
|
y=self.height - 127,
|
||||||
|
text="HP|{} 攻|{} 防|{} 速|{} 敏|{} 魔|{} 抗|{} 智|{} 八围:{}",
|
||||||
|
width=400,
|
||||||
|
multiline=False,
|
||||||
|
font_name="黑体",
|
||||||
|
font_size=15,
|
||||||
|
color=(0, 0, 0, 255),
|
||||||
|
batch=self.main_batch,
|
||||||
|
group=name_group,
|
||||||
|
)
|
||||||
|
name_entry = TextEntry(
|
||||||
|
x=40,
|
||||||
|
y=self.height - 100,
|
||||||
|
width=200,
|
||||||
|
text="x@x",
|
||||||
|
# 灰色背景
|
||||||
|
color=(*gray, 255),
|
||||||
|
text_color=(0, 0, 0, 255),
|
||||||
|
batch=self.main_batch,
|
||||||
|
group=name_group,
|
||||||
|
)
|
||||||
|
|
||||||
|
def rec_callback(rec, width: int, height: int, window: Window):
|
||||||
|
# rec.x = 20
|
||||||
|
rec.y = height - 135
|
||||||
|
|
||||||
|
self.main_frame.add_callback_func(name_rec, rec_callback)
|
||||||
|
self.main_frame.add_calculate_func(
|
||||||
|
name_info_label,
|
||||||
|
lambda obj, width, height, window: (25, height - 127, 0),
|
||||||
|
)
|
||||||
|
self.main_frame.add_calculate_func(
|
||||||
|
name_entry,
|
||||||
|
lambda obj, width, height, window: (40, height - 100),
|
||||||
|
)
|
||||||
|
self.push_handlers(name_entry)
|
||||||
|
self.name_info_displays["rec"] = name_rec
|
||||||
|
self.name_info_displays["label"] = name_info_label
|
||||||
|
self.name_info_displays["entry"] = name_entry
|
||||||
|
|
||||||
|
def on_draw(self) -> None:
|
||||||
|
self.clear()
|
||||||
|
self.main_batch.draw()
|
||||||
|
self.num_batch.draw()
|
||||||
|
|
||||||
|
def on_resize(self, width, height):
|
||||||
|
super().on_resize(width, height)
|
||||||
|
self.update_num_display()
|
||||||
|
|
||||||
|
def start(self) -> None:
|
||||||
|
pyglet.app.run(interval=1 / 30)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
window = MainWindow()
|
||||||
|
glClearColor(1, 1, 1, 1)
|
||||||
|
window.start()
|
Loading…
Reference in New Issue
Block a user