Kollision Maus/Terrain berechnen [gelöst]

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Kollision Maus/Terrain berechnen [gelöst]

Beitrag von Scarabol »

Hallo Leute,

[Edit]
Alter Titel:
Die hohe Kunst der Mathematik
[/Edit]

Bild
click


wie ihr sehen könnte bastel ich gerade an einem 3D Projekt.
Nun will ich die Spielfigur auch bewegen können was mit der Tastatur schon ganz gut klappt, aber ich möchte natürlich auch mit der Maus die Spielfigur bewegen können. Darum muss ich die Koordinaten von dem Punkt auf den geklickt wurde natürlich ausrechen, aber wie geht das? Ich weiß als Daten nur:
1. Wo sich der Spieler befindet
2. Welchen Winkel die Kamera zu Achse Null (Norden) hat
3. Wo sich die Kamera befindet
[Edit]4. Die Mauskoordinaten hab ich natürlich auch ;-)[/Edit]

Hoffe das mir daraus einer ne Formel basteln kann oder wenigstens sagen kann in welche Richtung ich mich vorarbeiten muss.

Gruß
Scarabol

ich war so frei, deinen extrem großen screenshot durch eninen thumbnail zu ersetzen.
bitte in zukunft selber machen. ;)
modedit - Kaeru fecit


Danke

Wie geht das mit dem Thumbnail?
Hab die Antwort bereits selbst gefunden.
Zuletzt geändert von Scarabol am 30.09.2007 15:37, insgesamt 4-mal geändert.
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

PureBasic Manual hat geschrieben:Distance between two points

(x1|y1) = XY coordinates of point No. 1
(x2|y2) = XY coordinates of point No. 2
a = Distance between the points

a = SQR((x1-x2)^2 + (y1-y2)^2)
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

@Fluid

das ist aber nur der zweidimensionale Phytagoras.
natürlich braucht man den später, aber erstmal geht es um den Klick-Punkt der Maus auf der ebene.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Bild
Bild

Bild

Besser?
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

:mrgreen: yo, das ist der dreidimensionale pythagoras :allright:

ich meine, der 2D wird reichen, denn man hat ja den fußpunkt des players auf der ebene.
das problem ist, dass man den schnittpunt der geraden Camera-Mauszeiger mit der ebene braucht.
um die gerade zu ermitteln braucht man aber erstmal den punkt des mauszeigers auf der bildebene.
(oder nicht? ich glaub schon)

ich hab das noch nie gemacht, bestimmt gibts irgendwo ne beschreibung für den algo...

mal meine grüblereien:
die bildebene ist 3D-senkrecht zum kamera-blickvektor.
damit kann man die 3D-koordinaten des mausbildpunktes errechnen.
nun muss man einen strahl von der kamera durch den 3D-Mauspunkt senden,
und den schnittpunkt mit dem terrain ermitteln.
(was ja auch keine ebene ist, wird also etwas komplizierter)

NTQ hat echt ahnung von sowas.
ich kann zwar den ansatz erstellen, weiß aber nicht, welche formeln ich brauche.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Hm. Ich würde als ersten Ansatz von jeder Ecke der Kamera-Projektions-Fläche einen Strahl aussenden. Da wo die Strahlen auf der Ebene auftreffen, wird der Treffpunkt zur Ecke der Kamerafläche in Raum-Daten... Dann könnte man die Abstände zwischen den Pixeln errechnen, da wir nun die Fläche in 3D haben, und...

Ach, Quack, das ist alles zu aufwendig. Konnte man in OpenGL (ich hab keine Ahnung, ob dus verwendest, wills nur mal einwerfen) nicht für jedes Fragment (=Pixel) die Daten der Vektoren/Quads/wieauchimmer auslesen? Ich bin mir sicher, dass man so auch ans Ziel kommen könnte... So ließe sich ein Boden mit fester Anzahl Kacheln machen (=Quads), auf die sich der Spieler ganz einfach zu bewegt. Dann bräuchte man keine großartigen Formeln mehr :D .

