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

Delphi Sources



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

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 23.06.2012, 11:21
Аватар для DIGS
DIGS DIGS вне форума
Прохожий
 
Регистрация: 23.06.2012
Сообщения: 9
Версия Delphi: Borland Delphi7
Репутация: 10
По умолчанию Delphi+OpenGL помогите разобраться

Здравствуйте дорогие форумчане, сейчас учусь совмещать делфи и OpenGL хотя до сих пор я был знаком только с Delphi.
Я делаю учебную программу(учебную для себя) в которой вам нужно передвигаться стрелочками клавиатуры. Дело в том, что я не знаю, как сделать так, что бы появилась некая непроходимость стен.
Стену рисую обычным GL_QUADS.
вот сам код:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, OpenGL, ExtCtrls, Math;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  User=record
    Position:record
      x,y,z:Single;
    end;
    Rotation:record
      y,zx:Single;
    end;
  end;

var
  Form1: TForm1;
  DC:HDC;
  HRC:HGLRC;
  Human:User;

implementation

{$R *.dfm}

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
const
  SPEED=0.2;
  var tmpx,tmpy:real;
begin
  case key of
    27: Form1.Close;
    37: begin
          Human.Position.z:=Human.Position.z+
          sin(DegToRad(Human.Rotation.y))*SPEED;
          Human.Position.x:=Human.Position.x+
          cos(DegToRad(Human.Rotation.y))*SPEED;
        end;
    38: begin
          Human.Position.z:=Human.Position.z+
          cos(DegToRad(Human.Rotation.y))*SPEED;
          Human.Position.x:=Human.Position.x-
          sin(DegToRad(Human.Rotation.y))*SPEED;
        end;
    39: begin
          Human.Position.z:=Human.Position.z-
          sin(DegToRad(Human.Rotation.y))*SPEED;
          Human.Position.x:=Human.Position.x-
          cos(DegToRad(Human.Rotation.y))*SPEED;
        end;
    40: begin
          Human.Position.z:=Human.Position.z-
          cos(DegToRad(Human.Rotation.y))*SPEED;
          Human.Position.x:=Human.Position.x+
          sin(DegToRad(Human.Rotation.y))*SPEED;
        end;
  end;

//---Как по мне, так именно тут должна находиться проверка на столкновения... только почему то она //не работает..
    tmpx:=human.position.x;
    tmpy:=human.position.y;
  
  if (Human.position.z<1) //and (human.Position.x>1)
   and (Human.Position.x<1)
   then
  begin
   Human.Position.z:=Human.Position.z+1;
  Human.Position.x:=Human.Position.x+1;
  end;
//---
  end;

procedure SetDCPixelFormat;
var
  pfd:TPixelFormatDescriptor;
  nPixelFormat:Integer;
begin
  FillChar(pfd,SizeOf(pfd),0);
  pfd.dwFlags:=PFD_DRAW_TO_WINDOW or
               PFD_DOUBLEBUFFER or
               PFD_SUPPORT_OPENGL;
  nPixelFormat:=ChoosePixelFormat(DC,@pfd);
  SetPixelFormat(DC,nPixelFormat,@pfd);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i:Integer;
