Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Графика и игры
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 17.12.2009, 03:41
Аватар для Енот
Енот Енот вне форума
Прохожий
 
Регистрация: 17.12.2009
Сообщения: 28
Репутация: 10
Восклицание Движок самописный. Ошибка. Нид хелп!

Я написал примитивный 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;
В основной форме есть Panel1, на которую выводится изображение. Координаты линии вводятся через Edit'ы. Когда нажимаю button1 координаты передаются в процедуру World.Addline и там должны строиться координаты относительно плоскости экрана(тоесть моей панельки). Но выбивает ошибку типа access violation на строке, которую я выделил. Прошу помочь разобраться в чём дело. Спасибо!
Ответить с цитированием
  #2  
Старый 17.12.2009, 08:23
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

Вам надо свой конструктор для класса 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  
Старый 18.12.2009, 06:50
Аватар для Енот
Енот Енот вне форума
Прохожий
 
Регистрация: 17.12.2009
Сообщения: 28
Репутация: 10
По умолчанию ответ

Обьясните пожалуйста смысл вот этих действий, что оно делает:
SetLength(List, 0);
Count := 0;

Таким же образом мне надо было бы написать конструкторы для всех классов?
Получается конструктор - это процедура, запрашивающая память для всех переменных класса, а без него эти переменные при обращении к ним ссылаются "вникуда"? Извиняюсь если вопросы слишком заезжаные. Я в работе с памятью не имею никаких навыков, только всё интуитивно теоретически понимаю.

2. Что значит "обьявить свойством"
Как может выйти за границы массива, если массив динамический, то есть не имеет чётких границ, что я не понимаю?

Спасибо.

Последний раз редактировалось Енот, 18.12.2009 в 06:56.
Ответить с цитированием
  #4  
Старый 18.12.2009, 10:04
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

1.Делать свой конструктор класса необязательно, т.к. по умолчанию все классы наследуются от базового класса у которого есть конструктор Create, но этот конструктор ничего не знает о наследнике и его переменных. И если для статических переменных вызов собственного конструктора можно упустить, то вот для динамических это уже обязательно.
2. Работа с динамическим массивом тоже требует определенных правил. Процедура SetLength инициализирует и устанавливает размерность для динамического масива. Без вызова хотя-бы раз этой процедуры, с таким массивом работать нельзя. В вашем случае, размерность изначально неизвестна, поэтому создаем пустой массив. При добавлении элеменета к массиву надо делать так:
Код:
SetLength(List, Length(List)+1);
Для получения текущей длины массива вызываем Length(List)
Но вот, если вам потребуется вставить или удалить элемент из массива, то уже придется потрудится, т.к. готовых процедур для этого нет.
Как альтернатива динамическому массиву, рекомендуется использовать базовый класс 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  
Старый 18.12.2009, 16:42
Аватар для Енот
Енот Енот вне форума
Прохожий
 
Регистрация: 17.12.2009
Сообщения: 28
Репутация: 10
По умолчанию

Схема действий:
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  
Старый 18.12.2009, 16:46
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,048
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Скорее всего, т.к. list - это динамический массив, то первый его элемент имеет индекс 0, а вот последний - Length(list) - 1. Кстати, то же самое относится и к стандарным классам списков - TList, TStringList, TObjectList. Т.е. ты, видимо, пытаешься обратиться к несуществующему элементу, при том - к объекту. Ну и получаешь соответсвенно ошибку.
Ответить с цитированием
  #7  
Старый 18.12.2009, 17:15
Аватар для Енот
Енот Енот вне форума
Прохожий
 
Регистрация: 17.12.2009
Сообщения: 28
Репутация: 10
По умолчанию

Вот такой код касательно 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  
Старый 18.12.2009, 17:15
Аватар для Енот
Енот Енот вне форума
Прохожий
 
Регистрация: 17.12.2009
Сообщения: 28
Репутация: 10
По умолчанию

Вот такой код касательно 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  
Старый 18.12.2009, 17:24
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,048
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Код:
function WorldObjects.GetCount: Integer;
begin
 Result := Length(List);
end;

Возвращает кол-во элементов. Но последний элемент имеет индекс Count-1.
Ответить с цитированием
  #10  
Старый 18.12.2009, 19:03
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

Код:
Count := Сount + 1;      //<-Даю порядковый номер след. обьекта
Это несколько не так, на самом деле вы увеличиваете массив, поэтому следующая инструкция вообще не в тему.
Код:
SetLength(List, 1)
Когда вы обращаетесь к свойству Count происходит вызов функции GetCount, а когда присваиваете Count какое либо значение, происходит уже вызов процедуры SetCount, поэтому когда вы пишете:
Код:
Count := Сount + 1;
на самом деле будет выполнен такой код:
Код:
SetCount(GetCount + 1)

Кроме того надо иметь ввиду, что отсчет элементов в динамическом массиве идет от нуля, поэтому ваша запись:
Код:
  list[count].name:=2;
будет вызывать ошибку, ведь Count возвращает количество элементов, а это число всегда больше на единицу, чем индекс последнего элемента. Следовательно надо так:
Код:
  list[count-1].name:=2;

Надеюсь все подробно расписал.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.

Последний раз редактировалось Страдалецъ, 18.12.2009 в 19:08.
Ответить с цитированием
  #11  
Старый 18.12.2009, 23:25
Аватар для s0Creator
s0Creator s0Creator вне форума
Местный
 
Регистрация: 20.02.2008
Адрес: Московская область
Сообщения: 420
Репутация: 884
По умолчанию

Вы забыли создавать и уничтожать 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;
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 09:54.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter