128
Tags:
delphi
Skrevet af
Bruger #1474
@ 24.11.2003
Nu kan vi bevæge os væk fra væggen igen, hvis vi er kollideret mod den. Det kunne være sjovt, hvis vi også lavede en kollision detektor med vores kasse, men samtidig gjorde det muligt for os at hoppe op på den, og skubbe rundt med den. Til det vil vi bruge en lidt anden teknik. Hvis vi beregner afstanden fra kassens centrum og vores position kan vi faktisk afgøre om vi er kollideret mod den. Jeg har lavet en illustration set fra oven.
Som du kan se vil selve kollisionen foregå i en cirkel rundt omkring kassen, i stedet for selve kassen, men dette vil ikke kunne bemærkes når vi kollidere. På denne måde vil vi nemlig også let kunne finde ud af om vi rammer kassen, hvis vi vil hoppe op på den. Ud over det, deler vi vores hop i følgende stadier: JumpStart, JumpUp og JumpDown. Illustrationen nedenunder illustrere dtte:
Ideen er at JumpStart skal indeholde Y position når vi påbegynder vores hop. JumpUp er fortæller at vi er på vej op i vores hop. JumpDown fortæller om vi er på vej ned fra vores fra hop. Hvis vi er på vej ned og vores position er er højere end kassens højde, og vi samtidig vil kollidere mod kassen betyder det, at vi rammer kassen, ellers rammer vi gulvet. Da vores kasse skal være i stand til at blive flyttet tilføjer vi en global variant: KassePosition, som en TVector og implementere KassePosition i kassens matrix i FormPaint proceduren. KassePositionen vil samtidig være kasses centrum!
procedure TForm1.FormPaint(Sender: TObject);
begin
glClearColor(0,0,0,0);
glClear(gl_Color_Buffer_Bit or gl_Depth_Buffer_Bit);
glEnable(gl_Depth_Test);
glEnable(gl_Normalize);
glEnable(gl_Color_Material);
glPushMatrix;
with Rotation do
begin
glRotatef(X,1,0,0);
glRotatef(Y,0,1,0);
glRotatef(Z,0,0,1);
end;
with Translation do
glTranslatef(X,Y-5,Z);
glLightfv(gl_Light0, gl_Ambient, @LysAmbient);
glLightfv(gl_Light0, gl_Diffuse, @LysDiffuse);
glLightfv(gl_Light0, gl_Specular, @LysSpecular);
glLightfv(gl_Light0, gl_Position, @LysPosition);
glEnable(gl_Light0);
glDisable(gl_Lighting);
glDisable(gl_Texture_2D);
glPointSize(4);
glBegin(gl_Points);
glVertex3fv(@LysPosition);
glEnd;
glEnable(gl_Lighting);
glEnable(gl_Texture_2D);
//Aktivere mit gulv texture
glBindTexture(gl_Texture_2D, Gulv_ID);
//Tegner mit gulv
glBegin(gl_Quads);
//Normal for gulvet (Peger lodret op!)
glNormal3f(0, 1, 0);
glTexCoord2f(0,4);
glVertex3f(-50, -3, -50);
glTexCoord2f(0,0);
glVertex3f(-50, -3, +50);
glTexCoord2f(4,0);
glVertex3f(+50, -3, +50);
glTexCoord2f(4,4);
glVertex3f(+50, -3, -50);
glEnd;
//Aktivere mit væg texture
glBindTexture(gl_Texture_2D, Vaeg_ID);
//Tegner min væg
glBegin(gl_Quads);
glNormal3f(0,0,1);
glTexCoord2f(0,1);
glVertex3f(-50, -3, -50);
glTexCoord2f(0,0);
glVertex3f(-50, +22, -50);
glTexCoord2f(4,0);
glVertex3f(+50, +22, -50);
glTexCoord2f(4,1);
glVertex3f(+50, -3, -50);
glEnd;
//Aktivere kassens texture med Loft_ID
glBindTexture(gl_Texture_2D, Loft_ID);
//Begynder på kassens matrix
glPushMatrix;
//Flytter kassen!
with KassePosition do
glTranslatef(X, Y, Z);
//Definere vores kasse
glBegin(gl_Quads);
// 1) normal. (Peger mod dig!)
glNormal3f( 0, 0, 1);
//Koordinater for første side (Forside)
glTexCoord2f(0, 0); glVertex3f(-3, -3, 3);
glTexCoord2f(1, 0); glVertex3f( 3, -3, 3);
glTexCoord2f(1, 1); glVertex3f( 3, 3, 3);
glTexCoord2f(0, 1); glVertex3f(-3, 3, 3);
// 3) normal (Peger væk fra dig!)
glNormal3f( 0, 0,-1);
//Koordinater for anden side (Bagsiden)
glTexCoord2f(1, 0); glVertex3f(-3, -3, -3);
glTexCoord2f(1, 1); glVertex3f(-3, 3, -3);
glTexCoord2f(0, 1); glVertex3f( 3, 3, -3);
glTexCoord2f(0, 0); glVertex3f( 3, -3, -3);
// 3) normal
glNormal3f( 0, 1, 0);
//Koordinater for tredje siden (Toppen)
glTexCoord2f(0, 1); glVertex3f(-3, 3, -3);
glTexCoord2f(0, 0); glVertex3f(-3, 3, 3);
glTexCoord2f(1, 0); glVertex3f( 3, 3, 3);
glTexCoord2f(1, 1); glVertex3f( 3, 3, -3);
// 4) normal
glNormal3f( 0,-1, 0);
//Koordinater for fjerde side (Bunden)
glTexCoord2f(1, 1); glVertex3f(-3, -3, -3);
glTexCoord2f(0, 1); glVertex3f( 3, -3, -3);
glTexCoord2f(0, 0); glVertex3f( 3, -3, 3);
glTexCoord2f(1, 0); glVertex3f(-3, -3, 3);
// 5) normal
glNormal3f( 1, 0, 0);
//Koordinater for femte side (Højre)
glTexCoord2f(1, 0); glVertex3f( 3, -3, -3);
glTexCoord2f(1, 1); glVertex3f( 3, 3, -3);
glTexCoord2f(0, 1); glVertex3f( 3, 3, 3);
glTexCoord2f(0, 0); glVertex3f( 3, -3, 3);
// 6) normal
glNormal3f(-1, 0, 0);
//Koordinater for sjette side (Venstre)
glTexCoord2f(0, 0); glVertex3f(-3, -3, -3);
glTexCoord2f(1, 0); glVertex3f(-3, -3, 3);
glTexCoord2f(1, 1); glVertex3f(-3, 3, 3);
glTexCoord2f(0, 1); glVertex3f(-3, 3, -3);
glEnd;
//Afslutter kassens matrix
glPopMatrix;
glPopMatrix;
SwapBuffers(Context.DeviceContext);
end;
Koden til kollision detektoren for kassen i Idle proceduren, vil blive ret lang. Jeg har derfor valgt at kommentere den undervejs.
var
FPS, I : Integer;
JumpUp, JumpDown, KasseKollision, MoveForward, MoveBackward : Boolean;
JumpHeight : Single = -5;
JumpStart : Single;
Gravity : Single = 0.2;
Speed : Single = 0.4;
procedure TForm1.Idle(Sender : TObject; var Done : Boolean);
var
P : TPoint;
S, X, Z : Single;
begin
Done := False;
//----------------------------------------------------------------------------
// Dreje Camera rundt med musen
//----------------------------------------------------------------------------
//Modtage cursorens position
GetCursorPos(P);
//Beregener
P.X := (Left+(Width div 2))-P.X;
P.Y := (Top+(Height div 2))-P.Y;
//Rotere
Rotation.Y := Rotation.Y-(P.X*0.1);
Rotation.X := Rotation.X-(P.Y*0.1);
//Saetter vores cursor til vores forms centrum
SetCursorPos(Left+(Width div 2),Top+(Height div 2));
//----------------------------------------------------------------------------
// Kollision
//----------------------------------------------------------------------------
//Simulere et skridt fremad
if MoveForward then
begin
X := Translation.X-(Sin(DegToRad(Rotation.Y))*Speed);
Z := Translation.Z+(Cos(DegToRad(Rotation.Y))*Speed);
end
else
//Simulere et skridt tilbage
if MoveBackward then
begin
X := Translation.X+(Sin(DegToRad(Rotation.Y))*Speed);
Z := Translation.Z-(Cos(DegToRad(Rotation.Y))*Speed);
end
else
//Står stille
begin
X := Translation.X;
Z := Translation.Z;
end;
//Udregner afstanden mellem vores position og kassens centrum
S := Sqrt(Power((-X)-KassePosition.X,2)+Power((-Z)-KassePosition.Z,2));
//Hvis afstanden mellem vores position og kassens centrum er mindre end 4 uints,
//betyder det at vi skal foretag en kollision detektion mod kassen!
if S < 4 then
KasseKollision := True
else
KasseKollision := False;
//Hopper op i luften
if JumpUp then
begin
//Hvis vi er under den højeste mulige position som vores hop tillader os,
//bliver vi trukket op ad
if JumpHeight+JumpStart < Translation.Y then
Translation.Y := Translation.Y-Gravity
else
//Vi er så højt oppe i luften som vores hop har tilladt os,
//forbereder os derfor til at falde ned ad igen
begin
//Præcisere vores position
Translation.Y := JumpHeight+JumpStart;
//Notere at vi er faerdig med at hoppe op ad
JumpUp := False;
//Notere at vi er klar til at falde ned igen
JumpDown := True;
end;
end
else
begin
//Hvis vi er i berøring af kassen
if KasseKollision then
begin
//Hvis vi befinder os over kassen
if Translation.Y <= -4.75 then
begin
//Hvis vi befinder os over kassens højde,
//bliver vi trukket ned ad
if Translation.Y < -5 then
Translation.Y := Translation.Y+Gravity
else
begin
//præcisere vores position
Translation.Y := -5;
//Notere at vi er landet og er klar til at hoppe igen
JumpDown := False;
end;
end
//Hvis vi befinder os ved siden af kassen
else
//Hvis vi befinder os over gulvet,
//bliver vi trukket ned ad
if Translation.Y < 0 then
Translation.Y := Translation.Y+Gravity
else
begin
//praecisere vores position
Translation.Y := 0;
//Notere at vi er landet og er klar til at hoppe igen
JumpDown := False;
end;
end
//Ingen berørelse af kassen
else
//Hvis vi befinder os over gulvet,
//bliver vi trukket ned ad
if Translation.Y < JumpStart then
Translation.Y := Translation.Y+Gravity
else
begin
//præcisere vores position
Translation.Y := 0;
//Notere at vi er landet og er klar til at hoppe igen
JumpDown := False;
end;
end;
//Væg kollision
if Kollision(-50,-48,+50,-48,-X,-Z) then
//Kasse Kollision
if KasseKollision then
begin
//Hvis vi står på kassen skal vi bevæge os som gik vi rundt på gulvet
if Translation.Y = JumpHeight then
begin
Translation.X := X;
Translation.Z := Z;
end
else
//Hvis ikke vi hopper kan vi skubbe kassen langs gulvet
if not JumpUp and not JumpDown then
begin
//Vi skubber kassen fremad (Står med front mod kassen)
if MoveForward then
begin
//Flytter os selv
Translation.X := Translation.X-(Sin(DegToRad(Rotation.Y))*(Speed * 0.1));
Translation.Z := Translation.Z+(Cos(DegToRad(Rotation.Y))*(Speed * 0.1));
//Flytter kassen
KassePosition.X := KassePosition.X+(Sin(DegToRad(Rotation.Y))*(Speed * 0.1));
KassePosition.Z := KassePosition.Z-(Cos(DegToRad(Rotation.Y))*(Speed * 0.1));
end;
//Vi skubber kassen, mens vi går tilbage (Står med ryggen til kassen)
if MoveBackWard then
begin
//Flytter os selv
Translation.X := Translation.X+(Sin(DegToRad(Rotation.Y))*(Speed * 0.1));
Translation.Z := Translation.Z-(Cos(DegToRad(Rotation.Y))*(Speed * 0.1));
//Flytter kassen
KassePosition.X := KassePosition.X-(Sin(DegToRad(Rotation.Y))*(Speed * 0.1));
KassePosition.Z := KassePosition.Z+(Cos(DegToRad(Rotation.Y))*(Speed * 0.1));
end;
end;
end
else
//Ingen kollision
begin
//Ingen kollision mod kassen, betyder at vi vil kunne flytte os rundt normalt
Translation.X := X;
Translation.Z := Z;
end;
FormPaint(nil);
Caption := IntToStr(FPS);
Inc(I);
end;
Som du kan se, har jeg yderligere defineret to varianter: Speed (Fart) og Gravity (Tyngdekraft), som Single. Så er det lettere for dig at tilpasse koden, hvis du hellere vil havde en anden resultat af effekten. Til sidst skal vi huske at give JumpStart en værdi inden vi starter med at hoppe. Det vil derfor blive i vores FormKeyDown procedure.
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
case Key of
vk_Space: if not JumpUp and not JumpDown then
begin
JumpStart := Translation.Y;
JumpUp := True;
end;
vk_Escape: Close;
end; //Case
end;
Kassen er skubbet hen i nærheden af lyskilden
Står oven på kassen og kigger ned
Prøv nu at skubbe kassen i nærheden af lyskilden. Du skulle gerne se, at shadingen på kassens sider ændres i takt med at afstand til lyset ændres. Du kan yderligere hoppe op på kassen og hoppe ned på gulvet igen.
Det var alt for denne fem-og-tyve-øre. Jeg håber I kunne lide min artikel. Nu skulle I faktisk være i stand til at kunne lave jeres helt eget spil. Der er dog stadig mange ting der mangler at blive fortalt, men det kan være at der dukker en ny artikel op engang i fremtiden! Jeg vil tilbage til mine studier og forberede mig til mine eksamener - for hvem ved, måske en eller anden dag BLIVER jeg rent faktisk færdig med min uddannelse som "Computer Games Designer", og måske tager jeg hjem til danmark igen og bruger verdens bedste sprog - DANSK
) Mine sidste ord vil blive.
Held og Lykke
Søren Klit Lambæk
University of Teesside, Middlesbrough, UK
PS: Endnu engang vil jeg lige nævne at der findes yderlige tutorials på mit site:
http://www.opengl-delphi.dk
Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.
Del også gerne artiklen med dine Facebook venner:
Kommentarer (33)
Denne artikel er (ligesom 1'eren) genialt skrevet! Let forståelig, men stadig med en masse information. Et fem tal fra mig.
Det er bare så dejligt at læse.... Igen en Top-artikel fra dig og den fortjener intet andet end 5...
Super flot arktikel
Jeg spekulerer på hvor lang tid han har gået og gemt disse genistreger oppe i ærmet. Det er jo guldkorn det her
Flot artikel. Der var nogle småfejl, så som en constant der var stavet forkert, og man skulle lige nærlæse artiklen for at få defineret KassePosition, men bortset fra det så virker det fint. Så vil vi gerne have et kursus i at tilføje bevægelige elementer, så som modstandere ...
I øvrigt et 5 tal fra mig.
kan ikke lave en exe(eller hvad det nu er) så man kan prøve det
Super artikel... Så skal der laves 3Dspil ;D
Kommer der måske en 3ér ??
Nice artikel (er)
Ikke lige i forløbet, jeg skal havde mine eksamner overstået først
!
Nice artitel men jeg kan stadig ikke bestemme mig for om jeg skal begynde at lave spil i c++ eller delphi hvad syntes du er bedst???
Hvis det bare er for at laere OpenGL og lave dine egne 3D OpenGL applikationer kan det gor fuldstaendig ligemeget om du vaelger Delphi eller C++. Men satser du paa engang at blive professionel Spil Programmoer paa et kommersielt udvikler Studie er det nok C++ du skal kigge paa. Jeg valgte Delphi fordi jeg er vild med dens syntaxer og den maade Delphi er konstrureret paa. Men selve OpenGL kaldende er de samme uanset hvilket sprog du benytter!
Hej jeg ved godt du programmere i delphi men du ved til feldigvis ikke hvor jeg kan finde en compiler som kan compile opengl i c++ jeg bruger dev-c++ men den kommer hele tiden med errors når jeg compillere.
øhhh jooo næsten alle C++ kompilere kan kompile OpenGL i et Windows miljø. Eksempelvis Borland's C++ Builder, Micrsoft's Visual C++ og Intels C++ kompiler... Nu ved jeg selvfølgelig ikke hvilket kode du anvender siden din kompiler viser fejlmeddelser!
5 Her fra!!!
Men dog, kommer der en pop-up før jeg starter programmet der siger NVIDIA Corparation???
he he... ja, det er vist rigtigt! Det er følgende kode:
ShowMessage(glGetString(gl_Vendor));
Der er grunden til det! Det kan du bare slette! Det fortæller bare hvilket firma der har produceret dit grafikkort! Der er også gl_Renderer, den fortæller, hvad dit grafikkort hedder!
Mange tak for din rating!
er der en der en der kan hjælpe mig jeg kan ik komme vider med artikel 1 der hvor man skal lave et nyt opject hvordan gør jeg det
Lars>> Send mig en udvikler mail, omkring dit problem saa vil jeg proeve at svare hurtigst muligt!
Fantastisk...
5 fra mig
Genial artikel...
Jeg gav ofcourse 5
fed artikel 5 her fra...
men min siger "stream read error" en der kan fortælle mig hvad jeg gør galt ??
Genial artikel!
Jeg har lige 2 spørgsmål:
1) Hvordan man kan gøre dele af bitmap'erne gennemsigtige? - er der en TransparentColor eller noget lignende?
2) Ville det trække FPS væsentligt ned, hvis man tilføjede 1000 grafikelementer som også skal tegnes i TForm1.FormPaint, men som alligevel ikke kan ses på skærmen, fordi man fx "står med ryggen til" eller "noget andet står foran"?
(finder OpenGL selv ud af hvad der skal tegnes?)
1) Du kan gøre en bitmap transparent på flere forskellige måder! Enten per vertex, eller per texture (AlphaMap) eller per pixel (Pixel Shading)! Til alle funktioner skal glEnable(gl_Blend) tilføjes i starten af dit kode! Derefter skal du yderligere definere hvilken slags blend du vil foretage dig med funktionen glBlendFunc()
Det kunne eksempelvis være dette:
glBlendFunc(gl_Src_Alpha,gl_One_Minus_Src_Alpha);
Kig i din openGL.Pas fil for andre blend specifikationer!
Per Vertex!
Ved hver coordinat af dit geometry (trekant, firkant, polygon osv.) kan du indsætte en glColor4f(). Den sidste parameter er en Alpha channel og når den er 0 er dit geometry helt gennemsigtigt omkring den vertex. (Lidt ligesom da vi farvede hver enkelt vertex i den første artikel).
Per Texture (Alpha Map)
Du kan også indlæse en texture (på normal vis) og benytte den som en alpha map. Bitmappen du benytter som alpha map skal helst bestå af grå-skalaer (sort/hvid). Det der er mørkest vil blive mest transparent! Vær venligst opmærksom på at bitmappen må IKKE bestå af IndexColors (Selv om det ville være fristende at bruge, det SKAL være RGB colors). Husk også at rette din glBlendFunc() funktion til, så det passer dig bedst!
Per Pixel (PixelShading)
Dette er for de meget avancerede OpenGL programmøre og tager RIGTIGT RIGTIGT langt tid at forklare! Men du kan selv læse om det på enten www.nvidia.com eller www.ati.com
2) Jo flere polygoner du vil have tegnet jo længere tid vil det tage for dit grafik-kort. Hverken OpenGL eller DirectX tjekker, hvilke polygoner der kan ses på skærmen. Der bliver bare tegnet! For at optimere din applikation kan du kigge lidt "Frustum Culling"! Den metode er lavet til lige præcist det du snakker om! Derfor vil jeg anbefale dig at søge efter artikler på nettet der omhandler "Frustum Culling". Der findes allerede et par klasser skrevet i Delphi rundt om på nettet - frit tilgængeligt for alle!
Held og Lykke
Søren Klit Lambæk
NB: Tak for rosen fra jer alle!
MANGE tak!!!
Hej alle sammen, jeg er lige blevet færdig med denne fantaktiske artikel, men jeg har lidt problemer da når jeg starter, så starter jeg "i" kassen og når jeg bevæger mig rundt så sidder kassen fast på mig, meget fint hvis jeg skulle have en kjole, men lidt noget skidt når jeg skal skubbe med den
Nogen der kan forklarer hvorfor den gør det....
God Jul (skulle lige sige det)
Du har sikkert overset et eller andet i koden!
Det lyder som om at det er nogle matrix definationer der gaar galt for dig, samtidig med at du muligvis ikke flytter din kasse overhovedet!
Send mig en udvikler post med dit kode og jeg vil se paa sagen!
Med venlig hilsen
Søren Klit Lambæk
(God jul til dig - og tak for rosen)!
Så er den sendt til mailen...
(for en uges tid siden)
Hmmm jeg har ikke modtaget nogen mails endnu! Prøv lige at send den igen!
Tak
Sendt til info@opengl-delphi.dk
Hej allesammen, jeg har lige fået lidt hjælp af den flinke Søren og ville lige sige at hvis I vil have det sådan at kassen er flyttet lidt fra centrum (så I ikke starter inde i kassen) skal I skrive følgende ved variablen KassePosition:
var
KassePosition : TVektor = (X: -10; Y: 0; Z: -10);
Endnu et guldkorn fra Søren....
Hvis I ønsker Quake effekten med at man maks kan se 90 grader op og 90 grader ned skal I indsætte følgende kode under glPushMatrix;
if Rotation.X > 90 then Rotation.X := 90;
if Rotation.X < -90 then Rotation.X := -90;
Hov glemte at sige at den skulle indsættes i FormPaint proceduren
Da jeg var færdig me artiklen følte jeg kunne lave Hitman 2 uden problemer!
MEGET flot skrevet. 5 herfra!!
Super lavet..
5 du ;P
men tænkte lige.. Hvad er "FormPaint proceduren " og hvor skal koden sættes ind henne ?
Hej Dennis,
FormPaint proceduren kan du finde ved hjælp af Delphi's "Object Inspector". Vælg flaget "Events" og dobbeltklik på "OnPaint". Det vil genere en FormPaint procedure for dig. Hvis du er meget ny i Delphi eller programmering generalt er denne artikel nok en lidt for stor en mundfuld for dig!
Held og Lykke
Søren Klit Lambæk
Du skal være
logget ind for at skrive en kommentar.