Ja, ich weiß, ist zu speziell für oGL und zu unflexibel...
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Sorry ich verwende keine OpenGL, sondern die ganz normalen PB 3D Funktionen. Ist zwar nicht so "gut" aber dafür funktionieren sie ohne Probleme und ich weiß wie man sie anwendet. ;-)

Meine Gedanken gingen auch schon in die Richtung die Kearu Gaman anschlägt aber ich muss mich leider anschließen und habe keine Ahnung wie ich mit diseser Idee weitermachen kann. Sollte einer was wissen oder auch nur wissen wo ich Ansätze dazu finde, ihr müsst sie ja nicht verstehen oder erklären ;-), bitte melden.

@Fluid Byte
Sorry, aber irgendwie versteh ich die Aussage deines Beitrags nicht so ganz, kannst du das nicht genauer erklären?
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Dostej
Beiträge: 529
Registriert: 01.10.2004 10:02
Kontaktdaten:

Beitrag von Dostej »

Es gibt irgendwo in den tiefen des Forums (oder des englischen) einen Code, der eine 2d-3d Mausprojektion vornimmt, also berechnet, wohin die 2d maus im 3d raum zeigt.

Vielleicht hilft Dir der weiter (wie gesagt, ist nicht von mir, hab nur keine Ahnung, woher der genau ist)

Code: Alles auswählen

;cheating a bit with this structure - I use it for both 3D points and vectors 
Structure vector 
  x.d 
  y.d 
  z.d 
EndStructure 

Structure mouse 
  x.l 
  y.l 
  v.vector 
  button.l 
  over.l 
EndStructure 

Structure bounded 
  object.l 
  centre.vector 
  radius.d 
  distance.d 
EndStructure 

Global height.l, width.l, mousedepth.d, camera.vector, lookat.vector, origin.vector 
Global NewList spheres.bounded() 

width  = 1024 
height = 768 
mousedepth = -665 

;width  = 800       ;These numbers seem to work for a 
;height = 600       ;800 by 600 screen but the graphic 
;mousedepth = -519  ;detail is better at 1024x768 

Procedure copy(*a.vector,*b.vector) 
  *a\x = *b\x 
  *a\y = *b\y 
  *a\z = *b\z 
EndProcedure 

Procedure new(*v.vector,x.d,y.d,z.d) 
  *v\x = x 
  *v\y = y 
  *v\z = z 
EndProcedure 

Procedure vectorise(*v.vector,*from.vector,*toPoint.vector) 
  new(*v, *toPoint\x - *from\x,*toPoint\y - *from\y,*toPoint\z - *from\z) 
EndProcedure 

Procedure equal(*a.vector,*b.vector) 
  If *a\x <> *b\x:ProcedureReturn 0:EndIf 
  If *a\y <> *b\y:ProcedureReturn 0:EndIf 
  If *a\z <> *b\z:ProcedureReturn 0:EndIf 
  ProcedureReturn 1 
EndProcedure 

Procedure translate(*v.vector, *t.vector) 
  *v\x+*t\x 
  *v\y+*t\y 
  *v\z+*t\z 
EndProcedure 

Procedure rotate(*v.vector, *r.vector) 
  copy(temp.vector,*v) ;rotate x axis 
  *v\y = temp\y*Cos(-*r\x)-temp\z*Sin(-*r\x) 
  *v\z = temp\y*Sin(-*r\x)+temp\z*Cos(-*r\x) 
  copy(temp.vector,*v) ;rotate y axis 
  *v\z = temp\z*Cos(-*r\y)-temp\x*Sin(-*r\y) 
  *v\x = temp\z*Sin(-*r\y)+temp\x*Cos(-*r\y) 
  copy(temp.vector,*v) ;rotate z axis 
  *v\x = temp\x*Cos(-*r\z)-temp\y*Sin(-*r\z) 
  *v\y = temp\x*Sin(-*r\z)+temp\y*Cos(-*r\z) 
EndProcedure 

Procedure.d dot(*a.vector,*b.vector) 
  ProcedureReturn (*a\x * *b\x)+(*a\y * *b\y)+(*a\z * *b\z) 
EndProcedure 

Procedure.d angle(*a.vector, *b.vector) 
  ProcedureReturn ACos(dot(*a,*b)/(Pow(dot(*a,*a),0.5)*Pow(dot(*b,*b),0.5))) 
