cjjJasonchen 发表于 2024-8-10 15:07:49

pygame窗口:任意缩放

本帖最后由 cjjJasonchen 于 2024-8-10 15:07 编辑

Pygame游戏开发 —— 梦开始的地方


好久不见~

不知道各位在使用pygame自带的全屏功能的时候,有没有感觉到各种不顺手呢~{:10_297:}

今天来教大家驯服pygame自带的全屏功能~~

(此教程为进阶pygame教程,萌新退散~~~)

在小甲鱼老师的旧版教程中,曾经提到过“不建议使用窗口的拖动变形功能,因为会导致动画精灵的变形,位置错误等问题”

但这次,我发现里拖动变形的正确打开方式:
https://www.bilibili.com/video/BV1owY5eCEzq/?spm_id_from=333.999.0.0&vd_source=541f9ab6e8c1eb21e01b17c4cc2c9785
(请看vcr{:10_328:} )




上面的视频展示了拖动窗口、全屏,背景填充,鼠标位置的设定与读取等操作,下面先看看源码:

(大概扫一眼就行,这里放出来主要是给大家运行,玩一下,感受一下和普通窗口的区别,别忘了注意控制台哦。后面我会分段细讲代码)
import pygame
import sys
from pygame.locals import *


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

# 常量
WHITE = 255, 255, 255

# 设定窗口
size = width, height = # 16*50 : 9*60
window = pygame.display.set_mode(size, RESIZABLE)# 自由拖动大小
screen = pygame.Surface(size)
pygame.display.set_caption("可拖动窗口")
window_bg = WHITE

clock = pygame.time.Clock() # 时钟

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

# 检测和修正全屏
# noinspection PyShadowingNames
def check_full(window, full_bool, size):# -> None
    """接受参数 fullscreen
      [窗口现在是否应该处于全屏状态,是否需要修正窗口状态]
      用于修改窗口状态(大小以及是否全屏,会自动修改full_bool的值)"""
    if full_bool and full_bool:# 现在窗口应该处于全屏状态,并且没有处于全屏状态
      window = pygame.display.set_mode(pygame.display.list_modes(), FULLSCREEN)# 全屏窗口
      full_bool = False
    elif full_bool:# 不处于全屏状态
      window = pygame.display.set_mode(size, RESIZABLE)# 自由拖拽窗口
      full_bool = False
    return window

# 是否全屏
full_bool = # [是否全屏,是否需要修正窗口状态]

# 得到鼠标位置
# noinspection PyShadowingNames
def get_pos(offset, ratio):
    """接受两个参数(屏幕绘制的偏移,屏幕缩放比例)"""
    pos = pygame.mouse.get_pos()
    pos = [(pos-offset)/ratio,
         (pos-offset)/ratio]
    return pos

# 设置鼠标位置
# noinspection PyShadowingNames
def set_pos(pos, offset, ratio):
    """接受三个参数(鼠标位置,屏幕绘制的偏移,屏幕缩放比例)"""
    pos = *ratio+offset,
         pos*ratio+offset]
    pygame.mouse.set_pos(pos)

displayed_screen_size = size# 屏幕的矩形大小
ratio = 1# 屏幕缩放率

# 背景颜色设定
bg_color = BLACK

running = True

while running:

    # 设定帧数
    clock.tick(60)

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

    delay -= 1

    # 检测并修改全屏状态
    window = check_full(window, full_bool, size)

    # 得到鼠标位置
    pos = get_pos(, displayed_screen_size],
                  ratio)

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

      # 鼠标
      if event.type == MOUSEBUTTONDOWN:
            if event.button == 1: # 左键按下,设置鼠标位置
                pos = pygame.mouse.get_pos()
                set_pos(
                  ,
                  , displayed_screen_size],
                  ratio)
                print(f"鼠标位置设定为屏幕(小白点)处")
            elif event.button == 3:# 右键按下,显示鼠标位置
                print(pos)

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

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


    # 窗口背景
    window.fill(WHITE)
   
    #屏幕背景
    screen.fill(BLACK)
   

    #画 xxxx
    # 一个圆
    pygame.draw.circle(screen, , , 50, width = 3)
    # 白点
    pygame.draw.rect(screen, rect=,color=(255,255,255))
   

    # 刷新xxx

    # 调整绘制大小,使之填充窗口
    screen_rect = screen.get_rect()
    window_rect = window.get_rect()
    r1, r2 = abs(window_rect/screen_rect), abs(window_rect/screen_rect)
    if r1 < r2:
      ratio = r1
      displayed_screen = pygame.transform.smoothscale(screen,
                                                      (ratio*size, ratio*size))
    elif r1 > r2:
      ratio = r2
      displayed_screen = pygame.transform.smoothscale(screen,
                                                      (ratio*size, ratio*size))
    else:
      ratio = 1
      displayed_screen = screen
    displayed_screen_size = displayed_screen.get_rect()
    displayed_screen_size.center = window_rect.center
    window.blit(displayed_screen,displayed_screen_size)
   

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







