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
Actor
para representar um bloco do jogo. -
Goomba
Classe que estende
Actor
para representar o Goomba, inimigo que se movimenta horizontalmente de um lado para o outro. -
Mario
Classe que estende
Actor
para representar o Mário, que é controlado pelo jogador. -
Spawner
Classe que estende
Actor
para 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
LoadTexture
para carregar uma textura com a SDL-
Utilize a função
IMG_Load
para carregar a imagem passada como parâmetrotexturePath
. Esse função retorna um ponteiro paraSDL_Surface*
. Retornenullptr
se a imagem não foi carregada com sucesso. -
Utilize a função
SDL_CreateTextureFromSurface
para 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_FreeSurface
para 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
InitializeActors
para inicializar os objetos do jogo-
Crie um objeto do tipo
Mario
e 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
LoadLevel
para carregar um nível do jogo- Leia o arquivo texto
levelPath
comheight
linhas ewidth
colunas para carregar um nível do jogo. Uma nível é representado por um grid com largurawidth
e alturaheight
, onde cada célula tem tamanho32x32
. Para cara caractere entreA
eI
, crie um objeto do tipoBlock
utilizando a textura correspondente. Para cara caractereY
, crie um objeto do tipoSpawner
utilizando a distância SPAWN_DISTANCE como parâmetro de criação.
- Leia o arquivo texto
-
-
DrawSpriteComponent.cpp
-
Implemente o construtor e o método
Draw
para desenhar sprites estáticos-
No construtor, utilize a função
LoadTexture
que você implementou na última etapa para criar uma textura a partir da imagemtexturePath
passada como parâmetro no construtor. Armazene o ponteiro retornadoSDLTexture*
na variável membromSpriteSheetSurface
. -
No método
Draw
, utilize a funçãoSDL_RenderCopyEx
para desenhar a textura armazenada na variável membromSpriteSheetSurface
. Você terá que criar umSDL_Rect
para definir a região da tela onde será desenhado o sprite. Além disso, você terá que criar uma flag do tipoSDL_RendererFlip
para 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
AABBColliderComponent
eDrawSpriteComponent
-
Crie o
AABBColliderComponent
com dimensões(0,0,32,32)
e tipo de colisãoColliderLayer::Blocks
. -
Crie o
DrawSpriteComponent
com texturatexturePath
(passada com parâmetro) e dimensões(32,32)
.
-
-
-
Mario.cpp
-
Adicione os componentes
DrawSpriteComponent
eRigidBodyComponent
no 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.png
e dimensões(32,32)
. -
Para que o jogador possa se mover, crie também um componente
RigidBodyComponent
com massa1.0
e coeficiente de atrito5.0
. Note que a classeMario
já tem atributos para armazenar esses componentes.
-
-
Implemente o método
OnProcessInput
para mover o jogador horizontalmente-
Verifique se o jogador pressionou a tecla
D
. Se sim, aplique uma força para a direita com magnitudemForwardSpeed
e altere a rotaçãomRotation
para0
. Além disso, altere a variávelmIsRunning
para 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 magnitudemForwardSpeed
e altere a rotaçãomRotation
paraMath::Pi
. Além disso, altere a variávelmIsRunning
para 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
,GetMax
eGetCenter
para 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ávelmOffset
define 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 membromWidth
emHeight
definem 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étodoGetMin
implementado 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étodoGetMin
implementado anteriormente).
-
-
Implemente método
Intersect
para verificar se duas AABBs têm interseção- Verifique se esta AABB está colidindo com a AABB
b
passada como parâmetro. Retorne verdadeiro se estiver e falso caso contrário. Utilize os métodosGetMin
eGetMax
para acessar os pontos de mínimo e máximo das duas AABBs.
- Verifique se esta AABB está colidindo com a AABB
-
Implemente método
GetMinOverlap
para calcular a sobreposição e lado de uma colisão-
Armazene no mapa
overlaps
as sobreposições (com sinal -/+) dos quatro lados da colisão: esquerda, direita, cima e baixo. Utilize os métodosGetMin
eGetMax
para 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
ResolveCollisions
para separar uma AABB após uma colisão-
Verifique se a sobreposição
minOverlap
ocorreu no lado de cimaCollisionSide::Top
com velocidade vertical negativa ou no lado de baixoCollisionSide::Down
com velocidade vertical positiva. Note que a estruturaminOverlap
já 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
minOverlap
ocorreu no lado esquerdoCollisionSide::Left
com velocidade horizontal negativa ou no lado direitoCollisionSide::Right
com 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
DetectCollision
para detectar colisões entre os objetos do jogo-
Utilize a função
std::sort
para ordenar o vetorcolliders
de acordo com a distância entre o centro dessa AABB e o centro de cada AABB desse vetor. O vetorcolliders
conté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
colliders
ordenado, 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
GetMinOverlap
para obter a sobreposição mínima dessa AABB com o elemento corrente. Em seguida, utilize a funçãoResolveCollisions
para 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 callbackOnCollision
para 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
AABBColliderComponent
para habilitar colisões do jogador com os blocos do nível- Crie um componente
AABBColliderComponent
no construtor da classeMario
com dimensões(0,0,32,32)
e o tipoColliderLayer::Player
da AABB. Se quiser desenhar a AABB do Mário para testas as colisões, crie um componenteDrawPolygonComponent
com os vértices da AABB.
- Crie um componente
-
Modifique o método
OnProcessInput
para implementar o pulo- Verifique se o jogador está no chão (
mIsOnGround
) e se ele pressionou a teclaA
. Se sim, altere a velocidade vertical paramJumpSpeed
e a variávelmIsOnGround
para falso. UtilizeSetVelocity
ao invés deApplyForce
para 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
UpdateCamera
para 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_WIDTH
eTILE_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
Draw
para 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
OnUpdate
para 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
Update
para 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
mAnimTimer
com base na taxa de atualização (mAnimFPS
) e no delta time -
Podemos converter o timer da animação
mAnimTimer
para 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çowhile
para decrementar o timer por esse mesmo número até essa condição seja falsa.
-
-
Implemente o método
Draw
para 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
mAnimations
com 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_RenderCopyEx
para 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
SetAnimation
para mudar a animação corrente- Salve o nome da animação corrente
name
na variável membromAnimName
e 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
DrawAnimatedComponent
ao invés deDrawSpriteComponent
-
Crie um componente
DrawAnimatedComponent
passando 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
AddAnimation
para adicionar as animações “dead”, “idle”, “jump” e “run”. -
Utilize a função
SetAnimation
para definir a animação inicial como “idle”. Em seguida, utilize a funçãoSetAnimFPS
para definir a taxa de atualização de quadros da animação para 10.0f.
-
-
Modifique o método
OnUpdate
para 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
Kill
para tocar a animação de morte e finalizar o jogo- Altere a animação para “dead” e o valor da variável
mIsDead
para verdadeiro. Além disso, desabilite (SetEnabled(false)
) os componentesmRigidBodyComponent
emColliderComponent
.
- Altere a animação para “dead” e o valor da variável
-
Implemente o método
OnCollision
para atualizar o estado do jogador após uma colisãoO mapa
responses
conté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 ponteirotarget
para 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::Blocks
pelo lado de baixoCollisionSide::Down
, significa que o jogador aterrizou no chão. Nesse caso, altere o valor da variávelmIsOnGround
para verdadeiro. -
Se a colisão ocorreu com um objeto do tipo
CollisionSide::Enemy
pelo 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 ponteirotarget
do elemento corrente para acessar o ponteiro para esse goomba e o métodoKill
do goomba para matá-lotarget->GetOwner()->Kill()
. -
Se a colisão ocorreu com um objeto do tipo
CollisionSide::Enemy
pelo lado direito ou esquerdo e o jogador está no chão, significa que o goomba acertou o jogador. Nesse caso, utilize a funçãoKill
para matar o jogador. -
Se a colisão ocorreu com um objeto do tipo
CollisionSide::Enemy
pelo 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
ManageAnimations
para selecionar a animação correta com base no estado do jogador-
Para implementar a troca de animação, basta utilizar os atributos
mIsDead
para verificar se o jogador está morto,mIsOnGround
se o jogador está no chão emIsRunning
se 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
, eDrawAnimatedComponent
no construtor-
Crie o
RigidBodyComponent
com massa1.0f
e coeficiente de atrito0.0
(basta omitir esse parâmetro para inicializa-lo com zero). Altere a velocidade horizontal do goomba paramForwardSpeed
. -
Crie o
AABBColliderComponent
com dimensões(0,0,32,32)
e tipo de colisãoColliderLayer::Enemy
. -
Crie o componente
DrawAnimatedComponent
passando os caminhos da imagem (.png) e dos dados (.json) do sprite sheet do goomba que você criou com o TexturePacker.-
Utilize a função
AddAnimation
para adicionar as animações “walk” e “dead”. -
Utilize a função
SetAnimation
para definir a animação inicial como “walk”. Em seguida, utilize a funçãoSetAnimFPS
para definir a taxa de atualização de quadros da animação para 5.0f.
-
-
-
Implemente o método
Kill
para tocar a animação de morte e desabilitar os componentes- Altere a animação para “dead” e o valor da variável
mIsDying
para verdadeiro. Além disso, desabiliteSetEnabled(false)
os componentesmRigidBodyComponent
emColliderComponent
- Altere a animação para “dead” e o valor da variável
-
Implemente o método
OnUpdate
para destruir os goombas que já morreram-
Verifique se a variável
mDyingTimer
é verdadeira. Se for, decremente o cronômetromDyingTimer
pelo 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
OnCollision
para alterar a direção do goomba quando ele colidir horizontalmente- Percorra o mapa de colisões
responses
atualizando 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
OnUpdate
para 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%)