EndProcedure 

Procedure map(*v.vector) 
  a.d:b.d:c.d 
  vectorise(LA.vector,camera,lookat) 
  new(screen.vector,0,0,mousedepth) 
  
  new(Lxy.vector,LA\x,LA\y,0) 
  new(Lyz.vector,0,LA\y,LA\z) 
  new(Lxz.vector,LA\x,0,LA\z) 
  new(Sxy.vector,screen\x,screen\y,0) 
  new(Syz.vector,0,screen\y,screen\z) 
  new(Sxz.vector,screen\x,0,screen\z) 
  a = angle(Sxy,Lxy) 
  b = angle(Syz,Lyz) 
  c = angle(Sxz,Lxz) 
  If equal(Lxy,origin)+equal(Sxy,origin):a=0:EndIf 
  If equal(Lyz,origin)+equal(Syz,origin):b=0:EndIf 
  If equal(Lxz,origin)+equal(Sxz,origin):c=0:EndIf 
  new(angles.vector,b,c,a) 
  rotate(*v,angles) 
  translate(*v,camera) 
EndProcedure 

Procedure.d distance(*a.vector,*b.vector,*c.vector) 
  ;distance between line AB and point C 
  new(AB.vector,*b\x-*a\x,*b\y-*a\y,*b\z-*a\z) 
  new(AC.vector,*c\x-*a\x,*c\y-*a\y,*c\z-*a\z) 
  angle.d = angle(AB,AC) 
  ProcedureReturn Pow(dot(AC,AC),0.5)*Sin(angle) 
EndProcedure 

