Upload
internet
View
108
Download
0
Embed Size (px)
Citation preview
Desenvolver Jogos em DelphiX
Passos
• Adicionar o TDXDraw– Onde se passa toda a acção
• Adicionar um TDXImageList– Um por cada tipo de imagens(heroi, balas...)– Adicionar as imagens aos Items– Associar ao TDXDraw– NOTA: ao adicionar uma imagem esta deve de ficar em TDIB
• Adicionar um TDXWaveList– Para termos sons prontos a utilizar
• Adicionar um TDXTimer:– Colocar a propriedade enabled a false– Definir o intervalo de disparo– É aqui que está o focus da questão!!
Classe’s VS Actores
• Construir Classes/UNIT’s para cada um dos actores do Jogo :type
TBullet = class(TImageSprite)
private
{colocar aqui atributos do actor}
public
{overload dos métodos que desejarmos redefinir} procedure DoMove(moveCount:integer);override;
procedure DoDraw();override;
procedure DoCollision(Sprite:TSprite;varDone:Boolean);override;
end;
{ utilizar class completion: ctrl^c }
DXSprite Unit• Components
– TDXSpriteEngine• Objects
– TBackgroundSprite• Chips property can be specified• collision judgment can be set with the CollisionMapproperty
– TImageSprite• Onde a imagem é mostrada• Atributos:
– Image – imagem a mostrar• surface é Image.PatternSurfaces[AnimStart+AnimPos]
– TSprite• Class abstracta que apresenta os métodos:
– DoDraw– DoMove– DoColision
– TSpriteEngine• Controlo os sprites a ele associados
Implementar os métodos de DXDraw para gestão dos eventos
• DXDrawInitialize{colocar o timer com 60 segs}dxtimer1.Interval := 1000 div 40;dxtimer1.enabled := true;{outras coisas que desejar iniciar}
• DXDrawFinalizedxtimer1.enabled := true;
Nota: as afectações ao Timer devem de ser feitas sempre nestes métodos por definição.
TDXTimer – o responsável (1)• Este objecto é quem contém o código importante da aplicação, pois permite
o evoluir do jogo:{se não conseguirmos desenhar, terminamos}
if (dxdraw1.canDraw = false) then exit; {actualiza a situação de input nos estados} DXInput1.Update();
{desenhar o fundo: sem stretch} DXImageFundos.Items[0].Draw( dxdraw1.surface, 0, 0, 0);
{colocar a superficie com cor} DXDraw1.Surface.Fill( dxdraw1.surface.colormatch(
RGB(0,100, 200)) ); {actualizar o ecrã, limpando os objectos mortos} DXSpriteEngine1.Dead(); {chamada aos DoMove dos actores com um numero de pixels} DXSpriteEngine1.move(2); {desenhar os sprites na superficie de fundo} DXSpriteEngine1.Draw();
TDXTimer – o responsável (2)
• O seguinte código também pode ser adicionado:{utilizado para mostrar os frames per segundo e valores de
variaveis} with DXDraw1.Surface.canvas do begin Brush.Style := bsClear; Font.Color := clRed; Font.Size := 20; TextOut(0, 0, 'fps: ' +
intToStr(DXTimer1.FrameRate)); Release(); {obrigatorio} end;
• Nunca esquecer NO FIM: {nao aparece nada sem esta chamada} DXDraw1.flip();
Criação dos objectos
• A criação é feita no Form onCreate event handler: {criar o jogo}
theGame := TGame.Create(); theGame.sprite := dxSpriteEngine1.engine; theGame.spriteEngine := dxdraw1; theGame.input := dxInput1; theGame.sound := dxSound1; theGame.imageListFUndos := dxImageFundos; theGame.imageListWalls := DXImageListWall; theGame.imageListHeroi := DXImageListHeroi; theGame.waveListHeroi := DXWaveHeroi; theGame.pontos := 0; {criar os actores} // criar o Heroi theHeroi := THeroi.Create(theGame);
• theGame e theHeroi é um atributo da form1• Na criaçao do jogo faz-se sempre a associação entre os componentes
DelphiX da form e a instância de TGame
TImageSprite – atributos
• TImageSprite– AnimCount– AnimLooped– AnimPos– AnimSpeed– AnimStart– Image– PixelCheck– Tile
•Derived from TSprite–BoundsRect–ClientRect–Collisioned–Count–Engine–Height–Items–Moved–Parent–Visible–Width–WorldX–WorldY–X–Y–Z
Um Actor
• Um Actor encontra-se associado a um jogo, logo para se construir um novo Actor deriva-se da classe TActor:
type TActor = class (TImageSprite) protected game: TGame; public
{apresenta um contructor apenas} constructor Create(game: TGame); end;
implementation
constructor TActor.Create(game: TGame);begin inherited Create(game.sprite); {associa o sprite} self.game := game; {associa-se ao jogo}
self.z := 10; {atribui um valor por omissão ao Z}end;
Dica
• Não esquecer de fazer a destruição de todos os actores e game no form onDestroy event handler:
theGame.free();
theGun.free();
TGame
• O Tipo TGame representa o Jogo• Existe para simplificar e aproveitar as capacidades
drag-drop do Delphi• Difere de jogo para jogo• Apresenta como atributos :
– tudo o que representa o jogo • (e.g.) score, vidas, tempo
– os elementos DelphiX utilizados• (e.g.) TDXWaveList’s, TDXImageList’s, TDXInput...
• Os atributos não são privados o que viola as regras de OOP, no entanto foi o melhor possível...
• Os atributos são afectados no evento de Create da form que contém os componentes.
(e.g) TGametype TGame = class // o que é indispensável {sempre} sprite : TSprite; spriteEngine: TDXDraw; input: TDXInput; sound: TDXSound; // imageLists necessarias imageListFUndos: TDXImageList; imageListWalls: TDXImageList; imageListHeroi: TDXImageList; // wavelists necessarias waveListHeroi: TDXWaveList; // atributos necessarios ao Jogo pontos: integer; vidas: integer; end;
Definição de um novo Actor
Derivar da classe TActor que deriva de TImageSprite: THeroi = class(TActor) private left, right, up, down: boolean;
public constructor Create(game:TGame);
procedure DoDraw();override; procedure DoMove(moveCount:integer);override; procedure DoCollision(sprite: TSprite; var Done:boolean);override; end;
• Redefinir os métodos em que estamos interessados.(exemplos de seguida)
• Nota: os atributos que se encontram apresentados são específicos deste Tipo
• Nota: cada Actor deve de existir numa única UNIT: encapsulamento.
O Constructor• A cada Actor está associado sempre um Game que é afectado
no Constructor – método Create(..):constructor THeroi.Create(game: TGame);begin inherited Create(game); {obrigatório} self.Image := self.game.imageListHeroi.Items[0]; self.Width := self.Image.Width; self.height := self.Image.Height; self.x := self.game.spriteEngine.Width div 2; self.y := self.game.spriteEngine.height -
(2*self.Image.Height); left := false;
right := false; up := false; down := false;end;
• É no constructor que se afectam os atributos que representam o Actor
Os Intervenientes
Movimento dos Objectos
• A redefinição do método onMove que é responsável pelo movimento:procedure THeroi.DoMove (moveCount: integer);begin inherited DoMove(moveCount);
if(isLeft in self.game.input.States) thenself.X := self.X - moveCount;
if(isRight in self.game.input.States) thenself.X := self.X + moveCount;
if(isUp in self.game.input.States)thenself.y := self.y - moveCount;
if(isDown in self.game.input.States) thenself.y := self.y + moveCount;
collision(); {para testar se houve colisões}end;
Pode ser utilizado para mexer todos os actores de igual forma.
É afectado no evento de DXTimer construção do TGame
BMP’s especiais – animação do Heroi
// animar o heroi
self.AnimPos := 0;
self.AnimStart := 20;
self.AnimCount := 6;
self.AnimSpeed := 5/1000;
self.AnimLooped := true;
Nota: as propriedades ParentHeight e ParentWidth têm que ser alterardas para representar o tamanho do Heroi
Choque – detecção de colisões?
• Sempre que é feito um movimento verifica-se se houve choque com outro actor de um tipo especificado:
procedure THeroi.DoCollision(sprite: TSprite; var Done: boolean);
begin
inherited;
if (sprite is TWall) then
begin
self.game.waveListHeroi.items[0].play(false); {gritar!!??}
end;
end;
Acesso a imagens ou sons
• Todos os TActor estão associados um game que conhece:type
TGame = class
// o que é indispensável {sempre}// imageLists necessarias
imageListFUndos: TDXImageList;
imageListWalls: TDXImageList;
imageListHeroi: TDXImageList;
// wavelists necessarias
waveListHeroi: TDXWaveList;
// atributos necessarios ao Jogo
pontos: integer;
vidas : integer:
• Logo o acesso é feito da seguinte forma:self.game.waveListHeroi.items[0].play(false);
self.game.imageListHeroi.Items[0]; {[‘nomeImagem’]}
False: nao espera terminar o som
True: bloqueia
Exemplo de um movimento pseudo-aleatorio
// a utilizar no DoMove if(random(30)=1) then begin self.Image := game.DXImageLaden.items[random(2)]; self.x := random(game.dxdraw1.Width); self.y := random(game.dxdraw1.height-self.Image.Height); end;
Não esquecer da chamada á função randomize(); no evento de criação da Form que contém o jogo.
Carregar paredes (leitura da informação de um Ficheiro)
assignFile(fich, 'level1.txt'); reset(fich); cnt:=0; while (not eof(fich)) do begin read(fich, ch); if(not ((ch = #13) or (ch=#10)))then begin aux[cnt] := ch; cnt := cnt + 1; end; end; cnt:=0; for yy:=0 to 6 do for xx:=0 to 9 do begin if(aux[cnt]='0') then TWall.Create(theGame, xx, yy); cnt := cnt + 1; end;
var xx, yy: integer; fich: file of char; aux : array[0..100] of char; cnt: integer; ch: char;
Opções de Projecto – em Delphi
Project --> Options --> application
Pode-se alterar várias definições:– icon– title– Help file