Membuat Animasi Sederhana


Animasi 2D mau bagaimana bentuknya pada dasarnya sama saja yaitu menampilkan gambar-gambar secara bergiliran. Untuk membuat animasi pada game 2D pada umumnya, sedikitnya ada tiga class yang terlibat. Ketiga class tersebut adalah:
  1. Class yang merepresentasikan citra/image yang akan dianimasikan. Biasanya disebut sprite. Dalam hal ini adalah TSprite.
  2. Container untuk menampung sprite objects. Container ini juga berperan sebagai sprite manager. Pada contoh code diberi nama TSpriteContainer.
  3. Class yang melakukan animasi. Bisa disebut sprite engine. Pada contoh code disebut TSpriteEngine.
Berikut adalah contoh code yang menampilkan teknik untuk melakukan animasi sederhana. Kelihatannya ribet yah. Mungkin iya karena code berikut adalah implementasi sederhana dari sebuah sprite engine untuk game 2D. Walaupun sederhana, mestinya sih sudah cukup untuk menjelaskan konsep animasi dan memperlihatkan bagaimana animasi berjalan tanpa flicker (bug paling menyebalkan dalam animasi). Contoh berikut terdiri atas dua unit, yaitu Sprite.pas dan Main.pas. Unit Sprite berisi empat buah class, yaitu:
  1. TUtils yang berisi method untuk yang bersifat utilisasi dan dipakai bersama-sama oleh semua class.
  2. TSprite yang merupakan class yang berisi informasi image yang akan digambar.
  3. TSpriteContainer yang berfungsi sebagai sprite container dan sprite manager.
  4. TSpriteEngine yang berfungsi melakukan animasi. Berisi sebuah method, yaitu OpenMouth.
Gambar-gambar yang akan di-raster di-load dan ditampung pada TSpriteContainer. Misalkan keempat file gambar tersebut bernama pac-1.bmp, pac-2.bmp, pac-3.bmp, pac-4.bmp, dan bg.bmp. Semuanya disimpan dalam directory “img\” yang path-nya relative terhadap .exe file.
File Sprite.pas:
unit Sprite;
 
interface
 
uses Windows, Graphics, Classes;
 
const
  BACKGROUND_PATH = 'img\bg.bmp';
 
type
  TUtils = class
  public
    class procedure ReleaseItems(AList: TList);
  end;
 
  TSprite = class
  private
    FName: string;
    FImage: TGraphic;
    FTop: Integer;
    FLeft: Integer;
    FWidth: Integer;
    FHeight: Integer;
  public
    constructor Create(AImgPath: string);
    destructor Destroy; override;
 
    property Name: string read FName write FName;
    property Image: TGraphic read FImage;
    property Top: Integer read FTop write FTop;
    property Left: Integer read FLeft write FLeft;
    property Width: Integer read FWidth write FWidth;
    property Height: Integer read FHeight write FHeigth;
  end;
 
  TSpriteContainer = class
  private
    FSprites: TList;
  public
    constructor Create;
    destructor Destroy; override;
    function Add(ASprite: TSprite): Integer;
    function Remove(ASprite: TSprite): Integer;
    function GetSprite(ASpriteName: string): TSprite;
    procedure Clear;
 
    property Sprites: TList read FSprites;
  end;
 
  TSpriteEngine = class
  private
    FContainer: TSpriteContainer;
    FScreen: TCanvas;
    FBackground: TGraphic;
  public
    constructor Create(AContainer: TSpriteContainer);
    destructor Destroy; override;
    procedure OpenMouth(ADuration: Integer);
 
    property Container: TSpriteContainer read FContainer;
    property Screen: TCanvas read FScreen write FScreen;
  end;
 
implementation
 
{TUtils}
 
class procedure TUtils.ReleaseItems(AList: TList);
begin
  while AList.Count > 0 do
  begin
    Dispose(AList.First);
    AList.Delete(0);
  end;
  AList.Capacity := 0;
end;
 
{TSprite}
 
constructor TSprite.Create(AImgPath: string);
begin
  FImage := TBitmap.Create;
  FImage.LoadFromFile(AImgPath);
 
  Fwidth := FImage.Width;
  FHeigth := FImage.Height;
  FTop := 0;
  FLeft := 0;
end;
 
destructor TSprite.Destroy;
begin
  FImage.Free;
  inherited;
end;
 
{TSpriteContainer}
 
