Se
você é fã de futebol e de computadores,
deve conhecer um jogo que fez muito sucesso há
algum tempo atrás (e ainda faz), chamado
Elifoot. Nele você faz o
papel de um técnico de futebol, que gerencia
um time. Compra jogadores, vende, participa de campeonatos,
etc. Não é um jogo de animação,
não é um jogo 3D e nem exige matemática
quântica para executar suas tarefas: é
um jogo de estratégia, um simulador de realidade.
O que chama a atenção
neste tipo de jogo é que com o advento da
internet eles se tornaram bem mais atraentes do
que eram antigamente e sua construção
não exige um trabalho extenuante, nem conhecimentos
profundos de programação. Qualquer
pessoa com um mínimo de conhecimento pode
montar um modelo de simulador. E não precisamos
ficar só na simulação de futebol,
basquete, tênis, ou outro esporte qualquer,
mas ir para campos ainda pouco explorados dentro
deste modelo de jogo, como batalhas navais, conquistas
espaciais, impérios financeiros, comerciais,
etc, etc, etc...
Como se isso não
bastasse, esse tipo de jogo está abrindo
novos negócios em termos de entretenimento
digital, via internet. Simuladores de futebol, só
no Brasil já existem mais de 3, inclusive
em regime de acesso pago com privilégios.
Um negócio que só tende a crescer
com o tempo.
Como se isso não
bastasse e contrariando o senso desenvolvimentista
atual, que prega a produção feita
por grandes equipes, construções sofisticadas
em 3D, investimentos astronômicos em motion
capture e marqueting, este tipo de jogo pertence
a uma categoria onde o grande diferencial é
a idéia central do mesmo. Não seus
recursos gráfico/visuais, mas o que ele nos
permite fazer, dentro da comunidade que se cria
à sua volta. O caso típico de jogo
que nasce de uma mente criativa, praticamente sem
recursos financeiros e invariavelmente como uma
criação solitária. Este talvez
seja um dos únicos segmentos no setor de
games onde uma boa idéia pode dar melhores
resultados que uma gigantesca produção.
A base técnica
para qualquer um desses jogos de simulação
é uma estrutura de cliente/servidor (no club
TILT tem um e-Book
só sobre isso), um pequeno e simples sistema
de banco de dados e a programação
da função específica do jogo,
ou simulação (aquilo que os hardgammers
adoram chamar de IA, cujas potencialidades
são cantadas em verso e prosa, mas que ainda
está muito longe de ser uma inteligência).
No que diz respeito
a banco de dados, não vamos exagerar e usar
tudo o que o Delphi tem sobre isso, mas vamos aproveitar
uma de suas estruturas de programação
mais práticas: o record.
Um record (ou registro) nada mais
é do que uma estrutura pré definida
de dados.
Por exemplo: digamos
que o propósito seja criar um simulador de
campeonato de futebol, à lá Elifoot
e assemelhados. Toda a estrutura do jogo gira em
torno de um cadastro de jogadores, então
o primeiro passo é criar esse modelo de dado:
implementation {$R *.DFM}
type Jogador = record Nome: string[30]; Nick: string[15]; Nasc: TDateTime; Passe: currency; Clube: byte; Titular: boolean; end;
|
Note
que essa estrutura apenas define um tipo de registro,
chamado Jogador. Podemos dizer
que as variáveis serão suas propriedades,
tais como nome completo, apelido, valor do passe,
data do nascimento, etc. O record
não é uma variável em si mesma,
mas uma definição de formato. Para
usá-la teremos que declarar as variáveis
efetivas, ou melhor, uma matriz de variáveis
(um array de Jogadores):
var Jogs: array of Jogador;
|
Portanto,
quando quisermos fazer referência a um jogador
em especial, usamos o índice da matriz e
a “propriedade” desejada. Por exemplo,
para saber o nome do jogador 5: Jogs[5].Nome.
O apelido dele: Jogs[5].Nick;
o valor do passe: Jogs[5].Passe
e assim por diante.
A declaração
acima é de um array dinâmico, ou seja,
não tem um número predeterminado de
entradas e cada vez que um jogador for incluído
na estrutura será preciso aumentar a quantidade
de itens na matriz (que começa invariavelmente
com zero). Para isso usamos a função
SetLength(array,quantidade)
e uma variável para controlar a quantidade
de jogadores (var TotJogs: integer;).
Imagine
que está montando um utilitário para
“criar e editar jogadores” e ao clicar
um botão, cria-se um determinado jogador:
procedure TForm1.SpeedButton1Click(Sender: TObject); begin TotJogs:= TotJogs + 1; SetLength(Jogs,TotJogs); Jogs[TotJogs-1].Nome:= ‘Nome do jogador’; Jogs[TotJogs-1].Nick:=’Apelido dele’; Jogs[TotJogs-1].Nasc:= StrToDate(‘10/10/80’); Jogs[TotJogs-1].Passe:= StrToCurr(‘100000,00’); Jogs[TotJogs-1].Clube:= índice da lista de nomes dos times; Jogs[TotJogs-1].Titular:= true; end;
|
O ideal
seria apontar para TEdits que permitissem
a digitação/alteração
dessas características ou propriedades. Para
completar esse pequeno utilitário, é
preciso gravar o cadastro em um arquivo, para que
outro programa tenha acesso a essa informação:
procedure TForm1.SpeedButton2Click(Sender: TObject); var ArqJog: file of Jogador; Tm: integer; begin AssignFile(ArqJog,'jogadores.dat'); Rewrite(ArqJog); for Tm:= 0 to TotJogs-1 do Write(ArqJog,Jogs[Tm]); CloseFile(ArqJog); end;
|
Sabemos
quantos jogadores existem no cadastro e portanto
basta fazer um looping e gravar um a um. A operação
inversa usa um conceito diferente para o looping,
uma vez que não se sabe o número exato
de jogadores que serão carregados:
procedure TForm1.SpeedButton3Click(Sender: TObject); var ArqJog: file of Jogador; begin TotJogs:= 0; AssignFile(ArqJog,'jogadores.dat'); Reset(ArqJog); while not eof(ArqJog) do begin TotJogs:= TotJogs + 1; SetLength(Jogs,TotJogs); Read(ArqJog,Jogs[TotJogs-1]); end; CloseFile(ArqJog); end;
|
O arquivo
é aberto e lido até que seu final
seja encontrado (eof
– End Of File). Esta é portando a base
do cadastro de jogadores, sobre a qual iremos montar
o simulador dos nossos sonhos. Claro, não
precisa ser necessariamente um simulador de campeonato
de futebol, como já falei.
O terceiro
aspecto característico deste tipo de jogo
é a mecânica funcional da partida.
Obviamente estamos considerando que essas operações
ocorrerão dentro do servidor, com acesso
total aos cadastros específicos do jogo.
As questões relevantes aqui irão aparecer
numa análise mais detalhada do que se pretende
fazer do jogo.
Por
exemplo, no caso do simulador de campeonato de futebol,
a base dos dados é o cadastro dos jogadores
e de um segundo cadastro, que é de times.
Cada usuário é na verdade um time
e como os jogadores podem ser referenciados pelo
seu índice na matriz, podemos considerar
que cada jogador tem um ID próprio
e portanto, um time nada mais é do que um
array com 22 Ids
de jogadores (e mais alguns dados, como nome do
técnico, nome do time, etc, etc).
O servidor
dá conta de duas tarefas distintas: transacionar
as operações dos usuários (lembre-se,
na estrutura cliente servidor, o programa cliente
solicita uma ação e o servidor a executa,
se possível) e proceder ao processamento
dos “turnos”. Se está em dúvida
de como montar a estrutura cliente/servidor, dê
uma revisada em nosso e-Book
sobre jogos multiplayer..
Transacionar
as operações dos usuários significa
promover (se possível) todas as solicitações
efetuadas. Por exemplo uma troca (por empréstimo)
de dois jogadores, entre dois times ou uma compra
e venda, etc. Esse tipo de processamento é
bem simples.
Já
o processamento de um turno é mais complicado
e necessita de algumas avaliações.
A pergunta que o desenvolvedor deve responder aqui
é: o que vai acontecer ou o que caracteriza
um turno do jogo? Pode ser por exemplo uma partida
disputada entre dois times. Como efetuar isso, ou
seja, como decidir uma partida/disputa sem arrancar
os cabelos e sem perder noites de sono com programação
em sânscrito?
Simples:
use o sistema de pesos. Todo tipo de disputa, ocorra
ela entre times de futebol, navios de guerra, naves
espaciais, negócios na bolsa de valores ou
seja lá o que você inventar, está
baseada no potencial de cada um e mais um tiquinho
de sorte, que chamaremos de "o imponderável",
apenas para usar uma palavra mais bonita. É
isso mesmo: o bom e velho randomize (gerador de
números aleatórios).
Não
é apenas randomizar um resultado, correto?
Usamos pesos, para orientar a forma como o número
aleatório será gerado. Um cálculo
de probabilidades bem simples: quanto mais potencial
um time tem (jogadores mais habilidosos, melhores
condições físicas, jogando
em casa, histórico das partidas com o adversário,
etc), mais chances ele terá de vencer a partida.
Mas, como diria um jogador famoso: o jogo só
termina quando acaba, ou seja, ter maiores chances
não significa necessariamente que irá
ganhar e é aí que entra o imponderável.
As vezes, contra tudo e contra todos, o mais fraco
e menos cotado ganha.
No
final do processamento de um turno, apuram-se os
ganhos e perdas de cada usuário e passa-se
à preparação da próxima
rodada. Simples e sem maiores sofisticações.
Portanto,
deixe de lado por algum tempo aquela sua insistente
idéia de que vai parir a novissima geração
de jogos 3D, mais sofisticada do que as produzidas
à lá roliúde e que será
reverenciado pelas próximas gerações
como o maior criador de jogos de todos os tempos
e concentre-se numa idéia simples e que esteja
afinada com o gosto das pessoas.
Se
precisar de ajuda para descascar alguns pepinos
da programação ou de design do jogo,
estamos aqui para isso mesmo.