-
Здравствуйте, уважаемые мастера. Пишу вот я игру, плоскую, самолётик летает и всякую фигню сбивает. Снаряды и всякая фигня запихнуты в массивища. Снаряды надобно всё время добавлять и удалять. У снаряда есть тип, координаты, скорость. Ну,да,это всё не важно. ?-Как бы лучше их сделать - object'аим \ record'ами или class'ами [или ещё чем] (массив из них) Спасибо за внимание.
-
Лично у меня они сделаны рекордами. Удаление: Последний элемент кладеться на место удаляемого(ведь нам же порядок неважен), а количество уменьшаеться на единицу. Это позволяет не трогать память.
-
спасибо. Отлично. А вот если делать записями, то как сделать, чтобы массивы разных записей удалялись/ добавлялись одной процедурой?
-
> [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. Соответственно массив быстро увеличиваеться вначале, но потом поддерживаеться стабильный размер и нет постоянного перераспределения памяти.
-
В жизни не видел столь сложного решения для столь простой проблемы. Вопрос был про хорошее добавление и удаление элементов. Чтобы небыло aces ...
-
> В жизни не видел столь сложного решения для столь простой > проблемы.
Ваши предложения?
> Вопрос был про хорошее добавление и удаление элементов.
Чем не устраивает? Написать одно и тоже нельзя, вернее можно, но только в двух случаях 1) Работаем не как с массивом, а как с областью памяти и учитываем размер структуры. 2) В массиве храним не элементы, а указатели на них.
> Чтобы небыло aces ...
1) Это называеться AV 2) Мое решение не вызывает AV никогда. ;)
-
Не вызывает AV - я делал так же в точности; и вызывалосЬ, когда я часто стрелял!
-
Использую для назначения процедур на выполнение при рендеринге. 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.
-
Для этих целей, имхо, больше подходят связанные списки. и никаких АВ не будет.
-
Причина 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).
-
> [9] ggg (03.09.07 05:56)
А потеря скорости на выделение памяти при каждом создании класса?
-
Аналогично выделению памяти при объявлении записи )
-
> [11] ggg (03.09.07 09:46)
Да, конечно. Только у меня удаление элементов не ведет к перераспределению памяти. А удаление/создание классов - ведет. Хотя вы правы, логичнее работать с массивом указателей, тогда копировать придеться лишь указатель и не будет одной серъезной проблемы, с которой я столкнулся, а именно - не валидные указатели на элементы массива.
-
-
Использовать указатели. И лучше не изобретать велосипед и юзать связанные списки. Процедура удалния\вставки будет элементарная. А проход будет гарантировать отстутствие АВ на почве выхода за пределы массива. А если написать нормальный распределитель памяти, то большой выигрыш еще и на аллоках\деаллоках будет.
-
Полностью согласен с PixelShader. Связанные списки прекрасно решают эту задачу.
-
Статический массив. Перебирать полностью. Пустые не трогать. Убираемые помечать пустыми. Добавлять в первый попавшийся пустой.
-
Сложно и ограниченно заданым размером статического массива.
Может я чего-то непонимаю, но чем плохи связанные списки? Они, как будто специально придуманы для подобных задач. Зачем изобретать сложности на свою голову?
-
Приветствую Вас!Вы можете купить у нас качественный трафик по очень привлекательным ценам! Если у Вас есть какие либо вопросы, или пожелания Вы всегда можете обратиться в службу тех.поддержки. Мы с радостью ответим на все ваши вопросы и найдём оптимальное решение в любом случае. За подробностями, идем сюда: <quote><a href= http://drocim.com/paytraff.php>http://drocim.com/paytraff.php</a> У нас очень отзывчивый суппорт, работает практически 24\24 ответят на все ваши вопросы.</quote>
|