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:
- Class yang merepresentasikan citra/image yang akan dianimasikan. Biasanya disebut sprite. Dalam hal ini adalah TSprite.
- Container untuk menampung sprite objects. Container ini juga berperan sebagai sprite manager. Pada contoh code diberi nama TSpriteContainer.
- 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:
- TUtils yang berisi method untuk yang bersifat utilisasi dan dipakai bersama-sama oleh semua class.
- TSprite yang merupakan class yang berisi informasi image yang akan digambar.
- TSpriteContainer yang berfungsi sebagai sprite container dan sprite manager.
- 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