=Paper=
{{Paper
|id=Vol-1754/EPoGames_2016_AR_paper_1
|storemode=property
|title=Desenvolvimento de um Escalonador de Cenas para motores de jogos
|pdfUrl=https://ceur-ws.org/Vol-1754/EPoGames_2016_AR_paper_1.pdf
|volume=Vol-1754
|authors=Lucas Pinheiro Otaviano Andre
}}
==Desenvolvimento de um Escalonador de Cenas para motores de jogos==
Desenvolvimento de um Escalonador de Cenas para motores de jogos Lucas Pinheiro Otaviano Andre1 1 Instituto Metrópole Digital – Universidade Federal do Rio Grande do Norte (UFRN) lpoandre@inf.ufrgs.br Abstract. During development of a game engine it is always important to make a well-defined separation between its game engine core and the game code. A way to meet that need is with the Scene Scheduler, where the classic Scheduler concept used by Operating Systems is applied to the Scene handling. The Scheduler has the purpose of handling each game scene and providing the necessary resources to them. Thus, making the engine internals transparent to the game developer. Resumo. Durante o desenvolvimento de um motor de jogos é importante manter o código do motor separado do código do jogo. Uma maneira de obter essa separação é com um Escalonador de Cenas, onde o conceito clássico de escalonador usado em Sistemas Operacionais é aplicado ao gerenciamento de cenas. Cada cena do jogo vai ser gerenciada pelo escalonador, que deve providenciar todos os recursos e funcionalidades necessárias para a cena atual. Desta maneira, fazendo com que o código interno do motor seja transparente para os desenvolvedores de jogos. 1. Introdução Normalmente durante o desenvolvimento de um motor de jogos é preferível manter o código do motor separado do código do jogo. A única interação entre o código do jogo com o motor de jogos é o conjunto de funcionalidades disponíveis para o desenvolvedor, por exemplo: renderização, redes, física, informações de entradas (como teclado e controle). Desta maneira, o desenvolvedor não precisa interagir diretamente com as funcionalidades internas do motor, mas com uma interface de programação que fornece acesso aos recursos (renderização, física, redes) para o desenvolvimento do jogo. Dessa forma, neste trabalho é apresentado o Escalonador de Cenas, um escalonador que gerência as funcionalidades e recursos fornecidos para a cena atual do jogo. Além disso, ele gerencia a memória utilizada, isto é, se a cena não está sendo mais utilizada, o escalonador vai liberar os recursos utilizados por ela, garantindo assim robustez e estabilidade ao motor de jogos. Essa técnica foi desenvolvida durante o desenvolvimento da Nightmare Fiction Framework (NF Framework), um motor de jogos com código aberto. Porém, como o conceito é genérico, o escalonador pode ser implementado em outros motores de jogos. O resto deste artigo está dividido da seguinte maneira: na seção 2 é apresentada brevemente o motor de jogos Nightmare Fiction Framework. A seção 3 apresenta o conceito de escalonador utilizado neste trabalho. As seções 4, 5 e 6 apresentam maiores detalhes da implementação do Escalonador de Cenas. A seção 4 é responsável por 106 apresentar o ambiente de desenvolvimento enquanto que as seções 5 e 6 apresentam, respectivamente, detalhes sobre o que consiste uma cena e o escalonador de cenas. 2. NF Framework NF Framework é um motor de jogos totalmente aberto e que está em desenvolvimento utilizando a linguagem C++ e Modern OpenGL. O motor ainda se encontra em estágio inicial de desenvolvimento, porém pretende ser portável para várias plataformas, inclusive consoles. Figura 1. Fã game em desenvolvimento na NF Framework A figura 1 ilustra o jogo que vem sendo desenvolvido utilizando o Nightmare Fiction Framework. Um fã game de Resident Evil ©, jogo originalmente desenvolvido pela Capcom para a plataforma Playstation no ano de 1998. 3. Escalonadores Figura 2. Funcionamento do escalonador Fonte: Based on New York University - Operating Systems Diagram Em Sistemas Operacionais, a chave para a multiprogramação é o escalonamento [Stallings, 2009]. O escalonador vai despachar o processo que deve ser executado no 107 momento. Como pode ser observado na Figura 2, cada processo tem um estado e dependendo do estado o escalonador vai realizar diferentes tarefas com ele (inicializar, executar, encerrar). Outra forma de gerenciar atividades nos sistemas operacionais é com os escalonadores de threads, onde cada processo tem um conjunto de threads que vão executar independentemente e são gerenciadas pelo escalonador de threads. 4. Desenvolvimento O escalonador foi implementado durante o desenvolvimento inicial da NF Framework, devido a necessidade de separar o código do motor do código do jogo. A vantagem de ter o código do jogo e motor separados é a maior organização e o desenvolvimento independente de partes dos códigos, facilitando sua manutenção. Além disto, o valor dessa separação se torna evidente quando os desenvolvedores começam a licenciar jogos e eles são adaptados com novas artes, cenários, armas, personagens, regras de jogo com apenas mudanças mínimas no código do motor de jogos [Jason, 2014]. O código do motor foi escrito em C++ e a ideia é que o código do jogo só tenha acesso às referências dos objetos necessários para o seu desenvolvimento. Para resolver esse problema, foi utilizado o conceito de escalonadores de threads e processos. Em sistemas operacionais é comum existir um escalonador que vai despachar qual o processo que deve ser executado no momento. Qual processo ele vai executar e por quanto tempo, vai variar de acordo com o algoritmo implementado no escalonador. Figura 3. Funcionamento do escalonador A partir dessa ideia de escalonador, temos o conceito de Escalonador de Cenas. Uma cena é uma classe genérica que vai utilizar o conceito de polimorfismo, onde as classes que herdam dela podem ter seu comportamento modificado através da herança. Como ilustrado na Figura 3, uma cena pode ser por exemplo, a Tela Inicial do jogo. Para o gerenciamento das cenas, foi escrita uma outra classe, que é o 108 escalonador de cenas. O escalonador vai verificar qual a cena atual e vai passar para essa as referências dos objetos para essa classe, ele também deve verificar se a cena deve ser alterada, bem como verificar se é necessário limpar os recursos utilizados por ela. Outro fator importante para o desenvolvimento do escalonador na NF Framework foram os smart pointers, recurso fornecido a partir do padrão C++11. Esse recurso de gerenciamento de memória dinâmica é muito importante pois cada cena é um objeto alocado dinamicamente. A vantagem de utilizar cenas alocadas dinamicamente é que: sempre que não haja a necessidade de utilizar a cena, o escalonador pode liberar a memória, mantendo assim um bom gerenciamento de memória. 5. Cena A cena é uma classe genérica que vai ser herdada pelas classes principais do código do jogo. Ela possui uma máquina de estado, que é onde suas funcionalidades devem ser escritas. Ela também pode dizer ao escalonador qual a próxima cena a ser executada. Além disso, a cena também pode dizer ao escalonador através dos estados, o que deve fazer com a cena que está sendo executada. 5.1. Estados de uma cena Os estados de uma cena servem para dizer ao escalonador de cenas o que deve ser feito com a cena que está sendo executada no momento. A figura 4 ilustra os estados de uma cena, abaixo a descrição de cada estado: Figura 4. Estados possíveis em uma cena INIT: A cena deve ser inicializada, assim, deve-se passar todas as referências dos objetos para ela. RUN: A cena já foi inicializada, assim, chama-se a função que executa a máquina de estados da cena. SLEEP: O escalonador deve mudar para a próxima cena e o contexto da cena atual deve ser mantido. END: O escalonador deve mudar para a próxima cena e a cena atual deve ser liberada da memória assim como todos os recursos usados por ela. 5.2. Inicialização de uma cena Essa função só vai ser executada apenas uma vez, quando o escalonador detecta que o estado atual é INIT, normalmente deve-se colocar aqui todos os recursos que vão ser carregados e inicializados pela cena, como carregamento de texturas, modelos, shaders [...]. 109 5.3. Máquina de estado de uma cena Toda vez que a cena estiver no estado RUN, o escalonador vai executar a função responsável pela máquina de estados. A máquina de estados deve ser onde o código da cena a ser executado deve se encontrar. 5.4. Fim da execução de uma cena Se uma cena vai para o estado END ou SLEEP é necessário avisar ao escalonador qual a próxima cena a ser executada. No caso do END o escalonador deve liberar todos os recursos utilizados pela cena. 6. Escalonador de Cenas O conceito de um escalonador de cenas é semelhante ao conceito de um escalonador de processos. O escalonador, que também pode ser chamado de despachante, vai ser executado com frequência e verificar o estado atual da cena que está sendo executada. As ações tomadas pelo despachante variam de acordo com o estado da cena. O escalonador deve primeiro verificar qual o estado da cena atual, sua decisão é feita de acordo com o estado da cena que está sendo executada. As decisões que o escalonador pode tomar são as seguintes: Caso a cena esteja no estado INIT, o escalonador deve passar a referência dos objetos utilizado por essa cena e após isso chamar a função para inicializar os recursos da cena. Caso a cena esteja no estado RUN, o escalonador apenas vai executar a função de máquina de estados da cena. Caso a cena esteja no estado SLEEP, o escalonador deve escalonar a próxima cena e verificar se a cena está alocada. Caso não esteja, o escalonador deve alocar a próxima cena. Se a cena já estiver alocada, porém no estado SLEEP, o escalonador deve mudar o estado da cena para RUN. Caso a cena esteja no estado END, o escalonador deve pegar qual a próxima cena e verificar se a cena está alocada, caso não esteja, o escalonador deve alocar a próxima cena. Se a cena já estiver alocada, porém no estado SLEEP, o escalonador deve mudar o estado da cena para RUN. Como o estado da cena atual é END, O escalonador deve liberar todos os recursos alocados por ela. O escalonador deve garantir que quando uma cena for encerrada os recursos alocados por ela devem ser liberados da memória. Além disso, também deve verificar se a próxima cena solicitada está pronta, caso contrário ele deve alocar a cena e inicializar. Se a cena está pronta, ele sempre executará a função da máquina de estados da cena. O despachante é inicializado pelo núcleo do motor de jogos. Ele deve passar informações como as referências dos objetos que o despachante deve providenciar para as cenas. 1. Conclusões e Trabalhos futuros Neste artigo, a técnica Escalonador de Cenas foi apresentado como uma possível solução de separar o código do motor de jogos do código do jogo. O destaque dessa 110 solução é sua fácil implementação e eficiência ao garantir que recursos não utilizados sempre vão ser liberados. Como trabalhos futuros, existem melhorias que podem ser acrescentadas na técnica de Escalonadores de Cenas como, por exemplo, o compartilhamento de recursos entre cenas. Atualmente cada cena tem seus próprios recursos e não há nenhum compartilhamento de informação entre elas. O próximo passo seria uma possível forma de enviar um buffer de informações entre cenas contendo as informações que devem ser compartilhadas. Outra melhoria é o paralelismo de cenas. O escalonador pode utilizar threads e executar duas cenas ao mesmo tempo. Isso seria útil quanto, por exemplo, precisamos de uma cena secundária que vai carregar os recursos (texturas, modelos 3d, cenários) enquanto a primária renderiza o que já foi carregado pela cena secundária. Referências [Stallings, 2009] Stallings, W (2009). Arquitetura e Organização de Computadores. 8. ed. São Paulo, Pearson. [Jason, 2014] Jason Gregory (2014), Game Engine Architecture. 2. ed. CRC Press. Allan Gottlieb - Operating Systems (2010-11 Spring), New York University. http://cs.nyu.edu/courses/spring11/G22.2250-001/lectures/lecture-04.html 111