如何在pygame中制作切换类型按钮?

时间:2018-09-23 01:28:22

标签: pygame

我正在用pygame制作游戏,但是我遇到一个问题,就是按钮不能用作切换按钮。

while True:
mousepos = pygame.mouse.get_pos()
mouseclk = pygame.mouse.get_pressed()
game.fill((0,0,0))
game.blit(cic, (0,0))

if mouseclk[0] and 1227 > mousepos[0] > 1120 and 485 > mousepos[1] > 413:
    while True:
        game.blit(pbut_rgm84, (1120,413))
        pygame.mixer.music.load("sounds\se_beep.mp3")
        pygame.mixer.music.play(0)
        current_weaponinf = font.render(current_weapon[1], True, (255, 0, 0))
        game.blit(current_weaponinf, (930,45))
else:
    game.blit(but_rgm84, (1120,413))

这是我的按钮代码。如您所知,如果我单击该按钮,则该按钮的图像将被更改并且将播放声音。但这会在我按下按钮时发生。因此,我希望按钮为切换类型。你有什么想法吗?

1 个答案:

答案 0 :(得分:1)

编辑1 :很抱歉。 答案在第一部分 。剩下的只是一些注释,以更标准的方式来执行您在PyGame中要求的操作。毕竟,答案不仅是针对OP,而是访问此页面的每个人。

编辑2 :注意,我还必须更改代码以将FPS降低到5,这样才能正常工作。您检查点击的方式意味着每次在我的机器上单击鼠标按钮时大约会按下30到40帧,因此当只需要一个按钮时,会导致30到40个按钮切换,因此我不得不将FPS降低到5在代码中。这就是为什么您可能想使用我描述的其他方法进行事件处理的另一个原因。


答案:

老实说,我很欣赏您用来检查鼠标单击是否在被按下对象范围内的简单逻辑。

我可以稍微扩展代码以获得所需的“切换”类型按钮(即,单击一次,图像和声音会发生变化。再次单击,图像和声音会恢复正常)。

但是,我还想向您展示一些更好的方法来处理Pygame模块中可用的鼠标单击事件和单击检测,以改善您的代码。如果您有兴趣并想知道我的意思,请在下面的代码后继续阅读。如果您只是想接受代码然后离开,我完全尊重(我也做了很多事情)。

在这里,您的代码已修改为符合您的“切换”按钮要求(如果我理解您想做的正确的话)。将其替换为您在答案中显示的部分代码,但是请注意,由于我没有完整的代码或您使用的图像/配乐,这可能无法正常工作

toggle = False
pygame.mixer.music.load("sounds\se_beep.mp3")
pygame.mixer.music.play(-1)
pygame.mixer.music.pause()
clock = pygame.time.Clock()

while True:
    mousepos = pygame.mouse.get_pos()
    mouseclk = pygame.mouse.get_pressed()

    game.fill((0, 0, 0))
    game.blit(cic, (0, 0))

    if mouseclk[0] and 1227 > mousepos[0] > 1120 and 485 > mousepos[1] > 413:
        if toggle:
            toggle = False
            pygame.mixer.music.pause()
        else:
            toggle = True
            pygame.mixer.music.unpause()

    if toggle:
        game.blit(pbut_rgm84, (1120, 413))
        current_weaponinf = font.render(current_weapon[1], True, (255, 0, 0))
        game.blit(current_weaponinf, (930,45))
    else:
        game.blit(but_rgm84, (1120,413))

    clock.tick(5)

更好的方式:处理事件

处理鼠标单击事件以及实际上所有其他事件很简单,这就是所谓的事件循环。尽管还不止如此,但现在可以说,事件循环可以检查每帧触发的某些事件(例如按键,鼠标单击,退出游戏事件),然后触发回调函数。

您的代码中已经有一个! -在while循环的每个循环中,您都使用mouseclk = pygame.mouse.get_pressed()

检查是否单击了鼠标

但是,这是不完整的,不是使用Pygame模块实现事件循环的标准方法。这是您的操作方法(阅读每行上方的注释以了解其作用):

import pygame
from pygame.locals import *

...

# Main game loop - this is the while loop you have in your code. This is where frames are rendered on every new loop
while True: 
    #Get all event that have been triggered from the last frame
    events = pygame.event.get()

    # Now we go through each event separately
    for event in events:
        #Use an if statement to check what the event is. For example...
        if event.type == MOUSEBUTTONDOWN:  #If this event was a mouse button click
            print("Clicked")  #Do whatever function
        elif event.type == QUIT: #If this event was quitting the game, i.e: pressing the X button on the game window
            pygame.quit() #Close the game
        #and so on. You can have as many elifs to check all the events you need


   game.fill((0,0,0)) #... The rest of your code goes after the for loop (event loop)

因此,基本上在您的主游戏循环(您的while循环)中,您具有一个for循环(事件循环),然后在其回到主while循环中之后,您便拥有了其余的代码,需要在每个循环中运行框架,例如渲染图像和动画精灵。


更好的方法:矩形对象

您将发现,要查看鼠标单击位置(x,y)是否在鼠标按钮的范围内,您必须检查鼠标单击的x值是否在所对象的X1到X2的范围内重新点击(右上角和左上角),同时它还必须在对象的Y1到Y2范围内(右上角和右下角),这实际上意味着当鼠标移到对象上时鼠标单击事件已触发

为此,Pygame实现了 Rect 对象。 rect可以解释为一个假想的矩形,该矩形具有在创建时定义的宽度和高度(我将在下面的代码中向您展示如何完成此操作)。更为现实的是,它是一个pygame对象,用于存储矩形坐标(该矩形内所有点的范围)。

现在情况是,此rect对象具有类似Rect.collidepoint的方法,如果鼠标单击位置在rect内部,则该方法将返回True。这是一种检测鼠标单击位置在矩形内部还是外部的更简单,更容易理解的方法。

所以..

# Constructing a rect at position (0, 0) with width 100 and height 500
r = pygame.Rect(0, 0, 100, 50)

# Now lets assume that above there is code where a mouse click is detect and the position is stored in `mousepos`, where `mousepos[0]` is the X and `mousepos[1]` is the Y
# All we have to do now is tell pygame to check if this position is inside our Rect object *r* or not
if r.collidepoint(mousepos):
    print("You clicked inside an imaginary box")
else:
    print("You clicked outside my imaginary box")

# Simple!!!

更轻松,更易读! (尤其是在删除注释后,您将因其简单性而傻眼(碰撞点指的是矩形内部)。

实际上,这不是您通常使用rects的方式,尽管它使您基本了解它们是什么。在更面向对象的方法中使用Rect,其中按钮是Pygame.sprite.Sprite类的子类。然后,您可以将rect对象分配为其self.image.rect属性,并从那里使用它。注意:这不是很详细:D。

此外,这不是rect的唯一用法。您可以检查一个rect是否在另一个rect内部。您可以检查一组对象是否在矩形内。即使只用一行代码,您也可以检查组中的一个对象是否在某个矩形内,如果是,则将其删除!


要了解更多关于如何从头到尾编写pygame的信息(因为该答案的其余部分谈论事件和区域是非常不完整的,仅作为起点),我建议使用此excellent yet very simple and easy to understand book。您只需要对python语法有基本了解即可。