|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
||||
|
||||
Движок самописный. Ошибка. Нид хелп!
Я написал примитивный 3Д движок(незнаю как это ещё назвать). Вот код юнита:
Код:
unit Engine; interface uses EngineDraw,Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls; const ConstRad=57.295779513082320876798154814105; //1 радиан = ConstRad type ZoomRange = 1..20; MyCamera = class hAngle:integer; vAngle:integer; Zoom:ZoomRange; procedure TL; procedure TR; Procedure TUP; Procedure TD; {FOV:???} end; MyDisplay = class handle:HWND; Canvas:TCanvas; Camera:MyCamera; public procedure AssignTo(wnd:TWinControl); end; coords = class x:integer; y:integer; z:integer; p:integer; t:integer; public procedure Draw(display:MyDisplay); procedure SetDefault; end; line = class stp:coords; enp:coords; public procedure Draw(display:MyDisplay); procedure SetDefault; end; obj = class name:integer; dot:coords; lin:line; end; WorldObjects = class list:array of Obj; count:integer; procedure AddDot(x,y,z:integer); procedure AddLine(stp,enp:coords); end; implementation function ATR(Angle:integer):real;//Перевод из градусов в радианы.Стандартную begin //функцию не нашёл. Надо писать свою. ATR:=(Angle/ConstRad); end; {function ITF(input:integer):real; begin ITF:=strtofloat(IntToStr(input)); end; } procedure MyDisplay.AssignTo(wnd:TWinControl);//На что мы будем выводить изобр. var buffer:MyDisplay; begin buffer:=MyDisplay.Create; buffer.Canvas:=TCanvas.create; buffer.Canvas.Handle:=GetDC(wnd.Handle); self:=buffer; self.Camera:=(Self.Camera); Buffer.Canvas.Destroy; end; procedure MyCamera.TL; begin if hAngle=0 then hAngle:=359 else dec(hAngle); end; procedure MyCamera.TR; begin if hAngle=359 then hAngle:=0 else inc(hAngle); end; procedure MyCamera.TUP; begin if vAngle=0 then vAngle:=359 else dec(vAngle); end; procedure MyCamera.TD; begin if vAngle=359 then vAngle:=0 else inc(vAngle); end; procedure coords.SetDefault; //Обнуление параметров begin x:=0; y:=0; z:=0; p:=0; t:=0; end; procedure line.SetDefault; //Обнуление begin with stp do begin x:=0; y:=0; z:=0; p:=0; t:=0; end; with enp do begin x:=0; y:=0; z:=0; p:=0; t:=0; end; end; Procedure CalculateDotPos(Dot:coords;Display:MyDisplay); begin //Координата p(горизонталь) плоскости экрана dot.p:=round(cos(ATR(Display.Camera.hangle))*dot.x+Sin(ATR(Display.Camera.hangle))*dot.y); //Координата t(вертикаль) плоскости экрана dot.t:=0; end; Procedure CalculateLinePos(Line:line;display:MyDisplay); begin CalculateDotPos(Line.stp,display); //Вычисление координат начала линии CalculateDotPos(Line.enp,display); //Вычисление координат конца линии end; Procedure CalculateObjPos(s:obj;Display:MyDisplay); begin case s.name of 1:CalculateDotPos(s.dot,Display); //Вычисление позиции точки на экране 2:CalculateLinePos(s.lin,Display); //Вычисление позиции линии на экране end; end; Procedure coords.Draw(Display:MyDisplay); begin Display.Canvas.Pixels[self.p,self.t]; end; Procedure line.Draw(Display:MyDisplay); begin Display.Canvas.MoveTo(self.stp.p,self.stp.t); Display.Canvas.LineTo(enp.p,enp.t); end; procedure WorldObjects.AddDot(x,y,z:integer); begin list[count+1].name:=1; list[count+1].dot.x:=x; list[count+1].dot.y:=y; list[count+1].dot.z:=z; inc(count); end; procedure WorldObjects.AddLine(stp,enp:coords); var buf:WorldObjects; begin list[count+1].name:=2; list[count+1].lin.stp:=stp; list[count+1].lin.enp:=enp; inc(count); end; end. Код:
var Form1: TForm1; Display:MyDisplay; World:WorldObjects; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin Display:=MyDisplay.Create; Display.AssignTo(Panel1); World:=WorldObjects.Create; World.count:=0; end; procedure TForm1.Button1Click(Sender: TObject); var bufstp,bufenp:coords; begin bufstp:=coords.Create; bufenp:=coords.Create; Bufstp.x:=strtoint(edit1.Text); Bufstp.y:=strtoint(edit2.Text); Bufstp.z:=strtoint(edit3.Text); Bufenp.x:=strtoint(edit4.Text); Bufenp.y:=strtoint(edit5.Text); Bufenp.z:=strtoint(edit6.Text); World.AddLine(bufstp,bufenp); end; |
#2
|
||||
|
||||
Вам надо свой конструктор для класса WorldObjects написать, где вы будете инициализировать свои переменные, а то вы описываете динамический массив, а создать его забываете.
Код:
WorldObjects = class list:array of Obj; count:integer; constructor Create; procedure AddDot(x,y,z:integer); procedure AddLine(stp,enp:coords); end; constructor WorldObjects.Create; begin SetLength(List, 0); Count := 0; end; И потом по логике Count надо бы свойством объявить, т.к. возвращает по сути длину List. ЗЫ: И еще, имейте ввиду, что динамический массив ведет отсчет от 0-элемента, поэтому list[count+1].name будет вызывать ошибку выхода за границы диапазона массива. Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. Последний раз редактировалось Страдалецъ, 17.12.2009 в 11:20. |
#3
|
||||
|
||||
ответ
Обьясните пожалуйста смысл вот этих действий, что оно делает:
SetLength(List, 0); Count := 0; Таким же образом мне надо было бы написать конструкторы для всех классов? Получается конструктор - это процедура, запрашивающая память для всех переменных класса, а без него эти переменные при обращении к ним ссылаются "вникуда"? Извиняюсь если вопросы слишком заезжаные. Я в работе с памятью не имею никаких навыков, только всё интуитивно теоретически понимаю. 2. Что значит "обьявить свойством" Как может выйти за границы массива, если массив динамический, то есть не имеет чётких границ, что я не понимаю? Спасибо. Последний раз редактировалось Енот, 18.12.2009 в 06:56. |
#4
|
||||
|
||||
1.Делать свой конструктор класса необязательно, т.к. по умолчанию все классы наследуются от базового класса у которого есть конструктор Create, но этот конструктор ничего не знает о наследнике и его переменных. И если для статических переменных вызов собственного конструктора можно упустить, то вот для динамических это уже обязательно.
2. Работа с динамическим массивом тоже требует определенных правил. Процедура SetLength инициализирует и устанавливает размерность для динамического масива. Без вызова хотя-бы раз этой процедуры, с таким массивом работать нельзя. В вашем случае, размерность изначально неизвестна, поэтому создаем пустой массив. При добавлении элеменета к массиву надо делать так: Код:
SetLength(List, Length(List)+1); Но вот, если вам потребуется вставить или удалить элемент из массива, то уже придется потрудится, т.к. готовых процедур для этого нет. Как альтернатива динамическому массиву, рекомендуется использовать базовый класс TList. Там уже предусмотрены все основные методы работы с таким массивом. 3. Объявить свойством в данном случае, это воспользоваться специальной конструкцией для классов - property. В вашем случае для чтения Count надо вызвать Length(List) и для записи в него SetLength(List, Length(List)+1). Код:
WorldObjects = class private procedure SetCount(Value: Integer); function GetCount: Integer; public list:array of Obj; count:integer; property Count: Integer read GetCount write SetCount; ... end; ... implementation procedure WorldObjects.SetCount(Value: Integer); begin SetLength(List, Value); end; function WorldObjects.GetCount: Integer; begin Result := Length(List); end; Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. |
#5
|
||||
|
||||
Схема действий:
1. Обьявляю что существует такой массив WorldObjects: Код:
constructor WorldObjects.Create; begin SetLength(List,0); Count := 0; end; 2. Указываю что в нём есть 1 элемент: Код:
procedure WorldObjects.SetCount(Value: Integer); begin SetLength(List, Value); end; ... WorldObjects.Setcount(1); 3. Пытаюсь сказать что это линия: Код:
list[count].name:=2; И на 3 этапе выбивает ошибку access violation! |
#6
|
|||
|
|||
Скорее всего, т.к. list - это динамический массив, то первый его элемент имеет индекс 0, а вот последний - Length(list) - 1. Кстати, то же самое относится и к стандарным классам списков - TList, TStringList, TObjectList. Т.е. ты, видимо, пытаешься обратиться к несуществующему элементу, при том - к объекту. Ну и получаешь соответсвенно ошибку.
|
#7
|
||||
|
||||
Вот такой код касательно WorldObjects:
Код:
WorldObjects = class private procedure SetCount(Value: Integer); function GetCount: Integer; public list:array of Obj; property Count: Integer read GetCount write SetCount; procedure AddDot(x,y,z:integer); procedure AddLine(stp,enp:coords); constructor create; end; implementation constructor WorldObjects.Create; begin SetLength(List,0); Count := 0; end; procedure WorldObjects.SetCount(Value: Integer); begin SetLength(List, Value); end; function WorldObjects.GetCount: Integer; begin Result := Length(List); end; ... procedure WorldObjects.AddLine(stp,enp:coords); begin list[count].name:=2; list[count].lin.stp:=stp; list[count].lin.enp:=enp; Count:=count+1; //<-Даю порядковый номер след. обьекта SetLength(List, 1) // <-Даю место для следующего обьекта end; Ну что же у меня не так? |
#8
|
||||
|
||||
Вот такой код касательно WorldObjects:
Код:
WorldObjects = class private procedure SetCount(Value: Integer); function GetCount: Integer; public list:array of Obj; property Count: Integer read GetCount write SetCount; procedure AddDot(x,y,z:integer); procedure AddLine(stp,enp:coords); constructor create; end; implementation constructor WorldObjects.Create; begin SetLength(List,0); Count := 0; end; procedure WorldObjects.SetCount(Value: Integer); begin SetLength(List, Value); end; function WorldObjects.GetCount: Integer; begin Result := Length(List); end; ... procedure WorldObjects.AddLine(stp,enp:coords); begin list[count].name:=2; list[count].lin.stp:=stp; list[count].lin.enp:=enp; Count:=count+1; //<-Даю порядковый номер след. обьекта SetLength(List, 1) // <-Даю место для следующего обьекта end; Ну что же у меня не так?access violation! |
#9
|
|||
|
|||
Код:
function WorldObjects.GetCount: Integer; begin Result := Length(List); end; Возвращает кол-во элементов. Но последний элемент имеет индекс Count-1. |
#10
|
||||
|
||||
Код:
Count := Сount + 1; //<-Даю порядковый номер след. обьекта Код:
SetLength(List, 1) Код:
Count := Сount + 1; Код:
SetCount(GetCount + 1) Кроме того надо иметь ввиду, что отсчет элементов в динамическом массиве идет от нуля, поэтому ваша запись: Код:
list[count].name:=2; Код:
list[count-1].name:=2; Надеюсь все подробно расписал. Жизнь такова какова она есть и больше никакова. Помогаю за спасибо. Последний раз редактировалось Страдалецъ, 18.12.2009 в 19:08. |
#11
|
||||
|
||||
Вы забыли создавать и уничтожать Obj
Код:
WorldObjects = class private Flist: array of Obj; procedure SetCount(Value: Integer); function GetCount: Integer; function GetList(Index: Integer): Obj; public constructor create; destructor Destroy(); override; property Count: Integer read GetCount write SetCount; procedure AddLine(stp, enp: coords); property List[Index: Integer]: Obj read GetList; end; implementation constructor WorldObjects.Create; begin // это не обязательно // SetLength(List, 0); // Count := 0; end; function WorldObjects.GetCount: Integer; begin Result := Length(FList); end; procedure WorldObjects.SetCount(Value: Integer); var oldCount, i: Integer; begin oldCount := Count; for i := oldCount downto Value do Flist[i].Free; SetLength(Flist, Value); for i := oldCount to Value - 1 do Flist[i] := Obj.Create(); end; //... procedure WorldObjects.AddLine(stp, enp: coords); var nextObj: Obj; begin nextObj := list[count]; // смотри GetList - создастся следующий Obj nextObj.name := 2; nextObj.lin.stp := stp; nextObj.lin.enp := enp; end; function WorldObjects.GetList(Index: Integer): Obj; begin if Index >= Count then Count := Index + 1; Result := FList[Index]; end; destructor WorldObjects.Destroy; begin Count := 0; // уничтожаем все Obj inherited; end; |