Академический Документы
Профессиональный Документы
Культура Документы
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
Site: Url:
Introduo
A maioria das linguagens de programao modernas oferece suporte para programao orientada a objetos (POO). Essas so baseadas em trs conceitos fundamentais: encapsulamento (normalmente implementado com classes), herana e polimorfismo (ou ligao tardia-late binding). Uma classe um tipo de dado definido pelo usurio, o qual tem alguns dados internos (variveis e propriedades) e alguns mtodos (procedimentos e funes) e normalmente descreve as caractersticas genricas e o comportamento de alguns objetos semelhantes. Um objeto uma instncia de uma classe ou de uma varivel do tipo de dados definido pela classe. Os objetos so entidades reais. Quando o programa executado, os objetos ocupam certa memria para sua representao interna. Voc pode ter quantos objetos precisar de uma classe, levando em conta que os objetos ocupam memria no computador. Veremos adiante como implementar classes e objetos utilizando o Delphi. Para isso vamos desenvolver um aplicativo que permita instnciar vrios objetos de uma mesma classe.
Criando as Classes
Programao Orientada a Objetos
Definindo as classes
A linguagem Object Pascal utilizada pelo Delphi totalmente orientada a objetos. Quando voc cria um novo projeto no Delphi, ele insere no seu projeto um novo form ( TForm1 ). Esse form na verdade herana do TForm, conforme a prpria declarao do Delphi
type TForm1 = class(TForm) private { Private declarations } public { Public declarations } end;
Renomeie o form para frmGame , salve a unit como Game.pas e o projeto como Game_POO.dpr. Jogos de estratgia possuem diversas classes e instncias. Para facilitar a programao podemos desenvolver uma classe "base" para as demais. Vamos criar uma classe padro chamada TVeiculo. Aps a seo Uses do form, declare:
type TVeiculo = class(TObject) Bitmap: TBitmap; PosX, PosY, Speed: Integer; procedure Draw; procedure Move; //Herda funes do TObject //Guarda a imagem do veiculo //Posio e velocidade //Desenha a imagem no plano //Responsvel pela movimentao
procedure LoadBitmap(AFile: string); //Carrega a imagem a partir do HD constructor Create; destructor Destroy; //Responsvel pela construo do objeto //Responsvel pela destruio do objeto
1 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
end;
Pressionando a combinao de teclas Ctrl+Shift+C sobre as procedures o Delphi montara para voc a implementao das mesmas. Digite as implementaes conforme descrito abaixo:
{ TVeiculo } procedure TVeiculo.LoadBitmap(AFile: string); begin //Desenha a Imagem "Bitmap" no Form Bitmap.LoadFromFile(AFile); Bitmap.Transparent := True; end;
procedure TVeiculo.Draw; begin //Desenha a Imagem "Bitmap" no Form frmGame.Canvas.Draw(PosX, PosY, Bitmap); end;
Construtores, como o prprio nome diz so mtodos executados quando o objeto est sendo criado. Nossa classe necessita criar o Bitmap para guardar a imagem. Faremos isso no construtor:
constructor TVeiculo.Create; begin inherited Create; //Chama a herana do TObject Bitmap := TBitmap.Create; //Cria o bitmap end;
destructor TVeiculo.Destroy;
Notem que apareceu a algo novo: Inherited. Esse comando serve para chamar a herana de criao e destruio do objeto TObject, nesse caso estamos reaproveitando essa funo. Voc vai ter mais informaes sobre Herana no prximo captulo desse tutorial.
Herana
Programao Orientada a Objetos
Herana
Uma das principais caractersticas da POO a Herana. Esse conceito facilita o reaproveitamento do cdigo.
2 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
No nosso exemplo, criamos uma classe chamada TVeiculo. Ela serve como base para todos os veculos. Imagine que vamos ter avies, carros e navios. Todos eles sero desenhados no plano, todos vo se mover, todos tero coordenadas X e Y e todos tero uma velocidade. A que est a facilidade... no precisamos reescrever nossas classes do zero, podemos partir da classe TVeiculo. Abaixo da classe TVeiculo declare uma classe TBalloon :
Repare na maneira em que a classe TBalloon foi declarada. No existe nenhuma diferena entre a sua antecessora (TVeiculo). TBalloon possui os mtodos Draw, Move, Create e Destroy e as propriedades PosX, PosY, Bitmap e Speed somente pelo fato de ter herdado da classe pai (TVeiculo), mesmo no aparecendo na declarao da mesma. Mas queremos que nosso balo movimente-se com uma caracteristica especial. Portanto devemos re-declarar o mtodo Move, no esquecendo de incluir a palavra chave override que indica que essa classe est sendo reescrevida:
type TBalloon = class(TVeiculo) procedure Move; override; //Re-declaramos o mtodo Move end;
Como o mtodo Move pertence a classe TVeiculo, precisamos "avis-la" que esse mtodo vai ser re-declarado em suas classes "filhas". Para isso utilizamos a palavra-chave Virtual. Repare tambm que o mtodo Move no foi implementado diretamente na classe TVeiculo. Isso porque todos os veiculos do projeto iro se mover, porm cada um de uma maneira diferente. O mtodo move, portanto, deve ser implementado em cada classe "filho". por isso alm de informar que o mtodo Move Virtual, tambm devemos dizer que um mtodo Abstract, ou seja, no ter implementao na classe "pai". A nossa classe TVeiculo ficar assim:
type TVeiculo = class(TObject) Bitmap: TBitmap; PosX, PosY, Speed: Integer; procedure Draw; procedure Move; Virtual; Abstract; //Pode ser redeclarada e no ser implementada na classe "pai" procedure LoadBitmap(AFile: string); constructor Create; destructor Destroy; end;
Pressionando a combinao de teclas Ctrl+Shift+C sobre o mtodo Move da classe TBalloon far com que o Delphi prepare implementao da mesma:
{ TBalloon } procedure TBalloon.Move; begin //Determina o movimento do balo PosY := PosY + Speed; end;
3 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
Alm da classe TBalloon, vamos criar mais uma nova classe, a TZeppelin herdando da TVeculo. Nessa classe, alm de implementar o mtodo Move ( obrigatrio em todas as classes "filhos" ), vamos tambm criar uma nova variavel SpeedFly que indica a velocidade que o Dirigivel ir voar:
type TZeppelin = class(TVeiculo) SpeedFly: Integer; //Nova caracteristica ( exclusiva da classe TZeppelin ) procedure Move; Override; end;
Percebam que o campo SpeedFly pertence somente para a classe TZeppelin. Esse campo no est presente nas classes TVeiculo e TBalloon. Pressione Ctrl+Shift+C e implemente o mtodo move da classe TVeculo:
{ TZeppelin } procedure TZeppelin.Move; begin //Determina o movimento do Dirigivel PosY := PosY + Speed; PosX := PosX + SpeedFly;
Nosso dirigvel desaparece-r no campo direito e dever reaparecer no canto esquerdo da tela. No prximo captulo iremos explicar como proteger e ocultar suas propriedades e mtodos.
Encapsulamento
Programao Orientada a Objetos
Encapsulamento
Existem maneiras de proteger informaes da sua classe. A essa caracterstica da-se o nome de Encapsulamento. Para implementar essa caracterstica, utilizamos as palavras-chave: Private, Protected, Public e Published, onde:
Private: Variveis e mtodos declarados como private somente sero acessados pela prpria classe. Protected: Variveis e mtodos declarados como protected podero ser acessadas por qualquer classe que esteja na mesma Public: Variveis e mtodos declarados como public podero ser acessadas por qualquer classe. Published: Usado na criao de componentes ( mas isso fica para outro tutorial ). Unit .
No nosso exemplo, a varivel Bitmap no pode ser alterada diretamente no programa. Para carregar a imagem deve-se utilizar o mtodo LoadBitmap. Portanto vamos declarar a varivel Bitmap como Private. Nossa classe TVeiculo ficar assim:
4 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
Bitmap: TBitmap; public PosX, PosY, Speed: Integer; procedure Draw; virtual; //Pode ser redeclarada procedure Move; virtual; Abstract; procedure LoadBitmap(AFile: string); constructor Create; virtual; //Pode ser redeclarada destructor Destroy; virtual; //Pode ser redeclarada end;
Aproveitamos tambm alterar os mtodos Draw, LoadBitmap, Create e Destroy, permitindo ser re-declarada por outras classes. Vamos agora criar uma nova classe chamada TFly:
type TFly = class(TVeiculo) private BitmapInv: TBitmap; public SpeedFly: Integer; procedure Draw; override; procedure Move; override; procedure LoadBitmapInv(AFile: string); constructor Create; override; destructor Destroy; override; end;
{ TFly } procedure TFly.Move; begin //Determina o movimento do avio PosY := PosY + Speed; PosX := PosX + SpeedFly;
if (PosX < 0) or (PosX > frmGame.ClientWidth) then SpeedFly := SpeedFly * -1; end;
procedure TFly.LoadBitmapInv(AFile: string); begin //Carrega a imagem invertida do avio BitmapInv.LoadFromFile(AFile); end;
constructor TFly.Create;
5 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
begin Inherited Create; //Chama a herana na classe TVeiculo BitmapInv := TBitmap.Create; BitmapInv.Transparent := True;
end;
destructor TFly.Destroy; begin BitmapInv.Free; Inherited Destroy; //Chama a herana na classe TVeiculo end;
procedure TFly.Draw; begin if SpeedFly > 0 then inherited Draw //Somente chama a herana se o SpeedFly for maior que "0" else frmGame.Canvas.Draw(PosX, PosY, BitmapInv); end;
Note que no mtodo Draw smente chamamos a herana quando a varivel SpeedFly for maior que "0", caso contrrio desenharemos a imagem invertida na tela. No prximo captulo estaremos estudando como instnciar e controlar nossas classes.
Instnciando
Programao Orientada a Objetos
object frmGame: TfrmGame Left = 192 Top = 114 Width = 600 Height = 400 Caption = "Tutorial Sobre Orientao a Objeto" object Panel1: TPanel Height = 40 Align = alTop object btBalao: TButton Left = 4 Top = 5 Width = 80 Height = 30 Caption = "Balo" end
6 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
object btAviao: TButton Left = 88 Top = 5 Width = 80 Height = 30 Caption = "Avio" end object btDirigivel: TButton Left = 172 Top = 5 Width = 80 Height = 30 Caption = "Dirigivel" end end object TimerDraw: TTimer Interval = 50 end object TimerMove: TTimer Interval = 50 end end
Poderiamos declarar variveis para as classes, mas se analizarmos bem, nos jogos de estratgia no sabemos quantas instncias ( veiculos ) teremos, o nmero aumenta e diminui durante o jogo. Portanto vamos utilizar um objeto que servir para organizar nossas instnicas. o TList. Declare uma varivel List na clausula var do form:
7 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
{ TfrmGame } procedure TfrmGame.FormCreate(Sender: TObject); begin //Cria a lista onde armazenaremos as instncias List := TList.Create;
end;
Alm de criar a lista, tambm avisamos para o form trabalhar com duas surfaces (DoubleBuffered), inicializamos a funo que gera nmeros aleatrios (Randomize) e mudamos a cor da fonte do canvas. No evento OnDestroy do form devemos tambm destruir a lista.
procedure TfrmGame.FormDestroy(Sender: TObject); var i: integer; begin //Destroi as instncias for i := List.Count-1 downto 0 do TVeiculo(List[i]).Free;
Antes de destruir a lista, devemos destruir cada uma das instncias contidas nessa lista. A lista possui uma propriedade Count que indica quantos elementos esto contidos na lista. Fazemos um For para percorrer todos os elementos da lista e destrui-los atravz do mtodo Free. Repare que precisamos fazer um TypeCasting porque a lista no sabe qual classe est guardando... na verdade uma lista guarda ponteiros de memria, ou seja, a lista apenas aponta para o objeto em memria. Devemos fazer referncia ao objeto conforme o exemplo ( TVeiculo(List[ index ] ). Repare que no precisamos saber exatamente se o objeto um avio, dirigivel ou balo. Como todos herdam da classe TVeiculo, basta fazer referncia a ela. Cada vez que clicarmos nos botes, instanciaremos um novo objeto e adicionaremos ele em nossa lista. O cdigo dos botes ficar conforme o exemplo abaixo:
8 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
begin //criamos o balo Balloon := TBalloon.Create; Balloon.PosX := Random(ClientWidth); Balloon.PosY := 0; Balloon.Speed := Random(3)+1; Balloon.LoadBitmap("balao.bmp");
end;
procedure TfrmGame.btAviaoClick(Sender: TObject); var Fly: TFly; begin //criamos o avio Fly := TFly.Create; Fly.PosX := Random(ClientWidth); Fly.PosY := 0; Fly.Speed := Random(3)+1; Fly.SpeedFly := Random(6)-3; Fly.LoadBitmap("Aviao.bmp"); Fly.LoadBitmapInv("AviaoInv.bmp");
9 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
procedure TfrmGame.TimerMoveTimer(Sender: TObject); var i: integer; begin //Timmer responsvel por movimentar todos os objetos da lista for i := List.Count-1 downto 0 do begin TVeiculo(List[i]).Move;
//Quando o objeto sair da tela dever ser destruido e removido da lista if TVeiculo(List[i]).PosY > ClientHeight then begin TVeiculo(List[i]).Free; List.Delete(i); end; end; end;
var i: integer; begin //Timmer responsvel por desenhar todos os objetos da lista //Limpo a tela Canvas.Brush.Color := clBlack; Canvas.FillRect(Rect(0,40,ClientWidth,ClientHeight));
//Escrevo na tela quantos objetos existem Canvas.TextOut(5, 45, "Qtde de Veiculos: "+IntToStr(List.Count)); end;
Utilizamos o mtodo Delete da lista para remover os ponteiros. Executando nosso aplicativo, ficaria conforme a imagem abaixo:
10 de 11
21/02/2012 21:33
http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...
Concluso
Programao Orientada a Objetos
Concluso
Devemos ressaltar que esse tutorial tem como objetivo elucidar aos iniciantes a vantagem de desenvolver games baseados na orientao a objetos, reaproveitando cdigos atravz do uso de heranas... no est em discusso as tcnicas de controle de imagem, etc... Reparem tambm que se precisassemos modificar a maneira com que desenhamos os objetos na tela, no precisariamos mudar nas trs classes, e sim na classe "pai", que a TVeiculo. Alterando qualquer cdigo nessa classe, automaticamente estaria refletindo nas demais. Voc pode obter o fonte atravz do link: Tutorial POO Espero que tenham gostado deste tutorial... sugestes so sempre bem vindas. Meu email : dagmarbezerra@uol.com.br
11 de 11
21/02/2012 21:33