GameViewController, temos também que declará-lo na Impossible.h:
- (void)moveDown:(int)pixels;
Para podermos receber a informação de que a tela foi tocada, em nossa
GameViewController.m criaremos nosso objeto para reconhecer toques na tela:
- (void)viewDidLoad
{
//...
// Instancia um objeto para reconhecimento de gestos do tipo "Tap"
// e a ação a ser executada quando o usuário realizar o gesto
26
Casa do Código
Capítulo 2. Protótipo de um jogo
UITapGestureRecognizer *tapGesture =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleTapGesture:)];
// Adiciona o reconhecimento de gestos à view com a qual o
// usuário irá interagir
[self.impossibleView addGestureRecognizer:tapGesture];
}
A classe ainda não vai funcionar pois está faltando o método de callback de nosso UITapGestureRecognizer, que definimos como handleTapGesture:. Vamos implementá-lo:
- (void)handleTapGesture:(UITapGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateEnded) {
[self.impossibleView moveDown:10];
}
}
Rode o jogo. Mas temos um problema: ao tocar na tela, nosso player ainda
não está se movendo.
Isto acontece porque não estamos pedindo para nossa
Impossible redesenhar a tela.
Vamos corrigir este problema! No run da Impossible.m vamos informar que
a tela precisa ser redesenhada:
- (void)run
{
if (self.running == YES) {
NSLog(@"Impossible Running...!");
// Informa ao iOS que a tela deve ser redesenhada
[self setNeedsDisplay];
}
}
Rode o jogo. Algo já deve ocorrer ao tocar na tela: nosso player deve ter sua posi-
ção alterada. Mas agora temos um outro problema, veja como o player se movimenta
e o que acontece com a tela:
27
2.4. Captando os comandos do usuário e movendo objetos
Casa do Código
Figura 2.10: Player movendo na tela, mas temos um problema.
Importante: Limpando a tela
Lembra da relação
de um jogo com os desenhos em blocos de papel? O que dá a
impressão de movimento em um bloco como esse é que cada imagem é desenhada
com uma pequena variação de sua posição anterior. Nenhum desenho, se visto in-
dividualmente, da a impressão de movimento ou continuidade do desenho anterior.
É como se cada folha do bloco fosse totalmente redesenhada a cada frame.
O que faremos para que o player se mova na tela é zerar a tela toda vez que
formos renderizar um novo frame. Como nosso protótipo é simples e não tem um
fundo com imagens se movendo, podemos apenas iniciar o frame com um fundo
preto. Para jogos com backgrounds mais complexos a estratégia de limpar a tela será 28
Casa do Código
Capítulo 2. Protótipo de um jogo
mais complexa.
Na classe Impossible.m, altere o método drawRect: para pintar o back-
ground da tela de preto, chamando o novo método drawBackgroundInContext:
que iremos criar:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawBackgroundInContext:context];
[self drawPlayerInContext:context];
}
// Desenha o Plano de Fundo
- (void)drawBackgroundInContext:(CGContextRef)context
{
UIGraphicsPushContext(context);
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, CGRectMake(0, 0,
self.frame.size.width, self.frame.size.height));
UIGraphicsPopContext();
}
Rode agora e toque na tela. O player se moverá a cada toque!
2.5
Criando o inimigo
Chegamos à parte perigosa! São os inimigos que fazem um jogo ser mais desafiador, que nos instigam a superar algo. O inimigo em um jogo pode estar representado de
diversas maneiras. Pode ser o tempo, pode ser uma lógica complexa a ser resolvida ou mesmo outros objetos e personagens.
A partir dos inimigos podemos conhecer diversos conceitos importantes para
um jogo funcionar. Assim como o player principal, os inimigos possuem seus pró-
prios movimentos, porém, diferentemente do player, os movimentos do inimigo cos-
tumam ser definidos por lógicas internas do jogo. O interessante é que, por mais que os inputs do usuário não determinem diretamente o movimento do inimigo, quanto
mais inteligente ele for de acordo com a movimentação do player, mais interessante e desafiador pode ser o jogo.
Para o protótipo do jogo, nosso inimigo será um outro círculo, porém, como fa-
lamos anteriormente, esse círculo terá sua própria lógica. Ele crescerá com o tempo, 29
2.5. Criando o inimigo
Casa do Código
ou seja, de acordo com o passar do jogo, seu raio irá aumentando e consequente-
mente, ocupando cada vez mais a região do jogo.
Vamos criar, na classe Impossible.h, uma propriedade que representa o raio
do inimigo:
@property (nonatomic) int enemyRadius;
Assim como temos um método separado que desenha o player, na classe
Impossible.m teremos um que desenha o inimigo:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawBackgroundInContext:context];
[self drawPlayerInContext:context];
[self drawEnemyInContext:context];
}
//...
// Desenha o Inimigo
- (void)drawEnemyInContext:(CGContextRef)context