![]() |
Zielsuchende Objekte
Liebe Delphi Freunde,
Meine besten Freunde und ich arbeiten an einem langen Projekt. Worum es dabei geht ist denke ich nicht sehr wichtig. Es geht um den Nachbau eines Spieles, soviel sei gesagt. Das eigentliche Problem ist: Wir haben es bereits geschafft "Kriegsschiffe" am Rande des Bildschirms Random erscheinen zu lassen. Uns fehlt aber wissen/Ideen wie es umzusetzen ist diese TShapes dazu zu bringen sich intelligent zur Mitte zu bewegen. Nicht so dass man beispielsweise erst alle diagonal an einen Timer gekoppelt Richtung Mitte laufen lasst und nachdem sich ihre Höhe shape1.Top mit der der Mitte gleicht sie anfangen nur noch den Left wert zu ändern. Ich hoffe die Ausgrenzung it verständlich:-D Wichtig wäre also: - die zufällig am Rand erschienenen Schiffe (Kreise tshape) finden intelligent den kürzesten weg zur Mitte und halten etwa 20 davon entfernt an - sie sammeln sich nicht alle an einem Punkt also nicht alle Schiffe die von unten kommen landen genau aufeinander unterhalb der Base (Mitte) sondern wie es gerade passt. EDIT Die Schiffe können an jedem Punkt der genau 5 Pixel!? vom Rand entfernt ist erscheinen, also wäre jeder weg anders. Ich würde mich sehr über Hilfe freuen. LG Dunkelbunt |
AW: Zielsuchende Objekte
Diese sollen also in einer "direkten" geraden zur Mitte laufen?
da es ja "quasi" nur in ganzen Pixeln/Feldern/Schritten geht: - berechne die X&Y-Abstände zu dem gewünschten Zielpunkt (z.B. x_abstand = x_zielpunkt - x_position) - such dir den kleinesten Wert davon aus (mit abs das Vorzeichen entfernen) - in diese Richtung gehst du dann (if abs(x_abstand) > abs(y_abstand) then x_position=x_position+/-1 else y_position=y_position+/-1 ) - wenn wenn das Zielfeld aber schon besetzt ist, dann nimm die andere Richtung - wenn keiner der beiden Wege möglich ist, dann entweder per Zufall in einer der verbleibenden Wichtungen gehn oder erstmal stehenbleiben - sind beide Abstände kleiner-gleich 20, dann auch stehenbleiben falls auch diagonal gesprungen werden darf, dann - wenn x_abstand wesentlich größer als y_abstand und x_abstand größer 20, dann in nur x-richtung gehn - oder wenn y_abstand wesentlich größer als x_abstand und y_abstand größer 20, dann nur in y-richtung gehn - oder wenn x_abstand und y_abstand größer 20, dann in x und y gehn - oder wenn x_abstand größer 20, dann in x - oder wenn y_abstand größer 20, dann in y - oder stehenbleiben (auch hier die Abstände ohne Vorzeichen vergleichen) falls es nicht ganz gerade sein soll, dann auf diesen weg eine Zielrichtung berechnen und dann per zufall eine Richtung auswählen, dabei aber natürlich in Zielrichtung den Zufall höher gewichten. |
AW: Zielsuchende Objekte
Du brauchst erstmal die Richtung, in die sich die Schiffe bewegen sollen - sozusagen einen "Pfeil" der in Richtung der Mitte zeigt (man munkelt Fachleute sollen hier auch von einem "Vektor" sprechen). Diesen Vektor bekommst du ganz einfach:
Delphi-Quellcode:
Nun ist dieser Vektor jedoch für unterschiedliche Schiffe unterschiedlich lang (vergleiche Ecke oben links mit mitte links außen). Du musst den Vektor also normalisieren. Dazu brauchen wir erstmal die Länge des Vektors (entspricht dem Abstand zu Mitte), die einfach mit dem Satz des Pythagoras ausgerechnet werden kann:
var
vx, vy: Double; begin vx := MitteX - MitteSchiffX; vy := MitteY - MitteSchiffY; end;
Delphi-Quellcode:
Nun kannst du in einem Timer die Schiffe n Schritte an den Pfeil entlangwandern lassen, wobei n die Geschwindigkeit ist (in diesem Fall 10px pro Timerintervall):
var
laenge: double; begin laenge := sqrt(sqr(vx) + sqr(vy)); vx := vx / laenge; vy := vy / laenge; end;
Delphi-Quellcode:
Um die Schiffe nich miteinander Kollidieren zu lassen musst du auch hier den Abstand zwischen den Schiffen ausrechnen und entsprechend reagieren. Um die Schiffe einige Pixel vor der Mitte zu stoppen, musst du den Abstand zur Mitte berechnen und wenn dieser einen gewissen Wert hat stoppen.
procedure TForm1.Timer1Timer(Sender: TObject);
begin schiffx := round(schiffx + vx * 10); schiffy := round(schiffy + vy * 10); end; |
AW: Zielsuchende Objekte
Dank,
Hört sich schonmal super an. Hab vergessen wie eng Delphi mit Mathematik zusammenhängt. Wir haben noch eine weitere Frage: Ist es richtig wenn sie Schiffe erstmal in der Mitte sind: - es soll ein Laser entstehen Erste Gedanken:
Delphi-Quellcode:
Dann
Image1.canvas.moveto(schiffx, schiffy);
Delphi-Quellcode:
Image1.canvas.lineto(zielx, ziely);
Klang für uns logisch, es kommt aber statt einer Linie ein schwarzer flimmernder Bildschirm. Ich hoffe ihr wisst wieder so tolle antworten :) LG Dunkelbunt |
AW: Zielsuchende Objekte
Ein Spiel auf dem Canvas zeichnen ist keine gute Idee. Schau dir hier besser Lösungen an, welche uf DX/OpenGL basieren wie z.B. Andorra und Co.
Btw: Bite verwende Delphi-Tags für Delphi-Code |
AW: Zielsuchende Objekte
Zitat:
|
AW: Zielsuchende Objekte
Wenn es um eine Schiffsbewegung geht, kommen da sicherlich auch noch irgendwann Hindernisse mit ins Spiel, oder sei es nur, um bereits von anderen Schiffen blockierte Felder "auszukeyen"
Ich würde mich deswegen an deiner Stelle mal generell über Wegfindungs-Algorithmen wie A* oder dergleichen informieren, wenn man das Prinzip mal verstanden hat, spart es einem ne Menge Müllcode :D Michael Puff hat auch eine Delphi-Implementation des A*-Algorithmus inklusive PDF-Tutorial in seinem Gepäck: ![]() |
AW: Zielsuchende Objekte
@ igel
Deine Rechnung hat mir geholfen, jedoch gibt es ein problem: Ich rechne hier mal ein beispiel vor: schiffX= 2 schiffY = 2 MitteX = 26 MitteY = 12 zuerst Vektoren berechnen: vx = MitteX-SchiffX = 26-2 = 24 vy = MitteY - SchiffY = 12-2 = 10 Laenge: Wurzel(vx²+vy²) = 26 vx= vx/laenge = 24:26 = 0.923 vy= vy/laenge = 10:26 = 0,384 Das ist erstmal die Rechnung. Also muss sich mein schiff 0,923 einheiten um x bewegen und 0,384 um y.... Das Problem ist das 1Pixel doch schon die kleinste schrittweite ist ... daraus folgt das das schiff immer genau diagonal wandert und nicht ankommt... Höchstens wenn ich es mit 10 multipliziere, was leider zu große schritte sind. Ich werde mich jetz um den A* algorithmus kümmern auch wenn ich ihn noch nicht ganz verstanden habe. Gruß Dunkelbunt. |
AW: Zielsuchende Objekte
Speichere die Position der Schiffe als Fließkommazahl (Double) und runde diese ausschließlich für die Anzeige.
|
AW: Zielsuchende Objekte
Es ist fast immer eine gute Idee Positionen als Floats zu verwalten, und nur zum Zwecke der Anzeige beim Zeichnen zu runden.
Edit: Okay, nächstes Mal erst F5 drücken, dann antworten :) |
AW: Zielsuchende Objekte
Wenn man eine genügend kraftvolle Hardware hat
|
AW: Zielsuchende Objekte
Zitat:
Ich habe für solche Zwecke immer Floats genommen und meistens betrug die CPU-Last ohne Grafikausgabe 0%. |
AW: Zielsuchende Objekte
Ich würde auf jedenfall floats nehmen. Sobald man irgendwann mal auf DX / OGL für die Grafik-Ausgabe umsattelt, hat man es eh nur noch mit floats zu tun.
Das Leistungs-Einbruchs-Argument verstehe ich nun jetzt aucc nicht so ganz... |
AW: Zielsuchende Objekte
Ich meinte das vor allem in Verbindung mit dem Canvas
|
AW: Zielsuchende Objekte
Klasse, Zielsuchende random am Bildschirmrand erscheinende Schiffchen funktioniert.
Nächstes Problem ^^ Wir wollen das die Schiffe sobald sie halt nur noch 100 Pixel vom Ziel entfernt sind auf die Basis (Mitte) schießen. Am infachsten(so denken wir) ist eine Rote Linie wie einen Laser vom Schiff zur Basis zu zeichnen. Hier nun die Frage, wie funktioniert das? Ich hatte es schonmal mit canvas beschirben und jemand hat geantwortet lieber open GL zu benutzen. Open Gl ist uns leider nicht möglich, erstens weil wir davon leider keine ahnung haben und weil unser lehrer das ganze lieber mit canvas sehen würde. Wenn jemand genau beschreiben kann dies mit Open Gl zu verwirklichen wär ich auch dankbar, hauptsache wir bekommen eine Linie gezogen. Viele Liebe Grüße Dunkelbunt EDIT: omg sry nächstes mal F5 drücken |
AW: Zielsuchende Objekte
Zitat:
Wenn, dann wäre ALLES OpenGL und der Canvas wäre auch für die Schiffe erstmal Essig. OpenGL ist keine Zusatzkomponente, sondern eine generelle Grafik-Library, die du aber mit einem Canvas / GDI nicht mischen kannst (zumindest für die Elemente im OGL-Context). Dazu musst du auch erstmal einen OpenGL-Context erstellen und ab da hast du es nur noch mit Vektoren und Matrizen zu tun. Deinen Canvas-Code kannst du dann erstmal komplett in die Tonne kloppen, da OpenGL gänzlich anders funktioniert. Also würde ich das erstmal lassen und mich vielleicht parallel in das Konzept von OpenGL oder auch alternativ Direct3D einlesen. Die Lernkurve ist hier ziemlich steil. Allerdings, sollte daraus wirklich mal ein Spiel werden, würde ich den Canvas eh vergessen, weil viel zu langsam. Ist es nur ein Projekt für den Lehrer, dann ist es ja egal. Aber ein richtiges Spiel wird da wohl nicht draus :wink: Andererseits würdest du den Lehrer mit OpenGL sicherlich beeindrucken :lol::lol:, ich vermute nämlich mal, dass er selbst keine Ahnung davon hat... Allerdings schreibt man nicht "mal eben" ein Spiel mit OpenGL, da man erstmal (relativ lange) kapieren muss, wie da der Hase läuft. Das ist ungefähr so, als könntest du BobbyCar fahren und sattelst dann auf einen 40-Tonner um :D Was bekommst du denn dann mit dem Canvas nicht hin? Du weisst ja, wann die Schiffe an ihrem Zielpunkt angelangt sind, dann feuer doch ein Event, der dann mit LineTo oder sonstwas die Linie zeichnet? |
AW: Zielsuchende Objekte
Oder man verwendet etwas "Fertiges" wie Andora2D usw
|
AW: Zielsuchende Objekte
"Dann feuer doch ein Event" xD fand ich grad geil ^^
naja also es ist so ich habe LEIDER zu hause nur Lazarus... Ich habe folgendermaßen versucht eine linie zu ziehen: moveto zum schiff und lineto zur base, ich fand es klingt logisch, dann aber kam statt der line ein ständig komplett schwarz weiß flackernder bildschirm. :oops: Vllt kannst du ja mal einen kurzen quellcode ausschnitt aufschreiben der das schiff schiffx und schiffy (koordinaten) mit Mittex und mittey durch eine linie verbindet. wäre zur fehlerfindung sehr hilfreich =) Dunkelbunt Edit: gerade nochmal ausprobiert, wieder flackern: Hier der Quelltext:
Delphi-Quellcode:
if laenge = 100 then
begin image1.canvas.moveto(shape1.left, shape1.top); image1.canvas.lineto(shape1.left, shape1.top); end; |
AW: Zielsuchende Objekte
Zitat:
Ich kenne jetzt deinen Code nicht, aber ich schätze mal, dass das Flackern daher kommt, dass das Shape das Image überlappt...? Edit: Das ist generell keine gute Idee. Wenn du eine Zeichenfläche hast, dann sollte die auch für sich alleine stehen und nicht durch andere Objekte überlagert werden, das gibt sonst Chaos bei den Repaint-Zyklen der einzelnen Objekte. Sinnvoller wäre es doch, die Schiffe auch auf den Canvas zu zeichnen, anstatt dafür jeweils ein einzelnes Shape zu nehmen. Poste mal bitte ein wenig mehr code. |
AW: Zielsuchende Objekte
Hab einen fehler gemacht:
so ist mein eigentlicher Quelltext:
Delphi-Quellcode:
und das image ist bildschirmfüllend, also kann das shape das image nicht überlappen
if laenge = 100 then
begin image1.canvas.moveto(shape1.left, shape1.top); image1.canvas.lineto(round(mittex), round(mittey)); end; Edit: du wolltest etwas Quelltext^^ Hier hast du =)
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var n : integer; begin shape1.visible := True; Timer1.enabled := True; randomize; n := random(4)+1; if (n=1) or (n=2) or (n=3) then begin randomize; shape1.left:= 5; shape1.top:= random(775+1); end; if n=2 then begin randomize; shape1.left:= random(1320+1); shape1.top:= 5; end; if n=1 then begin randomize; shape1.left:= 1300; shape1.top:= random(775+1); end; if n=2 then begin randomize; shape1.left:= random(1320+1); shape1.top:= 775; end; end; procedure TForm1.Image1Click(Sender: TObject); begin end; procedure TForm1.Timer1Timer(Sender: TObject); begin mittex := shape2.Left; mittey := shape2.top; schiffx := shape1.left; schiffy := shape1.top; vx := mittex-schiffx; vy := mittey-schiffy; laenge := sqrt(sqr(vx)+sqr(vy)); if laenge >100 then begin vx := vx/laenge; vy := vy/laenge; schiffx :=round(schiffx+vx*1); schiffy := round(schiffy+vy*1); shape1.left := round(schiffx); shape1.top := round(schiffy); if laenge = 100 then begin image1.canvas.moveto(shape1.left, shape1.top); image1.canvas.lineto(round(mittex), round(mittey)); end; |
AW: Zielsuchende Objekte
Zitat:
Kannst du dein Projekt mal anhängen? Ich fürchte irgendwie, dass es konzeptionell überdenkbar ist bzw. ich hab da so ein "Sackgassen"-Gefühl gerade in der unteren Bauchgegend :) |
AW: Zielsuchende Objekte
Dann solltest du GANZ dringend einen Arzt aufsuchen! ;)
|
AW: Zielsuchende Objekte
Liste der Anhänge anzeigen (Anzahl: 1)
Okay mein Projekt im Anhang =)
Deine Idee mit: Zitat:
Schau dir das projekt an ^^ Anhang jetz da =O Hoffe die unit datei reicht =O weil alles andere irgendwie bei hochaden eine fehlermeldung bekam (auch ne 2 teilige rar datei) |
AW: Zielsuchende Objekte
Ööhm....:gruebel:
In der Unit wird ja gar nichts gezeichnet, und ein Image sehe ich auch nicht, da sind nur zwei Shapes, dessen Positionen im Klick durchs random gewurschtelt werden und dann im Timer verschoben werden. Ohne die DFM weiss ich jetzt auch nicht, wo die liegen müssen und wie gross die sind-... Aber da fehlt ja generell der ganze Zeichenteil? (der nicht funktioniert) Edit: ich habe das jetzt mal mit dem bildschirmfüllenden Bild nachgebaut. Dein Problem ist vermutlich, dass das Bild in der Hiararchie über den Shapes liegt. Das macht so lange kein Problem, bis du auf das Image etwas zeichnest. Dann verschwindet nämlich dessen anfängliche "Transparenz" und es wird mit der Brush.Color gefüllt, danach wird über den Pen die Linie gezeichnet. Dadurch, dass das Image über den Shapes liegt, siehst du danach aber die Shapes nicht mehr und es flackert kurz. Du kannst ja mal das Image im Form-Editor anwählen und dann über "Bearbeiten->Nach Hinten setzen" dieses in den Hintergrund legen. Dann klappt das Linien-Zeichnen, aber! du siehst nichts auf dem Bild gezeichnet, was z.B. hinter den Shapes liegen würde. Ist ja auch klar, da die Shapes über das Bild (und somit dem Laser) gezeichnet werden und das passiert, nachdem die Linie gezeichnet wurde. Somit überschreibt der Repaint-Zyklus des Shapes deinen schönen Laser und der hat einen Rohrkrepierer. Wie gesagt, ich würde von den Shapes Abstand nehmen und den Image-Canvas als einzige Zeichenfläche nehmen, ansonsten hast du Chaos pur in der Kajüte! :wink: |
AW: Zielsuchende Objekte
Liste der Anhänge anzeigen (Anzahl: 2)
Ich habe da mal was vorbereitet:
|
AW: Zielsuchende Objekte
Zitat:
|
AW: Zielsuchende Objekte
Danke für eure Kochtipps,
Wir werden uns alles durch den Kopf gehen lassen und mit Canvas zeichnen. Meine nächste Antwort wird dann wahrscheinlich eine Weile dauern bis wir was handfestes auf die Beine gestellt haben =) EDIT Kann man auch detaillierte Grafiken mit canvas zeichnen oder nur Kreischen? Klappt es in dem Fall dann ein image an das gezeichnete zu hängen um praktisch eine tolle grafik drüber zu legen? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz