Конференция "Игры" » Массивище
 
  • savyhinst © (02.09.07 21:06) [0]
    Здравствуйте, уважаемые мастера.
    Пишу вот я игру, плоскую, самолётик летает и всякую фигню сбивает.
    Снаряды и всякая фигня запихнуты в массивища.
    Снаряды надобно всё время добавлять и удалять.
    У снаряда есть тип, координаты, скорость. Ну,да,это всё не важно.
    ?-Как бы лучше их сделать - object'аим \ record'ами или class'ами [или ещё чем] (массив из них)
    Спасибо за внимание.
  • @!!ex © (02.09.07 21:12) [1]
    Лично у меня они сделаны рекордами.
    Удаление:
    Последний элемент кладеться на место удаляемого(ведь нам же порядок неважен), а количество уменьшаеться на единицу.
    Это позволяет не трогать память.
  • savyhinst_ (02.09.07 21:25) [2]
    спасибо. Отлично. А вот если делать записями, то как сделать, чтобы массивы разных записей удалялись/ добавлялись одной процедурой?
  • @!!ex © (02.09.07 21:38) [3]
    > [2] savyhinst_   (02.09.07 21:25)

    Хм. У меня разные классы. Например для пуль:
     TBullets = class
     public
       Constructor Create;
       Procedure   AddBullet(BulletType,LifeTime,Power:integer; BulletSpeed:single; CanCrossWall:boolean; const Position, Velocity:x_vector; NotRnd:boolean; Side:integer; UID:integer = -1);
       Procedure   Update(dt:integer);
       Procedure   Draw;
       Procedure   Clear;
     protected
       Items:array of TBullet;
       Count:integer;
       Size:integer;
       Procedure  DeleteItem(ID:integer);
     end;


    По поводу Count и Size.
    Как у меня реализовано(я не настаиваю, что это лучший вариант, но так работает довольно быстро):
    Изначально Count=Size=0
    Добавляется элемент, инкрементируется Size.
    Дальше идет проверка:
    while (Size>Count) do begin
     inc(Count,10);
     SetLength(Items, Count);
    end;


    В итоге массив никогда не уменьшаеться, а только увиличиваеться.
    При удалении, размер массива не уменьшаеться, тупо уменьшаеться Count.
    Соответственно массив быстро увеличиваеться вначале, но потом поддерживаеться стабильный размер и нет постоянного перераспределения памяти.
  • savyhinst_ (02.09.07 21:44) [4]
    В жизни не видел столь сложного решения для столь простой проблемы.
    Вопрос был про хорошее добавление и удаление элементов. Чтобы небыло aces ...
  • @!!ex © (02.09.07 21:51) [5]
    > В жизни не видел столь сложного решения для столь простой
    > проблемы.

    Ваши предложения?


    > Вопрос был про хорошее добавление и удаление элементов.

    Чем не устраивает? Написать одно и тоже нельзя, вернее можно, но только в двух случаях
    1) Работаем не как с массивом, а как с областью памяти и учитываем размер структуры.
    2) В массиве храним не элементы, а указатели на них.


    > Чтобы небыло aces ...

    1) Это называеться AV
    2) Мое решение не вызывает AV никогда. ;)
  • savyhinst_ (02.09.07 21:55) [6]
    Не вызывает AV - я делал так же в точности; и вызывалосЬ, когда я часто стрелял!
  • ANTPro © (02.09.07 22:42) [7]
    Использую для назначения процедур на выполнение при рендеринге.
    unit ProcArray;

    interface

    uses Windows, Messages;

    type
     TOnEvent=procedure;

     TProcArray = class
     private
       FProc: array of TOnEvent;
     protected
       function GetProc(const ItemIndex: Cardinal): TOnEvent;
       procedure SetProc(const ItemIndex: Cardinal; const Proc: TOnEvent);
     public
       procedure Clear;
       procedure Run;
       function Add(Proc: TOnEvent): Cardinal;
       procedure Delete(ItemIndex: Cardinal);
       property Item[const ItemIndex: Cardinal]: TOnEvent read GetProc write SetProc;
     end;

    implementation
     
    procedure TProcArray.Run;
    var
     i: Cardinal;
    begin
     for i := Low(FProc) to High(FProc) do
       if @FProc[i] <> nil then FProc[i];
    end;

    function TProcArray.GetProc(const ItemIndex: Cardinal): TOnEvent;
    begin
     if ItemIndex < Cardinal(Length(FProc)) then
       Result := FProc[ItemIndex]
     else
       Assert(True, as_OutOfRange);
    end;

    procedure TProcArray.SetProc(const ItemIndex: Cardinal; const Proc: TOnEvent);
    begin
     if ItemIndex < Cardinal(Length(FProc)) then
       FProc[ItemIndex] := Proc
     else
       Assert(True, as_OutOfRange);
    end;

    procedure TProcArray.Clear;
    begin
     SetLength(FProc, 0);
    end;

    function TProcArray.Add(Proc: TOnEvent): Cardinal;
    begin
     Result := Length(FProc);
     SetLength(FProc, Result + 1);
     FProc[Result] := Proc;
    end;

    procedure TProcArray.Delete(ItemIndex: Cardinal);
    var
     i: Cardinal;
    begin
     if ItemIndex < Cardinal(High(FProc)) then
     begin
       for i := ItemIndex to High(FProc) - 1 do
         FProc[i] := FProc[i + 1];
       SetLength(FProc, High(FProc));
     end
     else
       Assert(True, as_OutOfRange);
    end;

    end.

  • PixelShader (03.09.07 01:45) [8]
    Для этих целей, имхо, больше подходят связанные списки. и никаких АВ не будет.
  • ggg (03.09.07 05:56) [9]
    Причина AV кроется всё-таки не в том, что используются массивы, это отлаживать надо ;)

    Всё-таки рекомендую использовать именно классы. Примерно таким образом

    TGameObject = class
     ...
    end;
    TGameObjectArray = array of TGameObject;
    TBullet = class(TGameObject)
     ...
    end;
    TAirplane = class(TGameObject)
     ...
    end;


    И тогда удаление/добавление в движке реализовывалось бы двумя процедурами. Это позволило бы хранить вообще все объекты в одном массиве. Ну или хотя бы не писать для каждого массива всё заново, а создать функцию типа

    function AddToMassivishe(const AMass: TGameObjectArray; const ANewObject: TGameObject): Integer;
    begin
     Result := Length(AMass);
     SetLength(AMass, Result + 1);
     AMass[Result] := ANewObject;
    end;


    Кроме того, использование классов в данном случае даст прирост производительности, т.к. при переносе элементов внутри массива (например при удалении элемента) в случае записи (recorda) будут копироваться все данные, а в случае обекта (class), только ссылка на объект, которая занимает 4 байта.

    Кстати, возможно, стоит хранить даже не в массивах, а в специально придуманных для этого классах-коллекциях ;)
    Обратите свой взор в сторону TList, там уже есть реализованные методы Add и Delete. Либо TCollection - но в этом случае прийдётся делать TGameObject = class(TCollectionItem).
  • @!!ex © (03.09.07 06:58) [10]
    > [9] ggg   (03.09.07 05:56)

    А потеря скорости на выделение памяти при каждом создании класса?
  • ggg (03.09.07 09:46) [11]
    Аналогично выделению памяти при объявлении записи )
  • @!!ex © (03.09.07 10:21) [12]
    > [11] ggg   (03.09.07 09:46)

    Да, конечно. Только у меня удаление элементов не ведет к перераспределению памяти.
    А удаление/создание классов - ведет.
    Хотя вы правы, логичнее работать с массивом указателей, тогда копировать придеться лишь указатель и не будет одной серъезной проблемы, с которой я столкнулся, а именно - не валидные указатели на элементы массива.
  • Sapersky (03.09.07 14:24) [13]
    А вот если делать записями, то как сделать, чтобы массивы разных записей удалялись/ добавлялись одной процедурой?

    http://sapersky.narod.ru/files/Arrays.rar
  • PixelShader (03.09.07 21:34) [14]
    Использовать указатели. И лучше не изобретать велосипед и юзать  связанные списки. Процедура удалния\вставки будет элементарная. А проход будет гарантировать отстутствие АВ на почве выхода за пределы массива. А если написать нормальный распределитель памяти, то большой выигрыш еще и на аллоках\деаллоках будет.
  • Shirson © (05.09.07 22:48) [15]
    Полностью согласен с PixelShader. Связанные списки прекрасно решают эту задачу.
  • Megabyte-ceercop © (06.09.07 07:19) [16]
    Статический массив. Перебирать полностью. Пустые не трогать.
    Убираемые помечать пустыми. Добавлять в первый попавшийся пустой.
  • Shirson © (06.09.07 17:56) [17]
    Сложно и ограниченно заданым размером статического массива.

    Может я чего-то непонимаю, но чем плохи связанные списки? Они, как будто специально придуманы для подобных задач. Зачем изобретать сложности на свою голову?
  • Koldans (27.04.09 15:32) [18]
    Приветствую Вас!

    Вы можете купить у нас качественный трафик по очень привлекательным ценам!
    Если у Вас есть какие либо вопросы, или пожелания Вы всегда можете обратиться в службу тех.поддержки.
    Мы с радостью ответим на все ваши вопросы и найдём оптимальное решение в любом случае.

    За подробностями, идем сюда:

    <quote><a href=http://drocim.com/paytraff.php>http://drocim.com/paytraff.php</a>

    У нас очень отзывчивый суппорт, работает практически 24\24 ответят на все ваши вопросы.</quote>
Есть новые Нет новых   [134430   +4][b:0][p:0.002]