![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | 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; |