Brickosphere
Jogo desenvolvido pelos ingressantes do Bacharelado em Ciência da Computação do IME de 2015:
Victor Domiciano, André Nakazawa, Isabela Blucher, André Ferrari, Nicholas Lima
e pelo Adamastor, com auxílio dos membros-fundadores Vinicius Daros e Wilson Mizutani.
Início: meados de junho de 2015.
Fim: dezembro de 2015.
Tópico Oficial
http://uspgamedev.org/smf/index.php?topic=1765.0
7 de dezembro
Ata da Primeira (e última?) Retrospectiva do Projeto Brickosphere.
- Presentes: André, Isabela, Victor, Vinícius e Wil.
- Início: 15h25
- Término: 17h00
As ações que decidimos tomar com base na retrospectiva do projeto foram as seguintes.
Contas do LabX
O servidor continua instável, então temos que entrar em contato com o Nelson Lago para averiguar a situação. Além disso, falta fazer uma conta para o André (e quem mais?).
Not enough pizza
Para comemorar o término do projeto, faremos uma confraternização no almoço da sexta-feira dia 11/12, no Burger King da Corifeu.
Lançamento do Brickosphere
Para finalizar o lançamento do jogo, foi decido:
- Gerar os executáveis do jogo para as principais plataformas
- Publicar no site do grupo o lançamento do jogo
- Divulgar na turma do BCC 2015
- Falar sobre o desenvolvimento do jogo na palestra de apresentação do grupo no início de 2016
Projetos ágeis
Para ter uma referência rápida e conveniente das diversas técnicas usadas no grupo (em particular as de métodos ágeis), foi decido escrever e/ou atualizar uma série de artigos na Wiki sobre:
- Planejamento de tarefas
- Como fazer reuniões discursivas?
- Como fazer reuniões de trabalho?
- Como fazer retrospectivas?
- Workflow de Git
Curso introdutório
Para receber os novos membros no início do ano que vem, foi decidido fazer um curso (de tempo ainda indeterminado) para introduzir as noções gerais de programação em jogos. A ideia é que depois disso, os interessados comecem seus próprios projetos com o grupo uma vez que tenham dominado o básico. O curso terá dois momentos. No primeiro, ensinaremos com um framework mais simples (como LÖVE ou PyGame) para eles poderem entender o funcionamento "por baixo dos panos" dos jogos, e depois passaremos a focar na Godot, que é a ferramenta principal do grupo.
Vale notar que em Janeiro (confirmação?) ocorrerá um curso de verão do sobre desenvolvimento de jogos bem bacana do VKDaros-sensei e do Luis-sensei (do Lidet).
Identidade do jogo
Foi decidido que assim que uma equipe estiver familiarizada com a Godot, já se deve definir a identidade do jogo em que ela estiver trabalhando, para que isso possa ser devidamente levado em consideração durante o desenvolvimento.
Problemas de documentação da Godot
Para diminuir as dificuldade em entender funcionalidades mal documentadas da Godot, foi decidido que sempre que algo assim for detectado, dever-se-á (1) criar uma issue no projeto da Godot apontando a falta de documentação ou (2) fornecer uma documentação adequada nós mesmos ao time da Godot.
Global Game Jam 2016
A equipe do Brickosphere mostrou interesse em particiar do GGJ2016. Para tanto, será preciso encontrar ou montar um local oficial do evento em São Paulo (preferencialmente na USP).
DevLogs
Como todo mundo ficou babando para este artigo da Wiki, foi decidido que em todo projeto será incentivado a manutenção de algum tipo de relatório periódico no estilo DevLog.
Jogatinas com Boardgames
Dado o sucesso da reunião em que ficamos jogando board games até tarde, foi decidido que devemos marcar mais sessões de board games, principalmente porque alguns membros ainda não estão muito familiarizados com eles.
30 de novembro e 3 de dezembro
Mudamos algumas sprites de bricks para gerar mais contraste, tanto nas transições quanto em relação ao background.
Quando os bricks são atingidos pela bola, eles piscam (foi usado o mesmo efeito da bola) e tremem, para sinalizar melhor que houve uma colisão. A fonte do placar foi aumentada, e quando há alguma adição, ele também treme, no mesmo intuito dos bricks.
O número de bricks do estágio 1 foi reduzido, para diminuir a dificuldade e o tempo deste estágio. A posição inicial da bola foi transferida para o centro (a altura não foi modificada) e a velocidade inicial é aleatória, porém menos horizontal.
A contagem do combo foi modificada: a margem superior da tela e os blue bricks não mais resetam o combo.
O efeito sonoro do brick quando era eliminado foi retirado. O efeito sonoro da bola foi modificado, e o pitch depende do combo atual. Quanto maior o combo, maior o pitch (até atingir 24).
O jogo agora é executado em tela cheia, e o ponteiro do mouse fica invisível durante os estágios.
Foi criada uma nova cena, acessada quando o jogo é completado. Contém uma mensagem de congratulação e o placar final do jogador. Esta cena precede os créditos.
Foi implementado o pause (tecla 'ESC'). A tela possui dois botões ('Resume Game' e 'Quit').
Fizemos correções para evitar um loop infinito no último estágio (devido aos blue bricks). Consiste em um contador que é somado a cada colisão da bola com qualquer elemento do jogo, e é zerado quando colide com a barra. Ao atingir um valor arbitrário (talvez a bola tenha entrado em um loop) é aplicado uma força sutil na bola, imperceptível ao jogador, mas que é suficiente para retirar a bola do loop.
O jogo está concluído.
23 e 26 de novembro
Trocamos a música do estágio 3 por uma música eletrônica não 8-bit. Adicionamos efeitos sonoros quando a bola colide com qualquer elemento do jogo, quando algum brick morre, e nos botões do menu inicial. Para isso, criamos uma biblioteca de áudio utilizada pela classe 'SamplePlayer'. Com essa classe, podemos alterar o volume, utilizar pitch shift, entre outros.
Recebemos um feedback do Vinicius e do Wil sobre as últimas modificações / adições para serem feitas. Concluiremos o jogo no dia 3 de dezembro.
16 e 19 de novembro
Como as imagens de fundo dos estágios e as imagens de textura usadas para criar os sprites não foram de nossa autoria, adicionamos os criadores nos créditos.
Implementamos combo ao jogo. O combo se inicia após uma colisão da bola com algum brick (com exceção do blue brick, do terceiro estágio) e é somado 1 a cada nova ocorrência. O combo termina quando a bola colide com qualquer margem da tela, ou quando o jogador perde ou avança para o próximo estágio. O contador aparece na cor branca do lado direito da tela após atingir o valor 3. A cada soma ao contador, a cor da fonte mudar progressivamente até amarelo e depois para vermelho (13 é amarelo puro e 23 é vermelho puro. Após 23, a cor não se altera). A cada colisão com algum brick, a soma ao placar equivale ao número do combo multiplicado por 100.
Adicionamos música para os estágios, menu e créditos. O estágio 1 tem uma trilha sonora tribal, o 2 tem uma trilha orquestrada e o 3 tem uma música 8-bit em ritmo eletrônico. O menu e os créditos apresentam a mesma música ambiente.
9 e 12 de novembro
Adicionamos imagens de background para os 3 estágios de acordo com a temática de cada um (selva, aquática e espacial). Tornamos a contagem do placar dinâmica: a cada colisão da bola com algum brick, o placar soma 100. Quando algum brick é eliminado, há um bônus de um determinado valor para cada tipo (400 para o yellow brick, 2400 para o moving brick, etc.). Quando o jogador perde, a punição é multiplicar o placar por um valor aleatório entre 0,7 e 0,8, e quando completa algum estágio, o placar soma 10 mil.
Também desenvolvemos o level design de cada estágio seguindo uma progressão de dificuldade. A progressão de um estágio para o próximo é feita da seguinte forma: criamos um script e adicionamos como um filho da raiz (anteriormente, o único filho da raiz era a cena em execução). Portanto, a variável que indica o estágio atual fica armazenada nesse script, e não é perdida a cada troca de cena.
Criamos um novo tipo de brick chamado blue brick. Ele está presente apenas no último estágio e foi o mais simples de implementar: ele não possui nenhum script associado; funciona como um obstáculo, pois é colidível, porém indestrutível (não há soma no placar quando a bola o atinge).
Criamos uma cena contendo os créditos para o jogo que surge ao completar o estágio 3. Criamos também uma tela de menu inicial. Possui dois botões: 'Play' e 'Credits'.
Ata da Reunião do dia 04/11
Presentes: Victor, Isabela, André, Vinicius, Wil.
Início: 15:10
Fim: 16:15
Metas para o último mês de trabalho
- Progressão de fases;
- Menu e créditos;
- 3 Biomas;
- assets;
- level design;
- Música.
Sobre os biomas:
- Selva
- Aquático
- Espaço
Mudanças no projeto:
- Disposição dos bricks;
- Background.
Tema das músicas:
- Selva: tribal (percussão);
- Espaço: sci-fi 8-bit.
Pauta da Reunião do dia 04/11
Local: Sala de Reuniões do CCSL (Bloco C do IME).
Horário: 15:00
Duração máxima: 1 hora
Objetivo Principal: Definir a identidade do jogo.
Pré-leitura recomendada: https://en.wikipedia.org/wiki/Game_design_document
1.1 Inclusões na pauta: algum tópico importante está ausente?
1.2 Árvore de Requerimentos (continuação): o que precisamos aprender para implementar os fatores base?
2.1 Nosso jogo é um projeto de software, game design, ou um produto de mercado?
2.2 Como o nosso jogo se diferencia dos outros jogos de Brick Breaker? Qual é a identidade que nosso jogo possuirá?
2.3 Qual vai ser o nome do nosso jogo?
3.1 Quais elementos de juiciness acrescentam ou enfatizam a identidade do nosso jogo? E quais contribuem para a diversificação / dificuldade do gameplay?
3.2 O que precisamos aprender para implementar esses elementos?
4. O que faremos para facilitar a inclusão de novos integrantes do Grupo no nosso projeto?
5. Cronograma: quais atividades têm prioridade para o projeto?
26 e 29 de outubro
Corrigimos a condição de vitória da seguinte maneira: na inicialização de cada brick, ele é adicionado no grupo correspondente ao número de colisões necessárias para ele morrer. Na inicialização da cena principal, é carregado o número de nós que cada grupo possui e feito as operações necessárias.
Aprendemos como instanciar cenas via código. Segue um tutorial de como fazer isso:
Tutorial de como acessar variáveis de outras cenas:
- Definir duas variáveis globais:
- var scene = preload("[endereço_da_cena]")
- var node
- Na função ready:
- node = scene.instance()
- add_child(node)
Ata da Reunião do dia 22/10
Objetivo: Construir um planejamento de trabalho e definir cronograma
Presentes: André, Victor, Isa, Adamastor, VKDaros e eu
Início: Aproximadamente às 17h
Fim: 19h
Próxima reunião: 4/11/2015, às 15h (confirmar) na sala de reuniões do bloco C do IME
1. Cadeia de valor (quem tem valor para quem?)
As relações a seguir compõem a cadeia:
- Nós desenvolvemos o jogo
- O jogo traz aprendizado para nós
- O jogo acresce ao portfolio do USPGameDev
- O jogo diverte os jogadores
Fora isso, nessa parte da reunião foram destacados os principais motivos que levaram os novos membros a entrarem no grupo:
- Programação orientada a jogos
- Trabalho em equipe
- Organizar projetos
1.1 Fatores crítico para o sucesso
- Imersão na ação (flow)
- Som
- Ausência de enredo
- Visual
1.2 Atividades (fatores base)
- Bola, bricks, barra, score
- Menu
- Progressão de fases
- Sistema de saves
- Configurações
- Comandos (pausa, volume, etc)
- Instruções (sobre controles)
- Seleção de fases
- Condição de vitória: acabar os bricks
- Créditos
2. Elementos extras:
- Imersão
- Controle
- "Sharp" perceptivo
- Desafio de habilidade
- Dinâmica
- Micro
- Macro
- Self-competition
- Controle
- Som
- Sinalizar
- Embalar
- Diversidade por fase
- Visual
- Sinalizar
- Dinâmica
3. Árvore de requerimentos
- Progressão de fases
- Pilha de cenas
- Persistência de dados
- Menu
- Sistema de saves
- Especificar o formato do save
- Configuração
Não foi possível montar a árvore inteira pois acabou o tempo da reunião.
Pauta da Reunião do dia 22/10
1. Conceitos Introdutórios
- Formulação da cadeia de valor (em especial a diferença de valores entre o desenvolvedor e o jogador);
- Fatores críticos de sucesso (aspectos importantes para um jogo brick-breaker: ação, controle, etc.);
- Características essenciais do jogo (menu, sistema de saves, sons, etc.).
2. Mapa de Atividades
- Definir os elementos extras (juiciness);
- Separação das atividades: Temos pessoas especializadas / Não temos pessoas especializadas;
- Montar uma árvore de requerimentos para cada tópico;
- Organização por categorias (programação, arte, som, etc.);
- Duração esperada das atividades.
3. Abertura para novos integrantes do Grupo
- Discussão.
4. Revisão do Mapa
- Transferir atividades para outras categorias (opcional);
- Montar cronograma;
- Retrospectiva da Reunião.
15 de outubro
Estamos organizando uma reunião para discutir sobre a formulação de um mapa de atividades para o Brick Breaker. Este mapa é necessário para agilizar os processos e criar uma ordem de importância para as tarefas.
Começamos a separar os elementos comuns do jogo (bola, barra, etc.) que estão presentes em todas as fases em uma subcena. A intenção é que, a cada fase criada, os bricks sejam armazenados em outra subcena, e a cena principal conterá apenas a subcena dos elementos comuns e a subcena dos bricks da fase em questão.
Criamos um repositório no GitHub. Como as cenas criadas, por padrão, são salvas como sendo um arquivo binário (e não um plain text), tivemos que modificar a extensão dos arquivos (.scn para .xscn). É importante que os arquivos sejam plain text para que seja possível identificar modificações no controle de versão. Alguns comandos importantes:
$ git status
- Mostra a situação dos arquivos controlados pelo Git.
$ git add [nome_do_arquivo]
- Adiciona o arquivo nome_do_arquivo no stage (conjunto de modificações — commit — que serão entregues).
$ git commit
- Associa um conjunto de alterações (stage) a uma mensagem.
Obs.: stage: local; commit: remoto
$ git log
- Histórico de commit (versões).
$ git clone [endereço_do_repositorio_no_github]
- Copia o repositório remoto.
$ git pull
- Atualiza os arquivos que estão sendo monitorados pelo Git, sincronizando-os com o repositório remoto.
Começamos também a corrigir um erro no arquivo que armazena o placar.
5 e 8 de outubro
Mudamos a reação da bola ao colidir com a barra. A velocidade horizontal resultante da bola é determinada a partir da sua velocidade anterior à colisão somada com a velocidade da barra no instante da colisão (antes da soma, há um coeficiente que multiplica o valor da velocidade da barra, para que aumente sua influência na velocidade resultante da bola; empiricamente, o melhor valor encontrado foi 10). Essa modificação torna possível, inclusive, mudar a direção natural que a bola teria após a colisão (se a bola vem da esquerda e a barra está indo para este lado com uma velocidade suficientemente alta, ela será rebatida para a esquerda ao invés da direita, como seria a reação normal).
Com relação à jogabilidade, essa foi uma das mudanças mais importantes até o momento. As habilidades do jogador realmente fazem a diferença depois dessa modificação.
Ao iniciar o level, foi adicionado um efeito tweening nos bricks, onde é dada a impressão de que eles "caem" até a posição correta deles. A natureza do movimento foi caracterizada de forma elástica, e a amplitude, de forma aleatória para cada brick.
Foi criado um novo tipo de brick, chamado Ghost Brick. Após 3 segundos parado em uma posição, ele some durante 2 segundos e reaparece em uma coordenada horizontal aleatória, restrita a duas coordenadas verticais prefixadas. A determinação de qual das duas o brick irá aparecer é aleatório. Ele também possui uma imagem exclusiva.
28 de setembro e 1º de outubro
Adicionamos mais juiciness para a bola e os bricks. Quando a bola colide com a barra, os bricks ou a margem, ela aumenta de tamanho (150%) e volta ao normal depois de meio segundo. Ao mesmo tempo, ela também muda de cor (aumento de brilho) dando uma impressão de que ela pisca. Os bricks, quando colididos pela última vez, eles "caem" com um efeito fade out.
No caso dos bricks, surgiram algumas dificuldades e bugs. Inicialmente, o comando que fazia o brick desaparecer não poderia ser acionado juntamente com a função Tween, pois o efeito seria ignorado. Criamos um contador, que é acionado juntamente com a invocação da função Tween, e que aumenta a cada loop do jogo. Quando o contador atinge 30 (60 / 2), o brick desaparece. Um dos bugs corrigidos foi o caso em que a bola colidia mais de uma vez com um brick que estava desaparecendo (duas ou mais colisões durante meio segundo). A solução foi usar uma função que muda a "camada" em que ocorre a colisão do brick que está desaparecendo.
Foi criado uma nova cena contendo um Easter Egg. Se o jogador usar os cantos corretos da barra para fazer com que a velocidade horizontal da bola aumente cada vez mais, há uma possibilidade da bola atravessar a hitbox da margem, dado a taxa de atualização do jogo. Quando isso acontece, a cena muda para esse Easter Egg.
21 e 24 de setembro
Com as modificações implementadas nesta ocasião, o jogador poderá controlar sutilmente a direção da bola quando rebatida pela barra. A diferença com a versão anterior é que, ao invés de acelerar as velocidades vertical e horizontal igualmente, houve um acréscimo grande (130%, caso a bola seja rebatida na extremidade que aponta para o mesmo sentido do movimento da bola) ou decréscimo (80%, caso contrário) da velocidade horizontal, contra um acréscimo pequeno (105%) da velocidade vertical em ambas as situações, o que faz com que o ângulo aumente ou diminua. Se a bola já tiver atingido sua velocidade máxima vertical, há um decréscimo (80%) dela no caso em que houver os pequenos acréscimos da velocidade horizontal.
Também foi criada uma subcena no intuito de conter bricks que se mexem. O movimento dos bricks é feito usando tweening, e eles possuem imagens diferentes dos demais (azul ciano antes da primeira colisão, e pink depois), feitas novamente usando Pixel Art.
14 e 17 de setembro
Houve alteração das texturas dos elementos do jogo. As imagens foram feitas usando Pixel Art.
A colisão da bola com a margem da tela não é mais feita através de código. Foi criada uma hitbox sem identificação gráfica na parte externa da tela, e portanto os critérios de colisão são os implementados pela física da Godot.
Foram criados três tipos diferentes de bricks: os verdes (uma colisão para ser destruído), os amarelos (duas), e os vermelhos (três). A cada colisão da bola com algum brick há uma resposta visual. Se o brick for amarelo, sua textura é alterada para a do brick verde; se o brick for vermelho, sua textura é alterada para a do brick amarelo e, após outra colisão, para o verde. A implementação das subcenas dos bricks também foi modificada. Houve a criação de uma subcena contendo apenas um brick, e subsequentemente, outra subcena contendo várias dessas subcenas (posicionando-as adequadamente). A consequência foi que na cena principal só há 3 subcenas, ao invés de 60 (número atual de bricks).
7 e 11 de setembro
A mecânica básica do jogo foi concluída. Os próximos passos são direcionados ao design, adicionando juiciness ao jogo. Serão seguidas algumas características encontradas em um exemplo dado em uma palestra sobre juiciness.
O número de bricks mudou de 14 para 84; a bola, a barra e os bricks agora são coloridos (verde, azul e vermelho, respectivamente).
Houve alteração no modo como o jogador move a barra: anteriormente feito pelas teclas, agora o movimento é feito pelo mouse. Dessa forma, o jogo fica mais dinâmico e permite um maior controle sobre a barra.
Por fim, foram feitas algumas correções em displicências no código, como a adição de comentários informativos e padronização de variáveis.
31 de agosto e 3 de setembro
Foi adicionado um placar bem simples no canto superior direito: quando ocorre 'Game Over', o placar é subtraído em uma unidade; quando o último brick é atingido pela bola, é somado uma unidade. Foi utilizada a classe File da Godot, que carrega um arquivo que contém a variável toda vez que o jogo é iniciado.
Houve a adição de uma nova cena, utilizada quando o jogador vence.
A velocidade inicial da bola foi modificada: ela é definida a partir da função randf, que devolve um número pseudoaleatório entre 0 e 1. Portanto, cada partida é única.
A barra, anteriormente, era um Sprite, pois a colisão com a bola era bem simples de ser implementada via script. Ela foi alterada para ser um corpo cinemático.
Foi acrescentado aceleração na bola (110%) quando ela colide com a barra em uma superfície que representa 2/3 de sua extensão: 1/3 na esquerda e 1/3 na direita.
24 e 27 de agosto
Tutorial de como fazer e detectar colisões na Godot:
- Crie um node (Ctrl + A) do tipo 'Node' (por padrão, está selecionado 'Control'; mude a seleção para 'Node');
- Crie um node RigidBody2D;
- (*) Crie um node Sprite, filho de RigidBody2D;
- Inspector -> Sprite -> Texture -> Load -> icon.png -> Open;
- Use uma caixa de seleção para posicionar o RigidBody2D e o Sprite mais ou menos no centro da tela;
- Crie um node CollisionShape2D filho de RigidBody2D;
- Inspector -> CollisionShape2D -> CollisionShape2D -> Shape -> New RectangleShape2D;
- Inspector -> CollisionShape2D -> Node2D -> Scale (coloque um valor conveniente, recomendamos (3, 3));
- Crie um node StaticBody2D, filho de 'Node';
- Repita os passos acima com o StaticBody2D, a partir de (*), de modo semelhante ao que foi feito com RigidBody2D;
- Usando a caixa de seleção, posicione o StaticBody2D, junto com seu Sprite, abaixo do RigidBody2D;
- Salve a cena (Ctrl + S);
- Vá no menu Scene -> Project Settings -> application -> Main Scene -> File -> new_scene.scn -> Open;
- Execute o programa (F5) e observe que o RigidBody2D é afetado pela gravidade, e o StaticBody2D não;
- Obs.: A colisão deve estar funcionando.
- Selecione o RigidBody2D, crie uma script (clicando no 'pergaminho', na janela Scene);
- Digite o nome do script no campo 'Path' (extensão .gd) e clique em 'Create';
- Selecione o RigidBody2D, e vá em Inspector -> RigidBody2D -> Contacts Report = 1 e Contact Monitor on;
- Selecione o RigidBody2D, crie uma conexão (clicando na 'tomada', na janela Scene), selecione body_enter -> Connect;
- Selecione o RigidBody2D (a função de conexão está no campo "Method in Node") -> Connect;
- Preencha a função de conexão criada (_on_RigidBody2D_body_enter, por padrão) com um print;
- Observe o print em 'Output', na próxima execução do programa.
Foram vistos novos conceitos: Damp, Character Body, Subscene, Signals e Connections. A colisão da bola com os bricks foi corrigida, e foi utilizada subcenas para replicá-los.
17 e 20 de agosto
Estava havendo problemas com a colisão da bola com os bricks, pois a implementação utilizada era baseada no código, usando operações condicionais. Foi decidido que a maneira mais fácil de corrigir isso seria aprender mais sobre a física da Godot. Em suma, existem 3 tipos de corpos colidíveis em uma cena 2D: estático, cinemático e rígido. Corpos estáticos são os mais simples e, como o nome diz, não se movem. Corpos cinemáticos se movem na cena através de comandos no teclado ou no código. Corpos rígidos são os mais sofisticados. Eles reagem, basicamente, de acordo com a gravidade, e possuem características como a massa, a elasticidade da colisão e o atrito com superfícies.
Foi iniciado a implementação da física no Brick Breaker, sendo a bola um corpo rígido (a gravidade foi alterada para zero. Era preciso um corpo que simulasse colisões elásticas), e os bricks, corpos estáticos.
Ferramenta
Godot, engine open source adotada como opção padrão para desenvolvimento dos projetos do grupo.