Patterns


Criador

O framework utilizado possui a seguinte estrutura, onde o director é responsável por rodar as cenas (scenes), que são responsáveis por criar camadas (layers), que, por sua vez, cria e gerencia sprites.

sequenceDiagram director->>Scene: run() Scene->>Layer: create() Layer->>Sprite: create()

Controladora

Basicamente, as Layers (camadas) gerenciam os enventos realizados pelo usuário, como apertar uma tecla específica, e define uma resposta à essa ação do usuário, sendo que essa resposta pode envolver outras partes da arquitetura.

Event-based asynchronous

Padrões voltados para ocorrências em assíncrono, a fim de sanar a necessidade de receber inputs não esperados pelo usuario ou estados inesperados da aplicação:

import signal

def signal_handler(signal_received, frame):
    if signal_received is signal.SIGINT:
        # erase the ^C on Terminal
        print "\r  "
        exit(0)

if __name__ == "__main__":
    resource.path.append('data')
    resource.reindex()
    font.add_directory('data/fonts')

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGSEGV, signal_handler)

Singleton

Uma dificuldade que o time teve, foi a de conseguir um objeto keyboard que conseguisse manter os estados das teclas. A biblioteca pyglet fornecia uma solução, mas apenas a primeira instância de cada aplicação recebia as atualizações. A solução proposta então foi a de implementar esta instancia como singleton, a fim de garantir que sempre que a primeira instancia pudesse ler lida a qualquer momento da aplicação.

Singleton

Keyboard-event

class EventHandle(object):

"""docstring for EventHandle"""

keyboard = None

def __new__(cls):
    if not hasattr(cls, 'instance'):
        cls.instance = super(EventHandle, cls).__new__(cls)
    return cls.instance

keyboard = key.KeyStateHandler()
director.window.push_handlers(keyboard)
EventHandle().keyboard = keyboard

Combo: Factory-Singleton-Pool

A evolução anterior do Pool de objetos se fez a necessidade de ter um objeto que mantivesse o controle de produções e fornecimento dos objetos da pool, assim como destrui-los corretamente,caso necessário. Desta forma, foi implementada uma Factory responsavel pelo fornecimento dos objetos. Como a Factory poderia ser acionada de varias cenas do jogo, ela foi transformada em um singleton para garantir esta acessibilidade, evitando o desperdicio de recursos ao se criar objetos.

FireFactory

FireFactory

class FireFactory(object):

    """docstring for FireFactory"""

    ammo = {'hero': [], 'enemies': []}

    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(FireFactory, cls).__new__(cls)
        return cls.instance

    @classmethod
    def create_bullets(cls, bullet_type, qnt=50):
        if bullet_type in hero:
            for x in xrange(0, qnt):
                cls.ammo['hero'].append(SpaceShipBullet())
        elif bullet_type in rohenian:
            for x in xrange(0, qnt):
                cls.ammo['enemies'].append(RoheniansBullet())

Combo: Factory-Singleton-Pool-Dirty Flag

Uma das Factories presentes no código apresentou a requisição de se saber se ela se encontrava ou não vazia. Desta forma, uma flag foi acrescentada nela para manter esta informação. Como esta informação pode ser obtida de forma assincrona, acabou se apresentando o padrão Dirty Flag no contexto.

EnemyFactory

EnemyFactory

class EnemyFactory(object):

    """docstring for EnemyFactory"""
    enemy_list = {"Rohenian": [], "Aerolite": []}

    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(EnemyFactory, cls).__new__(cls)
        cls.empty = True
        return cls.instance

    @classmethod
    def populate_enemy(cls, enemy_type, qnt=1):

        if enemy_type in rohenian:
            for x in xrange(0, qnt):
                cls.enemy_list["Rohenian"].append(
                    Rohenian())
            cls.empty = False
            return
        if enemy_type in aerolite:
            for x in xrange(0, qnt):
                cls.enemy_list["Aerolite"].append(
                    Aerolite())
            cls.empty = False
            return
        assert 0, "Bad enemy creation: " + enemy_type