cjjJasonchen 发表于 2023-8-15 14:05:38

【pygameGUI 1.0】教程 —— 【已完结】 8/17

本帖最后由 cjjJasonchen 于 2023-8-22 13:32 编辑

pygameGUI教程


前言:
      大家都知道,pygame哪里都好,就是用起来太麻烦了,控件什么的甚至完全没有。。。{:10_282:}
      于是这次我写了一个专门用来给pygame写gui的库{:10_297:}
      源代码:源码及简单演示
      
      首先,阅读本教程之前,请你确保自己有一定的python基础,
      并且能够熟练至少会背游戏最小循环的使用pygame。



      这次我写了三个组件供玩家使用:Label、Button、Frame
      
      Label:生成简单的单行文本,可以作为参数传给Button作为Button上显示的文字
                内部的文本可以在创建之后通过 set() 方法多次改变

      Button:一个简单的按钮,拥有普通、选中(鼠标位于上方)、按下(鼠标点击)三种状态,
                被完成一次单机后(鼠标在按钮上按下,并且在按钮上松开)会调用command中的函数,
                command中的函数暂时不支持传入参数

      Frame: 一个简单的框架结构,你可以将Label组件和Button放在上面,以便于设定位置,
                此组件还有一个正在实验的用法:生成一个窗口,
                但是目前这个窗口没有阻塞控制和阻断其他进程的效果,点击窗口中的部件可能会导致触发被窗口遮盖的部件
      
      


pygameGUI最小循环




首先,掏出珍藏已久的pygame框架:作者使用的pygame框架



把pygameGUI和放在同一目录下:





导入库:
import pygame
import sys
import pygameGUI as pgui
from pygame.locals import *

创建gui组:guis = pgui.Group()

在主循环的开头添加:

    pos = pygame.mouse.get_pos()
    rel = pygame.mouse.get_rel()

得到鼠标实时位置和移动


在61行“#鼠标”处,修改:

      # 鼠标
      if event.type == MOUSEBUTTONDOWN:
            if event.button == 1:
                guis.press()

      if event.type == MOUSEBUTTONUP:
            if event.button == 1:
                guis.release()



guis会通过自动获取位置来得知你单击的是哪个组件

在第84行及之后的改为:

    guis.move()

    #画背景
    screen.fill(bg_color)   

    # 刷新guis
    guis.update(pos,rel)

    # 画guis
    guis.draw(screen)
   

    # 刷新界面
    pygame.display.update()

移动所有被拖动的组件,然后刷新,绘制



好的,看看完整代码~

import pygame
import sys
import pygameGUI as pgui
from pygame.locals import *


# 颜色常量
WHITE = (255,255,255)
BLACK = (0,0,0)

size = width, height = 800,600

screen = pygame.display.set_mode(size)

pygame.display.set_caption("pygame-GUI-Label")

guis = pgui.Group()


clock = pygame.time.Clock()

delay = 60 # 延时计时器(1秒)

# 是否全屏
fullscreen = False
screen_change = False

# 背景颜色设定
bg_color = WHITE

running = True

while running:
    pos = pygame.mouse.get_pos()
    rel = pygame.mouse.get_rel()

    # 设定帧数
    clock.tick(60)

    # 延时计时器刷新
    if delay == 0:
      delay = 60

    delay -= 1

    # 检测是否全屏
    if fullscreen and screen_change:
      screen = pygame.display.set_mode(size,FULLSCREEN,HWSURFACE)
      screen_change = False
    elif screen_change:
      screen = pygame.display.set_mode(size)
      screen_change = False

    # 事件检测
    for event in pygame.event.get():
      if event.type == QUIT:
            pygame.quit()
            sys.exit()

      # 鼠标
      if event.type == MOUSEBUTTONDOWN:
            if event.button == 1:
                guis.press()

      if event.type == MOUSEBUTTONUP:
            if event.button == 1:
                guis.release()

      # 按键按下事件
      if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
               
            #F11切换全屏
            if event.key == K_F11:
                fullscreen = not fullscreen
                screen_change = True

      # 按键抬起事件
      if event.type == KEYUP:
            pass

    guis.move()

    #画背景
    screen.fill(bg_color)   

    # 刷新guis
    guis.update(pos,rel)

    # 画guis
    guis.draw(screen)
   

    # 刷新界面
    pygame.display.update()




