![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | 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. Т.е. ты, видимо, пытаешься обратиться к несуществующему элементу, при том - к объекту. Ну и получаешь соответсвенно ошибку.
|