GDJ :: Introdução a Programação Orientada a Objetos

http://pjmoo.codigolivre.org.br/gdj/pag_artigo_leitura_impressao.php...

Site: Url:

GDJ - Grupo de Desenvolvedores de Jogos http://pjmoo.codigolivre.org.br/gdj

Introdução a Programação Orientada a Objetos
Autor : db

Programação Orientada a Objetos

Introdução
A maioria das linguagens de programação modernas oferece suporte para programação orientada a objetos (POO). Essas são baseadas em três conceitos fundamentais: encapsulamento (normalmente implementado com classes), herança e polimorfismo (ou ligação tardia-late binding). Uma classe é um tipo de dado definido pelo usuário, o qual tem alguns dados internos (variáveis e propriedades) e alguns métodos (procedimentos e funções) e normalmente descreve as características genéricas e o comportamento de alguns objetos semelhantes. Um objeto é uma instância de uma classe ou de uma variável do tipo de dados definido pela classe. Os objetos são entidades reais. Quando o programa é executado, os objetos ocupam certa memória para sua representação interna. Você pode ter quantos objetos precisar de uma classe, levando em conta que os objetos ocupam memória no computador. Veremos adiante como implementar classes e objetos utilizando o Delphi. Para isso vamos desenvolver um aplicativo que permita instânciar vários objetos de uma mesma classe.

Criando as Classes
Programação 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 é herança do TForm, conforme a própria declaração 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 estratégia possuem diversas classes e instâncias. Para facilitar a programação podemos desenvolver uma classe "base" para as demais. Vamos criar uma classe padrão chamada TVeiculo. Após a seção Uses do form, declare:

type TVeiculo = class(TObject) Bitmap: TBitmap; PosX, PosY, Speed: Integer; procedure Draw; procedure Move; //Herda funções do TObject //Guarda a imagem do veiculo //Posição e velocidade //Desenha a imagem no plano //Responsável pela movimentação

procedure LoadBitmap(AFile: string); //Carrega a imagem a partir do HD constructor Create; destructor Destroy; //Responsável pela construção do objeto //Responsável pela destruição do objeto

1 de 11

21/02/2012 21:33

begin //Desenha a Imagem "Bitmap" no Form frmGame. Esse conceito facilita o reaproveitamento do código. A mesma regra se aplica aos Destrutores: destructor TVeiculo.LoadBitmap(AFile: string). begin inherited Create. Esse comando serve para chamar a herança de criação e destruição do objeto TObject. Faremos isso no construtor: constructor TVeiculo. como o próprio nome diz são métodos executados quando o objeto está sendo criado.Free.Create. Notem que apareceu aí algo novo: Inherited. end.br/gdj/pag_artigo_leitura_impressao. Digite as implementações conforme descrito abaixo: { TVeiculo } procedure TVeiculo. procedure TVeiculo. begin //Desenha a Imagem "Bitmap" no Form Bitmap. //Cria o bitmap end. //Destroi o bitmap //Chama a herança do TObject inherited Destroy..Transparent := True. end.org.Create. nesse caso estamos reaproveitando essa função. begin Bitmap.Draw. Nossa classe necessita criar o Bitmap para guardar a imagem. Você vai ter mais informações sobre Herança no próximo capítulo desse tutorial. Pressionando a combinação de teclas Ctrl+Shift+C sobre as procedures o Delphi montara para você a implementação das mesmas.. Construtores.LoadFromFile(AFile).php. Bitmap. end.Destroy.codigolivre. PosY.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo.Draw(PosX. Bitmap).Canvas. 2 de 11 21/02/2012 21:33 . end. Herança Programação Orientada a Objetos Herança Uma das principais características da POO é a Herança. //Chama a herança do TObject Bitmap := TBitmap.