constructor TSpriteContainer.Create;
begin
  FSprites := TList.Create;
end;
 
destructor TSpriteContainer.Destroy;
begin
  FSprites.Free;
  inherited;
end;
 
function TSpriteContainer.Add(ASprite: TSprite): Integer;
begin
  Result := FSprites.Add(ASprite);
end;
 
function TSpriteContainer.Remove(ASprite: TSprite): Integer;
begin
  Result := Fsprites.Remove(ASprite);
end;
 
function TSpriteContainer.GetSprite(ASpriteName: string): TSprite;
var
  i: Integer;
  sprite: TSprite;
begin
  Result := nil;
  for i := 0 to FSprites.Count-1 do
  begin
    sprite := FSprites.Items[i];
    if sprite.Name = ASpriteName then
    begin
      Result := sprite;
      Exit;
    end;
  end;
end;
 
procedure TSpriteContainer.Clear;
begin
  TUtils.ReleaseItems(FSprites);
end;
 
{TSpriteEngine}
 
constructor TSpriteEngine.Create(AContainer: TSpriteCOntainer);
begin
  FContainer := AContainer;
  FBackground := TBitmap.Create;
  FBackground.LoadFromFile(BACKGROUND_PATH);
end;
 
destructor TSpriteEngine.Destroy;
begin
  FBackground.Free;
  inherited;
end;
 
procedure TSpriteEngine.OpenMouth(APosition: TPoint;
  ADuration: integer);
var
  startTick, deltaTick: Cardinal
  frameDuration: Cardinal;
  spriteIndex: Integer;
  buffer: TBitmap;
begin
  startTick := GetTickCount;
  spriteIndex := 0;
  desltaTick := 0;
  frameDuration := ADuration div FContainer.Sprites.Count;
 
  buffer := TBitmap.Create;
  buffer.Width := FBackground.Width;
  buffer.Height := FBackground.Height;
 
  while (deltaTick
Unit Main.pas terdiri dari sebuah form yang berisi sebuah control bertipe TPainBox yang berfungsi sebagai screen, dan sebuah tombol bertipe TButton. Penggalan Main.pas adalah sebagai berikut:
unit Main;
 
interface
 
uses Windows, ..., ExtCtrls, Sprite;
 
const
  IMAGES_NUMBER = 4;
  PLAYING_DURATION = 200;
  LOOP_DELAY = 100;
  X = 200;
  Y = 100;
 
type
  TformMain = class(TForm)
    PaintBox: TPaintBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    ...
    procedure LoadAllImages(AContainer: TSpriteContainer);
    ...
 
  end;
 
implementation
 
{ TformMain }
 
constructor TformMain.Create(AOwner: TComponent);
begin
  inherited;
  FContainer := TSpriteContainer.Create;
  { Load semua image yang akan di-raster, Kemas menjadi object
    bertipe TSprite, kemudian simpan di dalam container menjadi
    data yang siap raster }
  LoadAllImages(FContainer);
 
  FSpriteEngine := TSpriteEngine.Create(FContainer);
  FSpriteEngine.Screen := PaintBox.Canvas;
end;
 
...
 
procedure LoadAllImages(AContainer: TSpriteCOntainer);
var
  i: Integer;
  sprite: TSprite;
  spriteName: string;
begin
  for i := 0 to IMAGES_NUMBER-1 do
  begin
    spriteName := 'pac-' + IntToStr(i+1) + '.bmp';
 
    sprite := TSprite.Create('img\' + spriteName);
    sprite.Name := spriteName;
    AContainer.Add(sprite);
  end;
end;
 
procedure TFormMain.Button1Click(Sender: TObject);
begin
  while True do
  begin
    FSpriteEngine.OpenMouth(Point(X, Y), PLAYING_DURATION);
    Sleep(LOOP_DELAY);
  end;
end;
 
end.
Gambar-gambar yang akan dianimasikan adalah:

Yang perlu diingat, code di atas hanyalah prototipe dari sprite engine sebuah dimensi dua yang memperlihatkan bagaimana memanipulasi sprite sehingga bisa menjadi gambar yang bergerak (animasi). Semoga bermanfaat dan silakan dimodifikasi sesuai dengan kebutuhan.

sumber : blogriza.com

Comments

Popular posts from this blog

Shortest Path Finder dengan Djikstra’s Algorithm

Mengenal dan Menggunakan Komponent MaskEdit pada Delphi

Membuat object Runtime pada Delphi