Pygame: how to write event-loop polymorphically

user9825338 :

I'm some-what new to pygame, and while trying to get back into it, I found the advice "replace your conditionals with polymorphism." Most pygame tutorials recommend using the "for event in pygame.event.get()" loop and then using a conditional to determine if any particular event has occured.

1: How do I write that code using a polymorphic function 2: Is it worth it to re-factor the code, or just leave the conditional as-is

Below is what most tutorials recommend

def gameloop():
"""
Stuff that comes before the event-loop
"""

for event in pygame.event.get():
    if event.type == pygame.QUIT:   # This is the conditional I want to remove
        quit_functions()

Below is how I want to approach this

from abc import ABC, abstractmethod
import pygame


def detect_event(event_class_name):
    for event in pygame.event.get():
        # This is how I want to get the event and then assign it a function
        event_class_name.determine_event(event)


# Above: I want to use this function to detect events and call their functions

# Below: This is how I want to assign functions to the events


class EventHandler(ABC):
    @staticmethod
    @abstractmethod
    def determine_event(event): pass


class Exit(EventHandler):
    @staticmethod
    # How do I identify this with the event-type "pygame.QUIT," for example
    def determine_event(event):
        pygame.quit()
        quit(0)
Rabbid76 :

In pygame the event type is an enumerator constant. You have to map this constant to the corresponding class. Use a dictionary:

eventhandler = {pygame.QUIT: Exit, pygame.KEYDOWN: Keydown}

Of course, the dictionary can be generated or even extended dynamically, too. (e.g.: eventhandler[pygame.MOUSEBUTTONDOWN] = MouseDown)

e.g.:

class EventHandler():
    @staticmethod
    def determine_event(event): pass

class Exit(EventHandler):
    @staticmethod
    def determine_event(event):
        pygame.quit()
        quit(0)

class Keydown(EventHandler):
    @staticmethod
    def determine_event(event):
        print(event.key)

eventhandler = {pygame.QUIT: Exit, pygame.KEYDOWN: Keydown}

while True:
    for event in pygame.event.get():
        if event.type in eventhandler:
            eventhandler[event.type].determine_event(event)

For a more general approach, the handlers can be managed in a list. So multiple actions can be associated to an event type. e.g:

class EventHandler():
    targets = {}
    @staticmethod
    def add(type, event):
        EventHandler.targets.setdefault(type, []).append(event) 
    @staticmethod
    def notify(event):  
        if event.type in EventHandler.targets:
            for target in EventHandler.targets[event.type]:
                target.determine_event(event)
    @staticmethod
    def determine_event(event): pass

class Exit(EventHandler):
    @staticmethod
    def determine_event(event):
        pygame.quit()
        quit(0)

class KeydownPrint(EventHandler):
    @staticmethod
    def determine_event(event):
        print(event.key)

class KeydownAction(EventHandler):
    @staticmethod
    def determine_event(event):
        print("action")

EventHandler.add(pygame.QUIT, Exit)
EventHandler.add(pygame.KEYDOWN, KeydownPrint)
EventHandler.add(pygame.KEYDOWN, KeydownAction)

while True:
    for event in pygame.event.get():
        EventHandler.notify(event)

Or even a combination of both answers (see answer of @AKX):

class EventHandler:
    targets = {}
    def register(type):
        def decorator(fn):
            EventHandler.targets.setdefault(type, []).append(fn)   
        return decorator
    def notify(event):
        fnl = EventHandler.targets[event.type] if event.type in EventHandler.targets else []  
        for fn in fnl: 
          fn(event)

@EventHandler.register(pygame.QUIT)
def onExit(event):
    pygame.quit()
    quit(0)

@EventHandler.register(pygame.KEYDOWN)
def keydownPrint(event):
    print(event.key)

@EventHandler.register(pygame.KEYDOWN)
def keydownAction(event):
    print("action")

while True:
    for event in pygame.event.get():
        EventHandler.notify(event)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=9562&siteId=1