begin
  DC:=GetDC(Handle);
  SetDCPixelFormat;
  HRC:=wglCreateContext(DC);
  wglMakeCurrent(DC,HRC);
  Form1.WindowState:=wsMaximized;
  ShowCursor(False);
  glClearColor(0.0,0.0,0.0,1.0);
  glEnable(GL_DEPTH_TEST);
  glNewList(1,GL_COMPILE);
    glBegin(GL_LINES);
      glColor3f(0.7,1.0,0.7);
      for i:=-50 to 50 do
      begin
        glVertex3f(-50,-1,i);
        glVertex3f(50,-1,i);
        glVertex3f(i,-1,-50);
        glVertex3f(i,-1,50);
      end;
       glColor3f(1,0,0);
      for i:=-5 to 5 do
      begin
   glBegin(GL_QUADS);
    // back Face
    glColor3f(1,0,0); glVertex3f(-1, -1,  1);
    glColor3f(1,0,0); glVertex3f(0, -1,  1);
    glColor3f(1,0,0); glVertex3f(0,  1,  1);
    glColor3f(1,0,0); glVertex3f(-1,  1,  1);
    // front Face
    glColor3f(0,1,0); glVertex3f(-1, -1, -1);
    glColor3f(0,1,0); glVertex3f(-1,  1, -1);
    glColor3f(0,1,0); glVertex3f(0,  1, -1);
    glColor3f(0,1,0); glVertex3f(0, -1, -1);
    // Top Face
    glColor3f(0,0,1); glVertex3f(-1, 1, -0.5);
    glColor3f(0,0,1); glVertex3f(-1,  1,  0.5);
    glColor3f(0,0,1); glVertex3f(0,  1,  0.5);
    glColor3f(0,0,1); glVertex3f(0,  1, -0.5);
    // Bottom Face
    glColor3f(0,1,1); glVertex3f(-1, -1, -0.5);
    glColor3f(0,1,1); glVertex3f(0, -1, -0.5);
    glColor3f(0,1,1); glVertex3f(0, -1,  0.5);
    glColor3f(0,1,1); glVertex3f(-1, -1,  0.5);     
    // Right face
    glColor3f(1,1,1); glVertex3f(0, -1, -1);
    glColor3f(1,1,1); glVertex3f(0,  1, -1);
    glColor3f(1,1,1); glVertex3f(0,  1,  1);
    glColor3f(1,1,1); glVertex3f(0, -1,  1);
    // Left Face
    glColor3f(1,0,1); glVertex3f(-1, -1, -1);
    glColor3f(1,0,1); glVertex3f(-1, -1,  1);
    glColor3f(1,0,1); glVertex3f(-1,  1,  1);
    glColor3f(1,0,1); glVertex3f(-1,  1, -1);
  glEnd();
      end;
    glEnd;
  glEndList;
  with Human do
  begin
    with Position do
    begin
      x:=5;
      y:=0;
      z:=0;
    end;
    with Rotation do
    begin
      y:=0;
      zx:=0;
    end;
  end;
  SetCursorPos(Round(Form1.ClientWidth/2),
               Round(Form1.ClientHeight/2));

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  wglMakeCurrent(0,0);
  wglDeleteContext(HRC);
  ReleaseDC(Handle,DC);
  DeleteDC(DC);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  SetCursorPos(Round(Form1.ClientWidth/2),
               Round(Form1.ClientHeight/2));
  InvalidateRect(Handle,nil,false);
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  glViewport(0, 0, ClientWidth, ClientHeight);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  gluPerspective(30.0, ClientWidth / ClientHeight, 0.1, 1000.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
end;

procedure TForm1.FormPaint(Sender: TObject);
var
  ps:TPaintStruct;
begin
  BeginPaint(Handle,ps);
  glClear(GL_COLOR_BUFFER_BIT or
          GL_DEPTH_BUFFER_BIT);

  glLoadIdentity;
  glRotatef(Human.Rotation.zx,Abs(cos(DegToRad(Human.Rotation.y))),0,0);
  glRotatef(Human.Rotation.y,0,1,0);
  glTranslatef(Human.Position.x,
               Human.Position.y,
               Human.Position.z);

  glCallList(1);

  EndPaint(Handle,ps);
  SwapBuffers(DC);
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
  Divider=10;
begin
  Human.Rotation.y:=Human.Rotation.y+
      Round((Mouse.CursorPos.X-Round(Form1.ClientWidth/2))/Divider);
  if Human.Rotation.y>=360 then Human.Rotation.y:=0;
  if Human.Rotation.y<0 then Human.Rotation.y:=360;

  Human.Rotation.zx:=Human.Rotation.zx+
      Round((Mouse.CursorPos.Y-Round(Form1.ClientHeight/2))/Divider);
  if Human.Rotation.zx>90 then Human.Rotation.zx:=90;
  if Human.Rotation.zx<-90 then Human.Rotation.zx:=-90;
end;

end.

Возможно я делаю даже не правильными методами, помогите, пожалуйста, разобраться.
p.s. так же прикрепляю сам проект
Вложения
Тип файла: rar Engine_3D.rar (167.9 Кбайт, 12 просмотров)
Ответить с цитированием
  #2  
Старый 23.06.2012, 17:41
Аватар для Pilot_Red
Pilot_Red Pilot_Red вне форума
Продвинутый
 
Регистрация: 01.11.2006
Адрес: Карелия
Сообщения: 702
Версия Delphi: D7
Репутация: 11581
По умолчанию

Если посмотреть сверху, то у тебя куб образует квадрат, квадрат состоит из 4 отрезков (x1,z1)(x2,z1) .....
Ты двигаешься тоже вдоль какой-то линии от старых координат к новым
В общем вся задача сводится к тому, чтобы проверить пересечение линии движения с линиями препятствия

См. рис.
Ответить с цитированием
  #3  
Старый 23.06.2012, 18:59
Аватар для DIGS
DIGS DIGS вне форума
Прохожий
 
Регистрация: 23.06.2012
Сообщения: 9
Версия Delphi: Borland Delphi7
Репутация: 10
По умолчанию

как сделать это логически я понимаю, а вот как представить это в коде-нет.
Я пришел к такому выводу пока, я описал квадрат проверками, т.е. если я нахожусь в шаге от того квадрата, то просто прекратить движение. т.е. я завел переменную типа boolean и если я в шаге от квадрата я присваиваю ей "ложь" что в переделанном коде значит, что я не могу двигаться...
Мой вариант мне не очень подходит, так как в таком случае я не могу двигаться вообше, а мне надо что бы только в сторону куба
Ответить с цитированием
  #4  
Старый 23.06.2012, 21:45
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

Стоит завести переменную не Boolean, а перечисляемого типа (Step = (sLeft, sRight, sTop, sDown)). И запрещать только одно направление.
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.
Ответить с цитированием
  #5  
Старый 23.06.2012, 22:57
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Лучше разбить куб на треугольники и искать точку пересечения отрезка (как на рисунке Pilot_Red) с этими треугольниками. В случае пересечения присваивать "игроку" координаты точки пересечения. Тогда "игрок" будет как-бы "скользить" вдоль стены (если направление не вдоль нормали к стене).
И обрабатывать передвижение лучше не сразу при нажатии клавиш, а завести отдельные переменные (типа bool movleft, movright, movforv, movback), при нажатии/отпускании соответствующей клавиши давать им true/false, а в процедуре отрисовки (или отдельном таймере) "перемещать" игрока соответственно их значению.
Ответить с цитированием
  #6  
Старый 23.06.2012, 23:28
Аватар для DIGS
DIGS DIGS вне форума
Прохожий
 
Регистрация: 23.06.2012
Сообщения: 9
Версия Delphi: Borland Delphi7
Репутация: 10
По умолчанию

а как вот можно проверить столкновение вообще с чем-либо, без использования координат, т.е. сравнения координаты персонажа и координат обьектов?
Ответить с цитированием
  #7  
Старый 24.06.2012, 13:25
Anklav Anklav вне форума
Прохожий
 
Регистрация: 10.06.2011
Адрес: Харьков
Сообщения: 22
Версия Delphi: 7
Репутация: 10
По умолчанию

Используй физические движки.
Ответить с цитированием
  #8  
Старый 24.06.2012, 13:36
Аватар для DIGS
DIGS DIGS вне форума
Прохожий
 
Регистрация: 23.06.2012
Сообщения: 9
Версия Delphi: Borland Delphi7
Репутация: 10
По умолчанию

поподробнее и в коде пожалуйста
Ответить с цитированием
  #9  
Старый 24.06.2012, 14:48
Anklav Anklav вне форума
Прохожий
 
Регистрация: 10.06.2011
Адрес: Харьков
Сообщения: 22
Версия Delphi: 7
Репутация: 10
По умолчанию

Как бы физический движок это компонент который устанавливается допустим в делфи, или идет в комплекте с каким нибудь 3д движком..

Лично сам делал без сторонних физических движков.
Алгоритм следующий, создается массив из элеметов (целочисленных переменных допустим) допустим 15х15, то есть в 224 элемента. Это будет карта, суть следующая: при значении 0 мы данный квадрат проезжаем, при 1 - нет.

Для начала нужно разделить этот массив в плоскость. Делаем это следующими функциями

Код:
...
var
map:array [0..224] of integer; //наша карта
NtoX,NtoY:integer;

...

//Тут все понятно, вводишь x и y и тебе выдают номер квадрата
//15 - это число квадратов на карте
Function TForm1.XYToN(x,y:integer):integer;
var
N:integer;
begin
N:=(x+y*15);
Result:=N;
end;

//для этой функции понадобится 2 глобальные переменные
//так как вывести нам нужно 2 значения
//15 - это число квадратов на карте
//Здесь эти перменные: "NtoX" - это собственно Х и "NtoY" - это Y.
Procedure TForm1.NToXY(N:integer);
var
NtoXDemo:Extended;
begin
NtoY:=Trunc(N/15);
NtoXDemo:=Frac(N/15)*15;
NtoX:=Round(NtoXDemo);
end;

//Допустим тебе известны координаты квадрата (это будут переменные 
// X,Y) и тебе нужно изменить значение матрицы 


procedure TForm1.Button1Click(Sender: TObject);
begin
map[XYtoN(X,Y)]:=0;
end;

//Или тебе известен номер квадрата 
//и тебе нужно узнать где он находится
//NomerK это будет известный тебе номер квадрата 
//X и Y искомые кординаты

procedure TForm1.Button2Click(Sender: TObject);
begin
NtoXY(NomerK);
X:=NtoX;
Y:=NtoY;
end;

Но это мы просто работаем с массивом, для связи координат того же OpenGL и нашей карты нужны следующие функции:

Код:
//Данная функция переводит X или Y OpenGL в X или Y карты (map)
//у нас 1 квадрат имеет длину и ширину в 0.25 

Function TForm1.PixToK(K:Extended):integer;
var
i:integer;
MasPix:array [0..14] of Extended; //Длинна или ширина карты
begin
MasPix[0]:=0;
For i:=1 to 14 do
  begin
    MasPix[i]:=MasPix[i-1]+0.25;//0.25 это длинна квадрата в OpenGL
  end;

For i:=0 to 14 do
  begin
    If (MasPix[i]<=K) and (MasPix[i]+0.25>K) then Result:=i;
  end;
end;

//Данная функция переводит X или Y (map) в X или Y OpenGL
//у нас 1 квадрат имеет длину и ширину в 0.25 
Function TForm1.KToPix(p:integer):Extended;
var
i:integer;
NPix:Extended;
begin
NPix:=0;
For i:=0 to p-1 do NPix:=NPix+0.25;
Result:=NPix;
end;

//Примеры X Y - координаты(в OpenGL) нашего героя 
//0.01 шаг его ходьбы
//Angle - угол движения героя
procedure TForm1.Button1Click(Sender: TObject);
begin
//если с следующем шаге 
//мы поападаем в квадрат с значением 0, то идем дальше
If Map[XYToN(PixToK(X+0.01*cos(Angle)),PixToK(Y+0.01*sin(Angle)))] = 0 then 
      begin
        X:=X+0.01*cos(angle);
        Y:=Y+0.01*sin(angle);
      end;
end;

P.S. Видел эту программу в исходниках на сайте..
P.S.S. И по моему для рисования каждой грани объекта нужно заново объявлять glBegin(GL_QUADS); .. glEnd; там достаточно 1 раз указать цвет.
Т.к. скорее всего будут проблемы с нормалями, а они нужны для правильного освещения.

Последний раз редактировалось Anklav, 24.06.2012 в 16:38.
Ответить с цитированием
  #10  
Старый 24.06.2012, 16:34
Pyro Pyro вне форума
Так проходящий
 
Регистрация: 18.07.2011
Сообщения: 805
Версия Delphi: 7Lite
Репутация: 6063
По умолчанию

на gamedev.ru должны быть разжеванные статьи про это, на крайний случай можно на английском найти
Ответить с цитированием
  #11  
Старый 24.06.2012, 17:52
Аватар для DIGS
DIGS DIGS вне форума
Прохожий
 
Регистрация: 23.06.2012
Сообщения: 9
Версия Delphi: Borland Delphi7
Репутация: 10
По умолчанию

Anklav
Не могли бы вы, встроить этот код что вы написали в мое приложение??
У меня не получается...=(
Ответить с цитированием
  #12  
Старый 24.06.2012, 20:42
Anklav Anklav вне форума
Прохожий
 
Регистрация: 10.06.2011
Адрес: Харьков
Сообщения: 22
Версия Delphi: 7
Репутация: 10
По умолчанию

Как встроить? Чему вы научитесь, если за вас все будут делать?

P.S. http://dump.ru/file/5778289
Танчики написанные мной на чистом OpenGL без ботов, но с разрушаемыми препятствиями.

P.S.S. Да и кстати, тонкий намек, проверка проходимость должна быть, как бы, до движения... а не после... Я бы посоветовал бы вам, начать не с 3д редакторов, а хотя бы 2д, что бы уловить суть, надо начинать с малого. А на счет того кода который должен работать, по мне так он работает, только вы как то странно его написали.

Последний раз редактировалось Anklav, 24.06.2012 в 20:54.
Ответить с цитированием
  #13  
Старый 24.06.2012, 22:42
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Вот например, как я писал, проверка по треугольникам. Но добавлены 2 модуля, большинство ф-ций из них не используется, можешь юзать, разрешаю (сам "одолжил" с чужого проекта, немного доработав). Проверка не пересечения линии движения, а границ обьекта, так недежней. Надеюсь разберешся. Это только пример, начинать обучение с него нельзя.
Вложения
Тип файла: rar Engine_3D.rar (215.7 Кбайт, 18 просмотров)
Ответить с цитированием
  #14  
Старый 24.06.2012, 22:51
Аватар для DIGS
DIGS DIGS вне форума
Прохожий
 
Регистрация: 23.06.2012
Сообщения: 9
Версия Delphi: Borland Delphi7
Репутация: 10
По умолчанию

YVitaliy
Спасибо большое, но не могли бы вы обьяснять, куда надо что добавить, что бы заработало и с другими стенами, вот нарисовать я их нарисовал, а дальше что?=)
Заранее еще раз спасибо
Ответить с цитированием
  #15  
Старый 24.06.2012, 22:59
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Из модуля l_math.pas я использую класс TVector - точка с координатами X, Y, Z. Соответственно стену я рисую по 4м точкам - векторам v1, v2, v3..., которые задаю при создании формы
Код:
v1:=vector(-2,-1,-2);
          v2:=vector(-2,2,-2);
..........
Код:
 GLCOLOR3(ColorRGBV(clRed));
         GLQuad(v1, v2, v3, v4);
Вот добавляй такие векторы, задавай их координаты и рисуй. Конечно, лучше не "вручную" рисовать, а загружать соответствующую модель из файла. Поетому советую, например, книгу Краснов OpenGl с примерами, сам с нее начинал, там есть простые примеры, и вообще все азы.
Ответить с цитированием
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

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

ВКонтакте   Facebook   Twitter