Como fazer um Space Invaders - Parte 1

“Rather than the programmer saying how about like this, he keeps making the kind of environment which the designer can adjust to whatever their heart’s desire.” - Takuya Seki, Shadow of the Colossus

Essa série é um conjunto de textos com instruções para se programar do zero um Space Invaders. Notem que eu estou usando o termo programar, mas eu vou mencionar uma pequena parte de Game Design, especificamente a parte onde o design se transforma em programação. Isso parece ser bobo mas é um dos (vários) motivos pra um projeto de game design que é bom não dar certo. Os gráficos vão ser uma cópia do original com umas mudanças, o bom de fazer clones de jogos antigos é que os gráficos são simples ;). Os sons vão ser feitos usando um programa free que eu vou mencionar mais adiante nas próximas partes da série.

Para quem essa série é indicada

É essencial que você saiba programar e já tenha tido alguma experiência com programação de jogos antes, no caso, saber usar/criar headers, ponteiros, conhecer algumas estruturas de dados simples, saber o que é game loop, double buffering e etc. Ou seja, se você sabe programar e já programou algum jogo antes mas não acabou, ou teve dificuldades, ou pelo menos sabe usar alguma lib tipo Allegro ou SDL essa série será útil. Se você está aprendendo a programar pode tentar acompanhar já que eu vou dar umas dicas de práticas de programação que não precisam de muito conhecimento, são métodos de programar que eu considero importantes. Eu irei usar C(sem POO) com Allegro, mas o jogo será programado de uma maneira tal que será fácil portar o jogo para outras libs.

Primeiros Passos

No desenvolvimento de um jogo tradicional existem muitos processos a serem feitos até que efetivamente se comece a programar. Quando o motivo incial de fazer um jogo não é a tecnologia dentro dele e sim alguma idéia, se começa pelo design do jogo a partir dessa idéia.
Resumindo um pouco, a partir de uma (ou mais) idéia(s) o game designer vai moldando o jogo na cabeça dele, pensando em alguns detalhes do jogo, mas não nele todo, a partir disso são criados alguns protótipos da funcionalidade do que ele tinha pensado, e a partir disso é definido como o jogo será, ou seja, o design doc. Notem que alguns design docs ainda deixam espaço para experimentação. Nesses casos ele não é um documento que contém TUDO do jogo, já que seria complicado mudar alguma coisa no código caso essa coisa não tenha ficado boa como ele tinha pensado(isso acontece muito).
Mas o importante do design doc é que ele seja um guia para as outras pessoas da equipe(no nosso caso, o programador) para elas saberem o que elas tem que fazer. É importante existir uma comunicação entre o designer e o programador sobre essas partes que podem mudar, já que as vezes é complicado deletar tudo que já tinha sido feito e reprogramar do zero. Quando o programador sabe de antemão quais coisas podem vir a mudar no futuro, ele prepara o código para que ele seja facilmente modificavel. Sabendo disso vamos criar nosso design doc simplificado!

“Design Doc” simplificado

Como nós não estamos criando um jogo do zero e sim um clone, o design doc está praticamente pronto, ou seja, a gente já sabe tudo que o jogo tem, seria só passar pro papel e em teoria começar a programar… mas como a vida nunca é facil, não é assim que nós vamos começar.
Isso acontece porque mesmo se a gente jogasse o jogo todo dia e conhecesse tudo a respeito dele, nós estariamos pensando como jogadores e não como programadores. É muito fácil achar que um jogo é fácil de programar só porque ele parece simples, mas a verdade é outra… SEMPRE tem mais do que parece ter por trás de um jogo, e é isso que eu vou mostrar aqui.

Bom, supondo que todos que estão lendo sabem o que é o space invaders a gente pode fazer um design doc do jogo:

Obs: Eu estou chamando de Design Doc, mas é só uma descrição do jogo pra gente ter idéia de como ele funciona, o que existe dentro dele, quais as regras e etc, ao longo do texto vou usar design doc e descrição mas me refiro a mesma coisa.

screenshot do jogo

Em Space Invaders você controla um canhão que defende a terra de invasores do espaço. O canhão fica na parte inferior da tela, ele pode se mover para esquerda e para a direita. Ele se defende atirando contra os invasores.


Os invasores se movimentam para direita ou para a esquerda. Quando um dos flancos toca um lado da tela, eles descem uma linha e movem para o lado oposto:

