Mostrando postagens com marcador game. Mostrar todas as postagens
Mostrando postagens com marcador game. Mostrar todas as postagens

YAMS - Um clone do Jogo Campo Minado Perdido no Tempo

Este jogo foi originalmente escrito em Delphi 7 no final de 2003 como um exercício de aprendizado da linguagem Object Pascal e da programação de jogos do Windows.

O código-fonte original foi publicado no bom e velho site Delphi Pages, que agora está, infelizmente, morto. Foi um momento de sorte incrível quando encontrei uma versão quase finalizada de seu código-fonte em um CD-ROM de backup empoeirado e agora estou disponibilizando-o novamente no Git Hub.

Ele abriu e foi compilado perfeitamente 21 anos depois, no Delphi 12. Cara, isso é simplesmente incrível!!! 😮

Essa é a cara dele rodando no Windows 11!

Espero que apreciem.


Links

Repositório: https://github.com/fabianosalles/yams

Página de relase: https://github.com/fabianosalles/yams/releases

Executáveis: x86 | x64


Criando um Game Completo - Parte 7


Bem vindo à sétima parte do nosso mini curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joysticks e uma tabela de scores online! Tudo isto compilando em Delphi e Lazarus.

Neste post iremos criar o menu inicial do game, definir a lógica de transição entre as telas e realizar os ajustes necessários na tela de gameplay para que o jogador possa voltar à tela inicial.

Criando um Game Completo - Parte 6.1

Bem vindo à parte 6.1 do nosso mini curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joysticks e uma tabela de scores online! Tudo isto compilando em Delphi e Lazarus.

Neste post, vamos complementar as melhorias introduzidas no texto anterior e criar um efeito de estrelas para deixar o plano de fundo do jogo mais interessante. A imagem ao lado mostra como ficará o visual das animações na cena do gameplay no final do processo.

Criando um Game Completo - Parte 6

Bem vindo à sexta parte do nosso mini curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joysticks e uma tabela de scores online! Tudo isto compilando em Delphi e Lazarus.

Já faz um tempo desde o último artigo da série, um ano, para ser exato e eu gostaria de começar pedindo desculpas por esta ausência tão longa. Estive envolvido com vários projetos simultâneos nestes últimos 12 meses, ministrando muitas aulas e trabalhando com sistemas embarcados, o que foi muito enriquecedor mas acabou me afastando um pouco aqui do blog. Mea culpa, mea culpa...

Bom, explicações dadas, vamos ao que interessa: nosso game!

Criando um Game Completo - Parte 5

Sequencia de introdução do game
Bem vindo à quinta parte do nosso mini curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joysticks e uma tabela de scores online!

No último artigo completamos uma versão jogável do game. Os sons, as animações o tratamento de colisões, tudo o que planejamos foi implementado com sucesso. Mas ainda falta muita coisa para o game estar, de fato, completo.

A imensa maioria do código que escrevemos está contido dentro de uma única classe: TGame. Isto vinha funcionando bem, mas conforme o game cresce, fica evidente que as classes estão acumulando responsabilidades demais. Com a necessidade de criar outras telas, é preciso isolar algumas tarefas e criar objetos mais genéricos para que possamos reutilizá-los em outras partes.

Neste post, vamos fazer uma grande refatoração no código e criar nosso próprio motor, de modo que sejamos capaz de realizar tudo o que TGame faz atualmente e começar a esconder alguns detalhes de nível mais baixo do SDL. Vamos caminhar rumo a um modelo de programação menos procedural e mais orientado a eventos, um conceito bem familiar para quem está acostumado a bibliotecas como VCL e LCL.

Espero que apreciem.

Abraços!

Criando um Game Completo - Parte 4

Game rodando em debug no Lázarus
Bem vindo à quarta parte do nosso mini-curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joystics e uma tabela de scores online!

