2017-12-04 25 views
1

클릭 이벤트를 위해 파이 게임에서 버튼을 만들었습니다. 하지만 마우스 버튼을 클릭 할 때 문제가 발생합니다. 버튼 경계에서 마우스를 움직이면 클릭 이벤트가 반복됩니다. 마우스 버튼을 놓을 때까지 한 번 클릭하면됩니다. 어떻게 만들 수 있습니까?파이 게임 버튼 한 번 클릭

도면 및 버튼 코드는 while 루프 이벤트 루프에 있지만 외부에 있으면 안 :

import pygame,time 
pygame.init() 
x,y = (200,300) 
pencere = pygame.display.set_mode((x,y)) 
pygame.display.set_caption("Click") 

white = (255,255,255) 
black = (0,0,0) 
black2 = (30,30,30) 

class Counter: 
    count = 0 
    def click(self): 
     self.count += 1 

number = Counter() 
def text_objects(text, font, color): 
    textSurface = font.render(text, True, color) 
    return textSurface, textSurface.get_rect() 

def button(msg,x,y,w,h,c,ic,action=None): 
    mouse = pygame.mouse.get_pos() 
    click = pygame.mouse.get_pressed() 
    pygame.draw.rect(pencere, c,(x,y,w,h)) 

    smallText = pygame.font.Font("freesansbold.ttf",20) 
    textSurf, textRect = text_objects(msg, smallText, white) 
    textRect.center = ((x+(w/2)), (y+(h/2))) 
    pencere.blit(textSurf, textRect) 

    if x+w > mouse[0] > x and y+h > mouse[1] > y: 
     pygame.draw.rect(pencere, ic,(x,y,w,h)) 
     if click[0] == 1 != None: 
      action() 
     smallText = pygame.font.Font("freesansbold.ttf",20) 
     textSurf, textRect = text_objects(msg, smallText, white) 
     textRect.center = ((x+(w/2)), (y+(h/2))) 
     pencere.blit(textSurf, textRect) 
def loop(): 
    cikis = False 
    while not cikis: 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
       cikis = True 
       pygame.quit() 
       quit() 
      pencere.fill(white) 
      smallText = pygame.font.Font("freesansbold.ttf",50) 
      textSurf, textRect = text_objects(str(number.count), smallText, black) 
      textRect.center = ((x/2)), (30) 
      pencere.blit(textSurf, textRect) 
      button("Click",0,100,200,200,black,black2,number.click) 
      pygame.display.update() 
loop() 
pygame.quit() 
quit() 
+0

사용중인 코드를 제공 할 수 있습니까? – serge1peshcoff

+0

버튼 변수 ie에 추가해야합니다. 버튼에 할당 된 기능을 실행하기 전에 그것을 기억하고 확인하기 위해'clicked = True'를 사용하십시오. 마우스 버튼을 놓으면 클리어합니다. – furas

+0

BTW :'event.type == MOUSEBUTTONDOWN' 또는'pygame.mouse.get_pressed()'를 사용합니까? 'MOUSEBUTTONDOWN'을 사용하면 마우스 버튼이'누르지 않음 '상태로 바뀔 때만 이벤트가 생성되기 때문에이 문제는 발생하지 않아야합니다. 그러나 마우스 버튼을 계속 누르고 있으면 이벤트가 생성되지 않습니다. 'get_pressed()'는 마우스 버튼을 계속 누르고 있으면 True를 반환합니다. – furas

답변

1

변경해야 몇 가지가 있습니다. 이벤트가 발생할 때마다 (예 : 마우스가 움직이는 경우) button 함수를 호출합니다.

button 기능이 너무 많이 수행 중입니다. 텍스트 표면을 만들고 블리트하고, 직사각형을 그리고, 충돌을 확인하고 click 메서드를 호출합니다.

pygame.mouse.get_pressed()을 사용하지 말고 대신 이벤트 루프에서 MOUSEBUTTONDOWN 이벤트를 처리해야합니다. mouse.get_pressed은 마우스 버튼이 눌려져 있는지 확인하고 단 한 번의 클릭이 발생하지 않았는지 확인합니다.

여기서는 버튼이없는 기능과 버튼이없는 간단한 솔루션 만 보여 드리겠습니다. 충돌을 처리하고 이벤트 루프에서 번호를 업데이트합니다. 여러 단추를 만들려면 개체 지향 방식으로 다시 작성하는 것이 좋습니다 (원하는 경우 예제를 보여줄 수 있음).

import pygame 


pygame.init() 
width, height = (200,300) 
screen = pygame.display.set_mode((width, height)) 

WHITE = (255, 255, 255) 
BLACK = (0, 0, 0) 
GRAY = (30, 30, 30) 
FONT = pygame.font.Font("freesansbold.ttf", 50) 