movimento dos invasores

Os invasores também se defendem atirando contra o canhão. Eles se movem mais rápido a medida que vão sendo destruidos(mais adiante vai ser explicado como eles são destruidos). Existem 3 tipos de invasores(), e eles ficam organizados como uma matriz.

Eventualmente aparece um nave em cima() que se move para o lado oposto da tela e dá pontos especiais para o jogador.

Os tiros do jogador, se acertam a base, destroem ela parcialmente, se acertam uma nave inimiga destroem ela imediatamente.
Os tiros das naves não acertam naves, mas acertam a base, destruindo ela parcialmente, e quando acertam o canhão o jogador é destruido e ele perde uma vida.

O jogador passa de fase quando todos os invasores da matriz morrem, a cada fase que ele passa os invasores começam uma linha abaixo.
O jogador perde o jogo quando ele perde todas as vidas dele(ele começa com 3).
As fases são infinitas.

Bom, tá meio bagunçado mas descrevemos o jogo, certo? Em partes :) Isso é o que passa pela cabeça de um jogador quando ele descreve o jogo(e na de Game Designers que ainda estão aprendendo), mas falta algumas informações cruciais aí. Por exemplo, eu falei que “Eventualmente aparece uma nave em cima que se move para o lado oposto da tela e dá pontos especiais para o jogador“. Ok, mas, quais são os critérios para a nave aparecer? Ela aparece sempre pela esquerda? Ela aparece sempre pela direita? Se o jogador estiver mais pra direita ela aparece na direita e vice-versa? Ela aparece depois de um determinado tempo? Ela aparece depois de um número de tiros? Só jogando o jogo pra saber, e mesmo assim você ficaria na dúvida.
Mas vamos supor que Space Invaders é um jogo que ainda está sendo criado, que o game designer dele não sabe disso também, ou seja, ele simplesmente teve uma idéia de que seria legal uma nave aparecer em cima dando pontos especiais(geralmente quando a gente tem essas idéias legais, elas sempre são vagas em termos de programação). O game designer vai querer experimentar varias opções durante o jogo, ele vai querer experimentar todas aquelas opções que eu disse acima e mais o que a cabeça dele puder imaginar. você, como programador, na hora que estiver modelando o programa tem que identificar essas partes vagas de um documento de design e conversar com o designer do jogo sobre isso, pra que você não comece a programar algo que seja da sua cabeça, e quando o game designer ver que aquilo não era o que ele tava pensando você vai ter que deletar tudo porque não preparou o código pra mudanças.

Com base nisso vou mostrar aqui algumas coisas que ficaram faltando e outras que o game designer vai querer experimentar:

Canhão:

- Qual a posição inicial do canhão?
- O que acontece quando o jogador leva um tiro? Ele perde uma vida e fica quanto tempo sem se mexer? Ele fica invencível por um tempo? Por quanto tempo?
- Quando ele leva um tiro ele volta pra posição inicial?
- O que acontece quando ele toca um extremo da tela? Ele aparece no outro extremo? Ele para de se mexer?
- Ele tem tiros infinitos? Se tem, ele pode atirar uma vez até acabar o tiro ou quantas vezes ele quiser?

Invasores:

- Como eles ficam organizados? Qual é o tamanho da matriz?
- Qual a velocidade deles? Como é a progressão da velocidade a medida que eles vão morrendo?
- Qual é o critério pra eles atirarem?

Barreira:

- Como que a barreira vai sendo destruida? Ela tem seções que aguentam por exemplo 3 tiros? Ou ela é destruida por terreno(tipo worms)?

Pois é, quando a gente descreve o jogo, ou tem idéias pra um jogo, esse tipo de coisa passa batido, mas quando a gente para pra pensar nesses detalhes que ficam faltando acaba aparecendo um monte de coisas. Mas o importante é que isso apareça AGORA e não quando nós começarmos a programar. Eu vou responder todas essas perguntas agora já que nós estamos programando um clone, mas eu fiz isso porque eu quero que vocês vejam que quando nós estamos criando um jogo do zero, esse tipo de pergunta aparece, e as vezes a gente não sabe como responder e tem que experimentar. E no final das contas é o programador que tem que programar o jogo sem essas respostas, por isso ele tem que saber aonde que o designer quer experimentar pra que ele possa fazer um código flexivel o suficiente pra que possa haver espaço para essas experimentações.

Mas voltando as perguntas:

O canhão começa na esquerda mais ou menos em uns 20% da tela. Quando ele leva um tiro o jogo para e espera até o jogador apertar o botão de atirar e ele volta a posição inicial dele, mas os invasores continuam na posição aonde eles estavam. Quando o canhão se move até um extremo da tela ele para e não se move mais. Ele tem tiros infinitos e só pode dar um tiro por vez.

Os invasores se organizam em uma matriz com 11 colunas e 5 linhas. A velocidade inicial e a progressão é algo que nós vamos ter que experimentar :) Mas no jogo, quando sobra o ultimo invasor aparentemente a velocidade dele dobra quando ele se move pra direita, quando ele se move pra esquerda ela diminui um pouco(acho que é pro jogador ter mais chance, fica realmente muito rápido). O critério pra eles atirarem me parece ser algo assim: nas primeiras fases um deles atira aleatoriamente, enquanto o outro tiro é sempre da nave que está na coluna em que o jogador está, a medida que as fases vão passando vai aumentando o número de tiros aleatórios.

A barreira é destuida por terreno, de acordo com a animação. No jogo original, a barreira era “deletada” de acordo com a animação da explosão, por exemplo: Um tiro acertava a barreira(a colisão aparentemente é pixelperfect), o tiro virava uma explosão, o desenho dessa explosão simplesmente sobrepõe o que tinha sido desenhado na barreira(isso será explicado em detalhes nas próximas partes da série).

Bom, adicionando isso tudo ao “design doc” inicial, já temos coisa suficiente pra planejar algumas coisas de como iremos programar e a ordem de como iremos programar o jogo.

Pensando como programador

Primeiro, nós temos que identificar quantos objetos nós temos. Pela imagem(e pelo que a gente conhece do jogo) a gente sabe que tem o canhão, os inimigos, as 4 bases que defendem o jogador, tem também aquela nave que aparece em cima para dar pontos extras. Com isso nós já detectamos que vamos criar uma estrutura para o jogador, outra para as naves, e mais uma para as barreiras que ficam embaixo. Mas nós temos que lembrar que o jogador atira e as naves de cima também! Ou seja, mais uma estrutura para o tiro. Resumindo nós temos:

- Canhão(jogador)
- Naves
- Base
- Tiros

Note que poderiam ser 4 classes, mas não importa muito já que nós vamos separar por módulos cada estrutura, então mesmo não usando OOP vai ficar muito parecido já que estamos modelando o programa da mesma maneira, a diferença vai ser na hora de representar no código.

Depois nós temos que identificar os comportamentos, ou seja, o que cada um pode fazer e pensar em como isso pode ser programado:

- O canhão atira, leva tiros e se move.
- As naves atiram, levam tiros, se movem.
- A barreira somente leva tiros(coitada hehehe).
- Os tiros se colidem com outros tiros, com o canhão, com as naves e com a barreira.

Aparentemente é simples, mas agora é que vai ficar complicado pois nós vamos refinar isso. Não se espante se você não entender porquê vamos usar tal variável ou tal algoritmo, isso tudo será explicado nas seções mais a frente destinadas a programar cada parte do jogo, mas é importante fazer esse tipo de verificação agora para que não aconteçam imprevistos no futuro. E como que você vai saber qual algoritmo usar em determinada hora? Bom, isso é experiência, e é pra isso que você está lendo esse artigo :D

Canhão:

Nós sabemos que ele dá um tiro até atingir o final da tela ou algum outro objeto. Pra isso vamos precisar de alguma variável que indique se o jogador está atirando ou não.
O canhão se move para esquerda e para direita de acordo com o que o jogador aperta no teclado, isso é bem simples, vamos criar só uma váriavel X e Y e uma Velocidade pra podermos fazer isso.
Quando o jogador leva tiros ele simplesmente é destruido, então uma colisão de bounding boxes nesse caso será útil.

Naves Invasoras:

As naves atiram de acordo com aquele critério mencionado acima, teremos que criar uma função que terá um algoritmo que decidirá quais naves irão atirar.
A colisão delas é parecida com a do canhão, bounding box já que elas são destruidas na hora.
O movimento dos invasores é de acordo com o visto na imagem acima, iremos criar uma função pra mover também de acordo com o que sabemos.
Notem que nós pensamos em criar uma estrutura nave, e de fato nós vamos criar, mas o que importa para nós é o conjunto das naves, ou seja, a matriz! No caso os inimigos vão ser uma matriz da estrutura nave.