variablepygameGUI专用变量对象


通常,Variable被用来接受Button组件中Command的返回值



Variable

      __init__(value=None)
                value 可以是各种python的变量

      get()
      返回变量的值

      set(value)
      设置变量的值
                value 可以是各种python的变量





UI类


UI(pygame.sprite.Sprite)

一些每个ui组件都要具备的方法和调用时机
    def press(self,pos):
      "鼠标按下时调用"
      pass

    def release(self,pos):
      "鼠标松开时调用"
      pass

    def move(self,rel):
      "每帧调用,被拖动的组件判断是否需要移动"
      pass



set_pos(location="center",position=)

这是一种更高级的设置位置的方法,可以让你更方便的设置组件的位置

      location:
                "center"设置中心位置
                "right"    设置左侧位置
                "left"      设置右侧位置
                "top"             设置顶部位置
                "bottom"设置底部位置

      pos:
                当location为"center"时,接受一个列表或者元组,
                其他时候都只接受int






Label 单行文本


Label         (master=None, pos=,text=" ",font=(None,15),antialias=True,color=,background=None,alpha=255)

      master : 该对象绘制的对象(跟随移动,而不是真的绘制在上面),如果None就是绘制在screen上 -> Frame
      pos : 左上角位置 ->
      text : 文本 -> str
      font : 字体和字号 -> (字体(.ttf文件),字号(int))
      antialias : 抗锯齿 -> bool
      color : 字体颜色 -> (RGB)
      background : 背景颜色 -> (RGB) None表示透明
      alpha : 透明度 -> int 0到255


方法:

set_text      (text)

      text : 新的文本 -> str


set_pos : 更多设置位置的方法   ————>   见上方 ”基础知识-UI类“




举个例子{:10_271:}


我们先从最简单的出发:

在创建guis组后面,打上

# 生成控件
l = pgui.Label(text="I am Label!")
guis.add(l)

然后就可以看到



怎么样!是不是非常简单!是不是非常方便!


然后我们加一点点自定义:
# 生成控件
l = pgui.Label(
                text="I am Label!",
                pos=,
                font=("和音体.ttf",30),
                color=(0,200,180),
                )

然后就可以看到




设置一下颜色,改一下大小字体和位置,一下子就变得美观啦!


设置一下背景试试:
l = pgui.Label(
                text="I am Label!",
                pos=,
                font=("和音体.ttf",30),
                color=(100,255,200),
                background=(255,255,200)
                )

然后就可以看到



这个组件是不是比原版的font用起来舒服多了{:10_297:}




Button 简易按钮

是不是觉得太简单,甚至有点简陋{:10_307:} ,既然如此那就上难度


