python - 如何停止用户输入和 pygame 显示之间的滞后

标签 python user-interface pygame

我是 pygame 社区和 python 的新手。对于我的计算机作业,我们必须制作一个视频游戏。我想做的是有一个循环,它首先获取用户输入,然后获取该用户输入,然后基于该输入显示一个新 View 。我试图制作一个主菜单屏幕,用户可以按向上和向下箭头来选择屏幕上的选项。然而,当我运行它时,它非常出问题,并且对用户输入的响应速度很慢。只有当你按住它时它才会移动,但它会一直到第四个选项。

while Loop_2 == True:
    pygame.time.delay(75)
    #Checks what keys have been pressed
    keys = pygame.key.get_pressed()
   
    #Checks if player has pressed the exit button
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

    #Checks if the player has pressed escape and will end python        
    if keys[pygame.K_ESCAPE]:
     pygame.quit()

    #The second main menu if statements for moving the curser and selecting
    if keys[pygame.K_DOWN] and Position < 4:
        #If the player presses the down arrow to move the pointer and its not in the 4th position at the bottom. it will move down
        Position = Position + 1
    else:
        if keys[pygame.K_UP] and Position > 1:
            #If the player presses the up arrow to move the pointer and its not in the 1st position at the top. it will move up
            Position = Position - 1
        else:
            if keys[pygame.K_LSHIFT]:
                Loop_3 = True

                if Position == 1:
                    Play_Menu()
                elif Position == 2:
                    Saves_Menu()
                elif Position == 3:
                    Settings_Menu()
                elif Position == 4:
                    Quit_Menu()
       
           
    #Loads the second main Menu
    window.blit(main_menu_2,(0,0))

    if Position == 1:
        window.blit(main_menu_pointer,(650,-525))
       
    elif Position == 2:
        window.blit(main_menu_pointer,(650,-385))
       
    elif Position == 3:
        window.blit(main_menu_pointer,(650,-240))
       
    elif Position == 4:
        window.blit(main_menu_pointer,(650,-100))
       
   
   


    pygame.display.update()

我尝试将 pygame.delay 更改为不同的值,它要么使其响应过于灵敏,要么不响应。我只是想要它,以便我可以向下或向上按下,当松开它时,它将移至下一个选项,而不是一直向下移动到底部。我在这个网站上找不到任何关于此的信息。谢谢

最佳答案

核心问题是您希望能够循环浏览菜单选项,但又不会对普通人来说太快。

当前代码正在延迟整个程序以保持速度。但这里真正需要的是对选择下一个项目之间的时间进行限制。

执行此操作的一种方法是查看 Pygame Time当选择“事件”发生时。也就是说,用户在什么时间突出显示菜单项。一个方便的时间函数是.get_ticks(),它返回毫秒相对时间。

# user just changed selection
time_now = pygame.time.get_ticks()

这使我们能够创建一个 future 时间,之后允许进行新的选择。

# user just changed selection
time_now = pygame.time.get_ticks()
next_allowed  = time_now + 300       # 300 milliseconds in the future

现在,当用户尝试更改选择时,在当前时间超过将来的这个时间之前不允许这样做。根据我们的示例,这不会再持续 300 毫秒(这相当慢)。

# user has tried to change selection
time_now = pygame.time.get_ticks()
if ( time_now > next_allowed ):
    # ( TODO - menu selection change code )
    next_allowed = time_now + 300   # future time next change allowed

当然,我们应该为时间延迟设置一个常量,这样就可以轻松更改它,而无需在代码中寻找常量

MENU_DELAY = 300

...

next_allowed = time_now + MENU_DELAY   # future time next change allowed

下面是一些实现此类菜单的示例代码:

menu screen shot

import pygame

WIDTH = 500
HEIGHT= 500
FPS   = 60

MENU_DELAY = 200

BLACK = (  0,   0,   0)
WHITE = (255, 255, 255)
GREEN = ( 20, 180,  20)