def loop(): 
    clock = pygame.time.Clock() 
    number = 0 
    # The button is just a rect. 
    button = pygame.Rect(0, 100, 200, 200) 
    done = False 
    while not done: 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
       done = True 
      # This block is executed once for each MOUSEBUTTONDOWN event. 
      elif event.type == pygame.MOUSEBUTTONDOWN: 
       # 1 is the left mouse button, 2 is middle, 3 is right. 
       if event.button == 1: 
        # `event.pos` is the mouse position. 
        if button.collidepoint(event.pos): 
         # Increment the number. 
         number += 1 

     screen.fill(WHITE) 
     pygame.draw.rect(screen, GRAY, button) 
     text_surf = FONT.render(str(number), True, BLACK) 
     # You can pass the center directly to the `get_rect` method. 
     text_rect = text_surf.get_rect(center=(width/2, 30)) 
     screen.blit(text_surf, text_rect) 
     pygame.display.update() 

     clock.tick(30) 


loop() 
pygame.quit() 


부록 : 나는 pygame.sprite.Sprite의 서브 클래스이며, 스프라이트 그룹에 추가 할 수있는 Button 클래스와 객체 지향 솔루션을 사용하는 것이 좋습니다. 자신의 이미지를 Button 클래스에 전달하거나 기본 이미지를 사용할 수 있습니다. 또한 게임 클래스의 특정 특성을 업데이트하기 위해 handle_event 메서드에서 호출 될 각 단추 인스턴스에 콜백 함수 또는 메서드를 전달해야합니다. 여기에는 게임을 종료하는 카운터와 다른 메서드를 증가시키는 메서드가 있습니다.

import pygame as pg 


pg.init() 
screen = pg.display.set_mode((800, 600)) 
FONT = pg.font.SysFont('Comic Sans MS', 32) 
# Default button images/pygame.Surfaces. 
IMAGE_NORMAL = pg.Surface((100, 32)) 
IMAGE_NORMAL.fill(pg.Color('dodgerblue1')) 
IMAGE_HOVER = pg.Surface((100, 32)) 
IMAGE_HOVER.fill(pg.Color('lightskyblue')) 
IMAGE_DOWN = pg.Surface((100, 32)) 
IMAGE_DOWN.fill(pg.Color('aquamarine1')) 


# Button is a sprite subclass, that means it can be added to a sprite group. 
# You can draw and update all sprites in a group by 
# calling `group.update()` and `group.draw(screen)`. 
class Button(pg.sprite.Sprite): 

    def __init__(self, x, y, width, height, callback, 
       font=FONT, text='', text_color=(0, 0, 0), 
       image_normal=IMAGE_NORMAL, image_hover=IMAGE_HOVER, 
       image_down=IMAGE_DOWN): 
     super().__init__() 
     # Scale the images to the desired size (doesn't modify the originals). 
     self.image_normal = pg.transform.scale(image_normal, (width, height)) 
     self.image_hover = pg.transform.scale(image_hover, (width, height)) 
     self.image_down = pg.transform.scale(image_down, (width, height)) 

     self.image = self.image_normal # The currently active image. 
     self.rect = self.image.get_rect(topleft=(x, y)) 
     # To center the text rect. 
     image_center = self.image.get_rect().center 
     text_surf = font.render(text, True, text_color) 
     text_rect = text_surf.get_rect(center=image_center) 
     # Blit the text onto the images. 
     for image in (self.image_normal, self.image_hover, self.image_down): 
      image.blit(text_surf, text_rect) 

     # This function will be called when the button gets pressed. 
     self.callback = callback 
     self.button_down = False 

    def handle_event(self, event): 
     if event.type == pg.MOUSEBUTTONDOWN: 
      if self.rect.collidepoint(event.pos): 
       self.image = self.image_down 
       self.button_down = True 
     elif event.type == pg.MOUSEBUTTONUP: 
      # If the rect collides with the mouse pos. 
      if self.rect.collidepoint(event.pos) and self.button_down: 
       self.callback() # Call the function. 
       self.image = self.image_hover 
      self.button_down = False 
     elif event.type == pg.MOUSEMOTION: 
      collided = self.rect.collidepoint(event.pos) 
      if collided and not self.button_down: 
       self.image = self.image_hover 
      elif not collided: 
       self.image = self.image_normal 