Base:

A base só leva tiro, e a colisão é como explicamos acima, o algoritmo dela é meio complicado e será explicado mais adiante, mas o que nós precisamos saber agora é como representar essa base, a base nada mais vai ser do que um bitmap, sem energia sem nada, só vamos precisar do X e Y dela pra poder calcular a colisão.

Tiros:

Os tiros se movem de acordo com quem atirou, por exemplo, se o tiro foi do canhão, o tiro sempre se move pra cima. Se o tiro foi de alguma das naves ele vai se mover sempre pra baixo. A função de movimento deles é bem simples. A colisão também é feita com bounding box(com excessão da colisão de tiro com a barreira).

Uma regra geral pra caso você não saiba que algoritmo usar ou como representar tal objeto é, nessa hora do planejamento, fazer experimentos com partes do programa. Por exemplo, digamos que você ficou em dúvida sobre como fazer o movimento das naves, então crie um programa que SOMENTE tenha essas naves se movendo. Parece uma coisa simples mas isso envolve pesquisa e experimentação, até porquê nem todo programador sabe tudo, então quando um programador começa um projeto grande que ele não sabe como programar determinadas coisas, é nessa hora de planejamento que ele faz essa experiências, demos e pesquisas. Isso é super importante, e é um dos motivos que diferencia um programador preparado de um programador amador que programa “na doida”.

Bom, podemos já ter uma idéia do que vamos programar e como vamos programar. Agora nós precisamos decidir o que vamos programar primeiro. Isso muda de pessoa pra pessoa e de jogo pra jogo, acreditem. Mas como nós estamos programando jogos pequenos e já sabemos o que nós queremos, nós podemos usar uma regra bem simples que se aplica ao nosso caso: Comece programando o que não tem dependências. Ou seja, não dá pra começar programando a colisão se nós não temos ainda as estruturas que vão fazer essa colisão, não dá pra programar o algoritmo de mover as naves se nós ainda não fizemos ela nem desenhamos elas na tela! A idéia é simples.

No nosso caso, eu vou começar programando o canhão e a função de movimento dele. Depois nós poderiamos fazer a função de atirar, mas ia ser ruim porque depois nós iamos ter que programar as barreiras, as naves e depois voltar pra acabar os tiros! Porquê se nós fossemos programar os tiros do canhão logo após termos criado ele e sem nada no jogo, não teria com o quê colidir, então não faria muito sentido. Ou seja, depois de programar o canhão e o movimento dele, vamos criar as naves e o movimento delas, depois a barreira, depois os tiros e por aí vai. Vocês verão mais adiante na proxima parte da série, como isso será feito, por enquanto fiquem com isso que já é até bastante informação =)

Considerações Finais

A primeira parte acaba por aqui, ná próxima nós vamos montar o esqueleto do jogo e programar o canhão. Espero que não tenha ficado tão confuso! Eu tenho tendência a confundir o simples hehehe, mas creio que a partir das próximas partes fique mais fácil de acompanhar já que é uma parte mais prática e sem tanta teoria. Obrigado e espero ver os comentários pra saber as dúvidas e também poder melhorar nás próximas partes da série. ;)

7 Responses to “Como fazer um Space Invaders - Parte 1”

  1. Diego Says:

    Eu iniciei uma série sobre o mesmo assunto aqui.

  2. CrociDB Says:

    Muito bom o tutorial!

    Eu também estava querendo fazer um tutorial de Space Invaders com Allegro, mas concerteza não ficaria tão bom quanto o seu! =D

    Parabéns, adorei o tutorial, boa sorte com as próximas partes, estarei aguardando! :)

  3. Chrystian Sales Says:

    Parabéns pelo artigo!
    Andei procurando textos assim, bem explicados. Os que eu vi por aí, quando ví, eram muito mal escritos. Esse daí dá pra entender direitinho.

  4. Sushi Says:

    ooooo caaara, vlw mesmo pelo tutorialzão…

    tu explica certinho mesmo cara, continue assim ;)

  5. Ney Estrabelli » Blog Archive » Faça seu próprio Space Invaders Says:

    [...] o link: Como Fazer um Space Invaders Posted in | Leave a [...]

  6. Vitor Almeida Says:

    Parabéns, ficou bastante didático.

  7. samara Says:

    oi gente lindos

Leave a Reply