Button      (master=None,pos=, draw=, text=None, pad=, size=, command=None, variable=None,alpha=255)

      master : 该对象绘制的对象(跟随移动,而不是真的绘制在上面),如果None就是绘制在screen上 -> Frame

      pos : 该对象左上角的坐标位 ->


      draw :
            第一种使用方法:按钮填充该颜色 ->

            第二种使用方法:按钮的绘制函数 draw(image) -> def draw(image):
                                                                                        image.fill((255,0,0))
                                                                                        pygame.draw.rect(image,......
                                                                                             pygame.draw.circle(image,......

                注意!draw函数中禁止给image赋值


      size : 大小,如果设定了text值,则该属性无效 ->

      text : 绘制在draw函数绘制的图像上的文字 -> Text对象

      pad : 当设定text值时有效,将按钮的大小(size)设定为Text对象的(width+pad,height+pad) ->

      command : 当该对象被点击时调用的函数 -> callback(函数名)

      variable : 当该对象被点击时,command中函数的返回值 -> Variable

      alpha : 透明度 ->int (0到255之间)

      set_choose_image             (self,draw,size=,text=None,pad=):
                改变鼠标放在按钮上的样式
               
                属性同上
               
                注意!重新设置的图像初始image是一张透明的image,
                不是鼠标普通状态下的图片,所以如有需要,请不要忘记设置size,text等。。。

      set_down_image                  (self,draw,size=,text=None,pad=)
                改变鼠标点击按钮时的样式

                属性同上,注意事项同上


举个例子{:10_271:}



老规矩,从最简单的开始,生成一个默认的按钮:

# 生成控件
b1 = pgui.Button(
                pos=,
                )
guis.add(b1)

然后就可以看到



生成了一个默认按钮,

把鼠标移上去,按钮高亮了

点击鼠标左键,按钮变暗了

以上就是按钮的三种状态,材质全都可以自定义更改


我们小小自定义一下Button的普通材质:

# 生成控件
text=pgui.Label(
                text="I'm Button",
                color=(100,255,200),
                font=(None,20)
                )
               
b1 = pgui.Button(
                pos=,
                text=text,
                pad=,
                draw=(200,50,200),
                )
guis.add(b1)

首先创建一个Label ,然后传给Button,效果如下:




然后我们试一下通过draw的第二种使用方法来修改选择状态的材质和按下状态的材质:

把代码加在后头

# 设置选中颜色
def draw(image):
    image.fill((255,255,255))
    rect=image.get_rect()
    pygame.draw.rect(image,color=(0,0,0),rect=rect,width=2)
text=pgui.Label(
                text="I'm Button",
                color=(0,0,0),
                font=(None,20)
                )
b1.set_choose_image(draw=draw,text=text,pad=)

# 设置按下颜色
def draw(image):
    image.fill((0,0,0))
text=pgui.Label(
                text="I'm Button",
                color=(255,255,255),
                font=(None,20)
                )
b1.set_down_image(draw=draw,text=text,pad=)

来看看效果吧~



怎么样是不是简简单单!{:10_298:}


接下来我们来试试让按下的按钮变大,并且给他一个command参数

首先,再生成一个按钮:
text=pgui.Label(
                text="Click me",
                font=(None,20)
                )
def callback():
    print("hello world!")
b2 = pgui.Button(
                text=text,
                pad=,
                command=callback,
                )
guis.add(b2)





可以看到,已经打印了"hello world!"


然后我们通过 set_pos方法 (该方法见UI类)

来设置一下这个按钮的位置: 在按钮1的右边,高度与按钮1相同

b2.set_pos("left",b1.rect.right+10)
b2.set_pos("top",b1.rect.top)



效果不错,是我想象中的样子{:10_298:}

然后我们来设置一下按下状态的材质:

text = pgui.Label(text="Click me",font=(None,25))
b2.set_down_image(text=text,pad=,draw=(180,180,180))



嘿嘿,成功啦!{:10_298:} {:10_298:} {:10_298:}

真是太方便啦!

抛砖引玉

这是一个很简单的Button与Label联动的例子,先看代码

注意:callback函数,variable对象,label中的值

首先,我们先做一个按钮:
# 生成控件
var1 = pgui.Variable("0")
t = pgui.Label(text="1",font=(None,20))
def callback():
    return "1"
b1 = pgui.Button(
                pos = ,
                text=t,
                draw=(100,255,255),
                pad=,
                command=callback,
                variable=var1
                )
guis.add(b1)


把第二个按钮放在第一个按钮的边上:

var2 = pgui.Variable("0")
t = pgui.Label(text="2",font=(None,20))
def callback():
    return "2"

b2 = pgui.Button(
                text=t,
                draw=(100,255,255),
                pad=,
                command=callback,
                variable=var2
                )
b2.set_pos("left",b1.rect.right+10)
b2.set_pos("top",b1.rect.top)
guis.add(b2)

再做两个label,把他们摆好:

l1 = pgui.Label(text="0",font=(None,20),background=(255,255,100))
guis.add(l1)
l1.set_pos("top",b1.rect.bottom+10)
l1.set_pos("right",b1.rect.right)

l2 = pgui.Label(text="0",font=(None,20),background=(255,100,255))
guis.add(l2)
l2.set_pos("top",l1.rect.bottom+10)
l2.set_pos("right",b1.rect.right)


再放上最后一个按钮,摆好:

t = pgui.Label(text="OK",font=(None,20))
def callback():
    l1.set_text(var1.get()+var2.get())
    l2.set_text(str(int(var1.get())+int(var2.get())))
b3 = pgui.Button(
                pos = ,
                text=t,
                draw=(100,255,255),
                pad=,
                command=callback,
                )
b3.set_pos("left",b2.rect.right+10)
b3.set_pos("top",b1.rect.top)
guis.add(b3)



最后的结果是两行组件:
      一行Button
      一行Label

如下图:



依次点击上面的按钮,发现label中的文本发生了变化:




我们根据代码中的逻辑可以看出:

l1中的文本为var1和var2的拼接

l2中的文本为var1和var2的和



小试牛刀

我们目前已经解锁了两个组件:Label 、Button{:10_297:}

我们可以通过他们配合variable轻松的写一个计算器,来尝试一下吧~{:10_257:}


要把练习结果发在评论区哦~{:10_334:}

哪怕只作出来了一半也要发出来哦!{:10_295:}


答案会在教程末尾公布!



按钮中加入图片

先把素材拿好



看代码吧~

# 生成控件

def draw(image):
    image.blit(pygame.image.load("火柴人.png"),)
               
b1 = pgui.Button(
                pos=,
                draw=draw,
                size=,
                )
guis.add(b1)

效果:






神奇的Effect


Effect

      pygame-GUI专用的默认特效,提供了一些预设的效果给Button和Frame使用,
      让你的作品轻松的变得美观,虽然现在只有4个效果,但以后一定会有更多让你惊艳的效果

      使用方法:
                输入image,会返回带有效果的image对象
                把输出的image对象,贴在原本的image上


      light                        (image=None,color=(255,255,255),width=0,alpha=(50))
                生成高亮效果

                width : 同pygame中draw的使用方法,决定了是完全填充还是只画边框
                其他的同上

      
      dark                        (image=None,color=(0,0,0),width=0,alpha=(50))
                生成黑暗效果

                属性: 同上


      raised                  (image=None,light_color=(255,255,255),dark_color = (0,0,0),alpha=255,width=3)
                生成突起效果

                light_color : 明亮的颜色 -> (RGB)
                dark_color : 阴影的颜色 -> (RGB)
                width : 突起多少个像素 -> int   普通大小的按钮不建议超过10个像素,一般2-5个像素就足够了
                其他属性 : 同上

      sunken                  (light_color=(255,255,255),dark_color = (0,0,0),alpha=255,width=3)
                生成凹陷效果

                属性 :同上


举个例子{:10_271:}


这里给大家一个使用Effect中突起和凹陷效果的例子:

案例使用的是前面button的栗子


# 立体按钮
text = text=pgui.Label(
                text="I'm 3D Button",
                font=(None,20)
                )
def draw(image):
    image.fill((175,175,175))
    image.blit(pgui.Effect.raised(image),)
b3 = pgui.Button(
                text=text,
                pad=,
                draw=draw,
                )
guis.add(b3)
b3.set_pos("left",b2.rect.right+10)
b3.set_pos("top",b2.rect.top)

可以看到按钮的普通效果已经变为了”凸起“



然后设置一下它的其他两个效果:
def draw(image):
    image.fill((175,175,175))
    image.blit(pgui.Effect.raised(image),)
    image.blit(pgui.Effect.light(image),)
b3.set_choose_image(draw,text=text,pad=)

def draw(image):
    image.fill((175,175,175))
    image.blit(pgui.Effect.sunken(image),)
b3.set_down_image(draw,text=text,pad=)


看看效果~



真不错欸{:10_298:}






Frame 框架结构


注意!此UI类目前处于测试阶段,很多东西以后的版本可能会有比较大的变动

Frame                   (master=None, pos=,size=,draw=(190,190,190), title=False)      

        生成一个sprite对象 -> 类似与tkinter的frame,但是有更多使用方法,
        例如当成窗口,成为某个组件的一部分

        master : 该对象绘制的对象(跟随移动,而不是真的绘制在上面),如果None就是绘制在screen上 -> Frame
        pos : 左上角位置
      size : 大小
      draw :
            1、在这个部件中填充该颜色 -> / (R,G,B)
            2、输入一个的绘制函数 draw(image) -> def draw(image):
                                                image.fill((255,0,0))
                                                pygame.draw.rect(image,......
                                                pygame.draw.circle(image,......
      title : 是否有标题 -> bool

        set_close_button               (pos=,draw=_default_close_button_draw,text=None,pad=,size=,alpha=255)
                设置close_button的函数 返回Button组件

                draw :None时会生成一个红色的大叉
                其他属性 : 与Buton组件相同

       

        set_title               (text=Label(text="pygame-GUI",font=(None,15),color=(0,0,0)),pad = ,draw=(255,255,255))
                设置title的函数

                如果title为True会自动生成默认的标题

                draw : 在标题栏区域内绘制,其他同上
                其他属性同上



举个例子{:10_271:}


还是老规矩,从最简单的开始~

# 生成控件
f1 = pgui.Frame(pos=,draw=(0,0,0),size=)
guis.add(f1)


可以看到,出现了一个黑色的方块


然后做一个variable变量:num:

num = pgui.Variable(0)


我们往里面塞一些按钮和文本对象:

按钮1:
def draw(image):
    image.fill((200,200,200))
    pygame.draw.polygon(image,color=(0,0,0),points=[,,])
def callback():
    if num.get() < 100:
      num.set(num.get()+5)
        l1.set_text(str(num.get()))
b1 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b1.set_pos("right",f1.rect)
guis.add(b1)

按钮2:
def draw(image):
    image.fill((200,200,200))
    pygame.draw.polygon(image,color=(0,0,0),points=[,,])
def callback():
    if num.get() > 0:
      num.set(num.get()-5)
        l1.set_text(str(num.get()))
b2 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b2.set_pos("right",f1.rect)
b2.set_pos("bottom",f1.rect)
guis.add(b2)

然后放上去一个Label:
l1 = pgui.Label(master=f1,text=str(num.get()),font=(None,40),color=(255,255,255))
guis.add(l1)

然后我们看看效果:




非常好!!一个建议的数值输入器就完成啦!{:10_298:} {:10_298:} {:10_298:}

通过num.get()就可以得到输入的数哦!{:10_279:}


我们来尝试一下改变他的位置:

f1.set_pos("right",width)

可以看到,整个数值编译器一块儿挪到最右边啦~


是不是超级方便!!!{:10_254:}

至此,我们完成了一个自定义的组件!是不是很有成就感!{:10_298:}

=============================================================
小美化


然后我们稍稍美化一下,用Effect!

先看效果:



先动动脑子,再想代码哦!


# 生成控件
f1 = pgui.Frame(pos=,draw=(85,85,85),size=)
guis.add(f1)


num = pgui.Variable(0)

def draw(image):
    image.fill((200,200,200))
    pygame.draw.polygon(image,color=(0,0,0),points=[,,])
    image.blit(pgui.Effect.raised(image),)
def callback():
    if num.get() < 100:
      num.set(num.get()+5)
      l1.set_text(str(num.get()))
b1 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b1.set_pos("right",f1.rect)

def draw(image):
    image.fill((200,200,200))
    pygame.draw.polygon(image,color=(0,0,0),points=[,,])
    image.blit(pgui.Effect.sunken(image),)
b1.set_down_image(draw=draw,size=)
guis.add(b1)

def draw(image):
    image.fill((200,200,200))
    pygame.draw.polygon(image,color=(0,0,0),points=[,,])
    image.blit(pgui.Effect.raised(image),)
def callback():
    if num.get() > -0:
      num.set(num.get()-5)
      l1.set_text(str(num.get()))
b2 = pgui.Button(master=f1,size=,draw=draw,command=callback)
b2.set_pos("right",f1.rect)
b2.set_pos("bottom",f1.rect)
def draw(image):
    image.fill((200,200,200))
    pygame.draw.polygon(image,color=(0,0,0),points=[,,])
    image.blit(pgui.Effect.sunken(image),)
b2.set_down_image(draw,size=)
guis.add(b2)

def draw(image):
    image.fill((100,100,100))
    image.blit(pgui.Effect.sunken(image,width=5),)
f2 = pgui.Frame(master=f1,size=(f1.rect-15,f1.rect),draw=draw)
guis.add(f2)
l1 = pgui.Label(pos=(6,3),master=f2,text=str(num.get()),font=(None,40),color=(255,255,255))
guis.add(l1)




弹窗例子{:10_271:}



注意!此操作目前处于测试阶段,很多东西以后的版本可能会有比较大的变动

老规矩,我们从最简单的开始{:10_315:}

# 生成控件

f1 = pgui.Frame(pos=,draw=(85,85,85),size=,title=True)
guis.add(f1)



然后我们设置一下标题:

title = pgui.Label(text="pygameGUI-Frame-Window",font=(None,20))
f1.set_title(text=title,pad=)


拖动一下试试:



然后我们给他加一个关闭按钮:

b = f1.set_close_button()
b.set_pos("right",f1.rect)
guis.add(b)



不错!我们往里面塞点东西试试:
Label:
l = pgui.Label(master=f1,pos=(10,35),text="I am Frame!",font=(None,20),color=(255,255,255))
guis.add(l)

Button:
l = pgui.Label(master=f1,pos=(10,35),text="click me!",font=(None,20),color=(255,255,255))
b = pgui.Button(master=f1,pos=(10,60),text=l,pad=)
guis.add(b)



可以看到,再拖动的时候,其他组件跟着一起动了,关闭的时候,其他组件一起消失了{:10_315:}

是不是很有趣{:10_328:}

小试牛刀答案:计算器

好啦,万众瞩目的计算器参考答案来啦!

参考答案





未来的设想

Frame组件不再负责窗口的创建,而是由新的组件代替,这个组件可以由暂停其他组件的效果

Button里command的函数可以支持传参

新增一些更强大的按钮组件,如:支持双击,长按。。。

新增一个滑块组件,可以与Frame搭配,制作成滑条



正在更新。。。



更新中。。。。

您都看到这了给个评分在走呗{:10_257:}


歌者文明清理员 发表于 2023-8-15 14:10:18

支持,另外求开源

cjjJasonchen 发表于 2023-8-15 14:12:30

歌者文明清理员 发表于 2023-8-15 14:10
支持,另外求开源

有空会开源的

歌者文明清理员 发表于 2023-8-15 14:13:49

cjjJasonchen 发表于 2023-8-15 14:12
有空会开源的

https://www.zhihu.com/question/33573424

cjjJasonchen 发表于 2023-8-15 14:16:32

歌者文明清理员 发表于 2023-8-15 14:13
https://www.zhihu.com/question/33573424

{:10_282:}
我一不会魔法上网(fanqiang),二没学过git

别着急

多少给我一点时间吧

歌者文明清理员 发表于 2023-8-15 14:22:38

cjjJasonchen 发表于 2023-8-15 14:16
我一不会魔法上网(fanqiang),二没学过git

别着急


要是 Github 要魔法,你当我 v*n 限额还没到?

Ewan-Ahiouy 发表于 2023-8-15 15:02:05

激动人心,无法言表,真是难得一遇的好帖!

cjjJasonchen 发表于 2023-8-15 15:02:31

Ewan-Ahiouy 发表于 2023-8-15 15:02
激动人心,无法言表,真是难得一遇的好帖!

{:10_257:}

cjjJasonchen 发表于 2023-8-15 15:06:24

Ewan-Ahiouy 发表于 2023-8-15 15:02
激动人心,无法言表,真是难得一遇的好帖!

评个分喵{:10_254:}

Ewan-Ahiouy 发表于 2023-8-15 15:07:24

cjjJasonchen 发表于 2023-8-15 15:06
评个分喵

没有额度了{:10_266:}明天叫我评!

cjjJasonchen 发表于 2023-8-15 15:11:56

Ewan-Ahiouy 发表于 2023-8-15 15:07
没有额度了明天叫我评!

谢谢{:10_257:}

小小麦乐鸡 发表于 2023-8-15 16:21:04

{:10_275:}

小小麦乐鸡 发表于 2023-8-15 16:21:37

{:10_328:}

琅琊王朝 发表于 2023-8-15 16:30:57

{:5_106:}

琅琊王朝 发表于 2023-8-15 16:31:31

{:5_106:}

琅琊王朝 发表于 2023-8-15 16:32:05

评分了

cjjJasonchen 发表于 2023-8-15 16:50:14

小小麦乐鸡 发表于 2023-8-15 16:21


{:10_257:}

cjjJasonchen 发表于 2023-8-15 16:50:37

琅琊王朝 发表于 2023-8-15 16:32
评分了

感谢支持{:10_257:}

cjjJasonchen 发表于 2023-8-15 17:49:36

8/15已更新!

vcvsk 发表于 2023-8-15 19:36:13

{:7_146:}
页: [1] 2 3 4 5 6 7 8
查看完整版本: 【pygameGUI 1.0】教程 —— 【已完结】 8/17