podemos partir da classe TVeiculo. Speed: Integer. Bitmap e Speed somente pelo fato de ter herdado da classe pai (TVeiculo). end... porém cada um de uma maneira diferente. destructor Destroy. Aí é que está a facilidade. Todos eles serão desenhados no plano. ou seja. Repare também que o método Move não foi implementado diretamente na classe TVeiculo. carros e navios. procedure Move. Move. Abstract. Para isso utilizamos a palavra-chave Virtual. 3 de 11 21/02/2012 21:33 . portanto. //TBalloon herda caracteristicas do TVeiculo Repare na maneira em que a classe TBalloon foi declarada. todos vão se mover. Mas queremos que nosso balão movimente-se com uma caracteristica especial.. TBalloon possui os métodos Draw. não esquecendo de incluir a palavra chave override que indica que essa classe está sendo reescrevida: type TBalloon = class(TVeiculo) procedure Move. não precisamos reescrever nossas classes do zero. O método move. todos terão coordenadas X e Y e todos terão uma velocidade. //Re-declaramos o método Move end. A nossa classe TVeiculo ficará assim: type TVeiculo = class(TObject) Bitmap: TBitmap. override. precisamos "avisá-la" que esse método vai ser re-declarado em suas classes "filhas". end. também devemos dizer que é um método Abstract. por isso além de informar que o método Move é Virtual. Virtual. Imagine que vamos ter aviões. Não existe nenhuma diferença entre a sua antecessora (TVeiculo).Move. PosY. Portanto devemos re-declarar o método Move.php. Abaixo da classe TVeiculo declare uma classe TBalloon : type TBalloon = class(TVeiculo). Create e Destroy e as propriedades PosX. Ela serve como base para todos os veículos.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. PosX. PosY. criamos uma classe chamada TVeiculo.org.br/gdj/pag_artigo_leitura_impressao. Pressionando a combinação de teclas Ctrl+Shift+C sobre o método Move da classe TBalloon fará com que o Delphi prepare implementação da mesma: { TBalloon } procedure TBalloon. No nosso exemplo. begin //Determina o movimento do balão PosY := PosY + Speed. não terá implementação na classe "pai". //Pode ser redeclarada e não será implementada na classe "pai" procedure LoadBitmap(AFile: string). Isso porque todos os veiculos do projeto irão se mover. deve ser implementado em cada classe "filho".codigolivre. mesmo não aparecendo na declaração da mesma. procedure Draw.. constructor Create. Como o método Move pertence a classe TVeiculo.

Protected: Variáveis e métodos declarados como protected poderão ser acessadas por qualquer classe que esteja na mesma Public: Variáveis e métodos declarados como public poderão ser acessadas por qualquer classe.. Além da classe TBalloon. A essa característica da-se o nome de Encapsulamento.ClientWidth then PosX := 0. No próximo capítulo iremos explicar como proteger e ocultar suas propriedades e métodos. PosX := PosX + SpeedFly. end. Percebam que o campo SpeedFly pertence somente para a classe TZeppelin. Para implementar essa característica. além de implementar o método Move ( obrigatório em todas as classes "filhos" ). a variável Bitmap não pode ser alterada diretamente no programa.php. if PosX > frmGame. Override.org. Encapsulamento Programação Orientada a Objetos Encapsulamento Existem maneiras de proteger informações da sua classe. vamos também criar uma nova variavel SpeedFly que indica a velocidade que o Dirigivel irá voar: type TZeppelin = class(TVeiculo) SpeedFly: Integer. utilizamos as palavras-chave: Private.Move. No nosso exemplo. Nessa classe. Portanto vamos declarar a variável Bitmap como Private. Pressione Ctrl+Shift+C e implemente o método move da classe TVeículo: { TZeppelin } procedure TZeppelin. begin //Determina o movimento do Dirigivel PosY := PosY + Speed. Protected. Esse campo não está presente nas classes TVeiculo e TBalloon. a TZeppelin herdando da TVeículo.br/gdj/pag_artigo_leitura_impressao. Para carregar a imagem deve-se utilizar o método LoadBitmap.. Published: Usado na criação de componentes ( mas isso fica para outro tutorial ). Nosso dirigível desaparece-rá no campo direito e deverá reaparecer no canto esquerdo da tela. Nossa classe TVeiculo ficará assim: type TVeiculo = class(TObject) private 4 de 11 21/02/2012 21:33 . vamos criar mais uma nova classe. onde: Private: Variáveis e métodos declarados como private somente serão acessados pela própria classe. end.codigolivre.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. //Nova caracteristica ( exclusiva da classe TZeppelin ) procedure Move. Public e Published. Unit .