pygame.init()
screen = pygame.display.set_mode( ( WIDTH, HEIGHT ) )
pygame.display.set_caption( "Menuosity" )

font  = pygame.font.Font( None, 32 )  # font used to make menu Items
                

class MenuItem:
    """ Simple sprite-like object representing a Menu Button """
    def __init__( self, label ):
        super().__init__()
        self.image    = pygame.Surface( ( 200, 50 ) )   # long rectangle
        self.rect     = self.image.get_rect()
        self.label    = label.strip().capitalize()
        self.selected = False
        self.fore     = BLACK
        self.back     = WHITE
        self.makeImage( self.fore, self.back )

    def makeImage( self, foreground, background ):
        """ Make the image used for the menu item, in the given colour """
        self.image.fill( background )
        pygame.draw.rect( self.image, foreground, [0, 0, self.image.get_width(), self.image.get_height()], 3 )

        # centred text for Label
        text = font.render( self.label, True, foreground )
        text_centre_rect = text.get_rect( center = self.image.get_rect().center )
        self.image.blit( text, text_centre_rect )

    def moveTo( self, x, y ):
        """ Reposition the menu item """
        self.rect.x = x
        self.rect.y = y

    def makeSelected( self, selected=True ):
        """ If the button is selected, invert it's colours """
        if ( self.selected != selected ):
            # Only re-generate if different
            if ( selected ):
                self.makeImage( self.back, self.fore )  # inverted colours on selection
            else:
                self.makeImage( self.fore, self.back )  # non-selected, normal colours
        self.selected = selected

    def draw( self, surface ):
        """ Paint the item on the given surface """
        surface.blit( self.image, self.rect )



### Create a Menu of Items
menu = []
menu.append( MenuItem( "First Item" ) )
menu.append( MenuItem( "Second Item" ) )
menu.append( MenuItem( "Third Item" ) )
menu.append( MenuItem( "Fourth Item" ) )

### Highlight the first item
current_option = 0
menu[0].makeSelected()

### Lay-out the menu
for i,item in enumerate( menu ):
    item.moveTo( 150, 50 + ( i * 80 ) )   # spread out in a single column

### Used to slow down the UI Changes
clock = pygame.time.Clock()
next_change_time = 0  

###
### MAIN
###
while True:
    time_now = pygame.time.get_ticks()   # milliseconds elapsed time 

    # Handle events
    keys = pygame.key.get_pressed()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()

    # if the user pressed [space]
    if ( keys[pygame.K_SPACE] ):
        # When space is pushed move to the next item, but not more than every 300ms
        # So, has enough time elapsed since the last keypress?
        if ( time_now > next_change_time ):
            # enough time elapsed, un-select the current, and select the next menu-item
            menu[current_option].makeSelected( False )    
            current_option += 1
            if ( current_option >= len( menu ) ):
                current_option = 0
            menu[current_option].makeSelected( True )
            next_change_time = time_now + MENU_DELAY  # remember the time of the change

    # paint the screen
    screen.fill( GREEN )  # paint background

    # Paint the menu
    for item in menu:
        item.draw( screen );

    pygame.display.flip()
    clock.tick( FPS )       # keep a sane frame-rate

关于python - 如何停止用户输入和 pygame 显示之间的滞后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72195438/

相关文章:

python - 为什么一组数字看起来是有序的?

Python:如何使用生成器函数初始化列表

python - 保存时格式化会删除 VS-Code 中的导入语句

python - 以编程方式取消选中 wx.CheckListBox 中的复选框

c++ - Qt 从库中调用 QApplication::exec

c# - 涉及数据显示的极其奇怪的问题

python - 在pygame中使用滚动相机

python - tkinter:运行时错误:线程只能启动一次

python-3.x - 安装 Pygame/Python 3.4.1 时出错

python - builtins.TypeError : an integer is required (got type tuple)