P4: Super Mario Bros
Política de Atraso
- A penalização será de 15% para cada dia de atraso.
- Cada atraso pode ser de no máximo 2 dias.
Introdução
O Super Mario Bros (SMB), lançado pela Nintendo em 1985, foi um dos jogos mais populares da era dos consoles 8 bits. SMB é um jogo de plataforma de rolagem lateral onde o objetivo do jogador é se mover para a direita para chegar a um mastro de bandeira no final de cada nível. O jogador controla o Mario, protagonista da série. O irmão de Mario, Luigi, é controlado pelo segundo jogador no modo multijogador e assume o mesmo papel e funcionalidade de Mario. Na narrativa do jogo, o mundo é chamado de Reino do Cogumelo e o Mario está atravessando-o para salvar a Princesa Peach do antagonista Bowser. O video a seguir mostra um gameplay do jogo original:
Objetivo
O objetivo desse projeto é praticar a implementação de detecção de colisão com AABBs, rolagem de câmera, animação 2D e integração com editores externos. Para isso, você irá implementar as mecânicas básicas de correr, pular, e acertar inimigos no primeiro nível do SMB. Primeiro, você irá implementar o componente DrawSpriteComponent para desenhar sprites estáticos (i.e., não-animados) na tela. Como parte dessa tarefa, você irá escrever uma função para ler níveis de arquivos texto. Depois, você irá implementar o componente AABBCollideComponent para detectar colisões entre caixas delimitadoras alinhadas com os eixos (AABBs). Em seguida, você irá implementar a rolagem de câmera e o componente DrawAnimatedComponent, de animações de sprites, utilizando sprite sheets gerados por uma ferramente externa. Por fim, você irá implementar os goombas, incluindo as mecâmicas de matá-los quando o jogador pula em cima deles e de matar o jogador quando eles o acertam no chão. O vídeo a seguir mostra um gameplay da versão que você irá implementar (apesar do vídeo conter áudio, nesse projeto você não irá implementar essa funcionalidade):
Inicialização
Aceite o projeto p4-super-mario-bros no GitHub classroom [nesse link] e clone o seu novo repositório no seu computador:
# Substitua <GITHUB_USERNAME> pelo seu usuário do GitHub
git clone https://github.com/ufv-inf216/p4-super-mario-bros-<GITHUB_USERNAME>.git
Código Base
Abra o projeto p4-super-mario-bros na CLion e, antes de começar a sua implementação, verique com cuidado as definições de métodos e atributos de cada classe. O código base desse projeto foi construído a partir do código do projeto anterior [P3: Asteroids], portanto muitas das classes já foram introduzidas anteriormente. As novas classes desse projeto são:
-
DrawSpriteComponent
Componente para desenho de sprites estáticos (i.e., não animados).
-
DrawAnimatedComponent
Componente para desenho de sprites animados (estende
DrawSpriteComponent). -
AABBCollideComponent
Componente para detecção de colisão entre AABBs.
-
Block
Classe que estende
Actorpara representar um bloco do jogo. -
Goomba
Classe que estende
Actorpara representar o Goomba, inimigo que se movimenta horizontalmente de um lado para o outro. -
Mario
Classe que estende
Actorpara representar o Mário, que é controlado pelo jogador. -
Spawner
Classe que estende
Actorpara representar um “gatilho” (ou trigger) que cria um goomba quando o jogador está próximo.
Instruções
Parte 1: Sprites Estáticos
Na primeira parte, você irá implementar o componente DrawSpriteComponent para desenhar sprites estáticos na tela.
-
Game.cpp
-
Implemente o método
LoadTexturepara carregar uma textura com a SDL-
Utilize a função
IMG_Loadpara carregar a imagem passada como parâmetrotexturePath. Esse função retorna um ponteiro paraSDL_Surface*. Retornenullptrse a imagem não foi carregada com sucesso. -
Utilize a função
SDL_CreateTextureFromSurfacepara criar uma textura a partir da imagem carregada anteriormente. Essa função retorna um ponteiro paraSDL_Texture*. Logo após criar a textura, utilize a funçãoSDL_FreeSurfacepara liberar a imagem carregada. Se a textura foi carregada com sucesso, retorne o ponteiro para a textura. Caso contrário, retornenullptr.
-
-
Implemente o método
InitializeActorspara inicializar os objetos do jogo-
Crie um objeto do tipo
Marioe armazene-o na variável membromMario. -
Utilize a função
LoadLevel(que será implementa a seguir) para carregar o primeiro nível (Level1.txt) do jogo. Esse arquivo tem 14 linhas e 213 colunas.
-
-
Implemente o método
LoadLevelpara carregar um nível do jogo- Leia o arquivo texto
levelPathcomheightlinhas ewidthcolunas para carregar um nível do jogo. Uma nível é representado por um grid com largurawidthe alturaheight, onde cada célula tem tamanho32x32. Para cara caractere entreAeI, crie um objeto do tipoBlockutilizando a textura correspondente. Para cara caractereY, crie um objeto do tipoSpawnerutilizando a distância SPAWN_DISTANCE como parâmetro de criação.
- Leia o arquivo texto
-
-
DrawSpriteComponent.cpp
-
Implemente o construtor e o método
Drawpara desenhar sprites estáticos-
No construtor, utilize a função
LoadTextureque você implementou na última etapa para criar uma textura a partir da imagemtexturePathpassada como parâmetro no construtor. Armazene o ponteiro retornadoSDLTexture*na variável membromSpriteSheetSurface. -
No método
Draw, utilize a funçãoSDL_RenderCopyExpara desenhar a textura armazenada na variável membromSpriteSheetSurface. Você terá que criar umSDL_Rectpara definir a região da tela onde será desenhado o sprite. Além disso, você terá que criar uma flag do tipoSDL_RendererFlippara definir se o sprite será desenhado virado à direita ou à esquerda. A orientação do sprite (esquerda ou direita) depende da rotação do objeto dono do sprite. Se a rotação for zero, o sprite deve ser desenhado virado à direita. Se for igual aMath::Pi, deve ser desenhado à esquerda.
-
-
-
Block.cpp
-
Implemente o construtor para adicionar os componentes
AABBColliderComponenteDrawSpriteComponent-
Crie o
AABBColliderComponentcom dimensões(0,0,32,32)e tipo de colisãoColliderLayer::Blocks. -
Crie o
DrawSpriteComponentcom texturatexturePath(passada com parâmetro) e dimensões(32,32).
-
-
-
Mario.cpp
-
Adicione os componentes
DrawSpriteComponenteRigidBodyComponentno construtor-
Até que você termine a implementação do componente de animação
DrawAnimatedComponent, utilize o componente para desenho de sprites estáticosDrawSpriteComponent. Crie um desses componentes com a texturaAssets/Sprites/Mario/Idle.pnge dimensões(32,32). -
Para que o jogador possa se mover, crie também um componente
RigidBodyComponentcom massa1.0e coeficiente de atrito5.0. Note que a classeMariojá tem atributos para armazenar esses componentes.
-
-
Implemente o método
OnProcessInputpara mover o jogador horizontalmente-
Verifique se o jogador pressionou a tecla
D. Se sim, aplique uma força para a direita com magnitudemForwardSpeede altere a rotaçãomRotationpara0. Além disso, altere a variávelmIsRunningpara verdadeiro. Isso será importante para controlar as animações na Parte 4. -
Verifique se o jogador pressionou a tecla
A. Se sim, aplique uma força para a esquerda com magnitudemForwardSpeede altere a rotaçãomRotationparaMath::Pi. Além disso, altere a variávelmIsRunningpara verdadeiro. Caso o jogador não estiver pressionando nemD, nemA, altere essa variável para falso. Isso será importante para controlar as animações na Parte 4.
-
-
Ao final dessa parte, você deveria ser capaz de se mover no nível 1 sem colisão, sem animação e sem movimento de câmera.
Parte 2: Detecção de Colisão com AABBs
Na segunda parte, você irá implementar o componente AABBColliderComponent para detectar colisões no jogo.
-
AABBColliderComponent.cpp
-
Implemente os métodos
GetMin,GetMaxeGetCenterpara calcular os pontos de mínimo, máximo e centro da AABB, respectivamente-
No método
GetMin, calcule (e retorne) o ponto mínimo dessa AABB. A variávelmOffsetdefine a posição da AABB com relação a posição do objeto dono do componente. Portanto, basta somar a posição do objeto dono do componente a esse deslocamento. -
No método
GetMax, calcule (e retorne) o ponto máximo dessa AABB. As variáveis membromWidthemHeightdefinem a altura e a largura da AABB, respectivamente. Portanto, basta somar a largura à coordenada x e a altura à coordenada y do ponto mínimo da AABB (utilize o métodoGetMinimplementado anteriormente). -
No método
GetCenter, calcule (e retorne) o centro dessa AABB. Esse ponto pode ser calculado de forma similar ao ponto máximo, basta somar a metade da largura à coordenada x e a metade da altura à coordenada y do ponto mínimo da AABB (utilize o métodoGetMinimplementado anteriormente).
-
-
Implemente método
Intersectpara verificar se duas AABBs têm interseção- Verifique se esta AABB está colidindo com a AABB
bpassada como parâmetro. Retorne verdadeiro se estiver e falso caso contrário. Utilize os métodosGetMineGetMaxpara acessar os pontos de mínimo e máximo das duas AABBs.
- Verifique se esta AABB está colidindo com a AABB
-
Implemente método
GetMinOverlappara calcular a sobreposição e lado de uma colisão-
Armazene no mapa
overlapsas sobreposições (com sinal -/+) dos quatro lados da colisão: esquerda, direita, cima e baixo. Utilize os métodosGetMineGetMaxpara acessar os pontos de mínimo e máximo das duas AABBs. -
Encontre e retorne a sobreposição com distância mínima. Para isso, utilize os valores absolutos das sobreposições calculadas na etapa anterior.
-
-
Implemente método
ResolveCollisionspara separar uma AABB após uma colisão-
Verifique se a sobreposição
minOverlapocorreu no lado de cimaCollisionSide::Topcom velocidade vertical negativa ou no lado de baixoCollisionSide::Downcom velocidade vertical positiva. Note que a estruturaminOverlapjá possui o lado onde ocorreu a colisãominOverlap.side. Se um desses dois casos for verdadeiro, some a quantidade de sobreposiçãominOverlap.amountà posição vertical do dono dessa AABB e reinicialize sua velocidade vertical para zero. Dica: para verificar, por exemplo, se a colisão foi por cima, basta comparar seminOverlap.sideé igual aCollisionSide::Top. -
Caso nenhum dos dois casos anteriores sejam verdadeiros, verifique se a sobreposição
minOverlapocorreu no lado esquerdoCollisionSide::Leftcom velocidade horizontal negativa ou no lado direitoCollisionSide::Rightcom velocidade horizontal positiva. Se um desses dois casos for verdadeiro, some a quantidade de sobreposiçãominOverlap.amountà posição horizontal do dono dessa AABB e reinicialize sua velocidade horizontal para zero.
-
-
Implemente método
DetectCollisionpara detectar colisões entre os objetos do jogo-
Utilize a função
std::sortpara ordenar o vetorcollidersde acordo com a distância entre o centro dessa AABB e o centro de cada AABB desse vetor. O vetorcolliderscontém as AABBs de todos os atores do jogo (Mário, goombas e blocos). Ordenar esse vetor dessa forma fará com que as colisões mais próximas sejam resolvidas primeiro, zerando as velocidades dos objetos na ordem esperada. -
Utilize um laço para percorra o vetor
collidersordenado, verificando colisões com cada AABB alvo. Em cada iteração do laço, execute as seguintes operações:-
Verifique se o elemento corrente é a AABB desse objeto
this. Se for, continue para a próximo elemento, pois não precisamos verificar colisão de uma AABB com ela mesma. -
Verifique se o elemento corrente está habilitado
IsEnabled(). Se não estiver, continue para a próximo elemento, pois não queremos verificar colisão de uma AABB desabilitada. -
Utilize a função
GetMinOverlappara obter a sobreposição mínima dessa AABB com o elemento corrente. Em seguida, utilize a funçãoResolveCollisionspara resolver a colisão entre essa AABB e o elemento corrente. Por fim, armazene os dados dessa sobreposição no maparesponses. Essa mapa será utilizado para enviar uma mensagem de callbackOnCollisionpara o objeto dono dessa AABB. -
Verifique se já houve uma colisão vertical e uma horizontal durante o laço. Se sim, interrompa o laço (break), pois não precisamos verificar mais colisões.
-
-
-
-
Mario.cpp
-
Adicione o componente
AABBColliderComponentpara habilitar colisões do jogador com os blocos do nível- Crie um componente
AABBColliderComponentno construtor da classeMariocom dimensões(0,0,32,32)e o tipoColliderLayer::Playerda AABB. Se quiser desenhar a AABB do Mário para testas as colisões, crie um componenteDrawPolygonComponentcom os vértices da AABB.
- Crie um componente
-
Modifique o método
OnProcessInputpara implementar o pulo- Verifique se o jogador está no chão (
mIsOnGround) e se ele pressionou a teclaA. Se sim, altere a velocidade vertical paramJumpSpeede a variávelmIsOnGroundpara falso. UtilizeSetVelocityao invés deApplyForcepara que o pulo seja mais rápido e preciso.
- Verifique se o jogador está no chão (
-
Ao final dessa parte, você deveria ser capaz de se mover no nível 1 com colisão, porém sem animação nem movimento de câmera.
Parte 3: Rolagem de Câmera
Na terceira parte, você irá implementar a rolagem de câmera desenhando os objetos em relação à posição da câmera, ao invés da origem do mundo.
-
Game.cpp
-
Implemente o método
UpdateCamerapara fazer a câmera seguir o jogador- Calcule a posição horizontal da câmera subtraindo a posição horizontal do jogador (i.e., do Mário) da metade da largura da janela. Isso fará com que a câmera fique sempre centralizada no jogador. No SMB, o jogador não pode voltar no nível, portanto, antes de atualizar a posição da câmera, verifique se a posição calculada é maior do que a posição anterior. Além disso, limite a posição para que a câmera fique entre 0 e o limite superior do nível. Para calcular o limite superior do nível, utilize as constantes
LEVEL_WIDTHeTILE_SIZE.
- Calcule a posição horizontal da câmera subtraindo a posição horizontal do jogador (i.e., do Mário) da metade da largura da janela. Isso fará com que a câmera fique sempre centralizada no jogador. No SMB, o jogador não pode voltar no nível, portanto, antes de atualizar a posição da câmera, verifique se a posição calculada é maior do que a posição anterior. Além disso, limite a posição para que a câmera fique entre 0 e o limite superior do nível. Para calcular o limite superior do nível, utilize as constantes
-
-
DrawSpriteComponent.cpp
-
Modifique o método
Drawpara subtrair a posição da câmera da posição do objeto- Para que o objeto seja desenhado em relação a posição da câmera, subtraia a posição da câmera da posição do objeto quando for desenhá-lo com a função
SDL_RenderCopyEx.
- Para que o objeto seja desenhado em relação a posição da câmera, subtraia a posição da câmera da posição do objeto quando for desenhá-lo com a função
-
-
Mario.cpp
-
Modifique o método
OnUpdatepara garantir que a posição horizontal do jogador esteja sempre à frente da câmera- Para evitar que o jogador ultrapasse o limite inferior (esquerdo) da câmera, limite sua posição horizontal para ser sempre maior ou igual a posição horizontal da câmera.
-
Parte 4: Animações
Na quarta parte, você irá implementar o componente DrawAnimatedSprite para animar os objetos do jogo. No entanto, antes de
começar a escrever o código, você precisará utilizar o TexturePacker para gerar os sprite sheets do Mário, Goomba e dos blocos. Utilize o formato de dados json (Array) e o algoritmo Grid/Strip para
exportar os sprite sheets. Copie os sprite sheets (imagens e dados) para os seus respectivos locais dentro do diretório Assets do projeto. Por exemplo, copie o sprite sheet do Mário para o local Assets/Sprites/Mario.
-
DrawAnimatedComponent.cpp
Todos os quadros de um objeto estão armazenados no vetor
mSpriteSheetData. Cada posição desse vetor é um ponteiro para umSDL_Rect*, representando as coordenadas de um sprite no sprite sheet. Além disso, todas as animações estão armazenadas no mapamAnimations. Uma animação é identificada por um nome (string) e definida por um vetor de índices de quadros (armazenados emmSpriteSheetData). A nome da animação corrente é armazenado na variável membromAnimName.-
Implemente o método
Updatepara atualizar o timer da animação-
Verifique se animação está pausada (
mIsPaused). Se estiver, saia da função (return). -
Atualize o timer da animação
mAnimTimercom base na taxa de atualização (mAnimFPS) e no delta time -
Podemos converter o timer da animação
mAnimTimerpara inteiro para obter o índice do quadro atual. No entanto, temos que garantir que esse índice não será maior do que número total de quadros da animação corrente (mAnimations[mAnimName].size()). Verifique se o timer da animação é maior ou igual ao número de quadros da animação corrente. Se for, utilize um laçowhilepara decrementar o timer por esse mesmo número até essa condição seja falsa.
-
-
Implemente o método
Drawpara desenhar o sprite corrente da animaçãoSempre que um objeto com o componente
DrawAnimatedComponenté desenhado na tela, precisamos obter o índice do quadro corrente a partir do timer da animação. Para isso, basta converter o timer da animação (mAnimTimer) para inteiro.-
Obtenha o índice do quadro corrente indexando o mapa
mAnimationscom o timer da animação (mAnimTimer) convertido para inteiro. Note quemAnimations[mAnimName]armazena os índices dos quadros da animação atual. Armazene o resultado em uma variávelspriteIdx. -
Utilize a função
SDL_RenderCopyExpara desenhar o sprite com índicespriteIdx. O SDLRect que define a região do sprite no sprite sheet está armazenado emmSpriteSheetData[spriteIdx]. Além disso, você terá que criar um SDL_Rect para definir a região da tela onde será desenhado o sprite, assim como noDrawSpriteComponent. Não se esqueça de subtrair a posição da câmera da posição do objeto. Você também terá que criar uma flag do tipo SDL_RendererFlip assim como no DrawSpriteComponent.
-
-
Implemente o método
SetAnimationpara mudar a animação corrente- Salve o nome da animação corrente
namena variável membromAnimNamee chame a função Update passando delta time igual a zero para reinicializar o timer da animaçãomAnimTimer.
- Salve o nome da animação corrente
-
-
Mario.cpp
-
Modifique o construtor para adionar o componente de desenho
DrawAnimatedComponentao invés deDrawSpriteComponent-
Crie um componente
DrawAnimatedComponentpassando os caminhos da imagem (.png) e dos dados (.json) do sprite sheet do Mário que você criou com o TexturePacker. -
Utilize a função
AddAnimationpara adicionar as animações “dead”, “idle”, “jump” e “run”. -
Utilize a função
SetAnimationpara definir a animação inicial como “idle”. Em seguida, utilize a funçãoSetAnimFPSpara definir a taxa de atualização de quadros da animação para 10.0f.
-
-
Modifique o método
OnUpdatepara detectar quando o jogador morreu- Verifique se a posição vertical do jogador é maior do que o tamanho da tela. Se for, chame o método
Kill.
- Verifique se a posição vertical do jogador é maior do que o tamanho da tela. Se for, chame o método
-
Implemente o método
Killpara tocar a animação de morte e finalizar o jogo- Altere a animação para “dead” e o valor da variável
mIsDeadpara verdadeiro. Além disso, desabilite (SetEnabled(false)) os componentesmRigidBodyComponentemColliderComponent.
- Altere a animação para “dead” e o valor da variável
-
Implemente o método
OnCollisionpara atualizar o estado do jogador após uma colisãoO mapa
responsescontém os dados de cada colisão desse objeto nesse quadro. Cada elemento deresponsesé uma estrutura do tipoOverlap, que contém o lado da colisãoside, o tamanho da sobreposiçãoamount(com sinal -/+) e um ponteirotargetpara a AABB que colidiu com o objeto.-
Percorra essa mapa atualizando o estado do jogador bom base no tipo de colisão:
-
Se a colisão ocorreu com um objeto do tipo
ColliderLayer::Blockspelo lado de baixoCollisionSide::Down, significa que o jogador aterrizou no chão. Nesse caso, altere o valor da variávelmIsOnGroundpara verdadeiro. -
Se a colisão ocorreu com um objeto do tipo
CollisionSide::Enemypelo lado de baixo, significa que o jogador acertou um goomba no ar. Nesse caso, mate esse goomba e altere a velocidade do jogador para dar um “meio pulo” (mJumpSpeed/1.5f). Utilize o ponteirotargetdo elemento corrente para acessar o ponteiro para esse goomba e o métodoKilldo goomba para matá-lotarget->GetOwner()->Kill(). -
Se a colisão ocorreu com um objeto do tipo
CollisionSide::Enemypelo lado direito ou esquerdo e o jogador está no chão, significa que o goomba acertou o jogador. Nesse caso, utilize a funçãoKillpara matar o jogador. -
Se a colisão ocorreu com um objeto do tipo
CollisionSide::Enemypelo lado direito ou esquerdo e o jogador não está no chão, também significa que o jogador acertou um goomba no ar. Nesse caso, mate o goomba como no caso 2.
-
-
-
Implemente a método
ManageAnimationspara selecionar a animação correta com base no estado do jogador-
Para implementar a troca de animação, basta utilizar os atributos
mIsDeadpara verificar se o jogador está morto,mIsOnGroundse o jogador está no chão emIsRunningse o jogador está correndo.-
Se ele estiver morto, altere a animação para
idle -
Se estiver vivo, no chão e correndo, altere a animação para
run -
Se estiver vivo, no chão e não estiver correndo, altere a animação para
idle -
Se estiver vivo e não estiver no chão, altere a animação para
jump
-
-
-
Parte 5: Inimigos
Na quinta parte, você irá implementar os goombas e os spawners, que criam goombas quando o jogador está próximo.
-
Goomba.cpp
-
Crie os componentes
RigidBodyComponent,AABBColliderComponent, eDrawAnimatedComponentno construtor-
Crie o
RigidBodyComponentcom massa1.0fe coeficiente de atrito0.0(basta omitir esse parâmetro para inicializa-lo com zero). Altere a velocidade horizontal do goomba paramForwardSpeed. -
Crie o
AABBColliderComponentcom dimensões(0,0,32,32)e tipo de colisãoColliderLayer::Enemy. -
Crie o componente
DrawAnimatedComponentpassando os caminhos da imagem (.png) e dos dados (.json) do sprite sheet do goomba que você criou com o TexturePacker.-
Utilize a função
AddAnimationpara adicionar as animações “walk” e “dead”. -
Utilize a função
SetAnimationpara definir a animação inicial como “walk”. Em seguida, utilize a funçãoSetAnimFPSpara definir a taxa de atualização de quadros da animação para 5.0f.
-
-
-
Implemente o método
Killpara tocar a animação de morte e desabilitar os componentes- Altere a animação para “dead” e o valor da variável
mIsDyingpara verdadeiro. Além disso, desabiliteSetEnabled(false)os componentesmRigidBodyComponentemColliderComponent
- Altere a animação para “dead” e o valor da variável
-
Implemente o método
OnUpdatepara destruir os goombas que já morreram-
Verifique se a variável
mDyingTimeré verdadeira. Se for, decremente o cronômetromDyingTimerpelo delta time. Quando esse cronômetro chegar a zero, altere o estado do goomba paraActorState::Destroy -
Verifique se a posição vertical do goomba é maior do que o tamanho da tela. Se for, altere o estado do goomba para
ActorState::Destroy
-
-
Implemente o método
OnCollisionpara alterar a direção do goomba quando ele colidir horizontalmente- Percorra o mapa de colisões
responsesatualizando o estado do jogador bom base no tipo de colisão ocorrida. Se a colisão foi à esquerda, altere a velocidade horizontal paramForwardSpeed. Se foi à direita, altera a velocidade horizontal para-mForwardSpeed.
- Percorra o mapa de colisões
-
-
Spawner.cpp
-
Implemente o método
OnUpdatepara criar um goomba quando o jogador estiver próximo- Verifique se a distância horizontal entre o jogador (
GetGame()->GetMario()) e esse objeto spawner é menor do quemSpawnDistance. Se for, crie um novo goomba com velocidadeGOOMBA_FORWARD_SPEED. Altere a posição do goomba para ser igual a posição desse spawner. Em seguida, altere a velocidade do goomba para que ele se mova para a esquerda com velocidadeGOOMBA_FORWARD_SPEED. Por fim, destrua esse objeto spawner.
- Verifique se a distância horizontal entre o jogador (
-
Parte 6: Customização
Na sexta, e última etapa, você irá ajustar as variáveis do jogo para criar uma versão única do Super Mário Bros.
-
Altere os parâmetros de movimentação (velocidade, massa, coeficientes de atrito, etc.) do jogador para encontrar uma jogabilidade que mais lhe agrada.
-
Altere o nível dado ou crie um completamente novo.
-
Altere o fps da animação “run” com base na velocidade horizontal do jogador.
- Extras:
-
Implemente a lógica para mover os blocos para cima quando o jogador os acerta por baixo. Blocos com um ponto de interrogação podem ser configurados para dar uma moeda ou não (os cogumelos estão fora de escopo pois adicionam uma complexidade maior).
-
Ao invés de carregar níveis de arquivos texto, integre o seu jogo com o editor de níveis [Tiled].
Submissão
Para submeter o seu trabalho, basta fazer o commit e o push das suas alterações no repositório que foi criado para você no GitHub classroom.
git add .
git commit -m 'Submissão P4'
git push
Barema
- Parte 1: Sprites Estáticos (15%)
- Parte 2: Detecção de Colisão com AABBs (30%)
- Parte 3: Rolagem de Câmera (15%)
- Parte 4: Animações (25%)
- Parte 5: Inimigos (10%)
- Parte 6: Customização (5%)