No último artigo, o projeto começou a tomar uma cara de game. Criamos o código que distribui os inimigos na tela, incluímos o tratamento de colisões entre os tiros do jogador e os alienígenas e demos os primeiros passos na construção da interface do usuário.

Vamos seguir nossa jornada adicionando algumas animações extras, fazendo os inimigos se movimentar e atirar, ampliar a lógica de colisões para detectar os danos sofridos pelo jogador e adicionar vários efeitos sonoros.

No final, como bônus, vamos adicionar a capacidade de alternar entre os modos de tela cheia e exibição em janela. Acompanhe o código no GitHub ou faça o download nos links no final do texto e, mais uma vez, mãos à obra!

Minimon, game moderno 100% escrito em pascal




Veja o vídeo acima.

Ok, ok, você pode até não ser muito fã do gênero, mas tenho certeza que vai ficar surpreso com um fato: tudo, absolutamente tudo, foi feito em pascal! O motor gráfico, o interpretador de áudio, o código que trata as requisições de rede, o gerenciamento de assets... tudo!

Mas não é só isso. O game Minimon está disponível para PC, Mac, Android e iOS além de ter sido aprovado para venda na loja do Steam.

Seu autor, Sérgio Flores, disponibilizou o código do motor que ele desenvolveu para o projeto livremente em um repositório do GitHub.

Baixe o código e explore um pouco.
É uma leitura que, para todo mundo que escreve código em algum dialeto do pascal, vale muito à pena.

E não deixe de visitar o site oficial do game: http://minimon3d.com/

Criando um Game Completo - Parte 3

Inimigos, pontuação e colisões!
Bem vindo à terceira parte do nosso mini-curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joystics e uma tabela de scores online!

No último artigo, preparamos as fundações e demos os primeiros passos na construção do game. Agora, com as bases prontas, vamos começar a nos concentrar no conteúdo - imagens, animações e interação entre os objetos do jogo e a interface do usuário.

Este post será maior que os outros dois, construiremos objetos mais complexos e resolveremos alguns problemas mais difíceis portanto, é aconselhável baixar o código-fonte e ir acompanhando as explicações utilizando-o como referência. Caso não queira fazer o download, você também pode ver o código no repositório do GitHub.

Abraços, e mão à obra!

Criando um Game Completo - Parte 2

Modelo do controle usado para os testes
Bem vindo à segunda parte do nosso mini-curso Criando um Game Completo, onde criamos uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joystics e uma tabela de scores online!

No último artigo, criamos uma classe para encapsular a lógica do game, carregamos algumas imagens para a memória e exibimos o primeiro inimigo na tela.  Seguiremos, agora, com a animação dos sprites e a movimentação do jogador através do teclado ou do joystick.

Vamos lá!

Criando um Game Completo - Parte 1

Você não precisa ver toda a escada,
simplesmente dê o primeiro passo!
Bem vindo à primeira parte do nosso mini-curso Criando um Game Completo, onde iremos criar, do zero, uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2D, suporte a joysticks e uma tabela de scores online!

O jogo é propositalmente simples para que o leitor com pouca experiência na linguagem Pascal e no desenvolvimento de games possa acompanhar o texto e o código o início ao fim. Iremos utilizar uma abordagem mista de programação estruturada e orientada a objetos já que precisaremos interfacear com algumas bibliotecas de baixo nível, mas sempre buscaremos manter o código simples, comentando e explicando cada bloco que surgir.

O curso está divido em nove partes, com cada uma delas sendo publicada semanalmente aqui no blog. Dúvidas, críticas e sugestões poderão ser postadas livremente nos comentários.

Espero que apreciem.

Criando um Game Completo - Parte 0

Nesta série de artigos, divida em 9 partes, vamos partir do zero e criar uma versão do clássico Space Invaders compatível com Windows e Linux, utilizando aceleração de hardware para gráficos 2d, suporte a joystick e uma tabela de high scores online.

