PDA

View Full Version : Controlling all instances of a class



pjpdev
15-05-2009, 07:37 PM
Hi

I'm trying to get my sprite engine up and running, but I need to find a way to control all instances of the sprite class using one method.

TSprite:

type
TSprite = class
private
...
public
X, Y, Z: Integer;
...
procedure Draw();
end;


Instances:

var
Sprite1, Sprite2: TSprite;
...


Sprite Engine Class:

type
TSpriteEngine = class
private
...
public
...
procedure DrawAll();
end;

...

procedure TSpriteEngine.DrawAll();
begin
//Here all the instances of TSprite should be drawn...
end;


I know c/c++ has a way of doing it like this:


...
for each TSprite
{
Draw();
};
...


I'm trying to get the sprites to draw once and overlap each other according to the Z value. Is there a way that I can parse through all the instances of TSprite?

Thanks ahead...

User137
15-05-2009, 08:55 PM
Instances:

var
Sprite1, Sprite2: TSprite;
...

I think this is where it goes wrong. You should make array in TSpriteEngine and keep Sprite instances only there.

TSpriteEngine = class
private
...
public
Sprite: array of TSprite;
Count: integer;
...
procedure AddSprite(newSprite: TSprite);
destructor Destroy; override;
...
end;

TPlayerSprite = class(TSprite)
.. // You can add something custom to player here
end;

procedure TSpriteEngine.AddSprite(newSprite: TSprite);
var i,j: integer; temp: TSprite;
begin
inc(Count);
setlength(Sprite,Count);
Sprite[Count-1]:=newSprite;

// Z-Sort (is possible to optimize this...)
for i:=0 to Count-2 do
for j:=i+1 to Count-1 do
if sprite[i].Z>Sprite[j].Z then begin // Change places
temp:=sprite[i];
sprite[i]:=sprite[j];
sprite[j]:=temp;
end;
end;

destructor TSpriteEngine.Destroy;
var i: integer;
begin
for i:=0 to Count-1 do
sprite[i].Free;
setlength(sprite,0);
inherited;
end;


var newSprite: TPlayerSprite;
begin
..
newSprite:=TPlayerSprite.Create;
SpriteEngine.Add(newSprite);
newSprite.Z:=10;
..
end;

procedure TSpriteEngine.DrawAll();
var i: integer;
begin
// Here all the instances of TSprite should be drawn...
for i:=0 to Count-1 do
Sprite[i].Draw;
end;

Hope it helps ;)

chronozphere
15-05-2009, 09:06 PM
You should take a look at the (Un)delphix DXSprite.pas unit. It's a great example of what a sprite-engine could look like. I learned alot of tricks (including some OOP) form that unit. :)



...
for each TSprite
{
Draw();
};
...


Does this really work in C++? I've never seen anything like this (Iterating through all instances of a type). It looks more like python, If it's at all possible. :o

pjpdev
15-05-2009, 10:02 PM
Python? C++? I saw it somewhere...

Thanks for the tip. I got it right by making the TSpriteEngine a derived class from TList and each time a TSprite instance gets created its added to the TSpriteEngine list... So calling TSpriteEngine.Draw() will draw all the sprites... and calculate drawing order according to the Z value of TSprite.


type
  TSprite = class;
  TSpriteEngine = class(TList);

  TSprite = class
  private
    FEngine: TSpriteEngine;
  public
    constructor Create(AEngine: TSpriteEngine);
    property Engine: TSpriteEngine;
  end;

  TSpriteEngine = class(TList)
  private
    ...
  public
    procedure Add(Sprite: TSprite);
    property Items[Index: Integer]: TSprite read GetItem write SetItem;
    procedure Draw();
  end;

...

constructor TSprite.Create(AEngine: TSpriteEngine);
begin
  //Create the sprite and add to engine
  FEngine := AEngine;
  FEngine.Add(Self);
end;


That helps to stop errors: "Undeclared identifier - TSpriteEngine"

Thanks for the help everyone...

chronozphere
15-05-2009, 10:16 PM
You don't need to derive from TList. I always create a TList object inside my objects, because you might want to add lists in the future. Only derive from a class when your class has a "Is a kind of" relationship with the ancestor class. In this case, it isn't true, because the sprite-engine isn't just one list of sprites.

For example, in the DXSprite unit, the TSpriteEngine contains a "Sprite" list, a "Draw" list and a "dead" list.

The sprite-list contains all the sprites present in the game. The draw list contains all the sprites that are visible in drawing order (so you don't have to sort them every frame). The dead-list contains all sprites that are dead and should be removed from the game. This is usually only possible at the end of a frame, since other sprites might rely on it while the frame is being computed/rendered.

You should take a look at that unit. I found it really helpfull when i was learning this stuff. :)

pjpdev
17-05-2009, 10:27 AM
Mmm... Seems like thats the best way to do it. I'll give it a try, but I'll have to rewrite most of the sprite engine code.

Thanks everyone... ;)