![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
||||
|
||||
|
Здравствуйте дорогие форумчане, сейчас учусь совмещать делфи и 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. так же прикрепляю сам проект |
|
#2
|
||||
|
||||
|
Если посмотреть сверху, то у тебя куб образует квадрат, квадрат состоит из 4 отрезков (x1,z1)(x2,z1) .....
Ты двигаешься тоже вдоль какой-то линии от старых координат к новым В общем вся задача сводится к тому, чтобы проверить пересечение линии движения с линиями препятствия См. рис. ![]() |
|
#3
|
||||
|
||||
|
как сделать это логически я понимаю, а вот как представить это в коде-нет.
Я пришел к такому выводу пока, я описал квадрат проверками, т.е. если я нахожусь в шаге от того квадрата, то просто прекратить движение. т.е. я завел переменную типа boolean и если я в шаге от квадрата я присваиваю ей "ложь" что в переделанном коде значит, что я не могу двигаться... Мой вариант мне не очень подходит, так как в таком случае я не могу двигаться вообше, а мне надо что бы только в сторону куба |
|
#4
|
||||
|
||||
|
Стоит завести переменную не Boolean, а перечисляемого типа (Step = (sLeft, sRight, sTop, sDown)). И запрещать только одно направление.
|
|
#5
|
||||
|
||||
|
Лучше разбить куб на треугольники и искать точку пересечения отрезка (как на рисунке Pilot_Red) с этими треугольниками. В случае пересечения присваивать "игроку" координаты точки пересечения. Тогда "игрок" будет как-бы "скользить" вдоль стены (если направление не вдоль нормали к стене).
И обрабатывать передвижение лучше не сразу при нажатии клавиш, а завести отдельные переменные (типа bool movleft, movright, movforv, movback), при нажатии/отпускании соответствующей клавиши давать им true/false, а в процедуре отрисовки (или отдельном таймере) "перемещать" игрока соответственно их значению. |
|
#6
|
||||
|
||||
|
а как вот можно проверить столкновение вообще с чем-либо, без использования координат, т.е. сравнения координаты персонажа и координат обьектов?
|
|
#7
|
|||
|
|||
|
Используй физические движки.
|
|
#8
|
||||
|
||||
|
поподробнее и в коде пожалуйста
|
|
#9
|
|||
|
|||
|
Как бы физический движок это компонент который устанавливается допустим в делфи, или идет в комплекте с каким нибудь 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
|
|||
|
|||
|
на gamedev.ru должны быть разжеванные статьи про это, на крайний случай можно на английском найти
|
|
#11
|
||||
|
||||
|
Anklav
Не могли бы вы, встроить этот код что вы написали в мое приложение?? У меня не получается...=( |
|
#12
|
|||
|
|||
|
Как встроить? Чему вы научитесь, если за вас все будут делать?
P.S. http://dump.ru/file/5778289 Танчики написанные мной на чистом OpenGL без ботов, но с разрушаемыми препятствиями. P.S.S. Да и кстати, тонкий намек, проверка проходимость должна быть, как бы, до движения... а не после... Я бы посоветовал бы вам, начать не с 3д редакторов, а хотя бы 2д, что бы уловить суть, надо начинать с малого. А на счет того кода который должен работать, по мне так он работает, только вы как то странно его написали. Последний раз редактировалось Anklav, 24.06.2012 в 20:54. |
|
#13
|
||||
|
||||
|
Вот например, как я писал, проверка по треугольникам. Но добавлены 2 модуля, большинство ф-ций из них не используется, можешь юзать, разрешаю (сам "одолжил" с чужого проекта, немного доработав). Проверка не пересечения линии движения, а границ обьекта, так недежней. Надеюсь разберешся. Это только пример, начинать обучение с него нельзя.
|
|
#14
|
||||
|
||||
|
YVitaliy
Спасибо большое, но не могли бы вы обьяснять, куда надо что добавить, что бы заработало и с другими стенами, вот нарисовать я их нарисовал, а дальше что?=) Заранее еще раз спасибо |
|
#15
|
||||
|
||||
|
Из модуля 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); |