O jogo é propositalmente simples para que o leitor com pouca experiência na linguagem e no desenvolvimento de games possa acompanhar o texto e o código o início ao fim.

Ao final de cada etapa, como de costume, estarão disponíveis para download tanto o código fonte como o executável equivalente.

Espero que apreciem.

A Magnetic Adventure
Um game de física escrito no Lazarus



O jogo A Magnetic Adventure não é exatamente novo (seu release aconteceu em outubro de 2010), mas hoje, num fórum de OpenGL, eu tive a grata surpresa de descobrir que ele foi escrito inteiramente em pascal.

Para ser mais exato, ele foi feito usando o Lazarus para a programação, GLScene para os gráficos e os bindings do Box2D para calcular a física. E a física é o ponto alto do jogo.

O jogador controla um ímã para interagir com as partes metálicas de curiosos mecanismos que guardam "totens" que o personagem precisa alcançar para concluir cada um dos 50 níveis disponíveis.

Gráficos Higth Tech "Made in Delphi"



Faz um tempo que venho acompanhando o blog de um norueguês chamado Rick, que fala sobre o andamento de um projeto de um jogo chamado Tower22, um jogo de horror pessoal desenvolvido do zero usando o Delphi 7.

Animações em tempo real com a VCL - Parte III

No artigo anterior, configuramos um formulário padrão da VCL para que pudéssemos exibir animações em sua superfície. Criamos também uma bola, que podíamos manipular pelas setas do teclado e fazê-la se mover pela tela. Nesta parte, vamos falar um pouco de teoria e criar nossa primeira animação procedural.

Um pouco de teoria

O sistema ocular humano é limitado quanto ao espectro visível de luz e quanto à velocidade de interpretação das imagens. O cérebro, porém, é muito bom no trabalho de contornar estas limitações e nos fazer enxergar imagens corretas, nítidas e sem quebras. Mas este trabalho de interpretação está sujeito a falhas e são essas falhas de interpretação que causam as famosas ilusões de ótica. A animação por computador é um tipo de ilusão projetada para causar ao o observador a impressão de movimento.

Desde o surgimento da animação, o seu fundamento é o mesmo: exibir uma seqüência de imagens estáticas, ligeiramente diferentes entre si, numa a uma velocidade superior a 12 imagens por segundo. Quando isto acontece, o olho envia as imagens paradas ao cérebro, mas este acha que se trata de um objeto animado e une-as, criando os pedaços que faltam para que se tenha a impressão de se estar vendo um objeto animado. Muito embora, não pareça haver um consenso entre os cientistas sobre quantos quadros por segundo são necessários para que a “ilusão da animação” aconteça, 12 quadros parecem ser suficientes para que a maioria dos seres humanos visualize-os como uma animação.

A TV, o cinema, o computador, os desenhos animados e os jogos eletrônicos são todos construídos em cima desta idéia. O sistema PAL-M usado no Brasil usa uma taxa de 30fps (do inglês Frames per Second, literalmente quadros por segundo, é a unidade medida padrão usada na indústria e, portanto iremos utilizá-la de agora em diante), filmes em DVD de boa qualidade usam de 24 a 30fps e, na animação de jogos para computador, uma taxa ideal de 60fps vem se estabelecendo ao longo dos anos.

Quando digo “taxa ideal”, não estou afirmando que é necessário alcançar os 60fps ou que seja errado ultrapassá-los. Na realidade, quanto mais quadros por segundo você puder exibir, mais convincente e suave será sua animação, então, daqui pra frente, vamos escrever nossos programas para que alcancem a maior taxa de fps que conseguirmos.

A composição das cores


Como sabemos, tudo que enxergamos é luz. Os objetos que vemos são, na realidade, luz refletida e/ou emitida por suas superfícies. Sabemos também que a partir da mistura de umas poucas cores primárias, todas as outras cores podem ser obtidas. Pois bem, nos monitores de computador, todas as cores são formadas a partir da combinação de apenas três cores: o vermelho (red), o verde (green) e o azul (blue), o famoso padrão RGB.