好的,下面我们开始逐一讲解代码:
(默认各位都有pygame基础,有很多能网上轻易查到的和注释写的就不细说了)

首先看这段修改和检测窗口拖动与全屏模式的函数【约24-39行】

# 检测和修正全屏
# noinspection PyShadowingNames
def check_full(window, full_bool, size):# -> None
    """接受参数 fullscreen
      [窗口现在是否应该处于全屏状态,是否需要修正窗口状态]
      用于修改窗口状态(大小以及是否全屏,会自动修改full_bool的值)"""
    if full_bool and full_bool:# 现在窗口应该处于全屏状态,并且没有处于全屏状态
      window = pygame.display.set_mode(pygame.display.list_modes(), FULLSCREEN)# 全屏窗口
      full_bool = False
    elif full_bool:# 不处于全屏状态
      window = pygame.display.set_mode(size, RESIZABLE)# 自由拖拽窗口
      full_bool = False
    return window

# 是否全屏
full_bool = # [是否全屏,是否需要修正窗口状态]

先看第一个参数:window

这里先提一下本文中 window 和 screen 的定义:

小甲鱼曾经说过,pygame 通多 display.set_mode 创建的窗口(同样也是 Surface 对象),称为 window"窗口" 或 screen"屏幕" ,根据小甲鱼老师的习惯,我们一般把它称为 screen

但是,今天,我们把它称作 window , 因为 screen 还有其他任务要完成{:10_275:}

所以,window 今天的任务就是成为一个优秀的窗口,而 screen 仅仅只负责“屏幕”(显示区域)

先看图:


这是上面视频和代码中的窗口,这一整个窗口是 "window", 但只有黑色部分属于 "screen"。

让我拖拽改变一下窗口大小:

我将他拉长了,可以看到,白色的部分从上下两条变成了左右两条,屏幕变大了一些,说明此时窗口的宽度大于屏幕的宽度,高度与屏幕高度相等。
并且上面的红色圆和白色的点位置看起来没有发生变化。

所以,window的xy轴的长度都在能自由变化,而screen只是在比例缩放而已

其他的所有动画精灵等等对象可以像以前一样绘制在 screen 上,再把 screen 绘制再window上就ok辣!

好,现在大家已经知道window是什么了,我们回到代码看下一个参数~

full_bool:
这个参数中传入的就是函数后定义的列表,由两个bool值组成,第一个表示现在window是不是处于全屏状态,第二个是窗口的实际全屏状态是否与第一个布尔值的状态不一致

(在后续事件判定的代码中会判定是否全屏,但只是判定,不是修改,所以需要上面这个函数每帧修改全屏状态。)
(第二个布尔值的存在是为了防止重复重新设置屏幕全屏状态)

第三个参数size:
窗口在解除全屏后应该设置的大小

{:10_275:}

然后我们看下一段代码吧~

【约41-56行】
# 得到鼠标位置
# noinspection PyShadowingNames
def get_pos(offset, ratio):
    """接受两个参数(屏幕绘制的偏移,屏幕缩放比例)"""
    pos = pygame.mouse.get_pos()
    pos = [(pos-offset)/ratio,
         (pos-offset)/ratio]
    return pos

# 设置鼠标位置
# noinspection PyShadowingNames
def set_pos(pos, offset, ratio):
    """接受三个参数(鼠标位置,屏幕绘制的偏移,屏幕缩放比例)"""
    pos = *ratio+offset,
         pos*ratio+offset]
    pygame.mouse.set_pos(pos)

这两个函数差不多,但是可能有的鱼油不知道有什么用,为什么不用pygame默认的鼠标交互函数嘞?

上图:



如果使用pygame自带的鼠标位置计算函数:
得到的鼠标位置是

但如果使用上面我提供的函数:
鼠标位置是

这问题产生的原因再上面代码讲到window和screen定义时用加粗字表示出来了,没看到的可以爬楼回去看哦~

第一个参数pos:
和pygame的set_pos一样,设置鼠标的位置,但是不同的是我设置鼠标在screen中的位置,而pygame设置了在window中的位置

第二个参数:offset
可以理解为是 x1 的部分

第三个参数:ratio
可以理解为screen缩放的比例

(当然后面两个参数都在每帧代码末尾已经算好了,你们只需要填写第一个参数就可以啦~)