org. constructor TFly. 5 de 11 21/02/2012 21:33 .Move. Vamos agora criar uma nova classe chamada TFly: type TFly = class(TVeiculo) private BitmapInv: TBitmap.php. virtual. public SpeedFly: Integer. procedure Draw. Aproveitamos também alterar os métodos Draw. virtual. Abstract. Create e Destroy. PosY. //Pode ser redeclarada destructor Destroy. constructor Create..LoadFromFile(AFile). destructor Destroy. Pressionando novamente Ctrl+Shift+C teremos: { TFly } procedure TFly. public PosX.br/gdj/pag_artigo_leitura_impressao. LoadBitmap.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. PosX := PosX + SpeedFly.ClientWidth) then SpeedFly := SpeedFly * -1. Bitmap: TBitmap. virtual. end. override. permitindo ser re-declarada por outras classes. begin //Determina o movimento do avião PosY := PosY + Speed. override. procedure TFly.codigolivre. virtual. procedure LoadBitmapInv(AFile: string).. //Pode ser redeclarada end. procedure Move. procedure Draw. procedure LoadBitmap(AFile: string). Speed: Integer. //Pode ser redeclarada procedure Move. override. constructor Create. if (PosX < 0) or (PosX > frmGame. begin //Carrega a imagem invertida do avião BitmapInv. end. end.LoadBitmapInv(AFile: string). override.Create.

Destroy.org. Para tanto coloque em nosso Form 1 Panel. PosY. caso contrário desenharemos a imagem invertida na tela.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo.php. Inherited Destroy. //Chama a herança na classe TVeiculo BitmapInv := TBitmap.Canvas.Draw(PosX.. BitmapInv).. 3 botões e 2 Timers.codigolivre. Instânciando Programação Orientada a Objetos Instânciando Nossas Classes Num jogo de estratégia.Draw. mandando eles para batalhas onde acabam sendo destruidos por nossos inimigos. BitmapInv. como Command & Conquer por exemplo. No próximo capítulo estaremos estudando como instânciar e controlar nossas classes. end. definindo as propriedades conforme especificado abaixo: object frmGame: TfrmGame Left = 192 Top = 114 Width = 600 Height = 400 Caption = "Tutorial Sobre Orientação a Objeto" object Panel1: TPanel Height = 40 Align = alTop object btBalao: TButton Left = 4 Top = 5 Width = 80 Height = 30 Caption = "Balão" end 6 de 11 21/02/2012 21:33 . destructor TFly. ao mesmo tempo. a todo instante estamos construindo novos veiculos e.Create.Free.br/gdj/pag_artigo_leitura_impressao. begin Inherited Create. procedure TFly. //Chama a herança na classe TVeiculo end. end.Transparent := True. begin BitmapInv. begin if SpeedFly > 0 then inherited Draw //Somente chama a herança se o SpeedFly for maior que "0" else frmGame. Note que no método Draw sómente chamamos a herança quando a variável SpeedFly for maior que "0". Podemos fazer o mesmo com as classes que criamos.

mas se analizarmos bem.php. object btAviao: TButton Left = 88 Top = 5 Width = 80 Height = 30 Caption = "Avião" 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 Seu form deve ficar como o da figura abaixo: Poderiamos declarar variáveis para as classes. É o TList.org. Portanto vamos utilizar um objeto que servirá para organizar nossas instânicas..codigolivre.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. No evento OnCreate do Form devemos criar a nossa "lista": 7 de 11 21/02/2012 21:33 . Declare uma variável List na clausula var do form: var frmGame: TfrmGame. List: TList.br/gdj/pag_artigo_leitura_impressao. nos jogos de estratégia não sabemos quantas instâncias ( veiculos ) teremos.. o número aumenta e diminui durante o jogo.