Neste formato, utilizado exclusivamente por dispositivos emissores de luz, quando todos os três componentes RGB estão em 0% de sua intensidade obtém-se a cor preta e, no caso inverso, quando todos os três componentes estão em 100%, obtém-se a cor branca. Todas as outras cores são obtidas ao se combinar porções distintas de cada um destes componentes.

Imagens, bitmaps e Pixels


Como dito antes, toda imagem digital é um conjunto de pixels. Pra ser mais preciso, podemos defini-las como sendo uma matriz de pixels que é mapeada, pixel a pixel, para um dispositivo de saída (monitor, plotter, impressora, etc).

Nos primórdios da computação, quando os monitores eram monocromáticos, as imagens eram simplesmente uma seqüência de bits que dizia se um ponto numa determinada coordenada no monitor deveria estar acesa ou apagada. Um mapa de bits, um bitmap.

O Windows utiliza este conceito para representar tudo o que deve aparecer no monitor. Ele sempre mantém uma imagem do tipo bitmap em uma área especial da memória RAM que o sistema de vídeo usa para montar a imagem final na tela. A este espaço dá-se o nome de frame buffer.

O Delphi, através da classe TBitmap, oferece um excelente meio de manipular essas imagens, e o método BitBlit da API do Windows, nos fornece um modo rápido de copiar imagens para o frame buffer.

Um Pouco de Código (finalmente)

Para melhorar um pouco a organização do código escrito no post anterior, vamos criar uma interface IDrawable e fazer com que nosso objeto TBackground a implemente.

IDrawable = interface
  ['{3E41F055-58F6-4990-9C94-AA29FD4D7CF4}']
  function GetVisible: boolean;
  function GetRect : TRect;

  procedure SetVisible(const Value: boolean);
  procedure Draw(Canvas:TCanvas);

  property Rect: TRect read GetRect;
  property Visible: boolean read GetVisible write SetVisible;
end;

A interface é bem intuitiva e dispensa maiores explicações. Ela irá definir o “contrato” para todos os objetos renderizáveis no nosso programa. Agora segue nova definição de TBackground adaptado para implementar IDrawable.

TBackgroung = class(TInterfacedObject, IDrawable)
private
  fStep: byte;
  fSize: uCommon.TSize;
  fVisible: boolean;
  function GetVisible: boolean;
  function GetRect : TRect;
  procedure SetVisible(const Value: boolean);
public
  constructor Create(pWidth: integer=640; pHeight:integer=480);
  destructor Free;
published
  {IDrawable}
  property Rect: TRect read GetRect;
  property Visible: boolean read GetVisible write SetVisible;

  {TBackgroung}
  property Size : uCommon.TSize read fSize;
  property Step : byte read fStep write fStep;
end;

Além das propriedades e métodos da interface, criamos duas outras, Size e Step, que irão nos auxiliar no controle da renderização e no controle da animação. Vamos criar uma série de quadros vermelhos que irão mudar de cor de acordo com o valor da propriedade Step. Para isto, vamos implementar o método Draw.


procedure TBackgroung.Draw(Canvas: TCanvas);
const
  SquareW    = 40; {largura de cada bloco}
  SquareH    = 40; {altura de cada bloco}
  SquaresC   = 640 div SquareW + 1; {colunas}
  SquaresR   = 480 div SquareH + 1; {linhas}
var
  col, row, i : integer;
  r : TRect;
begin
  if fVisible then begin
  for col:=0 to SquaresC-1 do
      for row :=0 to SquaresR-1 do begin
          r.Left   := Col * SquareW;
          r.Top    := Row * SquareH;
          r.Right  := r.Left + SquareW;
          r.Bottom := r.Top + SquareH;

          Canvas.Brush.Color := col * row + Step;
         Canvas.FillRect(r);
      end;
  end;