Procedure over(*v.vector) 
  ForEach spheres() 
    Delay(0) 
    copy(centre.vector,spheres()\centre) 
    spheres()\distance=Pow(Pow(camera\x-centre\x,2)+Pow(camera\y-centre\y,2)+Pow(camera\z-centre\z,2),0.5) 
    basicangle.l = (180*angle(lookat,centre)/#PI) 
    If basicangle>90:spheres()\distance = -spheres()\distance:EndIf 
  Next 
  SortStructuredList(spheres(),0,OffsetOf(bounded\distance),#PB_Sort_Double) 
  ForEach spheres() 
    Delay(0) 
    If (spheres()\distance>=0) And (distance(camera,*v,spheres()\centre)<= spheres()\radius): ProcedureReturn spheres()\object:EndIf 
  Next 
  ProcedureReturn -1 
EndProcedure 

Procedure getMouse(*m.mouse) 
  ExamineMouse() 
  If MouseButton(#PB_MouseButton_Left) 
    *m\button=1 
  ElseIf MouseButton(#PB_MouseButton_Right) 
    *m\button=2 
  ElseIf MouseButton(#PB_MouseButton_Middle) 
    *m\button=3 
  Else 
    *m\button=0 
  EndIf 
  x = MouseX()-width/2 
  y = (height/2-MouseY()) 
  z = mousedepth 
  new(v.vector,x,y,z) 
  map(v) 
  *m\x = MouseX() 
  *m\y = MouseY() 
  copy(*m\v,v) 
  *m\over = over(v) 
EndProcedure 

Procedure.s displayMouse(*m.mouse) 
  ProcedureReturn "("+Str(*m\x)+","+Str(*m\y)+") - ["+StrD(*m\v\x,2)+","+StrD(*m\v\y,2)+","+StrD(*m\v\z,2)+"] - distance "+StrD(Pow(Pow(*m\v\x - camera\x,2)+Pow(*m\v\y - camera\y,2)+Pow(*m\v\z - camera\z,2),0.5),2) 
EndProcedure 

Procedure setcamera(cameraID.l,*v.vector) 
  If *v <> #Null:copy(camera,*v):EndIf 
  CameraLocate(cameraID,*v\x,*v\y,*v\z) 
  If lookat <> #Null:new(lookat,0,0,-1000):EndIf 
  CameraLookAt(cameraID,lookat\x,lookat\y,lookat\z) 
EndProcedure 

Procedure setlookat(cameraID.l,*v.vector) 
  If *v <> #Null:copy(lookat,*v):EndIf 
  CameraLookAt(cameraID,lookat\x,lookat\y,lookat\z) 
EndProcedure 

Procedure addSphere(object.l,*centre.vector,radius.d) 
  AddElement(spheres()) 
  spheres()\object = object 
  spheres()\centre\x = *centre\x 
  spheres()\centre\y = *centre\y 
  spheres()\centre\z = *centre\z 
  spheres()\radius = radius 
EndProcedure 

Procedure moveObject(object.l,*v.vector) 
  MoveEntity(object,*v\x,*v\y,*v\z) 
  SortStructuredList(spheres(),0,OffsetOf(bounded\object),#PB_Sort_Long) 
  ForEach spheres() 
    If spheres()\object = object:translate(spheres()\centre,*v):EndIf 
    If spheres()\object > object:ProcedureReturn:EndIf 
  Next 
EndProcedure 

;-Initialise 
ExamineDesktops() 
InitEngine3D() 
InitSprite() 
InitKeyboard() 
InitMouse() 
OpenScreen(width,height,32,"") 
UseJPEGImageDecoder() 
UsePNGImageDecoder() 
Add3DArchive("Data\", #PB_3DArchive_FileSystem) 
Parse3DScripts() 
LoadSprite(0,"Data\mouse.PNG") 

;-Setup Movement Vectors 
new(up.vector,0,0,-1):map(up) 
new(down.vector,0,0,1):map(down) 
new(left.vector,-1,0,0):map(left) 
new(right.vector,1,0,0):map(right) 

;-Set named Vectors 
new(origin,0,0,0) 
new(camera,0,0,0) 
new(lookat,0,0,mousedepth) 

;-Setup Camera 
CreateCamera(0, 0, 0, 100, 100) 
setcamera(0,camera) 
setlookat(0,lookat) 
CameraFOV(0, #PI / 3) 

;-Setup Cubes 
LoadMesh   (1, "cube.mesh") 
LoadTexture(1, "stone.jpg") 
CreateMaterial(1,TextureID(1)) 

For i=1 To 1000 
  new(r.vector,2*Random(width)-width,2*Random(height)-height,-Random(-mousedepth)) 
  CreateEntity(i,MeshID(1),MaterialID(1),r\x,r\y,r\z) 
  ScaleEntity(i,0.1,0.1,0.1) 
  addSphere(i,r,6.5) 
Next i 

;-Main loop 
Repeat 
  ClearScreen(0) 
  RenderWorld() 
  getmouse(mouse.mouse) 
  StartDrawing(ScreenOutput()) 
    DrawText(0,0, "Mouse location: "+displayMouse(mouse),$FFFF,0) 
    ovr = over(mouse\v) 
    If ovr<0 
      DrawText(0,16, "Mouse is over: nothing ",$FF,0) 
    Else 
      DrawText(0,16, "Mouse is over: object "+Str(ovr),$FF00,0) 
      If ExamineKeyboard() 
        If KeyboardPushed(#PB_Key_Up) 
          moveObject(ovr,up) 
        ElseIf KeyboardPushed(#PB_Key_Down) 
          moveObject(ovr,down) 
        ElseIf KeyboardPushed(#PB_Key_Left) 
          moveObject(ovr,left) 
        ElseIf KeyboardPushed(#PB_Key_Right) 
          moveObject(ovr,right) 
        EndIf 
      EndIf 
    EndIf 
  StopDrawing() 
  DisplayTransparentSprite(0,MouseX(),MouseY())    
  FlipBuffers() 
  ExamineKeyboard() 
Until KeyboardPushed(#PB_Key_Escape)
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Vielen Dank für den Code, sieht auf jeden Fall kompliziert aus, aber ich werd mich wohl druchkämpfen können.
Meld mich wieder.
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

So hab mir mal den Code angesehen, aber leider scheint es, dass die Formeln nicht auf meinen Code übertragbar sind, da der Coder ein ganz anderes Ziel verfolgt hat und wenn ich den Zahlen glauben darf auch ein Paar Fehler drin hat.

Aber vielleicht kann ja doch noch einer was da rausholen und auf mein Problem übertragen oder hat sonst noch einer Ansätze?

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Antworten