下一段【约134-151】:
# 调整绘制大小,使之填充窗口
    screen_rect = screen.get_rect()
    window_rect = window.get_rect()
    r1, r2 = abs(window_rect/screen_rect), abs(window_rect/screen_rect)
    if r1 < r2:
      ratio = r1
      displayed_screen = pygame.transform.smoothscale(screen,
                                                      (ratio*size, ratio*size))
    elif r1 > r2:
      ratio = r2
      displayed_screen = pygame.transform.smoothscale(screen,
                                                      (ratio*size, ratio*size))
    else:
      ratio = 1
      displayed_screen = screen
    displayed_screen_size = displayed_screen.get_rect()
    displayed_screen_size.center = window_rect.center
    window.blit(displayed_screen,displayed_screen_size)

这一段负责调整screen,将其放大或缩小(这里是按window短边比例计算,实际应用时可以灵活调整,按照长边或各计算50%都是可以的)

首先,得到窗口和屏幕的大小,
得到x轴和y轴长度比例,
判断得出短边,将screen大小改变为刚好顶满短边。

然后把screen放在window中间~

好啦,讲解结束~鱼油们学会了吗~~~



通俗来讲呢,上面这套框架的使用方法就是:

将原版游戏中绘制在原本screen上(本文中称window)的任何东西,都绘制在新的screen上,把这个screen当成原来的screen一样用就可以了。

但是要注意鼠标的交互函数,set_pos 和 get_pos 不能再使用原来的,要根据教程使用上面我提供的。

同时,只需要移动,旋转,缩放screen,就可以完成"震动反馈""地图拖动"等等高端操作,

不过话说,这层screen已经有它的工作了,为何不再加一层呢?不如就叫 word 怎么样{:10_307:}




       



cjjJasonchen 发表于 2024-8-11 11:40:29

妹人吗

cjjJasonchen 发表于 2024-8-11 11:45:25

@不二如是 @KeyError @中英文泡椒 @歌者文明清理员 @zhangchenyvn @小甲鱼 @Mike_python小 @学习编程中的Ben @python爱好者. @过默 @凌凌祺 @学习学习在研究 @flyps @某一个“天” @tommyyu @陶远航 @zhangjinxuan @python爱好者. @liuhongrun2022 @zhangchenyvn @Ewan-Ahiouy @琅琊王朝

没人看喔,浅浅@一下{:10_259:}

不二如是 发表于 2024-8-11 11:54:57

cjjJasonchen 发表于 2024-8-11 11:45
@不二如是 @KeyError @中英文泡椒 @歌者文明清理员 @zhangchenyvn @小甲鱼 @Mike_python小 @学习编程中的Be ...

{:10_275:}来了来了

小甲鱼 发表于 2024-8-12 06:40:46

支持一下~

中英文泡椒 发表于 2024-8-12 14:52:13

cjjJasonchen 发表于 2024-8-11 11:45
@不二如是 @KeyError @中英文泡椒 @歌者文明清理员 @zhangchenyvn @小甲鱼 @Mike_python小 @学习编程中的Be ...

来啦来啦{:10_254:}

python爱好者. 发表于 2024-8-13 07:30:17

{:10_256:}不错,好极了

smallwh 发表于 2024-8-13 16:09:56

就需要有这种探索精神的鱼油{:10_275:}

wwwhbg888 发表于 2024-8-16 16:20:14

\{:10_279:}

ydwb 发表于 2024-8-19 13:49:22

感谢分享

不二如是 发表于 2024-8-21 20:29:39

还需要更多热度@KeyError @中英文泡椒 @歌者文明清理员 @zhangchenyvn @小甲鱼 @Mike_python小 @学习编程中的Ben @python爱好者. @过默 @凌凌祺 @学习学习在研究 @flyps @某一个“天” @tommyyu @陶远航 @zhangjinxuan @python爱好者. @liuhongrun2022 @zhangchenyvn @Ewan-Ahiouy @琅琊王朝

liuhongrun2022 发表于 2024-8-21 20:57:55

支持

zhangchenyvn 发表于 2024-8-21 20:59:20

不二如是 发表于 2024-8-21 20:29
还需要更多热度@KeyError @中英文泡椒 @歌者文明清理员 @zhangchenyvn @小甲鱼 @Mike_python小 @学习编程 ...

已经支持,评分+淘帖

18408238295 发表于 2024-8-22 09:17:25

蛮有意思的,后续来学习这块

陶远航 发表于 2024-8-29 13:46:24

终于军训回来了,支持
页: [1]
查看完整版本: pygame窗口:任意缩放