end;


O que fazemos aqui é dividir a tela em linhas e colunas de acordo com as contantes SquareW (a largura de cada quadrado) e SquareH (altura de cada quadrado), atribuir a cada um destas “células” uma cor diferente, que calculamos com base na linha, na coluna e no valor da propriedade Step para finalmente, desenharmos uma a uma as “células” no Canvas.

Só nos resta agora “animar” a cena alterando a propriedade Step após cada renderização. Faremos isto no nosso loop principal através do método UpdateAnimation.

procedure TForm1.OnIdle(Sender: TObject; var Done: Boolean);
begin
  ProcessInput;
  UpdateAnimation;
  DrawToBuffer;
  Blit;
  Done := False;
end;

E agora, a implementação de UpdateAnimation.

procedure TForm1.UpdateAnimation;
begin
  BackGnd.Step := BackGnd.Step + 1;
end;

Pronto! Nosso background animado está concluído. Execute o código para ver o padrão vermelho mudando de tom e experimente brincar com as constantes do método Draw para chegar a outros resultados. Observe que a classe TBall também foi alterada para implementar a interface IDrawable e que uma outra interface (IMoveable) foi criada para definir os objetos capazes de se mover pela tela.

Downloads

Links

Links para as postagens que fazem parte do mini curso "Animações em Tempo real com a VCL"

Animações em tempo real com a VCL - Parte II

No post anterior, fizemos uma introdução ao conceito de “Double buffer” e realizamos o tratamento da mensagem WM_ERASEBKGND para ajudar a otimizar um formulário VCL com o intuito de exibir animações de qualidade nele. Neste post, iremos finalizar estas otimizações.

Usando o evento OnIdle

O objeto Application está presente em todos os programas GUI do Delphi e é utilizado para simplificar a interação com a API do Windows. De fato, o objeto Application encapsula todas as chamadas à API necessárias para inicializar, registrar e manipular janelas, além de publicar alguns eventos globais.

O evento TApplication.OnIdle é um desses eventos. Ele é disparado sempre que o programa fica ocioso, ou seja, sempre que não houver mais nenhuma instrução a ser executada, o evento OnIdle será chamado. Isso o torna especialmente útil quando queremos realizar uma tarefa em segundo plano sem utilizar threads, ou quando queremos que uma determinada função seja executada repetidamente sem afetar o desempenho do programa.

Dois passos são necessários para utilizarmos o evento OnIdle.

Primeiro declare um procedimento privado em seu formulário e implemente-o como o código a seguir:

procedure OnIdle(Sender: TObject; var Done: Boolean);
begin
 Done := false;
end;

Note que não importa o nome do que você der ao método. O que importa é que a lista de parâmetros seja idêntica à do exemplo para que a assinatura do método seja compatível com a definição do evento Application.OnIdle para que, dessa forma, possamos associar nosso método ao evento.

Para finalizar, ponha o trecho de código abaixo no OnCreate do formulário e estaremos prontos para realizar nosso processamento neste evento.

procedure TfrmCGScreen.FormCreate(Sender: TObject);
begin
 Application.OnIdle := OnIdle;
end;

O loop principal (main loop)

Iremos utilizar o OnIdle para nosso loop principal.

O loop principal de uma aplicação de computação gráfica pode assumir várias formas, mas todas elas implementam variações da mesma lógica:

1. INICIO
2. ENQUANTO(ESTADO  <>  SAIR)
  2.1. PROCESSA OS COMANDOS DO USUÁRIO;
  2.2. ATUALIZA DO ESTADO DA ANIMAÇÃO;
  2.3. DESENHA A CENA NO BUFFER;
  2.4. EXIBE A CENA NO MONITOR;
3. FIM;

Vamos criar então os métodos equivalentes. Declare na seção privada do formulário os métodos a seguir e pressione Ctl + Shit + C para que o Delphi crie a implementação de todos:


procedure ProcessInput;    {passo 2.1}
procedure UpdateAnimation; {passo 2.2}
procedure DrawToBuffer;    {2.3}
procedure Blit;            {2.4}

Agora implemente o método OnIdle para que a estrutura do nosso algoritmo fique completa.

procedure TForm1.OnIdle(Sender: TObject; var Done: Boolean);
begin
 ProcessInput;
 UpdateAnimation;
 DrawToBuffer;
 Blit;
end;

Se você compilar e executar o programa agora, você verá uma janela do Windows vazia. Nada muito empolgante até agora: temos a estrutura geral pronta, mas nada pra exibir.

Vamos criar um objeto to TBall (adicione o arquivo uBall.pas ao seu projeto) no centro da tela. Declare uma variável pública chamada Ball e modifique o evento OnCreate do formulário para:

procedure TForm1.FormCreate(Sender: TObject);
begin
 ReportMemoryLeaksOnShutdown := True;

 {teremos uma tela de 800 x 600 pixels}
 ClientWidth := 800;              
 ClientHeight := 600;

 {Criamos nosso bitmap de buffer}
 fOffScreen := TBitmap.Create; 

 {iremos trabalhar com cores de 24bit}
 fOffScreen.PixelFormat := pf24bit;

 {configura as dimensões do buffer de acordo com as dimensões do formulário}
 fOffScreen.Width := ClientWidth;
 fOffScreen.Height := ClientHeight;
 Ball := TBall.Create;
 Ball.Position:= Point(ClientWidth div 2, ClientHeight div 2);
 Ball.Color := clWhite;
 Ball.Diameter := 30;
 Application.OnIdle := OnIdle;
end;

Agora é preciso exibir o objeto. Vamos implementar os métodos DrawToBuffer e Blit:

procedure TForm1.DrawToBuffer;
var
 Canvas : TCanvas;
begin
 Canvas := fOffScreen.Canvas;

 {Primeiro, limpamos o buffer com um fundo preto...}
 Canvas.Brush.Color := clBlack;

 {Agora desenhamos a bola}
 Canvas.FillRect(fOffScreen.Canvas.ClipRect);
 Ball.Draw(Canvas);
end;

procedure TForm1.Blit;
begin
 BitBlt(Canvas.Handle, 0, 0, ClientWidth, ClientHeight,
        fOffScreen.Canvas.Handle, 0, 0, SRCCOPY);
end;

Com isto temos, finalmente, nosso framework funcionando. Tudo bem que ele não faz mais nada além de desenhar uma bola no meio da tela, mas o “trabalho sujo” de configuração do ambiente foi realizado.
Para finalizar este post, vamos movimentar um pouco a bola pela tela usando as setas do teclado.

Implemente o método ProccessInput usando a função GetKeyState como na listagem abaixo. Note que os botões + e - irão manipular a velocidade em que a bola se movimenta.

procedure TForm1.ProcessInput;
begin
 if GetKeyState(VK_UP) then
    Ball.Move(0,-1);

 if GetKeyState(VK_DOWN) then
    Ball.Move(0, 1);

 if GetKeyState(VK_LEFT) then
    Ball.Move(-1, 0);

 if GetKeyState(VK_RIGHT) then
    Ball.Move(1, 0);

 if GetKeyState(VK_SUBTRACT) then
    Ball.Speed := Ball.Speed - 0.1;

 if GetKeyState(VK_ADD) then
    Ball.Speed := Ball.Speed + 0.1;
end;

Compile o projeto e experimente um pouco. Note que a bola não ultrapassa os limites da tela e que a classe TBall é responsável por este tratamento.

No próximo post, iremos adicionar um fundo com animação iremos expandir a classe TBall para trabalhar com sprites animados.

Até o próximo post.

Downloads

Links

Links para as postagens que fazem parte do mini curso "Animações em Tempo real com a VCL"