Page 2 of 4 FirstFirst 1234 LastLast
Results 11 to 20 of 31

Thread: Dynamic in-game object creation and manipulation

  1. #11
    Quote Originally Posted by Super Vegeta View Post
    or maybe do something like NewLength := OldLength * 1.5.
    I strongly recommend against using of this approach. Why? Because it leads to exponential growth of the array and could therefore become a great memory hog.
    Imagine next scenario. You have an arrays with 100k items. Each item is 10KB in size. Which means that your array would be roughly 1GB in size. So following your approach adding 1 additional item would increase its size from roughly 1GB to 1.5GB in size. Or in other hand you would be wasting about 500MB of memory just because you had to increase the size of the array to hold additional item.
    So I would rather suggest increasing the array in fixed increments instead.

    Quote Originally Posted by Tomi View Post
    Wow, thanks, Super Vegeta! I didn't know this technique about dynamic arrays. But using of it are not recommended because the resizing is complicated?
    While dynamic arrays do allow you to change their size at any time you don't have to do this. If you want you can set their size at the start based on your expected requirement and don't update their size later on.
    One instance of this would be using dynamic arrays to store game map. You know the map dimensions upon level loading so you set the size of dynamic array to be big enough to hold that data and you don't resize them until you decide to load different level.
    So unless you are concerned about your game to be using as little memory as possible the whole time you don't need to be to much concerned about resizing of dynamic arrays you would probably do it rarely.

  2. #12
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524
    It's just an example - exponential array growth is a *good* solution - if you're using dynamic arrays in such a way then it means you have no idea on the maximum number of elements you need - ergo an exponential growth is a good default mode of operation.

    Take a parser that loaded lines of text - it might be asked to load 10 lines and then it might be asked to load 10 million lines - a fixed increment would have to be huge to make this close to efficient in terms of performance and it would then become inefficient in terms of storage for smaller numbers of lines.

    Exponential growth is the best trade-off you can make between performance and storage in a number of scenarios - the detriment remains roughly equal across both domains.

    In fact a better solution is to have an affordable but reasonably large initial size (say 4096 elements) and then grow exponentially from that - you lose a little bit of storage space for lots of small collections but you minimize the number of resizes as they're all bunched at the lower end with exponential growth.

    if you *know* you're storing 1GB of data in memory then you *never* want to be resizing an array of that size anyway - that's just silly - you'd pick a more efficient access pattern in the first place - one that doesn't rely on continuous blocks across the entire set.

    Memory is plentiful, you can afford to waste some for the sake of performance.
    Last edited by phibermon; 20-12-2015 at 12:01 AM.
    When the moon hits your eye like a big pizza pie - that's an extinction level impact event.

  3. #13
    Quote Originally Posted by phibermon View Post
    Take a parser that loaded lines of text - it might be asked to load 10 lines and then it might be asked to load 10 million lines - a fixed increment would have to be huge to make this close to efficient in terms of performance and it would then become inefficient in terms of storage for smaller numbers of lines.
    You could combine both approaches. In fact I have seen this somewhere in Delphi code. I'm not sure whether this was in a TList or one of it descendants or perhaps in TMemoryStream. But I do know I have seen approach where initially size is increased exponentially to some point. From then on it is increased in fixed increments.

    if you *know* you're storing 1GB of data in memory then you *never* want to be resizing an array of that size anyway - that's just silly - you'd pick a more efficient access pattern in the first place - one that doesn't rely on continuous blocks across the entire set.
    That is true. I have been exaggerating a bit with my example to make the point more obvious.

    In my projects I'm generally trying to avoid any array that would exceed 100 MB in size. If needed I split such arrays into multiple parts and then envelop them with class which then still allows me accessing to their data as it would still be stored in a single array. This way I lose a bit of performance but I avoid most problems that may arise due to memory fragmentation (not being able to find big enough continuous block of memory).

    Also I'm starting to use classes and list more and more. One reason is to avoid having large arrays. Second reason is much faster data soring since you are moving less data in the array.
    I even have a special list that provide multiple indexes and therefore allows me to have my data sorted by different criteria at all times.
    Of course this list is also designed in a way that when I'm adding new data or removing data from it all indexes are updated right away (sorted inserts).

  4. #14
    Quote Originally Posted by phibermon View Post
    please post your code for how you setup the array of bullets
    I'm using fixed length arrays:
    Code:
    bullets: array [0..100] of TBullet;
    Then in a Timer event I create, move and destroy the bullets:
    Code:
    if (plshoot=true) and (plcanshoot=true) then
      begin
             abullet:=TBullet.create(Player.Left,Player.Top,bulletpic);
             bullets[numofbullets]:=abullet;
             inc(numofbullets);
      end;
    
    
      if numofbullets>=1 then
      begin
           for i:=0 to numofbullets-1 do
           begin
            if bullets[i]<>nil then
            begin
                bullets[i].yplace:=bullets[i].yplace-4;
                if bullets[i].yplace<10 then
                begin
                     freeandnil(bullets[i]);
                     if i=numofbullets-1 then
                        dec(numofbullets)
                     else
                     begin
                          for j:=i+1 to numofbullets-1 do
                              bullets[j-1]:=bullets[j];
                          dec(numofbullets);
                     end;
                end;
            end;
           end;
      end;
    (I have already corrected the first variable of the loops from 1 to 0, as you wrote.)
    When I press the fire button, the bullets are only flash at the top of the player. :-/

  5. #15
    Is your numofbullets global variable or is it declared inside Timers OnEvent method.
    If it is declared in an OnTimer event method that means that it is cleared after ending of each Timer cycle and then recreated in another cycle with default value which is 0.

  6. #16
    The numofbullets is a global variable; only the i and j variables are declared in the timer.

  7. #17
    Then I'm afraid I can't help you out further without seeing more code. Best thing would be access to your whole game so I can try to debug it.

  8. #18
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524
    Yep - whatever is going wrong doesn't appear to be connected (at least entirely) with what you've posted so far - I will note however that :

    Code:
                     freeandnil(bullets[i]);
                     if i=numofbullets-1 then
                        dec(numofbullets)
                     else
                     begin
                          for j:=i+1 to numofbullets-1 do
                              bullets[j-1]:=bullets[j];
                          dec(numofbullets);
                     end;
    is convoluted and a mess - why free the bullet at all? just fill your array with created bullet objects and just have a new boolean property of TBullet called 'active'. Then you can simply do :

    Code:
    {go through the array and create a TBullet object with 'active' set to false for all objects as part of your game initialization}
    
    if (plshoot=true) and (plcanshoot=true) then
    begin
       I := 0;
       while Bullet[I].active do
          I := I + 1;
       if I > high(Bullet) then exit;
       Bullet[I].active := true;
       Bullet[I].Xplace := Player.Left;
       Bullet[I].Yplace := Player.Top;
    end;
    
    
    for I := 0 to numofbullets-1 do
    if bullets[I].active then
    begin
       bullet[I].YPlace := bullet[I].YPlace-4;
       if bullet[I].YPlace < 10 then
          bullet[I].Active := false;
    end;
    Then go through the array and only render 'active' bullets - yes you'll be skipping over 'inactive' bullets but that's still loads faster than constantly creating/destroying objects.

    An optimization of this would to be to treat the array like a ring-buffer - then by its very nature the start index is the oldest active bullet and the end index is the newest bullet - only iterate over these - still you'll itterate over some inactive bullets but it'll be much faster than constantly keeping the array tightly packed - you could also use a linked list but really unless you've got thousands of bullets there's no need to care performance wise.

    There are various reasons why you'd want to keep an array tightly packed - perhaps it needs to be kept sorted (but there are better structures such as linked lists) or perhaps you have a need to copy a continuous block of memory for some reason (uploading vertex data to a GPU) but you don't need either of these.

    Also bare in mind that there's no reason you can't have two container structures - a flat array and a linked list - scan the flat array for an inactive bullet - set it to active and add a reference to a linked list. If the bullet is to be 'destroyed' set it to inactive and remove it from the linked list - this way you have a flat array for 'storage' and the linked list for optimal iteration over active elements (linked lists are slow to index but are very fast for deletions/insertions - especially in your case where you delete from anywhere in the list but only add to the end)

    Even better have two linked lists - an active one and an inactive one - then you no longer have to scan for an active bullet or create one - you just remove one from the inactive list and add it to the active list and visa versa - a slow object creating, array shuffling operation becomes a case of setting a few pointers.

    --

    But : these are only suggestions to think about - it's overkill at this stage - as SilverWarrior suggests we'd need to see basically all of your code to tell you what's wrong.
    Last edited by phibermon; 20-12-2015 at 06:01 PM.

  9. #19
    Maybe I find what is wrong in my code: I have to put the drawings in the Timer event, not in Formpaint. Ehhh... I need more experience with Lazarus.
    Last edited by Tomi; 21-12-2015 at 01:29 PM.

  10. #20
    Hello and happy new year, everybody!


    At last, my first game with Lazarus is done: a small space shooter, with some enemies, one boss and power-ups.
    It's name is "Space Defender" and you can download from here:
    http://www.programozzunk.ucoz.hu/laz...k/spacedef.zip
    Unfortunately it has some bugs:
    - the appearance of bullets of enemies sometimes happens in wrong place,
    - the sprites of the spacehips are flashing,
    - sometimes the game throw you out, when the player is rebirth at the boss and you press buttons.
    In spite of all this, I hope that you will enjoy this game, but if you will find the solutions for these bugs, please tell me.

Page 2 of 4 FirstFirst 1234 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •