Forum > Games

Simple utility function for Allegro users

(1/2) > >>

mrguzgog:
Games tend to involve lots of images, sounds and fonts and keeping track of what needs to be destroyed when the program ends is a nuisance, especially during development when resources can be changed around frequently. I just came up with these two simple routines to help with this problem and they seem to work so I thought I'd share them.

Given that this is within scope...

--- Code: ---bitmapList: array of ALLEGRO_BITMAPptr;

--- End code ---

I can call addBitmap() whenever I want to load a bitmap and it gets added to the list to be destroyed by destroyBitmaps() so I don't have to remember to do it manually. Also, the array and routines can easily be changed to use the variant type so fonts, sounds etc could be stored in the same list - all that's needed is to check the actual type with vartype() in the destroy procedure and call the appropriate allegro routine.

Note: there's no error checking for existence of files etc as it stands!


--- Code: ---    function addBitmap(fileName: string): ALLEGRO_BITMAPptr;
    var
temp: ALLEGRO_BITMAPptr;
len:         integer;
    begin
temp := al_load_bitmap(fileName);
len := length(bitmapList) + 1;
setlength(bitmapList, len);
bitMapList[len - 1] := temp;
addBitmap := temp;
    end;
   
    procedure destroyBitmaps();
    var
i: integer;
    begin
for i:= 0 to length(bitmapList) - 1 do
al_destroy_bitmap(bitMapList[i]);
    end;

--- End code ---

Might help someone :D

Paul_:
What if you want remove single item? :)

E.g. linked list is better than array in this case.

mrguzgog:
Yes, the ability to remove a single item would need need a slightly different approach - a record with a 'tag' alongside the pointer to the bitmap might work and be easier than a linked list ;).

For my simple game and the comparatively huge amount of memory available these days I'm not interested in deleting individual resources (although those in the title/menu/options will get loaded and free'd via their own lists).

Ñuño_Martínez:
Instead of use a global variable, I recommend you to use a more Object Oriented approach (even without use of CLASSes, as you'll see).  That way you'll be able to manage your bitmaps more easy and grouped (i.e. PlayerImages, Alien1Images, Alien2Images...).  Even loading images would be more easy.

Also, you can reproduce the same to manage sound samples.

For example:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TYPE(* Contains a list of bitmaps. *)  TBitmapList = RECORD    Bmp: ARRAY OF ALLEGRO_BITMAPptr;    Count: INTEGER;  END;   (* Finds an empty place. *)  FUNCTION FindEmptyBmp (VAR aList: TBitmapList): INTEGER;  VAR    Ndx: INTEGER;  BEGIN    IF Length (aList.Bmp) < 1 THEN    BEGIN      aList.Count := 0;      EXIT (-1)    END;    FOR Ndx := 0 TO (aList.Count - 1) DO      IF aList.Bmp[Ndx] = NIL THEN EXIT (Ndx);    FindEmptyBmp := -1  END;   (* Adds a new bitmap.  Returns index. *)  FUNCTION AddBmp (VAR aList: TBitmapList; aBmp: ALLEGRO_BITMAPptr): INTEGER;  VAR    MyNdx: INTEGER;  BEGIN  { Find an empty place. }    MyNdx := FindEmptyBmp (aList);    IF MyNdx < 0 THEN    BEGIN    { If there's no space reserve more space. }      IF aList.Count < 1 THEN      BEGIN        SetLength (aList.Bmp, 8);        FOR MyNdx := 0 TO 7 DO aList.Bmp[MyNdx] := NIL      END      ELSE IF Length (aList.Bmp) <= aList.Count THEN      BEGIN        SetLength (aList.Bmp, aList.Count * 2);          FOR MyNdx := aList.Count TO HIGH (aList.Bmp) DO          aList.Bmp[MyNdx] := NIL      END;    { Where to put the new bitmap. }      MyNdx := aList.Count;       INC (aList.Count)    END;    aList.Bmp[MyNdx] := aBmp;    AddBmp := MyNdx  END;   (* Removes (and destroys) a bitmap. *)  PROCEDURE DestroyBitmap (VAR aList: TBitmapList; CONST Ndx: INTEGER);  BEGIN  { Avoid go outside the list. }     IF (0 > Ndx) OR (Ndx >= aList.Count) THEN Exit;     IF aList.Bmp[Ndx] = NIL THEN Exit;  { Destroy. }     al_destroy_bitmap (aList.Bmp[Ndx]);     aList.Bmp[Ndx] := NIL  END;   (* Destroy all bitmaps. *)  PROCEDURE ClearBitmapList (VAR aList: TBitmapList);  VAR    Ndx: INTEGER;  BEGIN    FOR Ndx := 0 TO (aList.Count - 1) DO      IF aList.Bmp[Ndx] <> NIL THEN al_destroy_bitmap (aList.Bmp[Ndx]);    SetLength (aList.Bmp, 0);    aList.Count := 0  END; 
Finding and fixing flaws and bugs are left as exercise (I didn't test the code so I'm not sure if it is correct).

If you want to use CLASSes, you can still using the ARRAY approach, but you would use TList or TFPList or any of the generics version instead.

[edit] I've fixed some very obvious flaws.

mrguzgog:
I'm sure that would work but I was shooting for simplicity :D Your code would also require a bunch of integer variables or arrays or something to hold the indexes but as you say if you need finer control that's the way to go.

I'm not using a global 'bitMapList' BTW, it's declared in the implementation of the particular unit along with the variables holding the bitmap pointers, which seems the most logical place. Where would you define 'aList' in your example?

Thanks for the suggestions :D

Navigation

[0] Message Index

[#] Next page

Go to full version