Devemos fazer referência ao objeto conforme o exemplo ( TVeiculo(List[ index ] ).Free. begin //Destroi as instâncias for i := List.Count-1 downto 0 do TVeiculo(List[i]). O código dos botões ficará conforme o exemplo abaixo: procedure TfrmGame. Como todos herdam da classe TVeiculo. No evento OnDestroy do form devemos também destruir a lista. inicializamos a função que gera números aleatórios (Randomize) e mudamos a cor da fonte do canvas. A lista possui uma propriedade Count que indica quantos elementos estão contidos na lista..php. Antes de destruir a lista.Font. também avisamos para o form trabalhar com duas surfaces (DoubleBuffered).. end. a lista apenas aponta para o objeto em memória. Além de criar a lista.br/gdj/pag_artigo_leitura_impressao. 8 de 11 21/02/2012 21:33 . basta fazer referência a ela. dirigivel ou balão.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. devemos destruir cada uma das instâncias contidas nessa lista. Fazemos um For para percorrer todos os elementos da lista e destrui-los atravéz do método Free. var i: integer. Repare que não precisamos saber exatamente se o objeto é um avião. instanciaremos um novo objeto e adicionaremos ele em nossa lista. //Prepara o canvas do form para trabalhar com 2 surfaces DoubleBuffered := True.Free. Cada vez que clicarmos nos botões. na verdade uma lista guarda ponteiros de memória. //Determinamos a cor da Fonte Canvas.FormDestroy(Sender: TObject). //Libera a lista da memória List.FormCreate(Sender: TObject).org. ou seja. end. Repare que precisamos fazer um TypeCasting porque a lista não sabe qual classe está guardando. { TfrmGame } procedure TfrmGame.. procedure TfrmGame.btBalaoClick(Sender: TObject). var Balloon: TBalloon.codigolivre.Color := clWhite.Create.. begin //Cria a lista onde armazenaremos as instâncias List := TList. //Inicializamos a função que gera números aleatórios Randomize.

procedure TfrmGame. Fly.bmp").PosY := 0.PosX := Random(ClientWidth). //Adicionamos o balão na lista List. Balloon.btAviaoClick(Sender: TObject). var Fly: TFly. //Adicionamos o avião na lista List. Fly.Create.SpeedFly := 1.codigolivre. begin //criamos o dirigivel Zeppelin := TZeppelin.bmp"). end. Fly.btDirigivelClick(Sender: TObject). Balloon.PosX := Random(ClientWidth). 9 de 11 21/02/2012 21:33 .SpeedFly = 0 then Fly.PosY := 0. procedure TfrmGame..Speed := Random(3)+1.LoadBitmap("balao.bmp")..Add(Fly). Balloon.PosY := 0.php.LoadBitmapInv("AviaoInv. begin //criamos o balão Balloon := TBalloon. end.Add(Balloon). Zeppelin.Create.Speed := Random(3)+1. begin //criamos o avião Fly := TFly.PosX := Random(ClientWidth).br/gdj/pag_artigo_leitura_impressao.LoadBitmap("Aviao.SpeedFly := Random(6)-3. Fly. if Fly.org. Fly.GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. Zeppelin. var Zeppelin: TZeppelin.Create. Fly. Balloon.

Zeppelin.Count-1 do TVeiculo(List[i]). begin //Timmer responsável por desenhar todos os objetos da lista //Limpo a tela Canvas.Speed := Random(3)+1.TextOut(5.TimerDrawTimer(Sender: TObject).40. end.ClientWidth. end. var i: integer.LoadBitmap("Dirigivel.PosY > ClientHeight then begin TVeiculo(List[i]).Brush.Count-1 downto 0 do begin TVeiculo(List[i]).Add(Zeppelin).GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo.Draw..php. procedure TfrmGame.SpeedFly := Random(3)+1.FillRect(Rect(0. //Quando o objeto sair da tela deverá ser destruido e removido da lista if TVeiculo(List[i]).Delete(i). begin //Timmer responsável por movimentar todos os objetos da lista for i := List. //Percorro cada objeto da lista desenhando na tela for i := 0 to List.br/gdj/pag_artigo_leitura_impressao.bmp"). end. List.codigolivre.org. //Adicionamos o dirigivel na lista List.ClientHeight)).Color := clBlack. 45. end. Agora vamos implementar o evento OnTimmer dos dois timmers: procedure TfrmGame. Utilizamos o método Delete da lista para remover os ponteiros. var i: integer.TimerMoveTimer(Sender: TObject).Move. Zeppelin. //Escrevo na tela quantos objetos existem Canvas.Count)). "Qtde de Veiculos: "+IntToStr(List. end. Canvas. Zeppelin. Executando nosso aplicativo. ficaria conforme a imagem abaixo: 10 de 11 21/02/2012 21:33 ..Free.

sugestões são sempre bem vindas. não precisariamos mudar nas três classes. Meu email é: dagmarbezerra@uol. Alterando qualquer código nessa classe... reaproveitando códigos atravéz do uso de heranças.codigolivre.com.. e sim na classe "pai".Colaboração das Comunidades ArsLudica/PDJ (2001/2003) 11 de 11 21/02/2012 21:33 .. etc. automaticamente estaria refletindo nas demais. Você pode obter o fonte atravéz do link: Tutorial POO Espero que tenham gostado deste tutorial.php..br/gdj/pag_artigo_leitura_impressao. Conclusão Programação Orientada a Objetos Conclusão Devemos ressaltar que esse tutorial tem como objetivo elucidar aos iniciantes a vantagem de desenvolver games baseados na orientação a objetos.org.br GDJ 2005 . que é a TVeiculo...GDJ :: Introdução a Programação Orientada a Objetos http://pjmoo. não está em discussão as técnicas de controle de imagem. Reparem também que se precisassemos modificar a maneira com que desenhamos os objetos na tela..

Sign up to vote on this title
UsefulNot useful