class Game: 

    def __init__(self, screen): 
     self.done = False 
     self.clock = pg.time.Clock() 
     self.screen = screen 
     # Contains all sprites. Also put the button sprites into a 
     # separate group in your own game. 
     self.all_sprites = pg.sprite.Group() 
     self.number = 0 
     # Create the button instances. You can pass your own images here. 
     self.start_button = Button(
      320, 70, 170, 65, self.increment_number, 
      FONT, 'Increment', (255, 255, 255), 
      IMAGE_NORMAL, IMAGE_HOVER, IMAGE_DOWN) 
     # If you don't pass images, the default images will be used. 
     self.quit_button = Button(
      320, 240, 170, 65, self.quit_game, 
      FONT, 'Quit', (255, 255, 255)) 
     # Add the button sprites to the sprite group. 
     self.all_sprites.add(self.start_button, self.quit_button) 

    def quit_game(self): 
     """Callback method to quit the game.""" 
     self.done = True 

    def increment_number(self): 
     """Callback method to increment the number.""" 
     self.number += 1 
     print(self.number) 

    def run(self): 
     while not self.done: 
      self.dt = self.clock.tick(30)/1000 
      self.handle_events() 
      self.run_logic() 
      self.draw() 

    def handle_events(self): 
     for event in pg.event.get(): 
      if event.type == pg.QUIT: 
       self.done = True 
      for button in self.all_sprites: 
       button.handle_event(event) 

    def run_logic(self): 
     self.all_sprites.update(self.dt) 

    def draw(self): 
     self.screen.fill((30, 30, 30)) 
     self.all_sprites.draw(self.screen) 
     pg.display.flip() 


if __name__ == '__main__': 
    pg.init() 
    Game(screen).run() 
    pg.quit() 

부록 2 : 사전으로 단추와 중간 용액. 또한 목록을 사용할 수도 있지만 사전은 읽기 쉽습니다.

import pygame 


pygame.init() 

WHITE = (255, 255, 255) 
ACTIVE_COLOR = pygame.Color('dodgerblue1') 
INACTIVE_COLOR = pygame.Color('dodgerblue4') 
FONT = pygame.font.Font(None, 50) 


def draw_button(button, screen): 
    """Draw the button rect and the text surface.""" 
    pygame.draw.rect(screen, button['color'], button['rect']) 
    screen.blit(button['text'], button['text rect']) 


def create_button(x, y, w, h, text, callback): 
    """A button is a dictionary that contains the relevant data. 

    Consists of a rect, text surface and text rect, color and a 
    callback function. 
    """ 
    # The button is a dictionary consisting of the rect, text, 
    # text rect, color and the callback function. 
    text_surf = FONT.render(text, True, WHITE) 
    button_rect = pygame.Rect(x, y, w, h) 
    text_rect = text_surf.get_rect(center=button_rect.center) 
    button = { 
     'rect': button_rect, 
     'text': text_surf, 
     'text rect': text_rect, 
     'color': INACTIVE_COLOR, 
     'callback': callback, 
     } 
    return button 


def main(): 
    screen = pygame.display.set_mode((640, 480)) 
    clock = pygame.time.Clock() 
    done = False 

    number = 0 

    def increment_number(): # A callback function for the button. 
     """Increment the `number` in the enclosing scope.""" 
     nonlocal number 
     number += 1 
     print(number) 

    def quit_game(): # A callback function for the button. 
     nonlocal done 
     done = True 

    button1 = create_button(100, 100, 250, 80, 'Click me!', increment_number) 
    button2 = create_button(100, 200, 250, 80, 'Me too!', quit_game) 
    # A list that contains all buttons. 
    button_list = [button1, button2] 

    while not done: 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
       done = True 
      # This block is executed once for each MOUSEBUTTONDOWN event. 
      elif event.type == pygame.MOUSEBUTTONDOWN: 
       # 1 is the left mouse button, 2 is middle, 3 is right. 
       if event.button == 1: 
        for button in button_list: 
         # `event.pos` is the mouse position. 
         if button['rect'].collidepoint(event.pos): 
          # Increment the number by calling the callback 
          # function in the button list. 
          button['callback']() 
      elif event.type == pygame.MOUSEMOTION: 
       # When the mouse gets moved, change the color of the 
       # buttons if they collide with the mouse. 
       for button in button_list: 
        if button['rect'].collidepoint(event.pos): 
         button['color'] = ACTIVE_COLOR 
        else: 
         button['color'] = INACTIVE_COLOR 

     screen.fill(WHITE) 
     for button in button_list: 
      draw_button(button, screen) 
     pygame.display.update() 
     clock.tick(30) 


main() 
pygame.quit() 
+0

정말 고마워요 !! 그리고 예, 몇 가지 단추를 만들어서 OOP 예제에 대한 도움이 필요합니다. –

+0

OOP 예제가 추가되었습니다. 파이 게임 스프라이트와 그룹으로 아직 작업하지 않았다면 [이 튜토리얼] (http://programarcadegames.com/index.php?chapter=introduction_to_sprites&lang=en#section_13)을보십시오. – skrx

+0

정말 고맙습니다.하지만 제게 문제가 있습니다. 제 언어는 영어가 아니기 때문에 클래스를 너무 많이 알지 못합니다. 아직도 배운다. 그래서 나는 그것을 너무 많이 이해하지 않는다. 그러나 나는 그것을 이해하려고 노력할 것이다. Btw, 내 코드에 대해 언제든지 도움을받을 수있는 기회가 있습니까? –