ich habe mich mal dem colorpicking gewidmet um herauszufinden auf welches meiner vielen vierecke geclickt wurde
also ich habe ein 2 dimesionales array (Karte array of array of TField;) welches der reihe nach abgearbeitet wird, jedes TField steht für ein viereck welches über eine ID verfügt, über welche das feld identifizieren kann
die koordinaten werden über 2 schleifen festgelegt sodass egal wie groß das array wird, es immer gleich gezeichnet werden kann
das sieht im ganzen so aus
Code:
procedure TMap.Render; const fac: single = 1/255; var x,y : Integer; iv: array[0..3] of byte absolute x; begin if Length(Karte) > 0 then for x := Low(Karte) to High(Karte) do for y := Low(Karte[x]) to High(Karte[x]) do begin TextureManager.BindTexture(Karte[x,y].Texture); {$ifdef ENDIAN_BIG} glUniform4f(ShaderManager.color, iv[1]*fac, iv[2]*fac, iv[3]*fac, 1.0); {$else} glUniform4f(ShaderManager.color, iv[0]*fac, iv[1]*fac, iv[2]*fac, 1.0); {$endif} glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex3f(x, 0, y); glTexCoord2f(1,0); glVertex3f(x+1, 0, y); glTexCoord2f(1,1); glVertex3f(x+1, 0, y+1); glTexCoord2f(0,1); glVertex3f(x, 0, y+1); glEnd; glBegin(GL_LINE_LOOP); glColor3f(0,0,0); glVertex3f(x, 0.02, y); glVertex3f(x+1, 0.02, y); glVertex3f(x+1, 0.02, y+1); glVertex3f(x, 0.02, y+1); glColor3f(0.7,0.7,0.7); glEnd; if Karte[x,y].Besezt then begin ObjectManager.RenderObject(x+0.5,y+0.5,Karte[x,y].Objekt); end; end; end;
dieser code gibt zu allererst einen wunderschönen farbverlauf und dann meine normale karte wieder. jedoch kann ich nicht jedes feld einzeln anklicken sondern funktioniert nur das anklicken eines ganzen "stranges" also immer des "X",
ich denke das problem liegt in der variable iv.
die auswertung hab ich bis jetzt so gelößt
Code:
procedure TForm1.FormClick(Sender: TObject); var i : LongWord; x,y : Integer; begin i := Select(MousePos.X, Mousepos.Y); for x := Low(Map.Karte) to High(Map.Karte) do for y := Low(Map.Karte[x]) to High(Map.Karte[x]) do if Map.Karte[x,y].ID = i then begin Map.Karte[x,y].Objekt := Form2.NewObjectCombo.Text; Map.Karte[x,y].Besezt := true; end; end;
ich hoffe ihr wisst was ich meine und könnt mir helfen
Also ich bin mir als C++-User nicht ganz sicher was "iv: array[0..3] of byte absolute x;" macht, aber ich nehme an iv ist ein Array der einzelnen Bytes des 32bit Integers x, richtig? In dem Fall wird dann doch y gar nicht berücksichtigt und die Objekte in jeder Zeile haben alle die gleiche ID?
Ich schlage vor du packst x in iv[0] bzw. iv[1] und y in iv[2] bzw. iv[3]. Das klappt natürlich nur wenn x und y zwischen 0 und 65535 liegen. Ggf. brauchst du eine kompliziertere Zerlegung, aber jedenfalls solltest du die ID so wählen das du sie, wenn sie vom Color-Picking zurückkommt direkt wieder in x/y zerlegen kannst ohne alle Objekte durch zu testen. Wenn das nicht möglich ist solltest du überlegen ob du nicht eine Map verwenden kannst. Auch Delphi hat bestimmt eine Datenstruktur in der Standard-Bib die eine ID effizient auf einen Objekt-Pointer mappen kann.
Des weiteren frage ich mich warum du überhaupt Color-Picking machst. Du hast doch da ein 2D-Feld von Quads? Ich meine x und y sollten sich doch quasi direkt aus den Cursor-Koordinaten ableiten lassen ohne das du erst tonnenweise Daten durch die Grafikkarte jagen musst. Gut, ich weiß natürlich nicht was du da genau machst
das einfach umrechnen geht eben nicht da es zwar 2d quads sind, sie aber 3d irgendwo im raum liegen, desweiteren sollten am ende auch objecte die auf der map stehen selektiert werden können
die ID die jedes feld bekommt wird vorher Festgelegt wenn die größe des "Spielfeldes" Festgelegt wird
Code:
procedure TMap.SetMapSize(pSize : Integer); var x,y,ID : Integer; begin ID := 0; SetLength(Karte, pSize); for x := Low(Karte) to High(Karte) do SetLength(Karte[x], pSize); for x := Low(Karte) to High(Karte) do for y := low(Karte[x]) to High(Karte[x]) do begin ID := ID+1; Karte[x,y].ID := ID; Karte[x,y].Besezt := false; Karte[x,y].Objekt := ''; end; end;
so hat wirklich jedes feld seine eigene ID
und das mit dem "iv : array[0..3] of Byte abslolute x; kann ich dir leider gar nicht sagen, ich hab nämlich auch keine ahnung was das darstellen soll das wurde im Tutorial dazu nicht erklärt. wobei ich das sowieso sehr knapp finde
und das mit de ID finden, da denke ich das ich eventuell einen Pointer auf Tfield setzen könnte und diesen dann aufrufe aber das muss ich mir nochmal ansehen
Also.... var iv: Array[0..3] of Byte absolute x; Heißt tatsächlich, dass iv[0], iv[1]... Zugriff auf das erste, zweite... Byte des Integers x bieten.
Zu deinem Problem: Wenn jedes Feld eine eindeutige, eindimensionale ID hat, warum nutzt du die nicht fürs Colorpicking und lässt die Koordinaten auf der Map völlig außer Acht?
Ne eindeutige Zuordnung sollte (wenn die Arraygrößen konstant sind, wenn sie nicht konstant sind müssen bei jeder Änderung neue ID's berechnet werden) wie folgt möglich sein:
Zuweisung der ID:
Code:
ID := (High(x) + 1) * y + x;
Aus den so vergebenen IDs lassen sich die Koordinaten im 2D-Array dann einfach wieder berechnen:
Code:
x := ID mod (High(x) + 1); y := ID div (High(x) + 1);
Es gibt auch ne Möglichkeit, von für nicht-konstante Arraydimensionen von vornherein eindeutige IDs zu vergeben:
Code:
ID := Power(2, x) * Power(3, y);
Mit Power(2, x) = 2^x - ich verdreh da immer die Argumente, deswegen stell ich das nochmal klar. Bei der Möglichkeit wird das Zurückrechnen von der ID auf die Koordinaten aber schwierig.
durch bisschen probieren was mir die funktion überhaupt zurückgibt habe ich erkannt das es mir ja direkt die positionsdaten des objects in meinem array zurückgibt.
und da is mir ein licht aufgegangen
passt auf die lösung ist folgende
als allererstes musste ich die renderprocedure abändern sodass ich eine art selektionsmodus habe. desweiteren habe ich noch ein iy array[0..3] of byte absolute y; abgelegt um die y werte abzudecken
Code:
procedure TMap.Render(const SelektionsMode : Integer); const fac: single = 1/255; var x,y : Integer; iv: array[0..3] of byte absolute x; iy: array[0..3] of byte absolute y; begin if Length(Karte) > 0 then for x := Low(Karte) to High(Karte) do for y := Low(Karte[x]) to High(Karte[x]) do begin TextureManager.BindTexture(Karte[x,y].Texture); case SelektionsMode of 1 : begin {$ifdef ENDIAN_BIG} glUniform4f(ShaderManager.color, (iv[1])*fac, (iv[2])*fac, (iv[3])*fac, 1.0); {$else} glUniform4f(ShaderManager.color, (iv[0])*fac, (iv[1])*fac, (iv[2])*fac, 1.0); {$endif} end; 2 : begin {$ifdef ENDIAN_BIG} glUniform4f(ShaderManager.color, (iy[1])*fac, (iy[2])*fac, (iy[3])*fac, 1.0); {$else} glUniform4f(ShaderManager.color, (iy[0])*fac, (iy[1])*fac, (iy[2])*fac, 1.0); {$endif} end; end;
das hatte auch zur folge das die eigentliche selektionsmethode abgeändert werden musste
Code:
function Select(x, y, Mode: integer): longword; [...] Form1.Render(Mode); [...]
die onclick sieht nun so aus
Code:
procedure TForm1.FormClick(Sender: TObject); var i,b : LongWord; begin i := Select(MousePos.X, Mousepos.Y, 1); b := Select(MousePos.X, MousePos.Y, 2); Map.Karte[i,b].Objekt := Form2.NewObjectCombo.Text; Map.Karte[i,b].Besezt := true; //ShowMessage(inttostr(i)+','+inttostr(b)); end;
so bekomme ich genau das feld was ich haben möchte
ich danke euch für eure anregungen und vorschläge, das hat mir wirlich geholfen
da das ganze noch recht langsam ist werde ich es noch bisschen verfeinern müssen aber es funktioniert wrstmal einwandfrei
Die einzige Vereinfachung, die eigentlich fehlt ist - das ganze auf den eindimensionalen Fall zu reduzieren, damit du nur einmal rendern musst...aber nagut...es sei dir überlassen, darauf zu kommen
Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.