<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0">
	<channel>
		<title>BlitzBasic Portal Worklogs - DaDaPlayground</title>
		<link>https://www.blitzforum.de/worklogs/292/</link>
		<description>Worklog von darth</description>
		<language>de</language>
		<managingEditor>mail@blitzforum.de</managingEditor>
		<webMaster>mail@blitzforum.de</webMaster>
		<pubDate>Sun, 25 Dec 2011 20:26:33 +0100</pubDate>
		<lastBuildDate>Sun, 25 Dec 2011 20:26:33 +0100</lastBuildDate>

		<item>
			<title>HO HO HO, I'm back!</title>
			<link>https://www.blitzforum.de/worklogs/292/#3416</link>
			<guid>https://www.blitzforum.de/worklogs/292/#3416</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;im letzten Worklog hatte ich angek&amp;uuml;ndigt mit BlitzBasic aufzuh&amp;ouml;ren. Daran hat sich eigentlich nicht viel ge&amp;auml;ndert. Vielmehr habe ich mich endlich dazu aufgerafft, richtig C/C++ zu lernen (und C#, aber das ist ein anderes Thema). Aber ich habe meine &amp;quot;Wurzeln&amp;quot; nicht vergessen, und darum bin ich heute hier. Nach Umwegen.&lt;br /&gt;&lt;br /&gt;Ich hatte, wie gesagt, beschlossen, mit C++ weiterzumachen. Das f&amp;uuml;hrte nat&amp;uuml;rlich dazu, dass ich meine tollen Funktionssammlungen (&amp;quot;Libraries&amp;quot;) von BlitzBasic nach C++ portieren musste. Dies geschah auch mit meiner RigidBody-Physik. Da nun also der Code schon bestand dachte ich mir vor ein paar Tagen, dass ich doch eine lustige DLL f&amp;uuml;r BB daraus zaubern k&amp;ouml;nnte. Also habe ich mich hingesetzt und angefangen.&lt;br /&gt;&lt;br /&gt;Und ich kann euch sagen: BB ist beschissen. Echt beschissen. Die Sprache hat sich gestr&amp;auml;ubt wo sie nur konnte. Ich kann in meinem C++ Struct nur Arrays und Basis-Datentypen (float, int) verwenden, alles andere f&amp;uuml;hrt &amp;uuml;ber kurz oder lang zu MAVs und das &amp;auml;rgert - enorm! Das hat mich gezwungen, meine wundervolle Codestruktur komplett &amp;uuml;ber den Haufen zu werfen, alle einfachen Operatoren&amp;uuml;berladungen zu verwerfen (weil ich ja keine Position in einem Vektor speichern darf..) und das meiste neu zu machen. Nat&amp;uuml;rlich f&amp;uuml;hrt das auch dazu, dass die DLL in ihrem Funktionsumfang gegen&amp;uuml;ber anderen Versionen eingeschr&amp;auml;nkt ist.&lt;br /&gt;&lt;br /&gt;Eine kurze Liste von Einschr&amp;auml;nkungen:&lt;br /&gt;- keine konkaven Formen&lt;br /&gt;- kein Splittern (zugegeben, das habe ich noch gar nicht umgesetzt in C++)&lt;br /&gt;- kein Wasser (auch nicht umgesetzt in C++)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Und dennoch&lt;/b&gt;: Die Grundfunktionalit&amp;auml;t (Rigid-Body-Physics f&amp;uuml;r konvexe Formen) ist vorhanden. Objekte werden automatisch zu Meshes verwandelt und angezeigt. Leider kam ich nicht um etwas Glue-Code herum, d.h ihr m&amp;uuml;sst trotzdem noch ein *.bb-File mitschleppen (darin sind Typen definiert und gewisse Meshdinge m&amp;uuml;ssen weitergeleitet werden, weil ich das Mesh nicht direkt in der DLL behandeln kann). Zus&amp;auml;tzliche Dinge wie Texturen habe ich (nat&amp;uuml;rlich) BlitzBasic &amp;uuml;berlassen. Ihr k&amp;ouml;nnt euch das Mesh &amp;uuml;ber eine Funktion holen und dann bearbeiten wie es euch beliebt.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Und hier ist sie nun:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_24_DaDaPhysics.rar&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://upload.wikimedia.org/wikipedia/en/7/71/DLL_icon_on_Windows_Vista.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Wie ihr mit DLLs umgehen m&amp;uuml;sst sollte eigentlich bekannt sein (zusammen mit der DECLS-Datei in den Userlib Ordner eurer BlitzBasic-Installtion packen und gut ist). Xeres hat mich noch darauf hingewiesen, dass man die DLL dem compilierten Programm beilegen muss, wenn mans weiterverbreiten will. Klingt eigentlich logisch :&amp;gt;&lt;br /&gt;Hier ein Beispiel, wie ein Code aussehen k&amp;ouml;nnte:&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Include &amp;quot;DaDaPhysics.bb&amp;quot;&lt;br /&gt;&lt;br /&gt;Graphics3D 800, 600, 0, 2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;pCreateCamera()&lt;br /&gt;&lt;br /&gt;Local ground.RBody = New RBody&lt;br /&gt;&lt;br /&gt;pCreateRect(ground, 800, 20)&lt;br /&gt;pSetDensity(ground, 0)&lt;br /&gt;pSetPosition(ground, 400, 500)&lt;br /&gt;pAddObject(ground)&lt;br /&gt;&lt;br /&gt;Local timer = CreateTimer(60)&lt;br /&gt;&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	RenderWorld&lt;br /&gt;	&lt;br /&gt;	pUpdate()&lt;br /&gt;	&lt;br /&gt;	If MouseHit(1)&lt;br /&gt;		Local box.RBody = New RBody&lt;br /&gt;		&lt;br /&gt;		pCreateRect(box, 50, 50)&lt;br /&gt;		pSetDensity(box, 0.1)&lt;br /&gt;		pSetPosition(box, MouseX(), MouseY())&lt;br /&gt;		pSetRotation(box, 0)&lt;br /&gt;		pAddObject(box)&lt;br /&gt;		pSetColor(box, Rand(0, 255), Rand(0, 255), Rand(0, 255))&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	fpsCount=fpsCount+1&lt;br /&gt;	If MilliSecs()-fpsTime&amp;gt;999&lt;br /&gt;		fpsCur=fpsCount&lt;br /&gt;		fpsCount=0&lt;br /&gt;		fpsTime=MilliSecs()&lt;br /&gt;	EndIf&lt;br /&gt;	Text 10,10,fpsCur&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	WaitTimer(timer)&lt;br /&gt;	Cls&lt;br /&gt;Wend&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;br /&gt;So. Ich habe festgestellt, dass es noch irgendwo ein Speicherleck hat, werde ich fixen sobald ich es finde. Aber im Moment ruhe ich mich darauf aus, dass es funktioniert. Zum Teil st&amp;uuml;rzt der bcc nach Beenden des Programmes ab, keine Ahnung woran das liegt, sollte ich das rausfinden, werde ich auch das noch beheben.&lt;br /&gt;&lt;b&gt;EDIT:&lt;/b&gt; Das Memoryleak ist behoben. Ich bin nicht 100% sicher woran es lag (ich habe tempor&amp;auml;re Polygone in eine Liste gef&amp;uuml;gt und am Schluss die komplette Liste gel&amp;ouml;scht, aber scheinbar bliebt immer was &amp;uuml;ber.. jetzt l&amp;ouml;sch ich sie direkt), aber der Memoryverbrauch ist jetzt stabil. Der (m&amp;ouml;gliche) Absturz nach Beenden des Programmes verwirrt mich nachwievor. F&amp;uuml;r Vorschl&amp;auml;ge bin ich dankbar - gilt auch allgemein f&amp;uuml;r Bug-Reports.&lt;br /&gt;&lt;br /&gt;Hier eine Liste der Funktionen:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code: &lt;/b&gt;&lt;span style=&quot;font-size:0.8em; display:inline;&quot; id=&quot;showcodebox0&quot;&gt; &lt;a href=&quot;javascript&amp;#058;show_code('0')&quot;&gt;[AUSKLAPPEN]&lt;/a&gt; &lt;/span&gt;&lt;span style=&quot;font-size:0.8em; display:none;&quot; id=&quot;hidecodebox0&quot;&gt; &lt;a href=&quot;javascript&amp;#058;hide_code('0')&quot;&gt;[EINKLAPPEN]&lt;/a&gt; &lt;/span&gt;&lt;div id=&quot;codebox0&quot; class=&quot;codebox&quot; style=&quot;max-height: 200px;&quot; onload=&quot;check_code('0');&quot;&gt;pCreateCamera&amp;#40;&amp;#41;&lt;br /&gt;pUpdate&amp;#40;&amp;#41;&lt;br /&gt;pAddObject&amp;#40;RBody&amp;#41;&lt;br /&gt;&lt;br /&gt;pAddVertex&amp;#40;RBody, x, y&amp;#41;&lt;br /&gt;pCreateRect&amp;#40;RBody, w, h&amp;#41;&lt;br /&gt;pCreateCircle&amp;#40;RBody, w, n&amp;#41;&lt;br /&gt;&lt;br /&gt;pSetDensity&amp;#40;RBody, d&amp;#41;&lt;br /&gt;pSetPosition&amp;#40;RBody, x, y&amp;#41;&lt;br /&gt;pSetRotation&amp;#40;RBody, r&amp;#41; &amp;lt;- in DEG&lt;br /&gt;&lt;br /&gt;pSetColor&amp;#40;RBody, red, grn, blu&amp;#41;&lt;br /&gt;&lt;br /&gt;pAddForce&amp;#40;RBody, x, y&amp;#41;&lt;br /&gt;pAddForceR&amp;#40;RBody, fx, fy, px, py&amp;#41; &amp;lt;- Punkt relativ zum K&amp;ouml;rper-Mittelpunkt&lt;br /&gt;pAddForceA&amp;#40;RBody, fx, fy, px, py&amp;#41; &amp;lt;- Punkt absolut in Weltkoordinaten&lt;br /&gt;&lt;br /&gt;pGetPosX&amp;#40;RBody&amp;#41;&lt;br /&gt;pGetPosY&amp;#40;RBody&amp;#41;&lt;br /&gt;pGetVelX&amp;#40;RBody&amp;#41;&lt;br /&gt;pGetVelY&amp;#40;RBody&amp;#41;&lt;br /&gt;pGetRot&amp;#40;RBody&amp;#41;&lt;br /&gt;pGetVelA&amp;#40;RBody&amp;#41;&lt;br /&gt;&lt;br /&gt;pGetMass&amp;#40;RBody&amp;#41;&lt;br /&gt;&lt;br /&gt;pSetGravity&amp;#40;x, y&amp;#41;&lt;br /&gt;&lt;br /&gt;pDegToRad&amp;#40;r&amp;#41;&lt;br /&gt;pRadToDeg&amp;#40;r&amp;#41;&lt;br /&gt;&lt;br /&gt;pGetMesh&amp;#40;RBody&amp;#41;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Dies sollten die wichtigsten Funktionen sein, die man braucht. Sollten noch zus&amp;auml;tzliche ben&amp;ouml;tigt werden, lassen sich diese ohne viel Aufwand (von mir) einbauen, &amp;uuml;ber eine Meldung diesbez&amp;uuml;glich w&amp;auml;re ich froh.&lt;br /&gt;Ich kenne mich Lizenzm&amp;auml;ssig &amp;uuml;berhaupt nicht aus, aber ihr seid eigentlich ziemlich frei die DLL zu benutzen, aber egal was ihr damit anstellt: ich bin nicht verantwortlich daf&amp;uuml;r (!!).&lt;br /&gt;Ihr solltet es aber irgendwo angeben, wenn ihr meine Lib benutzt, damit Leute sehen, von wem die coole Physik in euren Spielen stammt und mich alle lieben werden (weil ich cool bin!).&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_24_DaDaPhysics.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Tja, dies w&amp;auml;re mein Weihnachtsgeschenk an das Forum. Mal sehen was draus wird &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt;&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Sun, 25 Dec 2011 20:26:33 +0100</pubDate>
		</item>

		<item>
			<title>Das Ende ist nah</title>
			<link>https://www.blitzforum.de/worklogs/292/#3186</link>
			<guid>https://www.blitzforum.de/worklogs/292/#3186</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;ich bin gerade dabei, meine T&amp;auml;tigkeiten mit Blitzbasic einzustellen. Die Sprache eignet sich, um schnell kleine Dinge auszuprobieren, aber je l&amp;auml;nger ich versuche etwas Gr&amp;ouml;sseres damit zu machen, kriege ich Probleme. Ausserdem macht die schwindende Unterst&amp;uuml;tzung der Sprache zu schaffen, man kennt das ja. Ich k&amp;ouml;nnte ja nach BlitzMax umsteigen, aber ich habe eigentlich keine Lust f&amp;uuml;r eine (weitere) Sprache zu zahlen :/ Von der Uni her muss ich sowieso mit anderen Sprachen arbeiten (Java, Matlab, Fortran,..), ich habe genug Auswahl um weiter machen zu k&amp;ouml;nnen :&amp;gt; Allerdings darf ich die Dinge hier ja nicht vorstelle, weil mich sonst der b&amp;ouml;se BladeRunner t&amp;ouml;tet.. und tote Darths sind voll uncool!&lt;br /&gt;&lt;br /&gt;Nun denn, ich versuche mal mein Zeug zusammenzutragen, damit ich (vor allem f&amp;uuml;r mich, ich bin ja egoistisch) eine Liste meiner bisherigen Arbeiten habe. (Download-Links sind in den Titeln, booyaah!)&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_23_PhysicsTests.rar&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;DaDaPhysics&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Der aktuelle (irgendwas vor 19.2.11) Stand meiner Physik-Routinen. Ich habe die Einzelteile ein wenig aufgezettelt. Die St&amp;uuml;cke f&amp;uuml;gen sich &amp;uuml;ber ein &lt;i&gt;include&lt;/i&gt; gegenseitig hinzu (was halt gerade ben&amp;ouml;tigt wird), da BlitzBasic das zirkul&amp;auml;re-include unterbindet, ist das kein Problem. Die Programme haben Testfunktionen dabei, die ein kleines Programm starten das die Funktionen aufzeigt.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_23_DaDaPhysics.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Der momentane Stand ist: Man kann (konkave) Polygone eingeben, die automatisch in konvexe Einzelst&amp;uuml;cke zerlegt werden. Das Zeichnen der Polygone unterst&amp;uuml;tzt nebst dem normalen F&amp;uuml;llalgorithmus auch eine M&amp;ouml;glichkeit das Objekt zu texturieren. Weitere Funktionen sind das automatische Zerbrechen von Polygonen (das ~ experimentell ist..) und eine Wasserbox, in der physikalische Objekte schwimmen k&amp;ouml;nnen.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_23_Graphen.rar&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;Graphen&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Von der Uni her etwas Graphentheorie.&lt;br /&gt;AVL-B&amp;auml;ume sind eine Sonderart von bin&amp;auml;ren B&amp;auml;umen, sie sind so gemacht, dass die einzelnen &amp;Auml;ste ausgewogen sind. Dazu muss man beim Einf&amp;uuml;gen und Entfernen bestimmte Regeln beachten. Ein kleines Implementationsproblem ist, dass sich die Wurzel verschieben kann. Also muss die bei jedem Einf&amp;uuml;gevorgang zur&amp;uuml;ckgeliefert und aufgefangen werden.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_23_DaDaGraph.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Der Dijkstra Algorithmus ist eine Art &amp;quot;Pfadfinder&amp;quot; in einem gewichteten Graphen. Hier ist keine Testfunktion dabei, aber die Funktionen und Felder sollten ausf&amp;uuml;hrlich genug erkl&amp;auml;rt sein.&lt;br /&gt;Zus&amp;auml;tzlich noch einen Labyrinth-Generator um einen A*-Pathfinder zu testen.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_23_ConvexHull.rar&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;Grafisches&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Was man so mit Punkten halt machen kann. Zum Beispiel eine Konvexe H&amp;uuml;lle darum ziehen, in &lt;i&gt;O(n log n)&lt;/i&gt;. Dabei ist auch eine Delaunay-Triangulierung. Was fehlt (und was ich eigentlich immer mal machen wollte) ist eine saubere Voronoi-Zerlegung. Aber das sollte eigentlich nicht so schwer sein, sollte man meinen -.- trotzdem hab ichs nie gemacht.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_23_Voronoi.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Als kleines &amp;quot;Abschiedsgeschenk&amp;quot; :&amp;gt; Ich habe die Voronoi-Zerlegung eingebaut. Wird aus der Delaunay-Triangulierung generiert. Zus&amp;auml;tzlich sind noch einige Testfunktionen dabei, die nichtmehr verwendet werden. Die Berechnung eines Dreieck-Umkreises, Linienschnitte und &amp;Auml;hnliches. Das wars.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_23_Math.rar&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;Mathematik&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ein Stringparser, der durch ein bisschen String-Numerik unterst&amp;uuml;tzt wird. Dabei ist eine Funktion, die Terme auf ihre Korrektheit pr&amp;uuml;ft. Unterst&amp;uuml;tz werden automatisch die mir bekannten mathematischen Funktionen (sin, cos,..). Neue einzubauen ist ziemlich einfach (einfach die Liste erg&amp;auml;nzen). Numerisch unterst&amp;uuml;tzt werden Integration, Differentiation und einfache Nullstellenfindung.&lt;br /&gt;Dazu eine kleine Bibliothek um Matrizen zu verwalten und zu benutzen. Die meisten Funktionen r&amp;auml;umen selber auf, aber sicherheitshalber ist ein GarbageCollector dabei. Der Funktionsumfang beinhaltet so ziemlich alles was mir eingefallen ist, bis auf Eigenwerte/Eigenvektoren. (Wens interessiert: Ich habe in Java eine SVD-Zerlegung geschrieben, die die Eigenwerte aus der Matrix numerisch ann&amp;auml;hert.)&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_23_DaDaFigure.rar&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;Figuren&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Der Grund weshalb ich so lange in BlitzBasic verweilte. Meine 2D (gibts auch in 3D, aber nicht so ausgearbeitet..) Bone-Figuren. Mittlerweilen ist auch ein bisschen GUI-Zeug dabei, um damit umzugehen. Geplant war ein Editor um Figuren zu bauen und dann zu animieren, ist auf dem halben Weg stehen geblieben :&amp;gt; (ich hasse Programm Design..). Dabei ist auch eine Funktion um Schatten von der Figur auf einen beliebigen Hintergrund zu projezieren, siehe Testprogramm.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_23_FigureGUI.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Beiliegend sind ein Player und ein Animations-Generator f&amp;uuml;r die Figuren. Die Kn&amp;ouml;pfe sind nicht erkl&amp;auml;rt, aber ihre Funktion sollten aus den Namen im Programm erschlossen werden k&amp;ouml;nnen. Zus&amp;auml;tzlich dabei ist eine allgemein einsetzbare Scrollbar und ein Explorer-&amp;auml;hnliches Dateiauswahl Fenster (allerdings werden noch keine Dateien zur&amp;uuml;ckgeliefert, ist also in dem Zustand nur zur Suche einsetzbar, ein Return fehlt).&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_23_TreeGenerator.rar&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;B&amp;auml;ume&lt;/span&gt;&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Etwas neues, das ich bisher noch nicht gezeigt habe, einen Baum-Generator. In einem beigelegten Input-File kann man verschiedene Parameter einstellen, aus diesen werden dann zuf&amp;auml;llige B&amp;auml;ume generiert. Der Baum ist am Ende als Mesh-Feld in einem Type gespeichert. (Die Funktionsnamen sind vielleicht etwas irref&amp;uuml;hrend.. anfangs war es 2D.)&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_23_Tree.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Die B&amp;auml;ume haben (mit den Parametern im Beispiel) etwa 500-1000 Triangles, h&amp;auml;ngt allerdings stark von der Iterationstiefe und Anzahl Astunterteilungen ab. Zus&amp;auml;tzlich kann man verschiedene Wahrscheinlichkeiten einstellen. Ich hoffe, die Parameternamen sind selbsterkl&amp;auml;rend genug.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;Ende&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So. Das sind wohl so etwa die n&amp;uuml;tzlichsten und mir wichtigsten Programme und Funktionen die ich bisher in BlitzBasic geschrieben habe. Nat&amp;uuml;rlich w&amp;auml;ren noch viele kleine Fitzelchen hier und da, vieles das ich im Worklog mal vorgestellt habe und dann wieder vergessen. Aber die oben erw&amp;auml;hnten St&amp;uuml;cke sind die, die ich immer mal wieder zu Rate ziehe oder verwende um etwas daraus zu machen.&lt;br /&gt;Da ich BB nachwievor f&amp;uuml;r kleine Tests benutzen werde, wird vielleicht hin und wieder etwas Neues entstehen, aber ich werde nichtmehr gezielt f&amp;uuml;r/mit BlitzBasic programmieren. Ich w&amp;uuml;nsche aber allen, die weiterhin mit diesen Sprachen arbeiten viel Spass und Erfolg.&lt;br /&gt;&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Sat, 19 Feb 2011 13:12:11 +0100</pubDate>
		</item>

		<item>
			<title>Ferien ohne Internet</title>
			<link>https://www.blitzforum.de/worklogs/292/#3112</link>
			<guid>https://www.blitzforum.de/worklogs/292/#3112</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;ich war mal wieder ein wenig in den Ferien und habe festgestellt, dass man &amp;auml;usserst produktiv sein kann, wenn man kein Internet hat, das einen st&amp;auml;ndig mit neuem Inhalt ablenkt. Daher habe ich wieder einiges zu pr&amp;auml;sentieren, kleineres sowie gr&amp;ouml;sseres. Dann mal frisch ans Werk.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;RayTracer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ich habe als Teil meiner Maturarbeit mal einen kleinen Raytracer geschrieben. Den fand ich leider nichtmehr, aber ich habe ihn als ziemlich schrecklich in Erinnerung. Ein ziemlich instabiles Konstrukt und viele wichtige Teile hardcoded. Ich habe daher mal beschlossen, einen neuen Versuch zu wagen. Es war nicht das Ziel, einen bis ins letzte optimierte Maschine zu schreiben. Ich wollte einfach nochmal eine Version haben, anhand derer man die Funktionsweise sehen kann, und die ziemlich einfach erweiterbar sein sollte.&lt;br /&gt;Ich habe darauf verzichtet, die &amp;uuml;blichen kleinen Tricks einzubauen (Kugeln als wirkliche Kugeln erkennen z.B), er basiert alleine auf Dreiecken, und bringt daher nicht die &amp;uuml;blichen tollen Bilder einer perfekten Kugel in der sich dann ein Boden perfekt spiegelt.&lt;br /&gt;Auch auf Lichter habe ich bis anhin verzichtet (das k&amp;ouml;nnte noch folgen), aus dem einfachen Grund meiner Faulheit :&amp;gt; Zudem war ich nicht ganz sicher, wie ein Raytracer mit Lichtern umzugehen pflegt, wenn sie z.B auf eine spiegelnde Fl&amp;auml;che treffen. Ich habe es im Moment so gemacht, dass ich eine „Lichtquelle“ (= Kamera) habe, die sich dann auch im Spiegel spiegelt und von dieser dann die Helligkeit der Fl&amp;auml;che berechnet wird.&lt;br /&gt;Der Raytracer unterst&amp;uuml;tzt auch Textur und Heightmap (die noch etwas experimentell ist, aufgrund des Lichtvektors den ich „verzerre“..). Den Teil m&amp;ouml;chte ich gerne etwas genauer erl&amp;auml;utern, weil ich das Problem nun etwa zum dritten mal neu gel&amp;ouml;st habe, und das langsam nervt. Also habe ich mich mal hingesetzt und mir genauer aufgeschrieben, was ich eigentlich berechne. Vielleicht hilft es ja dem einen oder anderen, der ein &amp;auml;hnliches Problem hat.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Problemstellung:&lt;/i&gt; Ich habe einen Punkt &lt;i&gt;P = (x/y/z)&lt;/i&gt; in der Ebene des Dreiecks &lt;i&gt;T = (p1, p2, p3)&lt;/i&gt;. Ich brauche die UV-Koordinaten des Punktes.&lt;br /&gt;Gel&amp;ouml;st werden muss die Gleichung: &lt;i&gt;P = p1 +a *v1 + b *v2&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;L&amp;ouml;sungsansatz:&lt;/i&gt; (Ich gehe davon aus, dass die Funktion einer Matrixmultiplikation bekannt ist)&lt;br /&gt;Die Gleichung ist &amp;uuml;berdefiniert. Ich muss 3 Gleichungen (f&amp;uuml;r x, y und z) nach 2 Parametern (a und b) aufl&amp;ouml;sen. Man benutze hier den Ansatz der minimierung des quadratischen Fehlers.&lt;br /&gt;&lt;br /&gt;Man definiere die Matrix &lt;i&gt;A = [ v1 | v2 ]&lt;/i&gt;, den Vektor &lt;i&gt;x = [a ; b]&lt;/i&gt; und den Vektor &lt;i&gt;b = P – p1&lt;/i&gt;.&lt;br /&gt;Das Gleichungssystem lautet also &lt;i&gt;Ax = b&lt;/i&gt; (immernoch &amp;uuml;berdefiniert). Man multipliziere nun von links die transponierte der Matrix A hinzu, man erh&amp;auml;lt: &lt;i&gt;A' A x = A' b&lt;/i&gt;. Dieses System ist jetzt eine &lt;i&gt;2x2&lt;/i&gt; Matrix mal ein &lt;i&gt;2x1&lt;/i&gt; Vektor gleich einem anderen &lt;i&gt;2x1&lt;/i&gt; Vektor. Also standardm&amp;auml;ssig L&amp;ouml;sbar.&lt;br /&gt;L&amp;ouml;sung: &lt;i&gt;x = (A' A)^-1 * (A' b)&lt;/i&gt;. Da &lt;i&gt;(A' A) = M&lt;/i&gt; eine &lt;i&gt;2x2&lt;/i&gt; Matrix ist, ist die Inversion ziemlich einfach. Die Inverse von M ist &lt;i&gt;M^-1 = 1/det(M) * [m22, -m12; -m21, m11]&lt;/i&gt;. Auch die Determinante ist einfach zu berechnen. &lt;i&gt;det(M) = m11*m22 – m12*m21&lt;/i&gt;. (Wobei durch die spezielle Form hier gilt, dass &lt;i&gt;m12 = m21&lt;/i&gt;).&lt;br /&gt;M kann einfach &amp;uuml;ber die Vektoren berechnet werden, auch &lt;i&gt;y = A' b&lt;/i&gt; ist einfach errechenbar.&lt;br /&gt;Die erhaltenen Koeffizienten &lt;i&gt;a&lt;/i&gt; und &lt;i&gt;b&lt;/i&gt; sind die „pseudo-UV“ Koordinaten.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Bemerkungen:&lt;/i&gt;&lt;br /&gt;- Falls gilt: &lt;i&gt;a &amp;gt;= 0&lt;/i&gt; und &lt;i&gt;b &amp;gt;= 0&lt;/i&gt; und &lt;i&gt;a+b &amp;lt;= 1&lt;/i&gt;, liegt der Punkt innerhalb des Dreiecks. (Kann man sich einfach durch aufzeichnen des Parallelogramms erkl&amp;auml;ren.)&lt;br /&gt;- Die tats&amp;auml;chlichen UV-Koordinaten ergeben sich dann aus &lt;i&gt;C = c1 +a *(c3-c1) +b *(c2-c1)&lt;/i&gt;, wobei &lt;i&gt;ci&lt;/i&gt; die UV-Koordinaten der jeweiligen Punkte &lt;i&gt;pi&lt;/i&gt; sind.&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Function getTextureColor.TVector3D( x#, y#, z#, t.TTrig3D, light.TVector3D )&lt;br /&gt;	Local v0.TVector3D, v1.TVector3D, v2.TVector3D&lt;br /&gt;	&lt;br /&gt;	v0=newTVector3D(t\p3\x-t\p1\x, t\p3\y-t\p1\y, t\p3\z-t\p1\z)&lt;br /&gt;	v1=newTVector3D(t\p2\x-t\p1\x, t\p2\y-t\p1\y, t\p2\z-t\p1\z)&lt;br /&gt;	v2=newTVector3D(x-t\p1\x, y-t\p1\y, z-t\p1\z)&lt;br /&gt;	&lt;br /&gt;	Local dot00#, dot01#, dot02#, dot11#, dot12#&lt;br /&gt;	&lt;br /&gt;	dot00=vDot(v0, v0)&lt;br /&gt;	dot01=vDot(v0, v1)&lt;br /&gt;	dot02=vDot(v0, v2)&lt;br /&gt;	dot11=vDot(v1, v1)&lt;br /&gt;	dot12=vDot(v1, v2)&lt;br /&gt;	&lt;br /&gt;	Delete v0&lt;br /&gt;	Delete v1&lt;br /&gt;	Delete v2&lt;br /&gt;	&lt;br /&gt;	Local invDet#=1./(dot00*dot11 - dot01*dot01)&lt;br /&gt;	Local a#=(dot11*dot02 - dot01*dot12)*invDet&lt;br /&gt;	Local b#=(dot00*dot12 - dot01*dot02)*invDet&lt;br /&gt;	&lt;br /&gt;	Local uv1.TVector3D, uv2.TVector3D&lt;br /&gt;	&lt;br /&gt;	uv1 = newTVector3D(t\p3\u-t\p1\u, t\p3\v-t\p1\v, 0)&lt;br /&gt;	uv2 = newTVector3D(t\p2\u-t\p1\u, t\p2\v-t\p1\v, 0)&lt;br /&gt;	&lt;br /&gt;	Local u#, v#&lt;br /&gt;	&lt;br /&gt;	u = t\p1\u +a *uv1\x +b *uv2\x&lt;br /&gt;	v = t\p1\v +a *uv1\y +b *uv2\y&lt;br /&gt;	&lt;br /&gt;	Delete uv1&lt;br /&gt;	Delete uv2&lt;br /&gt;	&lt;br /&gt;	Local col = getStdRGB(t\tex, u, v)&lt;br /&gt;	Local cr, cg, cb&lt;br /&gt;&lt;br /&gt;	cr = (col And $FF0000	)/$10000&lt;br /&gt;	cg = (col And $FF00	)/$100&lt;br /&gt;	cb = (col And $FF	)&lt;br /&gt;	&lt;br /&gt;	Return newTVector3D(cr, cg, cb)&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_22_Raytracer.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Oben sieht man ein kleines Ergebnis des Raytracers. Ich verzichte darauf, den gesamten Code zu posten. Es gibt hunderte davon im Internet (viele davon um L&amp;auml;ngen besser), und es w&amp;auml;re sinnlos einen weiteren hinzuzuf&amp;uuml;gen.&lt;br /&gt;Ich bin grad noch dabei, den Prozess durch einen Octree etwas zu optimieren. Allerdings fehlt mir momentan eine Methode f&amp;uuml;r Ray-Box-Intersection. Sowas muss ich noch suchen :/ Ich habe es auf 2D mal kurz ausprobiert (Quadtree und Ray-Rect-Intersection). Das sollte sich eigentlich relativ einfach auf 3D konvertieren lassen, und dann das Traceverfahren anpassen und bla bla bla.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Parser&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ich habe vor einiger Zeit mal einen &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/?page=2#2168&quot; target=&quot;_blank&quot;&gt;Stringparser gepostet&lt;/a&gt;. Den wollte ich mal weiterf&amp;uuml;hren und etwas ausbauen. Leider musste ich feststellen, dass er (ganz &amp;auml;hnlich dem alten Raytracer) ziemlich steif programmiert ist und absolut unverst&amp;auml;ndlich. Ich habe ehrlich gesagt keine Ahnung mehr was die H&amp;auml;lfte der Schleifen da macht &lt;img src=&quot;/forum/images/smiles/icon_biggrin.gif&quot; alt=&quot;Very Happy&quot; /&gt; Ich weiss noch, dass ich Klammer gesetzt habe um Punkt-vor-Strich zu erzwingen und dann die Klammerausdr&amp;uuml;cke durch die Auswertung ersetzt habe. Das ganze absolut nicht rekursiv (wieso auch -.-) ... und ja :/ es hat funktioniert, ist aber unm&amp;ouml;glich damit weiterzuarbeiten.&lt;br /&gt;Darum habe ich auch hier neu angefangen \o/. Herausgekommen ist ein Produkt, auf das ich ehrlich stolz bin (jedenfalls im Moment..). Ich habe vor, daraus eine Art „MathPad“ zu machen. Vielleicht erinnert sich der eine oder andere noch an meine &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/?page=2#2168&quot; target=&quot;_blank&quot;&gt;Float Numerics&lt;/a&gt;. Die habe ich jetzt auch so umgeformt, dass sie in meine Parserstruktur passen. Sie ben&amp;ouml;tigen nun nichtmehr fix definierte Funktionen (das ist so geil!), sondern k&amp;ouml;nnen mit einem String aufgerufen werden, der dann als Funktion interpretiert und geparst wird!&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Function parse$( term$ )&lt;br /&gt;	;DebugLog &amp;quot;INPUT: &amp;quot;+term&lt;br /&gt;	&lt;br /&gt;	If checkTerm(term) = 0&lt;br /&gt;		Return &amp;quot;NaN&amp;quot;&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local signs$ = &amp;quot;+-*/^&amp;quot;&lt;br /&gt;	Local signPos, sign$&lt;br /&gt;	&lt;br /&gt;	; --a&lt;br /&gt;	If Mid(term, 1, 2) = &amp;quot;--&amp;quot;&lt;br /&gt;		term = Mid(term, 3, -1)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	For j = 2 To Len(term)&lt;br /&gt;		For i = 1 To Len(signs)&lt;br /&gt;			If Mid(term, j, 1) = Mid(signs, i, 1)&lt;br /&gt;				If signPos = 0&lt;br /&gt;					signPos = j&lt;br /&gt;					sign = Mid(signs, i, 1)&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Local lhs$, rhs$, mt$&lt;br /&gt;	&lt;br /&gt;	lhs = checkForSmallNumbers( Mid(term, 1, signPos-1) )&lt;br /&gt;	rhs = checkForSmallNumbers( Mid(term, signPos+1, -1) )&lt;br /&gt;	&lt;br /&gt;	Local result$&lt;br /&gt;	&lt;br /&gt;	If ( isNumber(lhs)+isText(lhs) = 1 ) And ( isNumber(rhs)+isText(rhs) = 1 )&lt;br /&gt;		&lt;br /&gt;		;/*                      *\&lt;br /&gt;		; * cannot handle &amp;quot;text&amp;quot; *&lt;br /&gt;		; * only numerical calc  *&lt;br /&gt;		;\*                      */&lt;br /&gt;		&lt;br /&gt;		If lhs = &amp;quot;NaN&amp;quot; Or rhs = &amp;quot;NaN&amp;quot; Or lhs = &amp;quot;Infinity&amp;quot; Or rhs = &amp;quot;Infinity&amp;quot;&lt;br /&gt;			result = &amp;quot;NaN&amp;quot;&lt;br /&gt;		Else&lt;br /&gt;			Select sign&lt;br /&gt;				Case &amp;quot;+&amp;quot;&lt;br /&gt;					result = Float(lhs) + Float(rhs)&lt;br /&gt;				Case &amp;quot;-&amp;quot;&lt;br /&gt;					result = Float(lhs) - Float(rhs)&lt;br /&gt;				Case &amp;quot;*&amp;quot;&lt;br /&gt;					result = Float(lhs) * Float(rhs)&lt;br /&gt;				Case &amp;quot;/&amp;quot;&lt;br /&gt;					If Float(rhs) &amp;lt; 10^-8&lt;br /&gt;						result = &amp;quot;NaN&amp;quot;&lt;br /&gt;					Else&lt;br /&gt;						result = Float(lhs) / Float(rhs)&lt;br /&gt;					EndIf&lt;br /&gt;				Case &amp;quot;^&amp;quot;&lt;br /&gt;					result = Float(lhs) ^ Float(rhs)&lt;br /&gt;				Case &amp;quot;&amp;quot;, &amp;quot; &amp;quot;&lt;br /&gt;					result = Float(lhs)&lt;br /&gt;			End Select&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		result = checkForSmallNumbers( result )&lt;br /&gt;		&lt;br /&gt;		;DebugLog &amp;quot;OUTPUT: &amp;quot;+result&lt;br /&gt;		Return result&lt;br /&gt;	Else&lt;br /&gt;		If Instr(term, &amp;quot;(&amp;quot;)&lt;br /&gt;			;klammern&lt;br /&gt;			&lt;br /&gt;			Local bOpen, bPosL, bPosR, calcPos&lt;br /&gt;			Local fnc$&lt;br /&gt;			&lt;br /&gt;			bPosL = Instr(term, &amp;quot;(&amp;quot;)&lt;br /&gt;			&lt;br /&gt;			For j = bPosL To Len(term)&lt;br /&gt;				If Mid(term, j, 1) = &amp;quot;(&amp;quot;&lt;br /&gt;					bOpen = bOpen +1&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				If Mid(term, j, 1) = &amp;quot;)&amp;quot;&lt;br /&gt;					bOpen = bOpen -1&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				If bOpen = 0&lt;br /&gt;					bPosR = j&lt;br /&gt;					&lt;br /&gt;					Exit&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;			&lt;br /&gt;			If bPosL = 1&lt;br /&gt;				;klammer steht ganz links&lt;br /&gt;				&lt;br /&gt;				lhs = Mid(term, 2, bPosR-bPosL-1)&lt;br /&gt;				rhs = Mid(term, bPosR+1, -1)&lt;br /&gt;				&lt;br /&gt;				Return parse( parse(lhs)+rhs )&lt;br /&gt;			;ElseIf bPosR = Len(term)&lt;br /&gt;			;	;klammer steht ganz rechts&lt;br /&gt;			;	&lt;br /&gt;			;	lhs = Mid(term, 1, bPosL-1)&lt;br /&gt;			;	rhs = Mid(term, bPosL+1, bPosR-bPosL-1)&lt;br /&gt;			;	&lt;br /&gt;			;	Return parse( lhs+parse(rhs) )&lt;br /&gt;			Else&lt;br /&gt;				;klammer steht irgendwo in der mitte&lt;br /&gt;				&lt;br /&gt;				lhs = Mid(term, 1, bPosL-1)&lt;br /&gt;				rhs = Mid(term, bPosR+1, -1)&lt;br /&gt;				mt  = Mid(term, bPosL+1, bPosR-bPosL-1)&lt;br /&gt;				&lt;br /&gt;				;functions?&lt;br /&gt;				calcPos = 0&lt;br /&gt;				For j = bPosL-1 To 1 Step -1&lt;br /&gt;					For i = 1 To Len(signs)&lt;br /&gt;						If Mid(term, j, 1) = Mid(signs, i, 1)&lt;br /&gt;							If calcPos = 0&lt;br /&gt;								calcPos = j&lt;br /&gt;							EndIf&lt;br /&gt;						EndIf&lt;br /&gt;					Next&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				fnc = Lower( Mid(term, calcPos+1, bPosL-calcPos-1) )&lt;br /&gt;				If isText(fnc)&lt;br /&gt;					lhs = Mid(term, 1, calcPos)&lt;br /&gt;					&lt;br /&gt;					Select fnc&lt;br /&gt;						Case &amp;quot;sin&amp;quot;&lt;br /&gt;							mt = Sin( Float( parse(mt) ) )&lt;br /&gt;						Case &amp;quot;cos&amp;quot;&lt;br /&gt;							mt = Cos( Float( parse(mt) ) )&lt;br /&gt;						Case &amp;quot;tan&amp;quot;&lt;br /&gt;							mt = Tan( Float( parse(mt) ) )&lt;br /&gt;						Case &amp;quot;asin&amp;quot;&lt;br /&gt;							mt = ASin( Float( parse(mt) ) )&lt;br /&gt;						Case &amp;quot;acos&amp;quot;&lt;br /&gt;							mt = ACos( Float( parse(mt) ) )&lt;br /&gt;						Case &amp;quot;atan&amp;quot;&lt;br /&gt;							mt = ATan( Float( parse(mt) ) )&lt;br /&gt;						Case &amp;quot;sqr&amp;quot;, &amp;quot;sqrt&amp;quot;&lt;br /&gt;							mt = Sqr( Float( parse(mt) ) )&lt;br /&gt;						Default&lt;br /&gt;							termError( lhs+fnc+mt+rhs, calcPos+1, bPosL-1, &amp;quot;Unknown function&amp;quot;)&lt;br /&gt;							&lt;br /&gt;							Return &amp;quot;NaN&amp;quot;&lt;br /&gt;					End Select&lt;br /&gt;					&lt;br /&gt;					Return parse( lhs+mt+rhs )&lt;br /&gt;				Else&lt;br /&gt;					Return parse( lhs+parse(mt)+rhs )&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Else&lt;br /&gt;			;punkt vor strich, hoch vor allem&lt;br /&gt;			&lt;br /&gt;			If Instr(term, &amp;quot;*&amp;quot;) Or Instr(term, &amp;quot;/&amp;quot;) Or Instr(term, &amp;quot;^&amp;quot;)&lt;br /&gt;				Local leftCalc, rightCalc&lt;br /&gt;				&lt;br /&gt;				If Instr(term, &amp;quot;^&amp;quot;)&lt;br /&gt;					For k = 2 To Len(term)&lt;br /&gt;						If Mid(term, k, 1) = &amp;quot;^&amp;quot;&lt;br /&gt;							Exit&lt;br /&gt;						EndIf&lt;br /&gt;					Next&lt;br /&gt;				Else&lt;br /&gt;					For k = 2 To Len(term)&lt;br /&gt;						If Mid(term, k, 1) = &amp;quot;*&amp;quot; Or Mid(term, k, 1) = &amp;quot;/&amp;quot;&lt;br /&gt;							Exit&lt;br /&gt;						EndIf&lt;br /&gt;					Next&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				For i = 1 To Len(signs)&lt;br /&gt;					For j = 2 To Len(term)&lt;br /&gt;						If Mid(term, j, 1) = Mid(signs, i, 1)&lt;br /&gt;							If j &amp;lt; k&lt;br /&gt;								If j &amp;gt; leftCalc&lt;br /&gt;									leftCalc = j&lt;br /&gt;								EndIf&lt;br /&gt;							ElseIf j &amp;gt; k&lt;br /&gt;								; a*-b&lt;br /&gt;								If Not ( j = k+1 And Mid(term, j, 1)=&amp;quot;-&amp;quot; )&lt;br /&gt;									If rightCalc = 0&lt;br /&gt;										rightCalc = j&lt;br /&gt;									EndIf&lt;br /&gt;								EndIf&lt;br /&gt;							EndIf&lt;br /&gt;						EndIf&lt;br /&gt;					Next&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				If leftCalc = 0&lt;br /&gt;					;punkt/hoch steht ganz links&lt;br /&gt;					&lt;br /&gt;					lhs = Mid(term, 1, rightCalc-1)&lt;br /&gt;					rhs = Mid(term, rightCalc, -1)&lt;br /&gt;					&lt;br /&gt;					Return parse( parse(lhs)+rhs )&lt;br /&gt;				ElseIf rightCalc = 0&lt;br /&gt;					;punkt/hoch steht ganz rechts&lt;br /&gt;					&lt;br /&gt;					lhs = Mid(term, 1, leftCalc)&lt;br /&gt;					rhs = Mid(term, leftCalc+1, -1)&lt;br /&gt;					&lt;br /&gt;					Return parse( lhs+parse(rhs) )&lt;br /&gt;				Else&lt;br /&gt;					;punkt/hoch steht in der mitte&lt;br /&gt;					&lt;br /&gt;					lhs = Mid(term, 1, leftCalc)&lt;br /&gt;					rhs = Mid(term, rightCalc, -1)&lt;br /&gt;					mt  = Mid(term, leftCalc+1, rightCalc-leftCalc-1)&lt;br /&gt;					&lt;br /&gt;					Return parse( lhs+parse(mt)+rhs )&lt;br /&gt;				EndIf&lt;br /&gt;			Else&lt;br /&gt;				;normale links -&amp;gt; rechts rechnung&lt;br /&gt;				&lt;br /&gt;				Local calcFound = 0&lt;br /&gt;				Local calcPos1, calcPos2&lt;br /&gt;				&lt;br /&gt;				For i = 1 To Len(signs)&lt;br /&gt;					For j = 2 To Len(term)&lt;br /&gt;						If Mid(term, j, 1) = Mid(signs, i, 1)&lt;br /&gt;							If calcFound = 0&lt;br /&gt;								calcPos1 = j&lt;br /&gt;								&lt;br /&gt;								calcFound = calcFound +1&lt;br /&gt;							ElseIf calcFound = 1&lt;br /&gt;								; a+-b&lt;br /&gt;								If Not ( Mid(term, j, 1) = &amp;quot;-&amp;quot; And j = calcPos1+1 )&lt;br /&gt;									calcPos2 = j&lt;br /&gt;									&lt;br /&gt;									calcFound = calcFound +1&lt;br /&gt;								EndIf&lt;br /&gt;							EndIf&lt;br /&gt;						EndIf&lt;br /&gt;					Next&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				lhs = Mid(term, 1, calcPos2-1)&lt;br /&gt;				rhs = Mid(term, calcPos2, -1)&lt;br /&gt;				&lt;br /&gt;				Return parse( parse(lhs)+rhs )&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;br /&gt;Geplant waren zus&amp;auml;tzlich zur normalen Termauswertung: Integration, Differentiation und ein einfacher Solver (der momentan eine „b&amp;ouml;se“ Schw&amp;auml;che hat, man muss die Gleichung so umformen, dass sie =0 ist). Der Solver soll eigentlich mal noch ausgebaut werden. Die Schw&amp;auml;che entfernt (nat&amp;uuml;rlich) und dann soll er auch mehrdimensionale lineare (und vllt nicht-lineare?) Gleichungssysteme l&amp;ouml;sen k&amp;ouml;nnen! Daf&amp;uuml;r w&amp;uuml;rde ich dann den Parser mit meiner TMatrix-Klasse verbinden, die ich auch schon vorgestellt habe.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_22_ParseEditor.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Auf dem Bild sieht man einige Beispiele die ich in meinem provisorischen „MathPad“ einprogrammiert habe. Daf&amp;uuml;r habe ich auch voll professionell eine GetKey-Input Routine geschrieben, die dann in Textzeilen umgewandelt wird. Man kann auch scrollen und mit dem Cursor irgendwo in der Mitte Text &amp;auml;ndern (eintippen, l&amp;ouml;schen). Sollte ich irgendwann einmal die Musse haben, werde ich einen kleinen Editor darum herum programmieren, mit (cooler) GUI und so. Aber wahrscheinlicher ist, (da ich das Ganze eh schon nach Java portiert habe), dass ich die dort (= Java) schon vorhandene GUI verwenden werde.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_22_Parser.rar&quot; target=&quot;_blank&quot;&gt;Download: Parser und Numerics&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_22_MathPad.rar&quot; target=&quot;_blank&quot;&gt;Download: (Pseudo-) Editor&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TMatrix&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Im Zuge des Parsers habe ich mir auch nochmal die TMatrix-Klasse angesehen. Dabei habe ich festgestellt, dass noch zwei wichtige Funktionen fehlten. (Wahrscheinlich fehlen noch mehr, die werde ich dann implementieren, sobald es mir auff&amp;auml;llt.)&lt;br /&gt;&lt;i&gt;tMInvert:&lt;/i&gt; Diese Funktion hat mich einige Zeit gekostet. Vor allem, weil ich das Prinzip falsch im Kopf hatte.. Ich habe es dann aber nach einigem herumprobieren mit Matlab geschafft, herauszufinden was ich &amp;uuml;berhaupt programmieren muss. Und es dann flux in meine Klasse eingebaut. Matrizen k&amp;ouml;nnen nun invertiert werden. Sie muss nat&amp;uuml;rlich quadratisch und nicht singul&amp;auml;r sein.&lt;br /&gt;&lt;i&gt;tMDeterminant:&lt;/i&gt; Keine Ahnung, warum ich die nicht schon viel fr&amp;uuml;her eingebaut hab. Die Determinante wird rekursiv &amp;uuml;ber die Unterdeterminanten berechnet. Die einzige Schwierigkeit dabei ist, die Untermatrix zu schreiben, aber selbst das geht nach 5min.&lt;br /&gt;&lt;i&gt;Geplant:&lt;/i&gt; Was ich noch vorhatte war, das Implementieren einer L&amp;ouml;sung f&amp;uuml;r unausgeglichene Systeme. Wenn also 3 Gleichungen f&amp;uuml;r nur 2 Variabeln vorhanden sind (z.B). Das w&amp;auml;re auch kein grosses Ding, ich m&amp;uuml;sste statt &lt;i&gt;Ax = b&lt;/i&gt; einfach &lt;i&gt;A'Ax = A'b&lt;/i&gt; l&amp;ouml;sen. Ich k&amp;ouml;nnte das sogar direkt in den Gauss-L&amp;ouml;ser einbauen, f&amp;uuml;r jeden Fall (bei ausgeglichenen Systemen &amp;auml;ndert sich nichts an der L&amp;ouml;sung). Dies w&amp;uuml;rde allerdings einen Mehraufwand bedeuten und ich bin mir nicht sicher, ob ich das einfach so still und heimlich durchf&amp;uuml;hren lassen sollte :/ Zudem bin ich mir nicht mehr sicher, ob das auch f&amp;uuml;r unterdefinierte Systeme (2 Gleichungen f&amp;uuml;r 3 Variabeln) funktioniert, das muss ich nochmal kurz nachlesen.&lt;br /&gt;Ebenfalls wollte ich Eigenwerte und Eigenvektoren ausrechnen, aber das ist ziemlich schwer musste ich feststellen. Ich habs nicht einmal hingekriegt, das charakteristische Polynom richtig aufzustellen, und ohne das.. kein Gras. Und auch keine Eigenwerte und damit auch keine Eigenvektoren. Traurig. Ich muss mir wohl mal den &lt;a href=&quot;http://en.wikipedia.org/wiki/Singular_value_decomposition&quot; target=&quot;_blank&quot;&gt;SVD&lt;/a&gt;-Algorithmus ansehen.&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Function tMInvert.TMatrix(A.TMatrix, flag=False)&lt;br /&gt;	Local R.TMatrix, Ac.TMatrix, v#, c#, tmp#, switch&lt;br /&gt;	&lt;br /&gt;	;f&amp;uuml;r quadratische Matrizen, A=R^{n,n}&lt;br /&gt;	If A\n&amp;lt;&amp;gt;A\m&lt;br /&gt;		RuntimeError &amp;quot;Matrix must be square&amp;quot;&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	R=tMIdentity(A\n)&lt;br /&gt;	Ac=tMClone(A)&lt;br /&gt;	&lt;br /&gt;	For i=1 To A\n&lt;br /&gt;		v=tMGetValue(Ac, i, i)&lt;br /&gt;		&lt;br /&gt;		If Abs(v)&amp;lt;10^-6&lt;br /&gt;			switch = False&lt;br /&gt;			For ii=i+1 To A\n&lt;br /&gt;				If Abs(tMGetValue(Ac, ii, i)) &amp;gt; 10^-6&lt;br /&gt;					switch = True&lt;br /&gt;					&lt;br /&gt;					For jj=1 To A\n&lt;br /&gt;						tmp = tMGetValue(Ac, i, jj)&lt;br /&gt;						&lt;br /&gt;						tMSetValue(Ac, tMGetValue(Ac, ii, jj), i, jj)&lt;br /&gt;						tMSetValue(Ac, tmp, ii, jj)&lt;br /&gt;						&lt;br /&gt;						tmp = tMGetValue(R, i, jj)&lt;br /&gt;						&lt;br /&gt;						tMSetValue(R, tMGetValue(R, ii, jj), i, jj)&lt;br /&gt;						tMSetValue(R, tmp, ii, jj)&lt;br /&gt;					Next&lt;br /&gt;					&lt;br /&gt;					v = tMGetValue(Ac, i,i)&lt;br /&gt;					&lt;br /&gt;					Exit&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;			&lt;br /&gt;			If Not switch&lt;br /&gt;				RuntimeError &amp;quot;Matrix is close to singular&amp;quot;&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		;Ac(i,i) wird zu 1&lt;br /&gt;		For k=1 To A\n&lt;br /&gt;			tMSetValue(Ac, tMGetValue(Ac, i, k)/v, i, k)&lt;br /&gt;			tMSetValue(R, tMGetValue(R, i, k)/v, i, k)&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		;Ac(:,j) wird zu [1;0..]&lt;br /&gt;		For j=i+1 To A\n&lt;br /&gt;			v=tMGetValue(Ac, j, i)&lt;br /&gt;			&lt;br /&gt;			For k=1 To A\n&lt;br /&gt;				tMSetValue(Ac, tMGetValue(Ac, j, k)-v*tMGetValue(Ac, i, k), j, k)&lt;br /&gt;				tMSetValue(R, tMGetValue(R, j, k)-v*tMGetValue(R, i, k), j, k)&lt;br /&gt;			Next&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		;Ac(:,j) wird zu [0..;1;0..]&lt;br /&gt;		For k=i-1 To 1 Step -1&lt;br /&gt;			v = tMGetValue(Ac, k, i)&lt;br /&gt;			&lt;br /&gt;			For j=1 To A\n&lt;br /&gt;				tMSetValue(Ac, tMGetValue(Ac, k,j)-v*tMGetValue(Ac, i,j), k,j)&lt;br /&gt;				tMSetValue(R, tMGetValue(R, k,j)-v*tMGetValue(R, i,j), k,j)&lt;br /&gt;			Next&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;;	For i=A\n To 2 Step -1&lt;br /&gt;;		For k=i-1 To 1 Step -1&lt;br /&gt;;			v = tMGetValue(Ac, k, i)&lt;br /&gt;;			&lt;br /&gt;;			For j=1 To A\n&lt;br /&gt;;				tMSetValue(Ac, tMGetValue(Ac, k,j)-v*tMGetValue(Ac, i,j), k,j)&lt;br /&gt;;				tMSetValue(R, tMGetValue(R, k,j)-v*tMGetValue(R, i,j), k,j)&lt;br /&gt;;			Next&lt;br /&gt;;		Next&lt;br /&gt;;	Next&lt;br /&gt;	&lt;br /&gt;	Delete Ac&lt;br /&gt;	&lt;br /&gt;	R\FLAG=flag&lt;br /&gt;	Return R&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Function tMDeterminant#(A.TMatrix)&lt;br /&gt;	Local d#, subA.TMatrix&lt;br /&gt;	&lt;br /&gt;	;f&amp;uuml;r quadratische Matrizen, A=R^{n,n}&lt;br /&gt;	If A\n&amp;lt;&amp;gt;A\m&lt;br /&gt;		RuntimeError &amp;quot;Matrix must be square&amp;quot;&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If A\n=2&lt;br /&gt;		Return tMGetValue(A, 1,1)*tMGetValue(A, 2,2) - tMGetValue(A, 1,2)*tMGetValue(A, 2,1)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	d = 0&lt;br /&gt;	For j=1 To A\n&lt;br /&gt;		s = 1-2*((j+1) Mod 2)&lt;br /&gt;		&lt;br /&gt;		subA = tMCreateMatrix(A\n-1, A\n-1)&lt;br /&gt;		&lt;br /&gt;		For i=2 To A\n&lt;br /&gt;			For k=1 To A\n&lt;br /&gt;				If k &amp;lt;&amp;gt; j&lt;br /&gt;					tMSetValue(subA, tMGetValue(A, i,k), i-1, k-(k&amp;gt;j))&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		d = d + s*tMGetValue(A, 1,j) *tMDeterminant(subA)&lt;br /&gt;		Delete subA&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return d&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_22_TMatrixClass.rar&quot; target=&quot;_blank&quot;&gt;Download&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Ich habe noch eine weitere Funktion erg&amp;auml;nzt (allerdings nicht im Download-Link, m&amp;uuml;sste von Hand noch hinzugef&amp;uuml;gt werden). Die QR-Zerlegung einer Matrix. Es zerlegt die Matrix A in &lt;i&gt;A=Q*R&lt;/i&gt;, wobei Q orthogonal (&lt;i&gt;QQ' = 1&lt;/i&gt;) und unit&amp;auml;r (&lt;i&gt;QQ* = 1&lt;/i&gt;), und R eine obere Dreiecksmatrix ist. Weil BB nur einen R&amp;uuml;ckgabewert liefern kann, wird die Inputmatrix A mit der R Matrix gef&amp;uuml;llt und Q zur&amp;uuml;ckgegeben. Will man sein A behalten, m&amp;uuml;sste man es also mit &lt;i&gt;tMQR(tMClone(A))&lt;/i&gt; aufrufen (auch wenn man dann keine Referenz auf den Klon von A hat..). Komischerweise bin ich mir &amp;uuml;berhaupt nichtmehr sicher, wof&amp;uuml;r man die QR-Zerlegung &amp;uuml;berhaupt gebraucht hat &lt;img src=&quot;/forum/images/smiles/icon_biggrin.gif&quot; alt=&quot;Very Happy&quot; /&gt; Ich erinner mich noch schwach an irgendwelche Gleichungssysteme oder so. Wahrscheinlich f&amp;uuml;r unausgeglichene Systeme (&amp;auml;hnlich zum Problem im Raytracer), weil dann in der Rechnung &lt;i&gt;M = A'A&lt;/i&gt; ein paar Teile wegfallen, und das Resultat einfacher (+einfacher zu berechnen) ist.&lt;br /&gt;&lt;i&gt;Bemerkung:&lt;/i&gt; Die Zerlegung ruft den &lt;i&gt;tMGC&lt;/i&gt; auf, weil in der Routine viele nicht-referenzierte Matrizen erstellt werden, die den Speicher zum&amp;uuml;llen. Man sollte also seine Matrizen mit den richtigen keep-Flags versehen, wenn man sie auch nach der QR-Routine noch haben m&amp;ouml;chte :&amp;gt;&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]; TMatrix tMQR, zerlegt A zu A=Q*R, wobei das resultierende A=R, und Q zur&amp;uuml;ckgeliefert wird&lt;br /&gt;;&lt;br /&gt;; A: TMatrix, die zu zerlegende Matrix&lt;br /&gt;; flag: Bool, die keep-flag der Matrix Q&lt;br /&gt;Function tMQR.TMatrix(A.TMatrix, flag=False)&lt;br /&gt;	Local n, m, Q.TMatrix, R.TMatrix, KMax, P.TMatrix, w.TMatrix, s#, t#, c#&lt;br /&gt;	&lt;br /&gt;	n = A\n&lt;br /&gt;	m = A\m&lt;br /&gt;	&lt;br /&gt;	Q = tMIdentity(m)&lt;br /&gt;	R = A&lt;br /&gt;	&lt;br /&gt;	If m=n&lt;br /&gt;		KMax = n-1&lt;br /&gt;	Else&lt;br /&gt;		KMax = n&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	For k = 1 To KMax&lt;br /&gt;		s = 0&lt;br /&gt;		For j = k To m&lt;br /&gt;			s = s +R\e[GetI(j,k, n,m)]^2&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		s = Sqr(s)&lt;br /&gt;		t = R\e[GetI(k,k, n,m)]&lt;br /&gt;		c = s *(s +Abs(t))&lt;br /&gt;		&lt;br /&gt;		w = tMCreateMatrix(m, 1)&lt;br /&gt;		w\e[GetI(k,1, m,1)] = t +s *Sgn(t)&lt;br /&gt;		&lt;br /&gt;		For j = k+1 To m&lt;br /&gt;			w\e[GetI(j,1, m,1)] = R\e[GetI(j,k, n,m)]&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		P = tMSubtract( tMIdentity(m), tMScale(1./c, tMMultiply( w, tMTranspose(w) ) ) )&lt;br /&gt;		&lt;br /&gt;		Q = tMMultiply(P, Q)&lt;br /&gt;		R = tMMultiply(P, R)&lt;br /&gt;		&lt;br /&gt;		Delete P&lt;br /&gt;		Delete w&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Q = tMTranspose(Q)&lt;br /&gt;	&lt;br /&gt;	For i = 1 To n&lt;br /&gt;		For j = 1 To m&lt;br /&gt;			idx = GetI(i, j, n, m)&lt;br /&gt;			&lt;br /&gt;			A\e[idx] = R\e[idx]&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Q\FLAG = True&lt;br /&gt;	A\FLAG = True&lt;br /&gt;	tMGC()&lt;br /&gt;	&lt;br /&gt;	Q\FLAG = flag&lt;br /&gt;	A\FLAG = flag&lt;br /&gt;	Return Q&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;On furhter notice&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ich habe festgestellt, dass ich immer wieder die gleichen Funktionen und Types schreibe. Also habe ich angefangen, zu kopieren und alles in eine Sammlung zu packen. Es handelt sich um N&amp;uuml;tzlichkeiten und Funktionen im 3D-Raum. Vektoren, Dreiecke und alles (jedenfalls alles was mir bisher eingefallen ist zu verwenden) was man davon braucht. Also Vektorrechnungen, Schnitte (kein Ebenen-Ebenen-Schnitt bisweilen.. l&amp;auml;sst sich aus zwei Vektor-Ebenen Schnitten basteln) und solches Zeug. Zudem sind noch meine Funktionen f&amp;uuml;r Texturen und Heightmaps drin.&lt;br /&gt;Ich weiss nicht, wieviel es anderen n&amp;uuml;tzen wird, deshalb werde ich keinen Code posten. Aber &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_22_DaDa3DUtilities.rar&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt; ist ein Link mit der Sammlung. Nur ein &lt;i&gt;include&lt;/i&gt; entfernt von der Verwendung, hussay \o/&lt;br /&gt;&lt;br /&gt;F&amp;uuml;r mein Figuren Animations Ding vom &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/#2694&quot; target=&quot;_blank&quot;&gt;vorletzten Mal&lt;/a&gt; habe ich eine kleine Erweiterung gebastelt, die aus den (quadratischen, 2 Trig) Bone-Sprites Dreiecke ausliest, die das Bild ungef&amp;auml;hr ann&amp;auml;hern. Die Dreiecke werden in einem weiteren Mesh gespeichert, aus dem ich irgendwann Schatten zu machen hoffe. Die Vorrichtung daf&amp;uuml;r habe ich das &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/#3025&quot; target=&quot;_blank&quot;&gt;letzte Mal&lt;/a&gt; vorgestellt. (Dort musste ich noch einen kleinen Fehler verbessern, nichts grossartiges, sowas zwischen Tipp- und Denkfehler halt.) Allerdings fehlt nachwievor ein kluger Hintergrund.. Meh.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_22_FigureShadow.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In meiner Physikimplementation habe ich die Art der Texturbeschreibung ge&amp;auml;ndert. Fr&amp;uuml;her war es ein „Ausschnitt“ aus der Textur (angegeben wurde oben links und Dimension, danach wurde das Objekt reingepasst), jetzt arbeitet es mit UV-Koordinaten. Das Problem dabei ist, dass es keine Dreiecke sind, sondern Polygone. Es werden daher nur die ersten drei Punkte des K&amp;ouml;rpers betrachtet, aus denen werden dann die UV-Koordinaten des Punktes berechnet. Das geht ziemlich analog zur Methode, die ich im Raytracer erkl&amp;auml;rt habe, mit dem Unterschied, dass man das System direkt l&amp;ouml;sen kann (weil 2D-&amp;gt;2D transformation). Ich habe dann auch die UV-Koordinaten beim Splitterprozess neu gesetzt, funktioniert ganz gut. Feldtest folgte mit einer etwas &amp;auml;lteren Version, sollte aber auch in der neuen 1:1 funktionieren, da ich eigentlich nur Type-/ Funktionsnamen ge&amp;auml;ndert habe (der &amp;Uuml;bersicht halber..).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ende&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, das w&amp;auml;rs vorerst. Ich muss jetzt wieder etwas f&amp;uuml;r die Uni tun, und s pielen, und Internet. Ich lass wohl mal wieder was von mir h&amp;ouml;ren, hier, in meinem Worklog.&lt;br /&gt;&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Sun, 09 Jan 2011 13:35:53 +0100</pubDate>
		</item>

		<item>
			<title>Eleganz ist für Wahnsinnige</title>
			<link>https://www.blitzforum.de/worklogs/292/#3025</link>
			<guid>https://www.blitzforum.de/worklogs/292/#3025</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;ich habe hier schon lange nichtsmehr gepostet wie mir scheint. Das hat einen ziemlich einfachen Grund, er heisst &amp;quot;Starcraft 2&amp;quot;, ich bin ein riesen Fanboy des Spiels, wie schon vom ersten Spiel. Ich schaue auch gerne Turniere von richtig guten Spielern. Das nimmt schon einige Zeit in Anspruch, da kann man nichtmehr programmieren. Ein weiterer Grund ist (mal wieder) die Universit&amp;auml;t (hach, RL..), da lerne ich gerade Fortran (geniale Sprache, solltet ihr euch mal reinziehn!) und mache wenig wirklich Essentielles, das mir Ansporn f&amp;uuml;r wirkliche Programmierarbeiten gibt.&lt;br /&gt;Ich habe zwar ein etwas gr&amp;ouml;sseres Projekt in Planung, aber davon existieren vor allem Theorien und Konzepte, aber nichts tats&amp;auml;chlich Brauchbares, hihi. Ich br&amp;auml;uchte da sowieso noch Grafiker und Sounddesigner, damit das wirklich Sinn machen wird. Horrorspiele leben so extrem von der Stimmung, die man halt irgendwie r&amp;uuml;berbringen muss, da kann ich mit tollen Algorithmen nicht viel reissen.&lt;br /&gt;&lt;br /&gt;Und damit w&amp;auml;re ich auch beim Punkt angekommen. Tolle Algorithmen. Die meisten werden wahrscheinlich den Titel gelesen haben und sich fragen, was ich damit meine. Ich habe vor, euch jetzt mal durch einen Prozess zu f&amp;uuml;hren, wie ich programmiere. Mal sehen wie vern&amp;uuml;nftig das Ergebnis wird &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;&lt;b&gt;Schritt 1: Der Plan&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Motivation:&lt;/b&gt; Ein vern&amp;uuml;nftiges Horrorspiel braucht vern&amp;uuml;nftige Schatten. Schatten haben mich in der Kindheit immer erschreckt, und konnte nicht schlafen, weil der Baum vor dem Fenster seltsame Schatten an die Wand warf.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Idee:&lt;/b&gt; Man betrachte vorerst eine Linie. Der geworfene Schatten passt sich dem Gel&amp;auml;nde an. Das heisst, ich suche den Anfangs- und Endpunkt, dazwischen kann ich einfach den Trigs entlangfahren. Damit das einigermassen funktioniert, muss ich den Dreiecken ihre Nachbarn zuweisen (jedes Dreieck hat 3). Dann hole ich den zweiten Punkt &amp;uuml;bers Lot auf die Ebene, damit ich die Projektion der Linie in der Ebene des Dreiecks habe. Anschliessend pr&amp;uuml;fe ich, auf welcher Seite diese Linie das Dreieck verl&amp;auml;sst, setze diesen Nachbarn als neues aktives Dreieck und wiederhole den Prozess bis ich im selben Dreieck wie der Endpunkt bin.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_21_ShadowTracing.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Probleme:&lt;/b&gt; Das zuordnen der Nachbarn muss eindeutig sein, das heisst, dass ich nur einfache Geometrien zulassen kann. Also sowas \|/ wird zu problemen f&amp;uuml;hren, w&amp;auml;hrend sowas \/ v&amp;ouml;llig zul&amp;auml;ssig ist. Jedes Dreieck darf also maximal 3 Nachbarn haben. Das hat mich nat&amp;uuml;rlich etwas gest&amp;ouml;rt, aber meine Idee nicht wirklich behindert, weil ich sowieso nicht vor hatte, komplizierte Hintergr&amp;uuml;nde zu basteln.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Implementation:&lt;/b&gt; Der Algorithmus wird umgesetzt, getestet und bis zur Funktionsf&amp;auml;higkeit gebracht. Toll!&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;&lt;b&gt;Schritt 2: Der Tag danach&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Am n&amp;auml;chsten Tag versucht man nat&amp;uuml;rlich, bei seinen Kollegen etwas Eindruck zu schinden und erz&amp;auml;hlt von seiner tollen Idee und dem grossartigen Algorithmus, den man sich ausgedacht hat. Irgendwann kam dann die Frage, wie man das optimieren k&amp;ouml;nnte. Da habe ich zu rechnen angefangen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code: &lt;/b&gt;&lt;span style=&quot;font-size:0.8em; display:inline;&quot; id=&quot;showcodebox1&quot;&gt; &lt;a href=&quot;javascript&amp;#058;show_code('1')&quot;&gt;[AUSKLAPPEN]&lt;/a&gt; &lt;/span&gt;&lt;span style=&quot;font-size:0.8em; display:none;&quot; id=&quot;hidecodebox1&quot;&gt; &lt;a href=&quot;javascript&amp;#058;hide_code('1')&quot;&gt;[EINKLAPPEN]&lt;/a&gt; &lt;/span&gt;&lt;div id=&quot;codebox1&quot; class=&quot;codebox&quot; style=&quot;max-height: 200px;&quot; onload=&quot;check_code('1');&quot;&gt;Anfangspunkt&amp;#58; Muss alle Dreiecke durchgehen &amp;#40;um den n&amp;auml;chsten Schnittpunkt zu finden&amp;#41; -&amp;gt; n&lt;br /&gt;Endpunkt&amp;#58; Nochmal alle Dreiecke durchgenen -&amp;gt; n&lt;br /&gt;&amp;#40;zugegeben, das k&amp;ouml;nnte man optimieren indem man die Punkte gleichzeitig sucht.&amp;#41;&lt;br /&gt;&lt;br /&gt;Trajektorie zwischen den Punkten&amp;#58; Maximal alle Dreiecke -&amp;gt; n&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Wie man sieht ist das Ergebnis der Messung &lt;b&gt;3n&lt;/b&gt; (oder 2n wie mans nimmt..). Das brachte mich nat&amp;uuml;rlich etwas ins gr&amp;uuml;beln. Wenn ich einfach &amp;quot;Bruteforce&amp;quot;m&amp;auml;ssig den Schatten auf jedes Dreieck einzeln werfe, kommte ich mit einem linearen Aufwand von nur &lt;b&gt;n&lt;/b&gt; klar. Der tolle Algorithmus vom Vortag ist weniger effizient.&lt;br /&gt;*Seufz* Also wird er umgeschrieben, die elegante L&amp;ouml;sung wird weggeworfen, der uncoole Algorithmus wird erstmal implementiert und getestet. Funktioniert nat&amp;uuml;rlich wunderbar (weil er so simpel ist) und spart etwa 5 verschiedene Funktionen, gut.&lt;br /&gt;&lt;br /&gt;Mit diesem Code wird jetzt weitergearbeitet (nat&amp;uuml;rlich, ist ja die effizientere L&amp;ouml;sung). Erweiterung auf Dreiecke folgt auf dem Fusse. Man projeziert alle drei Linien auf die Dreiecksebene und schneidet sie ab, sobald sie das Dreieck verlassen. Hierbei gibt es 3 m&amp;ouml;gliche F&amp;auml;lle:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_21_TrigLinePossibilities.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fall 1 kann doppelt vorkommen, daf&amp;uuml;r pr&amp;uuml;ft man einfach, ob Punkt1 oder Punkt2 der Linie innerhalb des Dreiecks ist, und tauscht dann aus, kein Problem. Der n&amp;auml;chste Schritt ist es dann, die erhaltenen Punkte zu Dreiecken zu verbinden.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;&lt;b&gt;Schritt 3: Die Kapitulation&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bei diesem Schritt sind mir dann nach und nach neue Probleme aufgefallen, die ich nicht bedacht habe. Es gibt hier 7 F&amp;auml;lle, wie sich zwei Dreiecke &amp;uuml;berlagern k&amp;ouml;nnen, aber nur drei verschiedene Zahlen von m&amp;ouml;glichen Schnittpunkten, auch hierzu wieder ein Bild zur Erkl&amp;auml;rung:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_21_shadowPossibilities.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wenn ich jetzt also weniger als 6 Schnittpunkte f&amp;uuml;r das projizierte Dreieck habe, muss ich anfangen zu pr&amp;uuml;fen, ob Eckpunkte drin liegen. Und genau hier ist etwa der Punkt, an dem ich aufgegeben habe. Wahrscheinlich k&amp;ouml;nnte man da irgendwie zwischen den Punkten was rechnen, ob man den Eckpunkt mit einbeziehen muss oder nicht. Aber ehrlich? Ich w&amp;uuml;rde vermuten, das wird wieder aufw&amp;auml;ndiger, als einfach die drei Punkte zu pr&amp;uuml;fen.&lt;br /&gt;F&amp;uuml;r das Verkn&amp;uuml;pfen zu Dreiecken mache ich auch etwas ziemlich tolles: Ich nehme alle M&amp;ouml;glichkeiten. Ich weiss, dass ich maximal 6 Punkte habe, das f&amp;uuml;hrt zu maximal 24 Dreiecken. Irgendetwas intelligentes zu schreiben, das dieses kleine System zu Punkten verkn&amp;uuml;pft kommt (mit ziemlicher Sicherheit) teurer als einfach alle M&amp;ouml;glichkeiten zu &amp;uuml;berlagern.&lt;br /&gt;Ich kenne zwar Trigonalisierungsalgorithmen f&amp;uuml;r beliebige Punkte (ich weiss ja, dass der Schatten des Dreiecks konvex sein wird), aber dazu m&amp;uuml;sste ich einen Basiswechsel ins System des Dreiecks durchf&amp;uuml;hren (damit ichs in 2D habe), und &amp;auml;h .. das ist einiges an Rechenaufwand -&amp;gt; lohnt sich nicht f&amp;uuml;r ein solch kleines System.&lt;br /&gt;So! Das wars! Eleganz? Ohne mich. Akhams razor! DONE!&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 14px;&quot;&gt;&lt;b&gt;Abschluss&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Im Anhang (also in etwa 4-5 Zeilen) folgt das Ergebnis. In einem etwas sp&amp;auml;teren Edit wird dann irgendwann ein kleiner Hintergrund folgen, auf den irgend ein bewegter Schatten projiziert werden wird. Aber solches Zeug muss ich als grafikalischer Anf&amp;auml;nger noch erst erledigen, das kann etwas dauern :&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_21_ShadowResult.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Und hier der Code dazu (ist noch nicht wirklich aufger&amp;auml;umt, auch das wird in einem weiteren Edit noch folgen) ist auch hier zu finden:&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/* LIB CODE */;&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Utilities&lt;br /&gt;; *		TVector3D&lt;br /&gt;; *			Vector for Points (with additional offset for normals)&lt;br /&gt;; *		TTrig3D&lt;br /&gt;; *			Background Triangle (will be projected on)&lt;br /&gt;; *		TSimpleTrig3D&lt;br /&gt;; *			Foreground Triangle (will be projected)&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TVector3D&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;	Field z#&lt;br /&gt;	&lt;br /&gt;	Field d#&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TTrig3D&lt;br /&gt;	Field p1.TVector3D&lt;br /&gt;	Field p2.TVector3D&lt;br /&gt;	Field p3.TVector3D&lt;br /&gt;	&lt;br /&gt;	Field n.TVector3D&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TSimpleTrig3D&lt;br /&gt;	Field p1.TVector3D&lt;br /&gt;	Field p2.TVector3D&lt;br /&gt;	Field p3.TVector3D&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTVector3D.TVector3D(x#, y#, z#)&lt;br /&gt;	Local v.TVector3D=New TVector3D&lt;br /&gt;	&lt;br /&gt;	v\x=x&lt;br /&gt;	v\y=y&lt;br /&gt;	v\z=z&lt;br /&gt;	&lt;br /&gt;	Return v&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function vNormalise(v.TVector3D)&lt;br /&gt;	Local il#=1./Sqr(v\x*v\x + v\y*v\y + v\z*v\z)&lt;br /&gt;	&lt;br /&gt;	v\x=v\x*il&lt;br /&gt;	v\y=v\y*il&lt;br /&gt;	v\z=v\z*il&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function vDot#(v1.TVector3D, v2.TVector3D)&lt;br /&gt;	Return v1\x*v2\x + v1\y*v2\y + v1\z*v2\z&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function vCross.TVector3D(v1.TVector3D, v2.TVector3D)&lt;br /&gt;	Return newTVector3D(v1\y*v2\z-v2\y*v1\z, v2\x*v1\z-v1\x*v2\z, v1\x*v2\y-v2\x*v1\y)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function vDist#(v1.TVector3D, v2.TVector3D)&lt;br /&gt;	Return Sqr( (v1\x-v2\x)*(v1\x-v2\x) + (v1\y-v2\y)*(v1\y-v2\y) + (v1\z-v2\z)*(v1\z-v2\z) )&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function shadowLineIntersect3D.TVector3D(p1.TVector3D, p2.TVector3D, p3.TVector3D, p4.TVector3D)&lt;br /&gt;	Local EPS#=10^-8&lt;br /&gt;	&lt;br /&gt;	Local p13.TVector3D, p43.TVector3D, p21.TVector3D&lt;br /&gt;	Local d1343#, d4321#, d1321#, d4343#, d2121#&lt;br /&gt;	Local numer#, denom#, mua#, mub#&lt;br /&gt;	&lt;br /&gt;	p13=newTVector3D(p1\x-p3\x, p1\y-p3\y, p1\z-p3\z)&lt;br /&gt;	&lt;br /&gt;	p43=newTVector3D(p4\x-p3\x, p4\y-p3\y, p4\z-p3\z)&lt;br /&gt;	If Abs(p43\x)&amp;lt;EPS And Abs(p43\y)&amp;lt;EPS And Abs(p43\z)&amp;lt;EPS&lt;br /&gt;		Delete p13&lt;br /&gt;		Delete p43&lt;br /&gt;		&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	p21=newTVector3D(p2\x-p1\x, p2\y-p1\y, p2\z-p1\z)&lt;br /&gt;	If Abs(p21\x)&amp;lt;EPS And Abs(p21\y)&amp;lt;EPS And Abs(p21\z)&amp;lt;EPS&lt;br /&gt;		Delete p13&lt;br /&gt;		Delete p43&lt;br /&gt;		Delete p21&lt;br /&gt;		&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	d1343 = p13\x * p43\x + p13\y * p43\y + p13\z * p43\z&lt;br /&gt;	d4321 = p43\x * p21\x + p43\y * p21\y + p43\z * p21\z&lt;br /&gt;	d1321 = p13\x * p21\x + p13\y * p21\y + p13\z * p21\z&lt;br /&gt;	d4343 = p43\x * p43\x + p43\y * p43\y + p43\z * p43\z&lt;br /&gt;	d2121 = p21\x * p21\x + p21\y * p21\y + p21\z * p21\z&lt;br /&gt;	&lt;br /&gt;	denom = d2121*d4343 -d4321*d4321&lt;br /&gt;	If Abs(denom)&amp;lt;EPS&lt;br /&gt;		Delete p13&lt;br /&gt;		Delete p43&lt;br /&gt;		Delete p21&lt;br /&gt;		&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	numer=d1343*d4321 -d1321*d4343&lt;br /&gt;	&lt;br /&gt;	mua=numer/denom&lt;br /&gt;	mub=(d1343+d4321*mua)/d4343&lt;br /&gt;	&lt;br /&gt;	Local pA.TVector3D=newTVector3D(p1\x+mua*p21\x, p1\y+mua*p21\y, p1\z+mua*p21\z)&lt;br /&gt;	Local pB.TVector3D=newTVector3D(p3\x+mub*p43\x, p3\y+mub*p43\y, p3\z+mub*p43\z)&lt;br /&gt;	&lt;br /&gt;	Delete p13&lt;br /&gt;	Delete p43&lt;br /&gt;	Delete p21&lt;br /&gt;	&lt;br /&gt;	If equalPoints(pA, pB)&lt;br /&gt;		If mua&amp;gt;0.01 And mua&amp;lt;1 And mub&amp;gt;=0 And mub&amp;lt;=1&lt;br /&gt;			Delete pB&lt;br /&gt;			Return pA&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Delete pA&lt;br /&gt;	Delete pB&lt;br /&gt;	&lt;br /&gt;	Return Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newTSimpleTrig3D.TSimpleTrig3D(p1.TVector3D, p2.TVector3D, p3.TVector3D)&lt;br /&gt;	Local t.TSimpleTrig3D=New TSimpleTrig3D&lt;br /&gt;	&lt;br /&gt;	t\p1=p1&lt;br /&gt;	t\p2=p2&lt;br /&gt;	t\p3=p3&lt;br /&gt;	&lt;br /&gt;	Return t&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newTTrig3D.TTrig3D(p1.TVector3D, p2.TVector3D, p3.TVector3D)&lt;br /&gt;	Local t.TTrig3D=New TTrig3D&lt;br /&gt;	&lt;br /&gt;	t\p1=p1&lt;br /&gt;	t\p2=p2&lt;br /&gt;	t\p3=p3&lt;br /&gt;	&lt;br /&gt;	Local vx1#=p2\x-p1\x&lt;br /&gt;	Local vy1#=p2\y-p1\y&lt;br /&gt;	Local vz1#=p2\z-p1\z&lt;br /&gt;	&lt;br /&gt;	Local vx2#=p3\x-p1\x&lt;br /&gt;	Local vy2#=p3\y-p1\y&lt;br /&gt;	Local vz2#=p3\z-p1\z&lt;br /&gt;	&lt;br /&gt;	t\n=newTVector3D(vy1*vz2-vz1*vy2, vz1*vx2-vx1*vz2, vx1*vy2-vy1*vx2)&lt;br /&gt;	vNormalise(t\n)&lt;br /&gt;	t\n\d= -t\n\x*p3\x -t\n\y*p3\y -t\n\z*p3\z&lt;br /&gt;	&lt;br /&gt;	Return t&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function linePlaneIntersection.TVector3D(p.TVector3D, v.TVector3D, t.TTrig3D)&lt;br /&gt;	If Abs(v\x*t\n\x + v\y*t\n\y + v\z*t\n\z)&amp;lt;1 ;vllt etwas gross?&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If Abs(p\x*t\n\x + p\y*t\n\y + p\z*t\n\z + t\n\d)&amp;lt;0.1&lt;br /&gt;		Return newTVector3D(p\x, p\y, p\z)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local k#= -(t\n\x*p\x +t\n\y*p\y +t\n\z*p\z +t\n\d)/(t\n\x*v\x +t\n\y*v\y +t\n\z*v\z)&lt;br /&gt;	k=k*0.999&lt;br /&gt;	&lt;br /&gt;	Return newTVector3D(p\x+k*v\x, p\y+k*v\y, p\z+k*v\z)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function pointInTrig3D(x#, y#, z#, t.TTrig3D)&lt;br /&gt;	If Abs(x*t\n\x + y*t\n\y + z*t\n\z + t\n\d)&amp;gt;0.1&lt;br /&gt;		Return False&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local v0.TVector3D, v1.TVector3D, v2.TVector3D&lt;br /&gt;	&lt;br /&gt;	v0=newTVector3D(t\p3\x-t\p1\x, t\p3\y-t\p1\y, t\p3\z-t\p1\z)&lt;br /&gt;	v1=newTVector3D(t\p2\x-t\p1\x, t\p2\y-t\p1\y, t\p2\z-t\p1\z)&lt;br /&gt;	v2=newTVector3D(x-t\p1\x, y-t\p1\y, z-t\p1\z)&lt;br /&gt;	&lt;br /&gt;	Local dot00#, dot01#, dot02#, dot11#, dot12#&lt;br /&gt;	&lt;br /&gt;	dot00=vDot(v0, v0)&lt;br /&gt;	dot01=vDot(v0, v1)&lt;br /&gt;	dot02=vDot(v0, v2)&lt;br /&gt;	dot11=vDot(v1, v1)&lt;br /&gt;	dot12=vDot(v1, v2)&lt;br /&gt;	&lt;br /&gt;	Delete v0&lt;br /&gt;	Delete v1&lt;br /&gt;	Delete v2&lt;br /&gt;	&lt;br /&gt;	Local invDenom#=1./(dot00*dot11 - dot01*dot01)&lt;br /&gt;	Local u#=(dot11*dot02 - dot01*dot12)*invDenom&lt;br /&gt;	Local v#=(dot00*dot12 - dot01*dot02)*invDenom&lt;br /&gt;	&lt;br /&gt;	Return (u&amp;gt;=0) And (v&amp;gt;=0) And (u+v&amp;lt;=1)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function equalPoints(p1.TVector3D, p2.TVector3D)&lt;br /&gt;	Local dist#=0.5&lt;br /&gt;	&lt;br /&gt;	If p1=p2&lt;br /&gt;		Return True&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If Abs(p1\x-p2\x)&amp;lt;dist And Abs(p1\y-p2\y)&amp;lt;dist And Abs(p1\z-p2\z)&amp;lt;dist&lt;br /&gt;		Return True&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return False&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Global shadowMesh&lt;br /&gt;Global shadowSurf&lt;br /&gt;&lt;br /&gt;Function initShadowMesh()&lt;br /&gt;	shadowMesh=CreateMesh()&lt;br /&gt;	EntityFX shadowMesh, 16&lt;br /&gt;	&lt;br /&gt;	shadowSurf=CreateSurface(shadowMesh)&lt;br /&gt;	EntityColor shadowMesh, 50, 50, 50&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function projectShadow(lightPos.TVector3D)&lt;br /&gt;	ClearSurface(shadowSurf)&lt;br /&gt;	&lt;br /&gt;	Local tProj.TSimpleTrig3D&lt;br /&gt;	Local tIter.TTrig3D&lt;br /&gt;	&lt;br /&gt;	Local lVec1.TVector3D, lVec2.TVector3D, lVec3.TVector3D&lt;br /&gt;	&lt;br /&gt;	Local p1.TVector3D, p2.TVector3D&lt;br /&gt;	Local v1.TVector3D, v2.TVector3D&lt;br /&gt;	&lt;br /&gt;	Local proj1.TVector3D&lt;br /&gt;	Local proj2.TVector3D&lt;br /&gt;	Local b1, b2, iCase&lt;br /&gt;	&lt;br /&gt;	Local pTmp.TVector3D, pCut1.TVector3D, pCut2.TVector3D, pCut3.TVector3D&lt;br /&gt;	Local tP1.TVector3D, tP2.TVector3D, tP3.TVector3D, tTr.TTrig3D&lt;br /&gt;	&lt;br /&gt;	Local projList.TVector3D[6]&lt;br /&gt;	Local pCount&lt;br /&gt;	Local vList[6]&lt;br /&gt;	&lt;br /&gt;	For tProj=Each TSimpleTrig3D&lt;br /&gt;		lVec1=newTVector3D(tProj\p1\x-lightPos\x, tProj\p1\y-lightPos\y, tProj\p1\z-lightPos\z)&lt;br /&gt;		lVec2=newTVector3D(tProj\p2\x-lightPos\x, tProj\p2\y-lightPos\y, tProj\p2\z-lightPos\z)&lt;br /&gt;		lVec3=newTVector3D(tProj\p3\x-lightPos\x, tProj\p3\y-lightPos\y, tProj\p3\z-lightPos\z)&lt;br /&gt;		&lt;br /&gt;		For tIter=Each TTrig3D&lt;br /&gt;			pCount=0&lt;br /&gt;			&lt;br /&gt;			For i=0 To 2&lt;br /&gt;				Select i&lt;br /&gt;					Case 0&lt;br /&gt;						p1=tProj\p1&lt;br /&gt;						p2=tProj\p2&lt;br /&gt;						&lt;br /&gt;						v1=lVec1&lt;br /&gt;						v2=lVec2&lt;br /&gt;					Case 1&lt;br /&gt;						p1=tProj\p2&lt;br /&gt;						p2=tProj\p3&lt;br /&gt;						&lt;br /&gt;						v1=lVec2&lt;br /&gt;						v2=lVec3&lt;br /&gt;					Case 2&lt;br /&gt;						p1=tProj\p3&lt;br /&gt;						p2=tProj\p1&lt;br /&gt;						&lt;br /&gt;						v1=lVec3&lt;br /&gt;						v2=lVec1&lt;br /&gt;				End Select&lt;br /&gt;				&lt;br /&gt;				proj1=linePlaneIntersection(p1, v1, tIter)&lt;br /&gt;				proj2=linePlaneIntersection(p2, v2, tIter)&lt;br /&gt;				&lt;br /&gt;				If proj1=Null Or proj2=Null&lt;br /&gt;					Delete proj1&lt;br /&gt;					Delete proj2&lt;br /&gt;					&lt;br /&gt;					pCount=-1&lt;br /&gt;					Exit&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				b1=pointInTrig3D(proj1\x, proj1\y, proj1\z, tIter)&lt;br /&gt;				b2=pointInTrig3D(proj2\x, proj2\y, proj2\z, tIter)&lt;br /&gt;				&lt;br /&gt;				iCase=-1&lt;br /&gt;				If b1=1 And b2=1&lt;br /&gt;					iCase=0&lt;br /&gt;				ElseIf b1=1 And b2=0&lt;br /&gt;					iCase=1&lt;br /&gt;				ElseIf b1=0 And b2=1&lt;br /&gt;					pTmp=proj1&lt;br /&gt;					proj1=proj2&lt;br /&gt;					proj2=pTmp&lt;br /&gt;					&lt;br /&gt;					iCase=1&lt;br /&gt;				ElseIf b1=0 And b2=0&lt;br /&gt;					iCase=2&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				Select iCase&lt;br /&gt;					Case 1&lt;br /&gt;						pTmp=shadowLineIntersect3D(proj1, proj2, tIter\p1, tIter\p2)&lt;br /&gt;						If pTmp&amp;lt;&amp;gt;Null&lt;br /&gt;							Delete proj2&lt;br /&gt;							proj2=pTmp&lt;br /&gt;						Else&lt;br /&gt;							pTmp=shadowLineIntersect3D(proj1, proj2, tIter\p2, tIter\p3)&lt;br /&gt;							If pTmp&amp;lt;&amp;gt;Null&lt;br /&gt;								Delete proj2&lt;br /&gt;								proj2=pTmp&lt;br /&gt;							Else&lt;br /&gt;								pTmp=shadowLineIntersect3D(proj1, proj2, tIter\p3, tIter\p1)&lt;br /&gt;								If pTmp&amp;lt;&amp;gt;Null&lt;br /&gt;									Delete proj2&lt;br /&gt;									proj2=pTmp&lt;br /&gt;								Else&lt;br /&gt;									Delete proj1&lt;br /&gt;									Delete proj2&lt;br /&gt;								EndIf&lt;br /&gt;							EndIf&lt;br /&gt;						EndIf&lt;br /&gt;					Case 2&lt;br /&gt;						pCut1=shadowLineIntersect3D(proj1, proj2, tIter\p1, tIter\p2)&lt;br /&gt;						pCut2=shadowLineIntersect3D(proj1, proj2, tIter\p2, tIter\p3)&lt;br /&gt;						pCut3=shadowLineIntersect3D(proj1, proj2, tIter\p3, tIter\p1)&lt;br /&gt;						&lt;br /&gt;						Delete proj1&lt;br /&gt;						Delete proj2&lt;br /&gt;						&lt;br /&gt;						If pCut1=Null&lt;br /&gt;							proj1=pCut2&lt;br /&gt;							proj2=pCut3&lt;br /&gt;						ElseIf pCut2=Null&lt;br /&gt;							proj1=pCut1&lt;br /&gt;							proj2=pCut3&lt;br /&gt;						ElseIf pCut3=Null&lt;br /&gt;							proj1=pCut1&lt;br /&gt;							proj2=pCut2&lt;br /&gt;						EndIf&lt;br /&gt;						&lt;br /&gt;						If pCut1=Null And pCut2=Null And pCut3=Null&lt;br /&gt;							Delete proj1&lt;br /&gt;							Delete proj2&lt;br /&gt;						EndIf&lt;br /&gt;				End Select&lt;br /&gt;				&lt;br /&gt;				If iCase&amp;lt;&amp;gt;-1&lt;br /&gt;					If proj1&amp;lt;&amp;gt;Null And proj2&amp;lt;&amp;gt;Null&lt;br /&gt;						projList[pCount]=proj1&lt;br /&gt;						projList[pCount+1]=proj2&lt;br /&gt;						pCount=pCount+2&lt;br /&gt;					EndIf&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;			&lt;br /&gt;			While pCount&amp;gt;0 ;damit ich ein Exit einbauen kann&lt;br /&gt;				If pCount&amp;lt;6&lt;br /&gt;					tP1=linePlaneIntersection(tProj\p1, lVec1, tIter)&lt;br /&gt;					tP2=linePlaneIntersection(tProj\p2, lVec2, tIter)&lt;br /&gt;					tP3=linePlaneIntersection(tProj\p3, lVec3, tIter)&lt;br /&gt;					&lt;br /&gt;					If tP1=Null Or tP2=Null Or tP3=Null&lt;br /&gt;						Delete tP1&lt;br /&gt;						Delete tP2&lt;br /&gt;						Delete tP3&lt;br /&gt;						&lt;br /&gt;						Exit&lt;br /&gt;					EndIf&lt;br /&gt;					&lt;br /&gt;					tTr=newTTrig3D(tP1, tP2, tP3)&lt;br /&gt;					&lt;br /&gt;					bool=pointInTrig3D(tIter\p1\x, tIter\p1\y, tIter\p1\z, tTr)&lt;br /&gt;					If bool&lt;br /&gt;						projList[pCount]=newTVector3D(tIter\p1\x, tIter\p1\y, tIter\p1\z)&lt;br /&gt;						pCount=pCount+1&lt;br /&gt;					EndIf&lt;br /&gt;					&lt;br /&gt;					bool=pointInTrig3D(tIter\p2\x, tIter\p2\y, tIter\p2\z, tTr)&lt;br /&gt;					If bool&lt;br /&gt;						projList[pCount]=newTVector3D(tIter\p2\x, tIter\p2\y, tIter\p2\z)&lt;br /&gt;						pCount=pCount+1&lt;br /&gt;					EndIf&lt;br /&gt;					&lt;br /&gt;					bool=pointInTrig3D(tIter\p3\x, tIter\p3\y, tIter\p3\z, tTr)&lt;br /&gt;					If bool&lt;br /&gt;						projList[pCount]=newTVector3D(tIter\p3\x, tIter\p3\y, tIter\p3\z)&lt;br /&gt;						pCount=pCount+1&lt;br /&gt;					EndIf&lt;br /&gt;					&lt;br /&gt;					Delete tP1&lt;br /&gt;					Delete tP2&lt;br /&gt;					Delete tP3&lt;br /&gt;					&lt;br /&gt;					Delete tTr\n&lt;br /&gt;					Delete tTr&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				For i=0 To pCount-1&lt;br /&gt;					vList&lt;i&gt;=AddVertex(shadowSurf, projList[i]\x, projList[i]\y, projList[i]\z)&lt;br /&gt;					Delete projList[i]&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				For i=0 To pCount-3&lt;br /&gt;					For j=i+1 To pCount-2&lt;br /&gt;						For k=j+1 To pCount-1&lt;br /&gt;							AddTriangle(shadowSurf, vList[i], vList[j], vList[k])&lt;br /&gt;						Next&lt;br /&gt;					Next&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				Exit&lt;br /&gt;			Wend&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		Delete lVec1&lt;br /&gt;		Delete lVec2&lt;br /&gt;		Delete lVec3&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/* LIB CODE */;&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Testumgebung&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Graphics3D 800, 600, 0, 2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;Local p.TVector3D&lt;br /&gt;Local t.TTrig3D&lt;br /&gt;&lt;br /&gt;;// Projektionsfl&amp;auml;che&lt;br /&gt;p1.TVector3d=newTVector3D(-30, -10, -10)&lt;br /&gt;p2.TVector3d=newTVector3D(-30, -10, 10)&lt;br /&gt;p3.TVector3D=newTVector3D(-10, -10, -10)&lt;br /&gt;p4.TVector3D=newTVector3D(-10, -10, 10)&lt;br /&gt;p5.TVector3D=newTVector3D(10, 10, -10)&lt;br /&gt;p6.TVector3D=newTVector3D(10, 10, 10)&lt;br /&gt;p7.TVector3D=newTVector3D(30, 10, -10)&lt;br /&gt;p8.TVector3D=newTVector3D(30, 10, 10)&lt;br /&gt;&lt;br /&gt;t1.TTrig3D=newTTrig3D(p1, p2, p3)&lt;br /&gt;t2.TTrig3D=newTTrig3D(p2, p3, p4)&lt;br /&gt;t3.TTrig3D=newTTrig3D(p3, p4, p5)&lt;br /&gt;t4.TTrig3d=newTTrig3D(p4, p5, p6)&lt;br /&gt;t5.TTrig3D=newTTrig3D(p5, p6, p7)&lt;br /&gt;t6.TTrig3D=newTTrig3D(p6, p7, p8)&lt;br /&gt;&lt;br /&gt;Local groundMesh=CreateMesh()&lt;br /&gt;EntityFX groundMesh, 16&lt;br /&gt;Local groundSurf=CreateSurface(groundMesh)&lt;br /&gt;&lt;br /&gt;For t=Each TTrig3D&lt;br /&gt;	v1=AddVertex(groundSurf, t\p1\x, t\p1\y, t\p1\z)&lt;br /&gt;	v2=AddVertex(groundSurf, t\p2\x, t\p2\y, t\p2\z)&lt;br /&gt;	v3=AddVertex(groundSurf, t\p3\x, t\p3\y, t\p3\z)&lt;br /&gt;	&lt;br /&gt;	AddTriangle(groundSurf, v1, v2, v3)&lt;br /&gt;Next&lt;br /&gt;&lt;br /&gt;;// Schattenwerfer&lt;br /&gt;Local lightPos.TVector3D=newTVector3D(0, 100, 0)&lt;br /&gt;&lt;br /&gt;point1.TVector3D=newTVector3D(-20, 20, 0)&lt;br /&gt;point2.TVector3D=newTVector3D(20, 20, 0)&lt;br /&gt;point3.TVector3D=newTVector3D(0, 20, 20)&lt;br /&gt;&lt;br /&gt;trig1.TSimpleTrig3D=newTSimpleTrig3D(point1, point2, point3)&lt;br /&gt;&lt;br /&gt;Local projMesh=CreateMesh()&lt;br /&gt;EntityFX projMesh, 16&lt;br /&gt;EntityColor projMesh, 255, 0, 0&lt;br /&gt;Local projSurf=CreateSurface(projMesh)&lt;br /&gt;&lt;br /&gt;v1=AddVertex(projSurf, point1\x, point1\y, point1\z)&lt;br /&gt;v2=AddVertex(projSurf, point2\x, point2\y, point2\z)&lt;br /&gt;v3=AddVertex(projSurf, point3\x, point3\y, point3\z)&lt;br /&gt;&lt;br /&gt;AddTriangle(projSurf, v1, v2, v3)&lt;br /&gt;&lt;br /&gt;;// 3D Umgebung&lt;br /&gt;Global camera=CreateCamera()&lt;br /&gt;PositionEntity camera, 0, 50, -100&lt;br /&gt;Local camPiv=CreatePivot()&lt;br /&gt;EntityParent camera, camPiv&lt;br /&gt;&lt;br /&gt;Local light=CreateLight()&lt;br /&gt;&lt;br /&gt;;// Init the shadowMesh&lt;br /&gt;initShadowMesh()&lt;br /&gt;&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	RenderWorld&lt;br /&gt;	TurnEntity camPiv, 0, KeyDown(203)-KeyDown(205), 0&lt;br /&gt;	&lt;br /&gt;	;// Project the shadow&lt;br /&gt;	projectShadow(lightPos)&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	Cls&lt;br /&gt;Wend&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;b&gt;Edit 1:&lt;/b&gt; Das erste der versprochenen Edits. Ich habe den Code etwas aufger&amp;auml;umt, zwei Fehler verbessert und eine kleine Sch&amp;ouml;nheitskorrektur gemacht. Ausserdem ist das Ding nun in eine Art Library verpackt (die ich der Einfachheit halber einfach direkt in den Code gepackt habe)&lt;br /&gt;[i]Fehler 1:&lt;/i&gt; Wenn der Licht-Punkt Vektor ann&amp;auml;hernd parallel zur Dreiecksebene ist (&lt;i&gt;Vektor * Normal ~ 0&lt;/i&gt;), gab es immernoch Schatten, allerdings &amp;auml;usserst unlogische. Diese habe ich nun rausgenommen, der Sch&amp;ouml;nheit halber.&lt;br /&gt;&lt;i&gt;Fehler 2:&lt;/i&gt; Wenn der eine Punkt noch knapp im Dreieck war (meist direkt auf der Linie) und der zweite ausserhalb, dann wurde die Linie nicht korrekt beschnitten, es entstanden Schatten im Nichts. Wurde korrigiert (indem ich bei einem solchen Fall einfach die Linie verwerfe :&amp;gt;).&lt;br /&gt;&lt;i&gt;Sch&amp;ouml;nheitskorrektur:&lt;/i&gt; Der Schatten liegt nun nichtmehr direkt auf dem projizierten Dreick, sondern wird ein bisschen in Richtung Punkt verschoben (Z-Sorting und so), sollte nun also immer &amp;uuml;ber dem Hintergrund angezeigt werden.&lt;br /&gt;&lt;b&gt;Edit 2:&lt;/b&gt; Noch einen kleinen Fehler gefunden mit den Cases. Korrigiert.&lt;br /&gt;&lt;b&gt;Edit 3:&lt;/b&gt; Langsam wirds m&amp;uuml;hsam. Noch einen kleinen Fehler gefunden, ein &lt;i&gt;&amp;gt;=&lt;/i&gt; statt einem &lt;i&gt;&amp;gt;&lt;/i&gt;, tse.&lt;br /&gt;&lt;br /&gt;So, nun gehe ich wieder ein paar Matches Spielen. Falls Werbung hier erlaubt ist: Holt euch SC2! Das Spiel ist absolut grossartig :&amp;gt; Und falls ihr es noch nicht habt: Holt euch SC1:BW, das Spiel ist noch grossartiger!&lt;br /&gt;&lt;br /&gt;MfG,&lt;br /&gt;Cabadath</description>
			<pubDate>Tue, 16 Nov 2010 20:57:44 +0100</pubDate>
		</item>

		<item>
			<title>Der Krug geht zum Brunnen bis er bricht</title>
			<link>https://www.blitzforum.de/worklogs/292/#2694</link>
			<guid>https://www.blitzforum.de/worklogs/292/#2694</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;ich bin gerade daran mir die notwendigen Komponenten f&amp;uuml;r mein geplantes Spiel zusammenzustellen. Die Physikengine kann momentan eigentlich so ziemlich alles was ich m&amp;ouml;chte (auch wenn die Kollisionsantwort bei konkaven Objekten noch besser sein k&amp;ouml;nnte). Also arbeitete ich am n&amp;auml;chsten Teil, der Spielfigur.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Animation in 3D&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;F&amp;uuml;r ein fr&amp;uuml;heres Spiel habe ich mal ein XML-Animationsformat aufgestellt das ich dann geparst habe. Allerdings war dieser Parser enorm umst&amp;auml;ndlich und un&amp;uuml;bersichtlich, also habe ich ihn neu geschrieben, nun ist er handlicher und verst&amp;auml;ndlicher (und h&amp;auml;lt sich gr&amp;ouml;sstenteils an meine eigenen Code-Konventionen). Das System basiert auf Joints, die je nach &amp;quot;Iterations&amp;quot;-Tiefe zu Knochen verwandelt werden, man kann den Knochen Meshes zuweisen wenn man will (mit bevorzugter Gr&amp;ouml;sse), ansonsten wird eine Stange als Knochen erstellt. Hier ein Beispiel:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_20_Figure3D.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bei der Animation werden die Knochen auf (ca) konstanter L&amp;auml;nge gehalten mit einer Verlet-artigen Stauchung/Streckung, das kann dazu f&amp;uuml;hren, dass der Endzustand der Animation jeweils ein wenig anders aussieht. Man kann das (im Code..) ausschalten, indem man eine Zeile auskommentiert. Wer das System in Aktion erleben m&amp;ouml;chte, kann sich &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_20_Animation3D.rar&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt; das Programm herunterladen, inklusive 3D-Animations-Parser-Code. Mit der Leertaste kann man das Skelett laufen lassen, Pfeiltasten drehen die Kamera im Kreis um die Figur.&lt;br /&gt;&lt;br /&gt;Ich habe nicht vor die 3D-Version weiterzuverwenden. Dies aus zwei Gr&amp;uuml;nden: Es passt nicht in den Rest des Spiels (das 2D und &amp;quot;2.5D&amp;quot; ist) und es ist absolut m&amp;uuml;hsam die Animationen zu machen, es hat viel zu viele Punkte auf die man achten muss, das wird m&amp;uuml;hsam -.-&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Animation in 2D&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Aus den oben erw&amp;auml;hnten Gr&amp;uuml;nden habe ich beschlossen, das System um eine Dimension zu k&amp;uuml;rzen. Es funktioniert nun (auch) in 2(.5)D. Statt der Meshes kann man nun Bilder angeben, die als Sprite geladen werden. Die Figur hat auch eine Richtung, entweder nach rechts (=1) oder nach links (=-1) schauend. Das sieht etwa so aus:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_20_FigurePhysics.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Die Rechtecke im Hintergrund sind die Verkn&amp;uuml;pfung der Animation mit der DaDaPhysik, die Figur wird an die Stelle des roten Klotzes gestellt, so kann ich ziemlich einfach Kollisionen f&amp;uuml;r Spr&amp;uuml;nge und &amp;auml;hnliches einbauen. Allerdings it das Prinzip noch nicht wirklich steuerungstechnisch ausgereift, es f&amp;uuml;hlt sich lahm und wackelig an, da bin ich noch ein wenig am experimentieren. (&lt;b&gt;Anm:&lt;/b&gt; Eine SNES Sprite-Animation hat etwa 4 Frames pro Schritt, meine Figur hat 60.. und der Sprung ist enorm verz&amp;ouml;gert, weil er sich zuerst duckt und dann abspringt.) Sobald ich in dieser Hinsicht etwas Interessantes erreiche, werde ich das wahrscheinlich zeigen &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt;&lt;br /&gt;&lt;br /&gt;(Gek&amp;uuml;rzt auf das Wesentliche.. sprich: Setter/Getter gestrichen)&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Global RENDERCAM&lt;br /&gt;&lt;br /&gt;Function initRenderCam()&lt;br /&gt;	RENDERCAM=CreateCamera()&lt;br /&gt;	&lt;br /&gt;	TurnEntity RENDERCAM, 180, 0, 0&lt;br /&gt;	PositionEntity RENDERCAM, GraphicsWidth()/2, GraphicsHeight()/2, GraphicsWidth()/2&lt;br /&gt;	&lt;br /&gt;	CameraClsMode RENDERCAM, 0, 1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Figure Definition&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const MAX_JOINTS=50&lt;br /&gt;Const MAX_BONES=50&lt;br /&gt;Const MAX_ANIMSEQ=20&lt;br /&gt;Const MAX_KEYFRAME=10&lt;br /&gt;&lt;br /&gt;Type TFigure&lt;br /&gt;	Field posX#&lt;br /&gt;	Field posY#&lt;br /&gt;	&lt;br /&gt;	Field phiZ#&lt;br /&gt;	&lt;br /&gt;	Field dir&lt;br /&gt;	&lt;br /&gt;	Field jList.TJoint[MAX_JOINTS]&lt;br /&gt;	Field jCount&lt;br /&gt;	Field bList.TBone[MAX_BONES]&lt;br /&gt;	Field bCount&lt;br /&gt;	&lt;br /&gt;	Field aList.TAnimationSequence[MAX_ANIMSEQ]&lt;br /&gt;	Field aCount&lt;br /&gt;	&lt;br /&gt;	Field frame&lt;br /&gt;	Field kf&lt;br /&gt;	Field animRunning ;=-1 falls keine Animation l&amp;auml;uft&lt;br /&gt;	&lt;br /&gt;	Field relX#&lt;br /&gt;	Field relY#&lt;br /&gt;	&lt;br /&gt;	Field dX#&lt;br /&gt;	Field dY#&lt;br /&gt;	&lt;br /&gt;	Field piv&lt;br /&gt;	&lt;br /&gt;	Field vX#&lt;br /&gt;	Field vY#&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TAnimationSequence&lt;br /&gt;	Field kList.TKeyframe[MAX_KEYFRAME]&lt;br /&gt;	Field kCount&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TKeyframe&lt;br /&gt;	Field endFrame&lt;br /&gt;	&lt;br /&gt;	Field jList.TJoint[MAX_JOINTS]&lt;br /&gt;	Field jCount&lt;br /&gt;	&lt;br /&gt;	Field posX#&lt;br /&gt;	Field posY#&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TJoint&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;	&lt;br /&gt;	Field parent.TJoint&lt;br /&gt;	Field cList.TJoint[MAX_JOINTS]&lt;br /&gt;	Field cCount&lt;br /&gt;	&lt;br /&gt;	Field vX#&lt;br /&gt;	Field vY#&lt;br /&gt;	&lt;br /&gt;	Field name$&lt;br /&gt;	&lt;br /&gt;	Field fix&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TBone&lt;br /&gt;	Field j1.TJoint&lt;br /&gt;	Field j2.TJoint&lt;br /&gt;	&lt;br /&gt;	Field length#&lt;br /&gt;	&lt;br /&gt;	Field sprite&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * String Handling&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const MAX_SPLITS=64&lt;br /&gt;Function splitString(source$, splitter$[MAX_SPLITS], splitterCount, split$[MAX_SPLITS])&lt;br /&gt;	Local idx=0&lt;br /&gt;	Local pos, minPos, minSplit&lt;br /&gt;	&lt;br /&gt;	While Len(source)&amp;gt;0&lt;br /&gt;		minPos=Len(source)&lt;br /&gt;		minSplit=-1&lt;br /&gt;		&lt;br /&gt;		For i=0 To splitterCount-1&lt;br /&gt;			pos=Instr(source, splitter[i])&lt;br /&gt;			&lt;br /&gt;			If pos&amp;lt;minPos And pos&amp;gt;0&lt;br /&gt;				minPos=pos&lt;br /&gt;				minSplit=i&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		pos=minPos&lt;br /&gt;		&lt;br /&gt;		If pos=0 Or minSplit=-1&lt;br /&gt;			split[idx]=Mid(source, 1, Len(source))&lt;br /&gt;			idx=idx+1&lt;br /&gt;			&lt;br /&gt;			Exit&lt;br /&gt;		Else&lt;br /&gt;			split[idx]=Mid(source, 1, pos-1)&lt;br /&gt;			idx=idx+1&lt;br /&gt;			&lt;br /&gt;			If Len(split[idx-1])=0&lt;br /&gt;				idx=idx-1&lt;br /&gt;			EndIf&lt;br /&gt;			&lt;br /&gt;			source=Right(source, Len(source)-pos-Len(splitter[minSplit])+1)&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	Return idx&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function cleanStringSplit(split$[MAX_SPLITS], count)&lt;br /&gt;	Local charsLeft$[2]&lt;br /&gt;	Local charsRight$[2]&lt;br /&gt;	&lt;br /&gt;	charsLeft[0]=&amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;	charsLeft[1]=&amp;quot;'&amp;quot;&lt;br /&gt;	&lt;br /&gt;	charsRight[0]=&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;	charsRight[1]=&amp;quot;'&amp;quot;&lt;br /&gt;	&lt;br /&gt;	Local chg=True&lt;br /&gt;	&lt;br /&gt;	While chg&lt;br /&gt;		chg=False&lt;br /&gt;		&lt;br /&gt;		For i=0 To count-1&lt;br /&gt;			For j=0 To 1&lt;br /&gt;				If Left(split[i], 1)=charsLeft[j]&lt;br /&gt;					split[i]=Right(split[i], Len(split[i])-1)&lt;br /&gt;					chg=True&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				If Right(split[i], 1)=charsRight[j]&lt;br /&gt;					split[i]=Left(split[i], Len(split[i])-1)&lt;br /&gt;					chg=True&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;		Next&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	For i=0 To count-1&lt;br /&gt;		split[i]=Lower(split[i])&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function stringMid$(txt$,start,stopp)&lt;br /&gt;	Return Mid(txt$,start+1,stopp-start-1)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function loadFigure.TFigure(file$)&lt;br /&gt;	Local stream=ReadFile(file)&lt;br /&gt;	&lt;br /&gt;	If stream=0&lt;br /&gt;		RuntimeError &amp;quot;File does not exist&amp;quot;&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local f.TFigure=New TFigure&lt;br /&gt;	Local a.TAnimationSequence&lt;br /&gt;	Local k.TKeyframe&lt;br /&gt;	&lt;br /&gt;	Local sLine$&lt;br /&gt;	Local split$[MAX_SPLITS], sCount&lt;br /&gt;	&lt;br /&gt;	Local splitter$[MAX_SPLITS]&lt;br /&gt;	splitter[0]=&amp;quot; &amp;quot;&lt;br /&gt;	splitter[1]=&amp;quot;=&amp;quot;&lt;br /&gt;	&lt;br /&gt;	Local jStack.TJoint[MAX_JOINTS]&lt;br /&gt;	Local sIdx&lt;br /&gt;	&lt;br /&gt;	Local vertexMode=0&lt;br /&gt;	&lt;br /&gt;	Local x#, y#, z#&lt;br /&gt;	&lt;br /&gt;	f\piv=CreatePivot()&lt;br /&gt;	f\animRunning=-1&lt;br /&gt;	&lt;br /&gt;	f\dir=1&lt;br /&gt;	&lt;br /&gt;	While Not Eof(stream)&lt;br /&gt;		sLine=Trim(ReadLine(stream))&lt;br /&gt;		&lt;br /&gt;		If Left(sLine, 1)=&amp;quot;&amp;lt;&amp;quot;&lt;br /&gt;			sLine=Right(sLine, Len(sLine)-1)&lt;br /&gt;		EndIf&lt;br /&gt;		If Right(sLine, 1)=&amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;			sLine=Left(sLine, Len(sLine)-1)&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		For i=0 To MAX_SPLITS-1&lt;br /&gt;			split[i]=&amp;quot;&amp;quot;&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		sCount=splitString(sLine, splitter, 2, split)&lt;br /&gt;		cleanStringSplit(split, sCount)&lt;br /&gt;		&lt;br /&gt;		;dbg$=&amp;quot;&amp;quot;&lt;br /&gt;		;For i=0 To sCount-1&lt;br /&gt;		;	dbg=dbg+split[i]+&amp;quot; &amp;quot;&lt;br /&gt;		;Next&lt;br /&gt;		;DebugLog dbg&lt;br /&gt;		&lt;br /&gt;		Select split[0]&lt;br /&gt;			;/*&lt;br /&gt;			; * Joint&lt;br /&gt;			; */&lt;br /&gt;				&lt;br /&gt;			Case &amp;quot;joint&amp;quot;&lt;br /&gt;				jStack[sIdx]=newJoint(0, 0)&lt;br /&gt;				sIdx=sIdx+1&lt;br /&gt;				&lt;br /&gt;				If sIdx&amp;gt;1&lt;br /&gt;					jStack[sIdx-1]\parent=jStack[sIdx-2]&lt;br /&gt;					&lt;br /&gt;					jStack[sIdx-2]\cList[jStack[sIdx-2]\cCount]=jStack[sIdx-1]&lt;br /&gt;					jStack[sIdx-2]\cCount=jStack[sIdx-2]\cCount+1&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				If vertexMode=0 ;Fill into Figure&lt;br /&gt;					f\jList[f\jCount]=jStack[sIdx-1]&lt;br /&gt;					f\jCount=f\jCount+1&lt;br /&gt;				Else ;Fill into Keyframe&lt;br /&gt;					If k&amp;lt;&amp;gt;Null&lt;br /&gt;						addJointToKeyframe(k, jStack[sIdx-1])&lt;br /&gt;					EndIf&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				For i=1 To sCount-1&lt;br /&gt;					Select split[i]&lt;br /&gt;						Case &amp;quot;name&amp;quot;&lt;br /&gt;							jStack[sIdx-1]\name=split[i+1]&lt;br /&gt;							&lt;br /&gt;							i=i+1&lt;br /&gt;						Case &amp;quot;coo&amp;quot;, &amp;quot;coords&amp;quot;, &amp;quot;coordinates&amp;quot;&lt;br /&gt;							jStack[sIdx-1]\x=Float(split[i+1])&lt;br /&gt;							jStack[sIdx-1]\y=Float(split[i+2])&lt;br /&gt;							&lt;br /&gt;							i=i+3&lt;br /&gt;					End Select&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				If vertexMode=0&lt;br /&gt;					If sIdx&amp;gt;1&lt;br /&gt;						;								parent			child&lt;br /&gt;						f\bList[f\bCount]=newBone(jStack[sIdx-2], jStack[sIdx-1])&lt;br /&gt;						f\bCount=f\bCount+1&lt;br /&gt;						&lt;br /&gt;						For i=1 To sCount-1&lt;br /&gt;							Select split[i]&lt;br /&gt;								Case &amp;quot;sprite&amp;quot;, &amp;quot;bonesprite&amp;quot;&lt;br /&gt;									f\bList[f\bCount-1]\sprite=nLoadSprite(split[i+1], 1+4)&lt;br /&gt;									&lt;br /&gt;									EntityFX f\bList[f\bCount-1]\sprite, 16+1&lt;br /&gt;									;SpriteViewMode f\bList[f\bCount-1]\sprite, 2&lt;br /&gt;									&lt;br /&gt;									;ScaleSprite f\bList[f\bCount-1]\sprite, f\bList[f\bCount-1]\length/2*1.2, f\bList[f\bCount-1]\length/2*1.2&lt;br /&gt;									ScaleEntity f\bList[f\bCount-1]\sprite, f\bList[f\bCount-1]\length/2*1.2, f\bList[f\bCount-1]\length/2*1.2, 1&lt;br /&gt;									&lt;br /&gt;									i=i+1&lt;br /&gt;								Case &amp;quot;order&amp;quot;&lt;br /&gt;									If f\bList[f\bCount-1]\sprite&amp;lt;&amp;gt;0&lt;br /&gt;										EntityOrder f\bList[f\bCount-1]\sprite, Int(split[i+1])&lt;br /&gt;									EndIf&lt;br /&gt;									&lt;br /&gt;									i=i+1&lt;br /&gt;							End Select&lt;br /&gt;						Next&lt;br /&gt;						&lt;br /&gt;						If f\bList[f\bCount-1]\sprite=0&lt;br /&gt;							f\bList[f\bCount-1]\sprite=nCreateSprite()&lt;br /&gt;							&lt;br /&gt;							EntityFX f\bList[f\bCount-1]\sprite, 16+1&lt;br /&gt;							;SpriteViewMode f\bList[f\bCount-1]\sprite, 2&lt;br /&gt;							&lt;br /&gt;							;ScaleSprite f\bList[f\bCount-1]\sprite, 2, f\bList[f\bCount-1]\length/2&lt;br /&gt;							ScaleEntity f\bList[f\bCount-1]\sprite, 2, f\bList[f\bCount-1]\length/2, 1&lt;br /&gt;						EndIf&lt;br /&gt;					EndIf&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				If split[sCount-1]=&amp;quot;/&amp;quot;&lt;br /&gt;					sIdx=sIdx-1&lt;br /&gt;				EndIf&lt;br /&gt;			Case &amp;quot;coo&amp;quot;, &amp;quot;coord&amp;quot;, &amp;quot;coordinates&amp;quot;&lt;br /&gt;				If sIdx&amp;gt;0&lt;br /&gt;					For i=1 To sCount-1&lt;br /&gt;						If split[i]&amp;lt;&amp;gt;&amp;quot;/&amp;quot;&lt;br /&gt;							Select i&lt;br /&gt;								Case 1&lt;br /&gt;									jStack[sIdx-1]\x=Float(split[i])&lt;br /&gt;								Case 2&lt;br /&gt;									jStack[sIdx-1]\y=Float(split[i])&lt;br /&gt;							End Select&lt;br /&gt;						Else&lt;br /&gt;							Exit&lt;br /&gt;						EndIf&lt;br /&gt;					Next&lt;br /&gt;				EndIf&lt;br /&gt;			Case &amp;quot;name&amp;quot;&lt;br /&gt;				If sIdx&amp;gt;0&lt;br /&gt;					jStack[sIdx-1]\name=split[1]&lt;br /&gt;				EndIf&lt;br /&gt;			Case &amp;quot;/joint&amp;quot;&lt;br /&gt;				sIdx=sIdx-1&lt;br /&gt;				&lt;br /&gt;			;/*&lt;br /&gt;			; * Bone&lt;br /&gt;			; */&lt;br /&gt;				&lt;br /&gt;			Case &amp;quot;sprite&amp;quot;, &amp;quot;bonesprite&amp;quot;&lt;br /&gt;				If f\bList[f\bCount-1]\sprite&amp;lt;&amp;gt;0&lt;br /&gt;					FreeEntity f\bList[f\bCount-1]\sprite&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				f\bList[f\bCount-1]\sprite=nLoadSprite(split[1], 1+4)&lt;br /&gt;				&lt;br /&gt;				EntityFX f\bList[f\bCount-1]\sprite, 16+1&lt;br /&gt;				;SpriteViewMode f\bList[f\bCount-1]\sprite, 2&lt;br /&gt;			Case &amp;quot;order&amp;quot;&lt;br /&gt;				If f\bList[f\bCount-1]\sprite&amp;lt;&amp;gt;0&lt;br /&gt;					EntityOrder f\bList[f\bCount-1]\sprite, Int(split[1])&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;			;/*&lt;br /&gt;			; * Animation&lt;br /&gt;			; */&lt;br /&gt;				&lt;br /&gt;			Case &amp;quot;animation&amp;quot;, &amp;quot;anim&amp;quot;&lt;br /&gt;				sIdx=0&lt;br /&gt;				&lt;br /&gt;				a=newAnimationSeq()&lt;br /&gt;				&lt;br /&gt;				f\aList[f\aCount]=a&lt;br /&gt;				f\aCount=f\aCount+1&lt;br /&gt;				&lt;br /&gt;				vertexMode=1&lt;br /&gt;			Case &amp;quot;/animation&amp;quot;, &amp;quot;/anim&amp;quot;&lt;br /&gt;				a=Null&lt;br /&gt;				&lt;br /&gt;				vertexMode=0&lt;br /&gt;				&lt;br /&gt;			;/*&lt;br /&gt;			; * Keyframe&lt;br /&gt;			; */&lt;br /&gt;				&lt;br /&gt;			Case &amp;quot;keyframe&amp;quot;, &amp;quot;kf&amp;quot;&lt;br /&gt;				k=newKeyframe()&lt;br /&gt;				&lt;br /&gt;				If a&amp;lt;&amp;gt;Null&lt;br /&gt;					a\kList[a\kCount]=k&lt;br /&gt;					a\kCount=a\kCount+1&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				For i=1 To sCount-1&lt;br /&gt;					Select split[i]&lt;br /&gt;						Case &amp;quot;frame&amp;quot;, &amp;quot;endframe&amp;quot;, &amp;quot;f&amp;quot;&lt;br /&gt;							k\endFrame=Int(split[2])&lt;br /&gt;					End Select&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				vertexMode=1&lt;br /&gt;			Case &amp;quot;frame&amp;quot;, &amp;quot;endframe&amp;quot;, &amp;quot;f&amp;quot;&lt;br /&gt;				If k&amp;lt;&amp;gt;Null&lt;br /&gt;					k\endFrame=Int(split[1])&lt;br /&gt;				EndIf&lt;br /&gt;			Case &amp;quot;pos&amp;quot;, &amp;quot;position&amp;quot;&lt;br /&gt;				If k&amp;lt;&amp;gt;Null&lt;br /&gt;					k\posX=Float(split[1])&lt;br /&gt;					k\posY=Float(split[2])&lt;br /&gt;				EndIf&lt;br /&gt;			Case &amp;quot;/keyframe&amp;quot;, &amp;quot;/kf&amp;quot;&lt;br /&gt;				k=Null&lt;br /&gt;				&lt;br /&gt;				vertexMode=0&lt;br /&gt;				&lt;br /&gt;			;/*&lt;br /&gt;			; * Uhm.. dunno what else&lt;br /&gt;			; */&lt;br /&gt;				&lt;br /&gt;			Default&lt;br /&gt;			;	DebugLog split[0]&lt;br /&gt;		End Select&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	f\jList[0]\fix=True&lt;br /&gt;	&lt;br /&gt;	Return f&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function nLoadSprite(path$, mode)&lt;br /&gt;	Local tmpSprite=CreateMesh()&lt;br /&gt;	Local tmpSurf=CreateSurface(tmpSprite)&lt;br /&gt;	&lt;br /&gt;	v1=AddVertex(tmpSurf, -1, -1, 0, 0, 1)&lt;br /&gt;	v2=AddVertex(tmpSurf, 1, -1, 0, 1, 1)&lt;br /&gt;	v3=AddVertex(tmpSurf, -1, 1, 0, 0, 0)&lt;br /&gt;	v4=AddVertex(tmpSurf, 1, 1, 0, 1, 0)&lt;br /&gt;	&lt;br /&gt;	AddTriangle(tmpSurf, v1, v2, v3)&lt;br /&gt;	AddTriangle(tmpSurf, v2, v4, v3)&lt;br /&gt;	&lt;br /&gt;	EntityTexture tmpSprite, LoadTexture(path, mode)&lt;br /&gt;	&lt;br /&gt;	Return tmpSprite&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function nCreateSprite()&lt;br /&gt;	Local tmpSprite=CreateMesh()&lt;br /&gt;	Local tmpSurf=CreateSurface(tmpSprite)&lt;br /&gt;	&lt;br /&gt;	v1=AddVertex(tmpSurf, -1, -1, 0, 0, 1)&lt;br /&gt;	v2=AddVertex(tmpSurf, 1, -1, 0, 1, 1)&lt;br /&gt;	v3=AddVertex(tmpSurf, -1, 1, 0, 0, 0)&lt;br /&gt;	v4=AddVertex(tmpSurf, 1, 1, 0, 1, 0)&lt;br /&gt;	&lt;br /&gt;	AddTriangle(tmpSurf, v1, v2, v3)&lt;br /&gt;	AddTriangle(tmpSurf, v2, v4, v3)&lt;br /&gt;	&lt;br /&gt;	Return tmpSprite&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Figure Functions&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Function newFigure.TFigure()&lt;br /&gt;	Local f.TFigure=New TFigure&lt;br /&gt;	&lt;br /&gt;	f\posX=0&lt;br /&gt;	f\posY=0&lt;br /&gt;	&lt;br /&gt;	f\animRunning=-1&lt;br /&gt;	&lt;br /&gt;	f\piv=CreatePivot()&lt;br /&gt;	&lt;br /&gt;	Return f&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function moveFigure(f.TFigure, x#, y#)&lt;br /&gt;	Local piv=CreatePivot()&lt;br /&gt;	&lt;br /&gt;	PositionEntity piv, f\posX, f\posY, 0&lt;br /&gt;	RotateEntity piv, 0, 0, f\phiZ&lt;br /&gt;	MoveEntity piv, x, y, 0&lt;br /&gt;	&lt;br /&gt;	f\posX=EntityX(piv)&lt;br /&gt;	f\posY=EntityY(piv)&lt;br /&gt;	&lt;br /&gt;	FreeEntity piv&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function updateFigure(f.TFigure)&lt;br /&gt;	If f\animRunning&amp;gt;-1&lt;br /&gt;		nextFrame(f)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	moveFigure(f, f\vX, f\vY)&lt;br /&gt;	&lt;br /&gt;	For i=0 To 5&lt;br /&gt;		adjustFigureLength(f)&lt;br /&gt;	Next&lt;br /&gt;	createFigureModel(f)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function destroyFigure(f.TFigure)&lt;br /&gt;	For i=0 To f\bCount-1&lt;br /&gt;		FreeEntity f\bList[i]\sprite&lt;br /&gt;		Delete f\bList[i]&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For i=0 To f\jCount-1&lt;br /&gt;		Delete f\jList[i]&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Delete f&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function createFigureModel(f.TFigure)&lt;br /&gt;	Local trash, x1#, y1#, x2#, y2#, length#&lt;br /&gt;	&lt;br /&gt;	RotateEntity f\piv,0,0,0&lt;br /&gt;	PositionEntity f\piv,0,0,0&lt;br /&gt;	&lt;br /&gt;	For i=0 To f\bCount-1&lt;br /&gt;		trash=f\bList[i]\sprite&lt;br /&gt;		&lt;br /&gt;		If trash&amp;lt;&amp;gt;0&lt;br /&gt;			EntityParent trash, 0&lt;br /&gt;			&lt;br /&gt;			x1#=f\bList[i]\j1\x&lt;br /&gt;			y1#=f\bList[i]\j1\y&lt;br /&gt;			&lt;br /&gt;			x2#=f\bList[i]\j2\x&lt;br /&gt;			y2#=f\bList[i]\j2\y&lt;br /&gt;			&lt;br /&gt;			PositionEntity trash, (x1+x2)/2, (y1+y2)/2, 0&lt;br /&gt;			RotateEntity trash, 0, 180, 180+ATan2(x2-x1, y2-y1)&lt;br /&gt;			&lt;br /&gt;			EntityParent trash, f\piv&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	PositionEntity f\piv, f\posX, f\posY, 0&lt;br /&gt;	&lt;br /&gt;	If f\dir=1&lt;br /&gt;		RotateEntity f\piv, 0, 0, f\phiZ&lt;br /&gt;	EndIf&lt;br /&gt;	If f\dir=-1&lt;br /&gt;		RotateEntity f\piv, 0, 180, f\phiZ&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newJoint.TJoint(x#, y#)&lt;br /&gt;	Local j.TJoint=New TJoint&lt;br /&gt;	&lt;br /&gt;	j\x=x&lt;br /&gt;	j\y=y&lt;br /&gt;	&lt;br /&gt;	j\cCount=0&lt;br /&gt;	&lt;br /&gt;	Return j&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addJointToKeyframe(k.TKeyframe, j.TJoint)&lt;br /&gt;	k\jList[k\jCount]=j&lt;br /&gt;	k\jCount=k\jCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function getJointFromKeyframe.TJoint(k.TKeyframe, name$)&lt;br /&gt;	name=Lower(name)&lt;br /&gt;	&lt;br /&gt;	For i=0 To k\jCount-1&lt;br /&gt;		If k\jList[i]\name$=name$&lt;br /&gt;			Return k\jList[i]&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function cloneJoint.TJoint(j.TJoint)&lt;br /&gt;	Local jc.TJoint=New TJoint&lt;br /&gt;	&lt;br /&gt;	jc\x=j\x&lt;br /&gt;	jc\y=j\y&lt;br /&gt;	&lt;br /&gt;	jc\name=j\name&lt;br /&gt;	&lt;br /&gt;	Return jc&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newBone.TBone(j1.TJoint, j2.TJoint)&lt;br /&gt;	Local b.TBone=New TBone&lt;br /&gt;	&lt;br /&gt;	b\j1=j1&lt;br /&gt;	b\j2=j2&lt;br /&gt;	&lt;br /&gt;	b\length=Sqr((j1\x-j2\x)^2+(j1\y-j2\y)^2)&lt;br /&gt;	&lt;br /&gt;	Return b&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newAnimationSeq.TAnimationSequence()&lt;br /&gt;	Return New TAnimationSequence&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newKeyframe.TKeyframe()&lt;br /&gt;	Return New TKeyframe&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function animateFigure(f.TFigure, seq=0)&lt;br /&gt;	Local copy.TJoint&lt;br /&gt;	&lt;br /&gt;	f\kf=0&lt;br /&gt;	f\frame=0&lt;br /&gt;	&lt;br /&gt;	If seq&amp;gt;=f\aCount&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	f\animRunning=seq&lt;br /&gt;	&lt;br /&gt;	If f\aList[seq]\kList[0]\endFrame=0 Then&lt;br /&gt;		For i=0 To f\jCount-1&lt;br /&gt;			copy=getJointFromKeyframe(f\aList[seq]\kList[0], f\jList[i]\name$)&lt;br /&gt;			&lt;br /&gt;			If copy&amp;lt;&amp;gt;Null&lt;br /&gt;				f\jList[i]\x=copy\x&lt;br /&gt;				f\jList[i]\y=copy\y&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		f\posX=f\posX+f\aList[seq]\kList[0]\posX&lt;br /&gt;		f\posY=f\posY+f\aList[seq]\kList[0]\posY&lt;br /&gt;		&lt;br /&gt;		f\relX=f\aList[seq]\kList[0]\posX*f\dir&lt;br /&gt;		f\relY=f\aList[seq]\kList[0]\posY&lt;br /&gt;		&lt;br /&gt;		moveFigure(f, f\relX, f\relY)&lt;br /&gt;	Else&lt;br /&gt;		setAnimationVelocity(f)&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function nextFrame(f.TFigure)&lt;br /&gt;	Local copy.TJoint&lt;br /&gt;	Local seq=f\animRunning&lt;br /&gt;	&lt;br /&gt;	If f\frame&amp;gt;=f\aList[seq]\kList[f\kf]\endFrame&lt;br /&gt;		f\kf=f\kf+1&lt;br /&gt;		&lt;br /&gt;		If f\kf&amp;gt;=f\aList[seq]\kCount&lt;br /&gt;			f\animRunning=-1&lt;br /&gt;			f\frame=0&lt;br /&gt;			f\kf=0&lt;br /&gt;			&lt;br /&gt;			Return&lt;br /&gt;		Else&lt;br /&gt;			setAnimationVelocity(f)&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	For i=0 To f\jCount-1&lt;br /&gt;		f\jList[i]\x=f\jList[i]\x+f\jList[i]\vX&lt;br /&gt;		f\jList[i]\y=f\jList[i]\y+f\jList[i]\vY&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	moveFigure(f, f\dX, f\dY)&lt;br /&gt;	&lt;br /&gt;	f\relX=f\relX+f\dX&lt;br /&gt;	f\relY=f\relY+f\dY&lt;br /&gt;	&lt;br /&gt;	f\frame=f\frame+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function setAnimationVelocity(f.TFigure)&lt;br /&gt;	Local x1#, y1#, x2#, y2#&lt;br /&gt;	&lt;br /&gt;	Local copy.TJoint&lt;br /&gt;	Local seq=f\animRunning&lt;br /&gt;	Local ef=f\aList[seq]\kList[f\kf]\endFrame&lt;br /&gt;	&lt;br /&gt;	For i=0 To f\jCount-1&lt;br /&gt;		copy=getJointFromKeyframe(f\aList[seq]\kList[f\kf], f\jList[i]\name$)&lt;br /&gt;		&lt;br /&gt;		If copy&amp;lt;&amp;gt;Null&lt;br /&gt;			x1#=f\jList[i]\x&lt;br /&gt;			y1#=f\jList[i]\y&lt;br /&gt;			&lt;br /&gt;			x2#=copy\x&lt;br /&gt;			y2#=copy\y&lt;br /&gt;			&lt;br /&gt;			f\jList[i]\vX=(x2-x1)/(ef-f\frame)&lt;br /&gt;			f\jList[i]\vY=(y2-y1)/(ef-f\frame)&lt;br /&gt;		Else&lt;br /&gt;			f\jList[i]\vX=0&lt;br /&gt;			f\jList[i]\vY=0&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	f\dX=(f\aList[seq]\kList[f\kf]\posX*f\dir-f\relX)/(ef-f\frame)&lt;br /&gt;	f\dY=(f\aList[seq]\kList[f\kf]\posY-f\relY)/(ef-f\frame)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function adjustFigureLength(f.TFigure)&lt;br /&gt;	For i=0 To f\bCount-1&lt;br /&gt;		stretchBone(f\bList[i])&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function stretchBone(b.TBone)&lt;br /&gt;	Local dx#, dy#, deltaL#, diff#&lt;br /&gt;	&lt;br /&gt;	Local j1.TJoint&lt;br /&gt;	Local j2.TJoint&lt;br /&gt;	&lt;br /&gt;	j1=b\j1&lt;br /&gt;	j2=b\j2&lt;br /&gt;	&lt;br /&gt;	dx#=j1\x-j2\x&lt;br /&gt;	dy#=j1\y-j2\y&lt;br /&gt;	&lt;br /&gt;	deltaL#=Sqr(dx^2+dy^2)&lt;br /&gt;	diff#=0.5*(b\length-deltaL)/deltaL&lt;br /&gt;	&lt;br /&gt;	If j1\fix Or j2\fix&lt;br /&gt;		diff=diff*2&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If Not j1\fix&lt;br /&gt;		j1\x=j1\x+dx*diff&lt;br /&gt;		j1\y=j1\y+dy*diff&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If Not j2\fix&lt;br /&gt;		j2\x=j2\x-dx*diff&lt;br /&gt;		j2\y=j2\y-dy*diff&lt;br /&gt;	EndIf&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Nach dem Versagen der Sprite Variante habe ich die Sprites nun durch kleine quadratische Meshes ersetzt, ich habe es noch nicht testen lassen, aber ich hoffe es funktioniert nun besser.&lt;br /&gt;&lt;br /&gt;Ich wollte die Animation in irgend einem lustigen Spielchen testen, allerdings war mir ein gescheites Jump&amp;amp;Run zu viel Aufwand (und zu tr&amp;auml;ge, siehe oben). Im Chat hatten wir es (aus irgend einem Grund :&amp;gt; ) von Point&amp;amp;Click Adventures, und da wollte ich das mal ausprobieren. Von daher habe ich mich hingesetzt und ein kurzes Point&amp;amp;Click Spielchen geschrieben. Da ich kein Grafiker bin und auch keine Erfahrung im R&amp;auml;tsel stellen habe, spielt sich alles nur in einem Raum ab. Ausserdem ist alles absolut hardgecoded, weil ich nicht noch ein Scriptsystem oder &amp;auml;hnliches entwickeln wollte. Aber eigentlich macht mir sowas einen Haufen Spass. Vielleicht mach ich daran noch weiter..&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_20_PandC.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Eine kurze Erkl&amp;auml;rung zum &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_20_PointAndClick.rar&quot; target=&quot;_blank&quot;&gt;Spiel&lt;/a&gt;:&lt;br /&gt;Ganz oben ist eine Zeile in der eure letzte Aktion/Mitteilung geschrieben steht, wenn ihr etwas aufhebt, steht da &amp;quot;You got ..&amp;quot; und weitere auftretende Vorkommnisse.&lt;br /&gt;Im Kreis unten links steht, welche Aktion gerade ausgew&amp;auml;hlt ist. Wenn ihr die rechte Maustaste dr&amp;uuml;ckt erscheint ein Auswahlmen&amp;uuml; &amp;uuml;ber der Figur, fahrt mit der Maus auf die Aktion die ihr ausw&amp;auml;hlen m&amp;ouml;chtet und lasst die rechte Maustaste los. Dann k&amp;ouml;nnt ihr auf eine Zone klicken und die Aktion wird ausgef&amp;uuml;hrt.&lt;br /&gt;Im Kreis unten rechts steht, welches Item ihr ausgew&amp;auml;hlt habt, klickt mit der linken Maustaste in den Kreis um zum n&amp;auml;chsten verf&amp;uuml;gbaren Objekt zu wechseln.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_20_PointAndClick.rar&quot; target=&quot;_blank&quot;&gt;Hier&lt;/a&gt; gehts zum &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_20_PointAndClick.rar&quot; target=&quot;_blank&quot;&gt;Download&lt;/a&gt;, ich hoffe das Spiel ist soweit Bug-frei und alle Dateien sind vorhanden :/ Ich sollte mir wirklich mal einen Content-Manager oder sowas schreiben, damit mir auff&amp;auml;llt wenn ich etwas vergesse. Naja, Zeit h&amp;auml;tte ich ja &lt;img src=&quot;/forum/images/smiles/icon_biggrin.gif&quot; alt=&quot;Very Happy&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Hmm, ich habe gerade erfahren, dass der Code bei (mindestens einer) gewissen Grafikkarten scheinbar Probleme macht (meine Vermutung liegt bei der Sprite-Verwendung die zickt). Aus diesem Grund habe ich dem Archiv den Code beigelegt (wollte ich vermeiden :&amp;gt; ist ein ziemlich grausamer Stil), damit ihr bei einem MAV testen k&amp;ouml;nnt, wo der Fehler auftritt.&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Ich habe die Version ge&amp;auml;ndert, es ist nun auch hier nicht l&amp;auml;nger Sprite sondern Surface-basiert. Hoffentlich funktioniert das nun bei (fast) allen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Inventarsystem&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Als letzes noch etwas das ich zu verwenden gedenke, wessen ich mir aber noch nicht sicher bin. Ich habe ein kleines &amp;quot;Inventar&amp;quot;-System geschrieben. Eigentlich habe ich vor, in meinem Spiel eine Art von Zauberei einzuf&amp;uuml;hren, und dies wollte ich dann dazu verwenden, die verschiedenen Spr&amp;uuml;che auszuw&amp;auml;hlen. Mal sehen was daraus wird &lt;img src=&quot;/forum/images/smiles/icon_biggrin.gif&quot; alt=&quot;Very Happy&quot; /&gt; So wie ich mich und meine Planung kenne, weiss ich nicht ob ich die Idee fallen lassen werde oder durchziehe, die Zeit wirds zeigen. Bildchen gibts nicht (es sind ein paar nummerierte Rechtecke, die im Kreis angeordnet sind, &lt;a href=&quot;http://www.youtube.com/watch?v=hNaUJfyVzRU&quot; target=&quot;_blank&quot;&gt;whoo&lt;/a&gt;!). Zum Ausprobieren:&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * TItem&lt;br /&gt;; *&lt;br /&gt;; * TInventory&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TItem&lt;br /&gt;	;f&amp;uuml;llen nach belieben&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newItem.TItem()&lt;br /&gt;	Return New TItem&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Const MAX_ITEMS=128&lt;br /&gt;Const MAX_RAD#=100&lt;br /&gt;&lt;br /&gt;Type TInventory&lt;br /&gt;	Field posX&lt;br /&gt;	Field posY&lt;br /&gt;	&lt;br /&gt;	Field turning&lt;br /&gt;	Field turnPhi&lt;br /&gt;	&lt;br /&gt;	Field turnStep#&lt;br /&gt;	&lt;br /&gt;	Field rad#&lt;br /&gt;	Field open&lt;br /&gt;	&lt;br /&gt;	Field pos&lt;br /&gt;	&lt;br /&gt;	Field iList.TItem[MAX_ITEMS]&lt;br /&gt;	Field iCount&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newInventory.TInventory()&lt;br /&gt;	Local i.TInventory=New TInventory&lt;br /&gt;	&lt;br /&gt;	i\turnStep=10&lt;br /&gt;	&lt;br /&gt;	i\turnPhi=1&lt;br /&gt;	i\turning=False&lt;br /&gt;	&lt;br /&gt;	i\pos=0&lt;br /&gt;	&lt;br /&gt;	Return i&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function setInventoryPosition(inv.TInventory, x, y)&lt;br /&gt;	inv\posX=x&lt;br /&gt;	inv\posY=y&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addItemToInveotory(inv.TInventory, it.TItem)&lt;br /&gt;	If inv\iCount&amp;gt;=MAX_ITEMS&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	inv\iList[inv\iCount]=it&lt;br /&gt;	inv\iCount=inv\iCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function removeItemFromInventory(inv.TInventory, it.TItem)&lt;br /&gt;	For i=0 To inv\iCount-1&lt;br /&gt;		If inv\iList[i]=it&lt;br /&gt;			removeEntryFromInvetory(inv, i)&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function removeEntryFromInvetory(inv.TInventory, i)&lt;br /&gt;	For j=i+1 To inv\iCount-1&lt;br /&gt;		inv\iList[j-1]=inv\iList[j]&lt;br /&gt;	Next&lt;br /&gt;	inv\iList[inv\iCount-1]=Null&lt;br /&gt;	&lt;br /&gt;	inv\iCount=inv\iCount-1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawInventory(inv.TInventory)&lt;br /&gt;	If Not inv\open&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local phi#, it.TItem, posX#, posY#&lt;br /&gt;	&lt;br /&gt;	phi=360./inv\iCount&lt;br /&gt;	&lt;br /&gt;	For i=0 To inv\iCount-1&lt;br /&gt;		posX=inv\posX + Cos(i*phi + inv\pos*phi + inv\turnPhi -90)*inv\rad&lt;br /&gt;		posY=inv\posY + Sin(i*phi + inv\pos*phi + inv\turnPhi -90)*inv\rad&lt;br /&gt;		&lt;br /&gt;		Rect posX,posY,32,32,0&lt;br /&gt;		Text posX,posY,i&lt;br /&gt;		&lt;br /&gt;		Count=Count+1&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function turnInventory(inv.TInventory, steps=10)&lt;br /&gt;	If Not inv\open&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local it.TItem&lt;br /&gt;	&lt;br /&gt;	If Not inv\turning&lt;br /&gt;		If KeyDown(203)&lt;br /&gt;			inv\turnPhi=-1&lt;br /&gt;			&lt;br /&gt;			inv\turning=True&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		If KeyDown(205)&lt;br /&gt;			inv\turnPhi=1&lt;br /&gt;			&lt;br /&gt;			inv\turning=True&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If inv\turning&lt;br /&gt;		inv\turnStep=inv\turnStep+1&lt;br /&gt;		&lt;br /&gt;		inv\turnPhi=inv\turnPhi+360./inv\iCount/steps*Sgn(inv\turnPhi)&lt;br /&gt;		&lt;br /&gt;		If inv\turnStep&amp;gt;=steps&lt;br /&gt;			inv\turning=False&lt;br /&gt;			&lt;br /&gt;			inv\pos=(inv\pos+Sgn(inv\turnPhi)) Mod inv\iCount&lt;br /&gt;			&lt;br /&gt;			inv\turnPhi=0&lt;br /&gt;			inv\turnStep=0&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function openInventory(inv.TInventory, steps=10)&lt;br /&gt;	inv\open=True&lt;br /&gt;	inv\rad=0&lt;br /&gt;	&lt;br /&gt;	Local dRad#=MAX_RAD/steps&lt;br /&gt;	&lt;br /&gt;	For i=0 To steps-1&lt;br /&gt;		inv\rad=inv\rad+dRad&lt;br /&gt;		&lt;br /&gt;		Cls&lt;br /&gt;		drawInventory(inv)&lt;br /&gt;		Flip&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function closeInventory(inv.TInventory, steps=10)&lt;br /&gt;	inv\rad=MAX_RAD&lt;br /&gt;	&lt;br /&gt;	Local dRad#=MAX_RAD/steps&lt;br /&gt;	&lt;br /&gt;	For i=0 To steps-1&lt;br /&gt;		inv\rad=inv\rad-dRad&lt;br /&gt;		&lt;br /&gt;		Cls&lt;br /&gt;		drawInventory(inv)&lt;br /&gt;		Flip&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	inv\open=False&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test Program&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Graphics 800,600,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;Local inv.TInventory=newInventory()&lt;br /&gt;setInventoryPosition(inv, 400, 300)&lt;br /&gt;&lt;br /&gt;timer=CreateTimer(60)&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	&lt;br /&gt;	;If Not inv\turning&lt;br /&gt;	If KeyHit(30)&lt;br /&gt;		addItemToInveotory(inv, newItem())&lt;br /&gt;	EndIf&lt;br /&gt;	;EndIf&lt;br /&gt;	&lt;br /&gt;	drawInventory(inv)&lt;br /&gt;	turnInventory(inv)&lt;br /&gt;	&lt;br /&gt;	If KeyHit(57)&lt;br /&gt;		If inv\open&lt;br /&gt;			closeInventory(inv)&lt;br /&gt;		Else&lt;br /&gt;			openInventory(inv)&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	WaitTimer(timer)&lt;br /&gt;	Cls&lt;br /&gt;Wend&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;br /&gt;Mit [A] f&amp;uuml;gt man neue Items in den Kreis ein, mit [Space] &amp;ouml;ffnet und schliesst man das Inventar und mit den Pfeiltasten [Links] und [Rechts] dreht man das Inventar (das obere Objekt ist das ausgew&amp;auml;hlte, sollte man vielleicht noch markieren..).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ende&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, das w&amp;auml;rs f&amp;uuml;r diesmal. Ich hoffe dass ich irgendwann die Motivation finde ein wenig intensiver zu arbeiten, bisher schaue ich lieber irgendwelche doofen Filme (meine G&amp;uuml;te, &amp;quot;Avatar: The last Airbender&amp;quot; war ziemlich mies :/ ), oder lese Comics. Ferien sind doch etwas tolles!&lt;br /&gt;&lt;br /&gt;So, sch&amp;ouml;ne Ferien w&amp;uuml;nsche ich auch euch,&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Thu, 15 Jul 2010 16:58:41 +0200</pubDate>
		</item>

		<item>
			<title>Sommer, Sonne, Sonnenschein</title>
			<link>https://www.blitzforum.de/worklogs/292/#2617</link>
			<guid>https://www.blitzforum.de/worklogs/292/#2617</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;nach den letzten beiden Pr&amp;uuml;fungen habe ich nun wieder ein bisschen Zeit etwas von meiner Arbeit vorzustellen. Dann gehts wieder zur&amp;uuml;ck ans Lernen. Aufgrund der Pr&amp;uuml;fungsphase, wird dieser Eintrag wahrscheinlich auch nicht so vielseitig wie vorg&amp;auml;ngige Exemplare, aber vielleicht tut etwas Koh&amp;auml;renz diesem Worklog gar nicht so schlecht. Nun denn, auf zur Tat!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Polygon Schatten&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Wo Licht ist, sollte auch Schatten sein, sonst schwitzt man zu sehr. Ausserdem gibt Schatten einer Szene etwas mehr Realit&amp;auml;t (hoffentlich :&amp;gt;). Ich habe im Internet einen &lt;a href=&quot;http://www.gamedev.net/reference/articles/article2032.asp&quot; target=&quot;_blank&quot;&gt;GameDev Artikel&lt;/a&gt; gefunden und nach dessen Anleitung einen &amp;quot;harten&amp;quot; Schatten gebastelt. Ich spare mir das posten des Codes, weil &amp;auml;hnliche Ans&amp;auml;tze schon im &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=31691&amp;amp;highlight=schatten&quot; target=&quot;_blank&quot;&gt;Code&lt;/a&gt; - &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=31951&amp;amp;highlight=schatten&quot; target=&quot;_blank&quot;&gt;Archiv&lt;/a&gt; zu finden sind.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_19_Shadow.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ich benutze hierf&amp;uuml;r die gleichen Types wie in meiner PhysikRoutine, deshalb k&amp;ouml;nnte man beide ziemlich einfach in einem Spiel parallel verwenden. Ich werde das allerdings nicht direkt in die Physik einbauen, weil ... deshalb!&lt;br /&gt;Theoretisch k&amp;ouml;nnte man auch Schatten von verschiedenen Lichtern einbauen (ich habs mal eingef&amp;uuml;hrt, und dann wieder verworfen), allerdings sieht das nicht so toll aus, da ich kein Licht berechne, sondern halt eben nur den Schatten, und verschiedenfarbige Schatten (mit unterschiedlichen Alphas) sehen nicht wirklich toll aus, wenn ich vielleicht mit Licht arbeiten w&amp;uuml;rde, dann k&amp;ouml;nnte es etwas anderes werden, mal sehn.&lt;br /&gt;Wer das Programm in Aktion sehen m&amp;ouml;chte, kann es &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_19_shadowTest.rar&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt; herunterladen und ausprobieren. Beschreibung steht im Fenster, daher nur kurz: Maus bewegt die Lichtquelle, Pfeil rauf/runter &amp;auml;ndert die Transparenz des Schattens [0, 1].&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Feuer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Wenn man schon Schatten hat, braucht man auch etwas, das Schatten wirft! &lt;a href=&quot;http://de.wikipedia.org/wiki/Maxwellsche_Gleichungen#Gleichungen&quot; target=&quot;_blank&quot;&gt;Licht&lt;/a&gt;. Weil Licht langweilig ist, dachte ich mir, als durchgeknallter Pyromane, ich mache ein Feuerchen. Im &lt;a href=&quot;http://www.google.ch/search?hl=de&amp;amp;q=google&amp;amp;aq=f&amp;amp;aqi=&amp;amp;aql=&amp;amp;oq=&amp;amp;gs_rfai=&quot; target=&quot;_blank&quot;&gt;Internet&lt;/a&gt; fand ich ein ziemlich geniales &lt;a href=&quot;http://processing.org/&quot; target=&quot;_blank&quot;&gt;Processing&lt;/a&gt; &lt;a href=&quot;http://www.escapemotions.com/experiments/fluid_fire_3/index.html&quot; target=&quot;_blank&quot;&gt;Applet&lt;/a&gt;, das eine ziemlich h&amp;uuml;bsche Feuersimulation bietet. So wie ich das sehe, arbeitet es mit dem ungef&amp;auml;hr gleichen Stokes L&amp;ouml;ser, den ich im &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/#2436&quot; target=&quot;_blank&quot;&gt;letzten Eintrag&lt;/a&gt; vorgestellt habe. Zus&amp;auml;tzlich fand ich im Codearchiv einen ziemlich h&amp;uuml;bschen &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=21784&amp;amp;highlight=&quot; target=&quot;_blank&quot;&gt;Ansatz&lt;/a&gt; von &lt;a href=&quot;https://www.blitzforum.de/forum/profile.php?mode=viewprofile&amp;amp;u=2483&quot; target=&quot;_blank&quot;&gt;Kr&amp;uuml;mel&lt;/a&gt;. Der benutzt zur Renderung ein Mesh, dessen Vertices er verf&amp;auml;rbt. Dieses Prinzip habe ich mal flux &amp;uuml;bernommen und bei meinem Ding eingebaut. Dadurch kann ich jetzt Alpha und &amp;Uuml;berlagerung nutzen.&lt;br /&gt;Damit habe ich mich dran gesetzt, Feuer zu basteln. Es ist eigentlich das gleiche. Ich habe eine neue &amp;quot;Matrix&amp;quot; eingef&amp;uuml;hrt (jetzt sind es zwei: eine f&amp;uuml;r Hitze, die andere f&amp;uuml;r Rauch).&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_19_Spectrum.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Zur F&amp;auml;rbung des Feuers benutze ich ein Spektrum, das ich im Internet gefunden habe (.. leider finde ich den Link zur Seite nichtmehr &lt;img src=&quot;/forum/images/smiles/icon_sad.gif&quot; alt=&quot;Sad&quot; /&gt; ). Eigentlich wurde dabei nur die Strahlung eines &lt;a href=&quot;http://de.wikipedia.org/wiki/Schwarzer_K&amp;ouml;rper&quot; target=&quot;_blank&quot;&gt;schwarzen K&amp;ouml;rpers&lt;/a&gt; berechnet, aber das ist mit BB ziemlich m&amp;uuml;hsam (weil die Werte von 470*10^-6 f&amp;uuml;r eine Wellenl&amp;auml;nge bis 3*10^8 f&amp;uuml;r Lichtgeschwindigkeit gehen), daher das Bild.&lt;br /&gt;Das Ergebnis wird mit einer Kamera gerendert, die den 2D Stoff nicht l&amp;ouml;scht, das heisst, ich kann Feuer in ein Bild simulieren. &lt;a href=&quot;http://img.brothersoft.com/screenshots/softimage/0/5_days_a_stranger-66158-1.jpeg&quot; target=&quot;_blank&quot;&gt;Hier&lt;/a&gt; das Original, und da mein Feuer:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_19_FireAction.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Das Ganze ist ziemlich langsam, leider. Ausserdem kommt es kaum an das Vorbild heran. Im Moment verwende ich 2 separate Meshes, in einem wird das Feuer, im anderen der Rauch gerendert. Ich kann die beiden nat&amp;uuml;rlich auch verschmelzen, das beschleunigt das Programm ein wenig. Allerdings leidet dabei die Qualit&amp;auml;t, ziemlich viel Kontrast geht verloren, ein Bild als Illustration (links: die momentane Version, rechts: beides in einem):&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_19_FireCompare.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Nat&amp;uuml;rlich ist es m&amp;ouml;glich, dass ich bei der &amp;Uuml;berlagerung einen Fehler mache, dar&amp;uuml;ber werd ich nochmal nachdenken. Allerdings ist auch das schnellere System (meiner Meinung nach) zu langsam, um in einem Spiel vern&amp;uuml;nftig eingesetzt werden zu k&amp;ouml;nnen, deshalb werde ich das (vorl&amp;auml;ufig) nicht tun, oder nur in kleinen Dimensionen. Die FeuerRaster sind n&amp;auml;mlich beliebig dimensionierbar (m&amp;uuml;ssen nicht quadratisch sein, gibt aber eine Maximalgr&amp;ouml;sse).&lt;br /&gt;Wer es ausprobieren m&amp;ouml;chte, kann es &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_19_StokesFire.rar&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt; herunterladen. Auf Mausklick wird neues Feuer erzeugt.&lt;br /&gt;&lt;br /&gt;-----&lt;br /&gt;&lt;br /&gt;&lt;b&gt;DaDaPhysics&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are three things i wanted to share about DaDaPhysics.&lt;br /&gt;First off, is the water simulation. I tried changing the interaction between a body and the water-surface to make it more accurate, the only problem is, that there never seems to be an equilibrium, everything always moves - I did not particularly like this, so I changed it back.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Well, I went ahead and cheated a little. I made a threshold (on the body speed) for the wave displacement, now I can use my a little more accurate intersection test. Now I have the effect, that the body will be moved if there is a wave. Well, that's good enough for the moment.&lt;br /&gt;&lt;br /&gt;The second thing is the splitter implementation. As you might remember, I had a huge worklog entry describing my failure trying to program a physical splitting of the body. So i settled for a given split by a square inside the body. I changed that, now the splitting is randomized, for a more interesting result.&lt;br /&gt;And third, i tried a stress-test for my polygon-decomposition-algorithm (dividing a given polygon into convex subparts). I did that with a sketching-sandbox as seen in &lt;a href=&quot;http://www.phunland.com/wiki/Home&quot; target=&quot;_blank&quot;&gt;Phun&lt;/a&gt; or &lt;a href=&quot;http://www.youtube.com/watch?v=QsTqspnvAaI&quot; target=&quot;_blank&quot;&gt;Crayon Physics&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_19_DrawPhysics.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I had some difficulties for specific types of drawings (try drawing a rectangle, and it will most certainly crash.. or just calculate forever) - which means, that the algorithm is not perfect. An error I knew would occur was for self-intersecting polygons, just .. don't do that, it's weird! But for simpler structures (with not that many points) it works pretty well.&lt;br /&gt;Another error I observed: for huge concave objects there are some slight errors in the collision response (because of the distance). As for very slim (sub)objects, there can be some jumps in the response.&lt;br /&gt;Because of these errors, i did not just yet implement it fully into the physics-routine, it is a separate program, that can be downloaded &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_19_drawingPhysics.rar&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; I changed the drawing system a little, the polygon is now not iteratively found from the subbodys, but rather precalculated (before the decomposition) and saved as a list of indices, which map to the subbody and vector in order of appearance in the polygon. Now there can not be a array-overflow in the translation algorithm, and it is a lot faster than before. So .. win-lose (because it needs more memory) for me.&lt;br /&gt;&lt;br /&gt;-----&lt;br /&gt;&lt;br /&gt;So, das wars von meiner Seite, ich w&amp;uuml;nsche der Leserschaft ein sch&amp;ouml;nes Wochenende, auf dass man die Sonne noch ein Weilchen geniessen m&amp;ouml;ge.&lt;br /&gt;&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Sat, 26 Jun 2010 19:06:56 +0200</pubDate>
		</item>

		<item>
			<title>I am sailing</title>
			<link>https://www.blitzforum.de/worklogs/292/#2436</link>
			<guid>https://www.blitzforum.de/worklogs/292/#2436</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;es wird Sommer, das bedeutet, es wird warm, richtig heiss sogar. Also sucht man Abk&amp;uuml;hlung, und weil ich als Paradenerd lieber im k&amp;uuml;hlen Kellerzimmer hocke statt hinaus in ein Schwimmbad zu gehen, habe ich mir Wasser programmiert. Traurig, nichtwahr?&lt;br /&gt;Aber zuerst etwas anderes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Punkte:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Geometrische Algorithmen sind immer etwas Sch&amp;ouml;nes, sind auch n&amp;uuml;tzlich f&amp;uuml;r verschiedene Dinge. Eigentlich habe ich die paar Algorithmen geschrieben, um sie in meinem Wasserding zu verwenden und dann festgestellt, dass es eigentlich viel zu aufw&amp;auml;ndig ist und einfacher gehen w&amp;uuml;rde.&lt;br /&gt;Hier die (grobe) Problemstellung: Gegeben ist eine Anzahl von Punkten in beliebiger Anordnung. Finde eine (minimale) konvexe H&amp;uuml;lle um diese Punkte.&lt;br /&gt;Zuerst sucht man eine konkave H&amp;uuml;lle durch alle Punkte und nimmt dan die Verbindungen raus, die zu einem konkaven Knick f&amp;uuml;hren w&amp;uuml;rden, dieses Prinzip nennt man den &lt;a href=&quot;http://de.wikipedia.org/wiki/Graham_Scan&quot; target=&quot;_blank&quot;&gt;Graham Scan&lt;/a&gt; Algorithmus, prinzipiell ordnet man einfach alle Punkte nach dem Winkel zu einem Startpunkt. Diesen Punkt muss man so w&amp;auml;hlen, dass er garantiert auf der H&amp;uuml;lle liegt, also z.b den Punkt ganz unten links.&lt;br /&gt;Nach der H&amp;uuml;lle wollte ich dann die Fl&amp;auml;che bestimmen, welche die Punkte ben&amp;ouml;tigen. Dazu habe ich die Punkte mit dem Delaunay Algorithmus trianguliert und dann einfach die Fl&amp;auml;chen der Dreiecke addiert. (&lt;b&gt;Anm&lt;/b&gt;: Im gegensatz zum &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=31457&amp;amp;highlight=dreiecke+zerlegen&quot; target=&quot;_blank&quot;&gt;Subtracting Ears&lt;/a&gt; Algorithmus trienguliert man hier nicht ein beliebiges Polygon, sondern das Polygon der konvexen H&amp;uuml;lle!)&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_18_ConvexHull.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Der Triangulierungs-Algorithmus ist relativ einfach und vielseitig einsetzbar, f&amp;uuml;r was auch immer man sich vorstellen k&amp;ouml;nnte. Ich habe hier eine eher aufw&amp;auml;ndigere Methode gew&amp;auml;hlt (weil sie einfacher ist &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt;), es gibt soweit ich weiss noch eine, die in &lt;i&gt;O(n*log(n))&lt;/i&gt; l&amp;auml;uft, aber ich fand nirgends eine wirkliche Beschreibung dazu, nur st&amp;auml;ndige Verweise auf Voronoi Diagrammerzeugung (dadurch kriegt man Delaunay praktisch &amp;quot;geschenkt&amp;quot;). Und das war mir zu bl&amp;ouml;d.&lt;br /&gt;&lt;b&gt;Anm1:&lt;/b&gt; Es hat eine kleine Unsauberheit im Algorithmus, wenn man ein perfektes Rechteck zeichnet, kann dieses nicht zerlegt werden, ich werde noch versuchen das zu beheben.&lt;br /&gt;&lt;b&gt;Anm2:&lt;/b&gt; Alle Algorithmen behandeln im Moment alle Punkte (der Einfachheit halber), allerdings ist das Prinzip des Algorithmus ziemlich einfach anzupassen, dass man den Funktionen auch eine Liste von Punkten mitgeben kann, ich habe das bloss noch nicht so gemacht, kommt vielleicht noch.&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * Grundstruktur&lt;br /&gt;; *&lt;br /&gt;; *		TPoint&lt;br /&gt;; *			x		X-Koordinate&lt;br /&gt;; *			y		Y-Koordinage&lt;br /&gt;; *			succ	N&amp;auml;chster Pfadpunkt&lt;br /&gt;; *&lt;br /&gt;; *		newPoint(x, y)&lt;br /&gt;; *			erstellt einen neuen Punkt&lt;br /&gt;; *&lt;br /&gt;; *		comparePoints(p1, p2)&lt;br /&gt;; *			Vergleichsoperation f&amp;uuml;r die Sortierung&lt;br /&gt;; *&lt;br /&gt;; *		isCCW(p1, p2, p3)&lt;br /&gt;; *			Pr&amp;uuml;fung auf Richtung (CounterClockWise - entgegen dem Uhrzeigersinn)&lt;br /&gt;; *&lt;br /&gt;; *		drawPoint(p, radius)&lt;br /&gt;; *			zeichnet den Punkt mit gegebenem Radius&lt;br /&gt;; *&lt;br /&gt;; *		drawAllPoints(radius)&lt;br /&gt;; *			zeichnet alle Punkte mit gegebenem Radius&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TPoint&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;	&lt;br /&gt;	Field succ.TPoint&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newPoint.TPoint(x#, y#)&lt;br /&gt;	Local p.TPoint=New TPoint&lt;br /&gt;	&lt;br /&gt;	p\x=x&lt;br /&gt;	p\y=y&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function comparePoints(p1.TPoint, p2.TPoint)&lt;br /&gt;	f#=p1\x*p2\y-p2\x*p1\y&lt;br /&gt;	&lt;br /&gt;	If f&amp;gt;0&lt;br /&gt;		Return True&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If f&amp;gt;=-0.0001 ; == 0&lt;br /&gt;		If Abs(p1\x)+Abs(p1\y)&amp;gt;Abs(p2\x)+Abs(p2\y)&lt;br /&gt;			Return True&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return False&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function isCCW(p1.TPoint, p2.TPoint, p3.TPoint)&lt;br /&gt;	Return (p2\x-p1\x)*(p3\y-p1\y)-(p2\y-p1\y)*(p3\x-p1\x)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawPoint(p.TPoint, rad#=2)&lt;br /&gt;	Oval p\x-rad, p\y-rad, 2*rad, 2*rad&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawAllPoints(rad#=2)&lt;br /&gt;	Local p.TPoint&lt;br /&gt;	&lt;br /&gt;	For p=Each TPoint&lt;br /&gt;		drawPoint(p, rad)&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Grundstruktur&lt;br /&gt;; *&lt;br /&gt;; *		TTriangle&lt;br /&gt;; *			p1		Punkt 1&lt;br /&gt;; *			p2		Punkt 2&lt;br /&gt;; *			p3		Punkt 3&lt;br /&gt;; *&lt;br /&gt;; *		newTriangle(p1, p2, p3)&lt;br /&gt;; *			erstellt ein neues Dreieck&lt;br /&gt;; *&lt;br /&gt;; *		drawTriangle(t)&lt;br /&gt;; *			zeichnet ein Dreieck&lt;br /&gt;; *&lt;br /&gt;; *		drawAllTriangles()&lt;br /&gt;; *			zeichnet alle Dreiecke&lt;br /&gt;; *&lt;br /&gt;; *		triangleArea()&lt;br /&gt;; *			liefert die Fl&amp;auml;che eines Dreiecks zur&amp;uuml;ck&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TTriangle&lt;br /&gt;	Field p1.TPoint&lt;br /&gt;	Field p2.TPoint&lt;br /&gt;	Field p3.TPoint&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTriangle.TTriangle(p1.TPoint, p2.TPoint, p3.TPoint)&lt;br /&gt;	Local t.TTriangle=New TTriangle&lt;br /&gt;	&lt;br /&gt;	t\p1=p1&lt;br /&gt;	t\p2=p2&lt;br /&gt;	t\p3=p3&lt;br /&gt;	&lt;br /&gt;	Return t&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawTriangle(t.TTriangle)&lt;br /&gt;	Line t\p1\x, t\p1\y, t\p2\x, t\p2\y&lt;br /&gt;	Line t\p2\x, t\p2\y, t\p3\x, t\p3\y&lt;br /&gt;	Line t\p3\x, t\p3\y, t\p1\x, t\p1\y&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawAllTriangles()&lt;br /&gt;	Local t.TTriangle&lt;br /&gt;	&lt;br /&gt;	For t=Each TTriangle&lt;br /&gt;		drawTriangle(t)&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function triangleArea#(t.TTriangle)&lt;br /&gt;	Local x1#, y1#, x2#, y2#&lt;br /&gt;	&lt;br /&gt;	x1=t\p2\x-t\p1\x&lt;br /&gt;	y1=t\p2\y-t\p1\y&lt;br /&gt;	&lt;br /&gt;	x2=t\p3\x-t\p1\x&lt;br /&gt;	y2=t\p3\y-t\p1\y&lt;br /&gt;	&lt;br /&gt;	Return 0.5*Abs(x1*y2-y1*x2)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Hull Finder&lt;br /&gt;; *&lt;br /&gt;; *		MAX_POINTS&lt;br /&gt;; *			Anzahl an maximal unterst&amp;uuml;tzter Punkte&lt;br /&gt;; *&lt;br /&gt;; *		buildConvexHull()&lt;br /&gt;; *			liefert eine verkettete Liste der H&amp;uuml;llenpunkte&lt;br /&gt;; *&lt;br /&gt;; *		buildConcaveHull()&lt;br /&gt;; *			liefert eine verkettete Liste des Pfades durch alle Punkte&lt;br /&gt;; *&lt;br /&gt;; *		quickSort(p[], lo, hi)&lt;br /&gt;; *			sortiert die Liste der Punkte&lt;br /&gt;; *&lt;br /&gt;; *		makeRelTo(p[], count, p0)&lt;br /&gt;; *			verschiebt die Punkte ins Koordinatensystem von p0&lt;br /&gt;; *&lt;br /&gt;; *		indexOfLowestPoint(p[], count)&lt;br /&gt;; *			Punkt mit dem kleinsten Y-Wert (und bei doppelten, mit dem kleinsten X-Wert)&lt;br /&gt;; *&lt;br /&gt;; *		exchange(p[], i, j)&lt;br /&gt;; *			vertauscht Punkte i und j&lt;br /&gt;; *&lt;br /&gt;; *		drawHull(p)&lt;br /&gt;; *			zeichnet die H&amp;uuml;lle vom Startpunkt der verketteten Liste aus&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const MAX_POINTS=100&lt;br /&gt;&lt;br /&gt;Function buildConvexHull.TPoint()&lt;br /&gt;	Local points.TPoint[MAX_POINTS]&lt;br /&gt;	Local pCount=0&lt;br /&gt;	&lt;br /&gt;	Local p.TPoint&lt;br /&gt;	&lt;br /&gt;	For p=Each TPoint&lt;br /&gt;		p\succ=Null&lt;br /&gt;		&lt;br /&gt;		points[pCount]=p&lt;br /&gt;		pCount=pCount+1&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	If pCount&amp;lt;3&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	exchange(points, 0, indexOfLowestPoint(points, pCount))&lt;br /&gt;	&lt;br /&gt;	Local pl.TPoint=newPoint(points[0]\x, points[0]\y)&lt;br /&gt;	makeRelTo(points, pCount, pl)&lt;br /&gt;	&lt;br /&gt;	quickSort(points, 1, pCount-1)&lt;br /&gt;	&lt;br /&gt;	pl\x=-pl\x : pl\y=-pl\y&lt;br /&gt;	makeRelTo(points, pCount, pl)&lt;br /&gt;	&lt;br /&gt;	Delete pl&lt;br /&gt;	&lt;br /&gt;	Local m=2&lt;br /&gt;	For i=3 To pCount-1&lt;br /&gt;		While isCCW(points[m-1], points[m], points&lt;i&gt;)&amp;lt;=0&lt;br /&gt;			m=m-1&lt;br /&gt;		Wend&lt;br /&gt;		&lt;br /&gt;		m=m+1&lt;br /&gt;		exchange(points, m, i)&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For i=1 To m&lt;br /&gt;		points[i-1]\succ=points[i]&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return points[0]&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function buildConcaveHull.TPoint()&lt;br /&gt;	Local points.TPoint[MAX_POINTS]&lt;br /&gt;	Local pCount=0&lt;br /&gt;	&lt;br /&gt;	Local p.TPoint&lt;br /&gt;	&lt;br /&gt;	For p=Each TPoint&lt;br /&gt;		p\succ=Null&lt;br /&gt;		&lt;br /&gt;		points[pCount]=p&lt;br /&gt;		pCount=pCount+1&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	If pCount&amp;lt;3&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	exchange(points, 0, indexOfLowestPoint(points, pCount))&lt;br /&gt;	&lt;br /&gt;	Local pl.TPoint=newPoint(points[0]\x, points[0]\y)&lt;br /&gt;	makeRelTo(points, pCount, pl)&lt;br /&gt;	&lt;br /&gt;	quickSort(points, 1, pCount-1)&lt;br /&gt;	&lt;br /&gt;	pl\x=-pl\x : pl\y=-pl\y&lt;br /&gt;	makeRelTo(points, pCount, pl)&lt;br /&gt;	&lt;br /&gt;	Delete pl&lt;br /&gt;	&lt;br /&gt;	For i=1 To pCount-1&lt;br /&gt;		points[i-1]\succ=points[i]&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return points[0]&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function quickSort(p.TPoint[MAX_POINTS], lo, hi)&lt;br /&gt;	Local i=lo, j=hi&lt;br /&gt;	Local q.TPoint=p[(lo+hi)/2]&lt;br /&gt;	&lt;br /&gt;	While i&amp;lt;=j&lt;br /&gt;		While comparePoints(p[i], q)&lt;br /&gt;			i=i+1&lt;br /&gt;		Wend&lt;br /&gt;		&lt;br /&gt;		While comparePoints(q, p[j])&lt;br /&gt;			j=j-1&lt;br /&gt;		Wend&lt;br /&gt;		&lt;br /&gt;		If i&amp;lt;=j&lt;br /&gt;			exchange(p, i, j)&lt;br /&gt;			i=i+1&lt;br /&gt;			j=j-1&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	If lo&amp;lt;j&lt;br /&gt;		quickSort(p, lo, j)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If i&amp;lt;hi&lt;br /&gt;		quickSort(p, i, hi)&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function makeRelTo(p.TPoint[MAX_POINTS], count, p0.TPoint)&lt;br /&gt;	Local p1.TPoint=newPoint(p0\x, p0\y)&lt;br /&gt;	&lt;br /&gt;	For i=0 To count-1&lt;br /&gt;		p[i]\x=p[i]\x-p1\x&lt;br /&gt;		p[i]\y=p[i]\y-p1\y&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Delete p1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function indexOfLowestPoint(p.TPoint[MAX_POINTS], count)&lt;br /&gt;	Local i, min=0&lt;br /&gt;	&lt;br /&gt;	For i=1 To count-1&lt;br /&gt;		If p[i]\y&amp;gt;p[min]\y Or (p[i]\y=p[min]\y And p[i]\x&amp;lt;p[min]\x)&lt;br /&gt;			min=i&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return min&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function exchange(p.TPoint[MAX_POINTS], i, j)&lt;br /&gt;	Local t.TPoint=p[i]&lt;br /&gt;	p[i]=p[j]&lt;br /&gt;	p[j]=t&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawHull(p.TPoint)&lt;br /&gt;	Local started, oldX#, oldY#&lt;br /&gt;	&lt;br /&gt;	Local startX#=p\x&lt;br /&gt;	Local startY#=p\y&lt;br /&gt;	&lt;br /&gt;	Local pStart.TPoint=p&lt;br /&gt;	&lt;br /&gt;	While p&amp;lt;&amp;gt;Null&lt;br /&gt;		If Not started&lt;br /&gt;			oldX=p\x&lt;br /&gt;			oldY=p\y&lt;br /&gt;			&lt;br /&gt;			started=True&lt;br /&gt;		Else&lt;br /&gt;			Line oldX, oldY, p\x, p\y&lt;br /&gt;			&lt;br /&gt;			oldX=p\x&lt;br /&gt;			oldY=p\y&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		p=p\succ&lt;br /&gt;		&lt;br /&gt;		If p=pStart&lt;br /&gt;			Exit&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	If started&lt;br /&gt;		Line oldX, oldY, startX, startY&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Delaunay Triangulation&lt;br /&gt;; *&lt;br /&gt;; *		generateDelaunay()&lt;br /&gt;; *			erstellt die Delaunay Triangulation der gegebenen Punkte&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Function generateDelaunay()&lt;br /&gt;	Delete Each TTriangle&lt;br /&gt;	&lt;br /&gt;	Local p1.TPoint, p2.TPoint, p3.TPoint, p4.TPoint, t.TTriangle&lt;br /&gt;	Local pointValid, mx#, my#, rad#, m1x#, m1y#, n1x#, n1y#, m2x#, m2y#, n2x#, n2y#, k#&lt;br /&gt;	&lt;br /&gt;	For p1=Each TPoint&lt;br /&gt;		p2=After p1&lt;br /&gt;		While p2&amp;lt;&amp;gt;Null&lt;br /&gt;			p3=After p2&lt;br /&gt;			While p3&amp;lt;&amp;gt;Null&lt;br /&gt;				m1x=(p1\x+p2\x)/2&lt;br /&gt;				m1y=(p1\y+p2\y)/2&lt;br /&gt;				&lt;br /&gt;				n1x=p2\y-p1\y&lt;br /&gt;				n1y=p1\x-p2\x&lt;br /&gt;				&lt;br /&gt;				m2x=(p2\x+p3\x)/2&lt;br /&gt;				m2y=(p2\y+p3\y)/2&lt;br /&gt;				&lt;br /&gt;				n2x=p3\y-p2\y&lt;br /&gt;				n2y=p2\x-p3\x&lt;br /&gt;				&lt;br /&gt;				k=-(m1x*n2y-m1y*n2x-m2x*n2y+m2y*n2x)/(n1x*n2y-n1y*n2x)&lt;br /&gt;				&lt;br /&gt;				mx=m1x+k*n1x&lt;br /&gt;				my=m1y+k*n1y&lt;br /&gt;				&lt;br /&gt;				rad=Sqr((p1\x-mx)^2+(p1\y-my)^2)&lt;br /&gt;				&lt;br /&gt;				pointValid=True&lt;br /&gt;				For p4=Each TPoint&lt;br /&gt;					If p4&amp;lt;&amp;gt;p1 And p4&amp;lt;&amp;gt;p2 And p4&amp;lt;&amp;gt;p3&lt;br /&gt;						If Sqr((p4\x-mx)^2+(p4\y-my)^2)&amp;lt;=rad&lt;br /&gt;							pointValid=False&lt;br /&gt;							Exit&lt;br /&gt;						EndIf&lt;br /&gt;					EndIf&lt;br /&gt;				Next&lt;br /&gt;				&lt;br /&gt;				If pointValid&lt;br /&gt;					t=newTriangle(p1, p2, p3)&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				p3=After p3&lt;br /&gt;			Wend&lt;br /&gt;			&lt;br /&gt;			p2=After p2&lt;br /&gt;		Wend&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test Programm&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Graphics 800,600,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;Local p.TPoint&lt;br /&gt;Local t.TTriangle&lt;br /&gt;&lt;br /&gt;Local Timer=CreateTimer(60)&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	Color 0,255,0&lt;br /&gt;	If MouseHit(1)&lt;br /&gt;		p=newPoint(MouseX(), MouseY())&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	drawAllPoints(4)&lt;br /&gt;	&lt;br /&gt;	Color 255,255,0&lt;br /&gt;	generateDelaunay()&lt;br /&gt;	drawAllTriangles()&lt;br /&gt;	&lt;br /&gt;	Color 0,0,255&lt;br /&gt;	p=buildConcaveHull()&lt;br /&gt;	If p&amp;lt;&amp;gt;Null&lt;br /&gt;	;	drawHull(p)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Color 255,255,255&lt;br /&gt;	p=buildConvexHull()&lt;br /&gt;	If p&amp;lt;&amp;gt;Null&lt;br /&gt;	;	drawHull(p)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	WaitTimer(Timer)&lt;br /&gt;	Cls&lt;br /&gt;Wend&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Stokes:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ich habe mal versucht sowas wie &amp;quot;realistisches&amp;quot; Feuer zu gestalten. Dies ist eigentlich nur ein Test, dienend zur Grundlagenforschung. Nach den &lt;a href=&quot;http://de.wikipedia.org/wiki/Navier-Stokes-Gleichungen&quot; target=&quot;_blank&quot;&gt;Stoke'schen Gleichungen&lt;/a&gt;, dazu gibt es &lt;a href=&quot;http://www.mikeash.com/pyblog/fluid-simulation-for-dummies.html&quot; target=&quot;_blank&quot;&gt;viele&lt;/a&gt; &lt;a href=&quot;http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf&quot; target=&quot;_blank&quot;&gt;Tutorials&lt;/a&gt; im Netz, die man ziemlich gut umsetzen kann. Eigentlich sind es gekoppelte Differentialgleichungen h&amp;ouml;herer Ordnung die man da zu l&amp;ouml;sen hat. Im Allgemeinen macht man das nicht von Hand (es sei denn man ist wahnsinnig oder hat gen&amp;uuml;gend Zeit und Erfahrung), sondern numerisch. Genau das macht man in den beschriebenen Tutorials.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_18_Stokes.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Das Prinzip ist Grid-based. Gerendert werden aufgeblasene Pixel (mit Rechtecken aus Lines, im LockBuffer Modus schnell genug). Wie gesagt ist das Programm als Grundlagenforschung gedacht, eigentlich m&amp;ouml;chte ich daraus eine kleine Partikelengine basteln, um lustige Dinge wie Fackeln oder &amp;Auml;hnliches zu simulieren. Ich m&amp;ouml;chte nicht einfach zuf&amp;auml;llig Partikel ausspucken, das sieht nicht wirklich toll aus (hab ich irgendwann mal gemacht und sollte irgendwo auf der Platte zu finden sein.. egal). &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_18_Stokes.rar&quot; target=&quot;_blank&quot;&gt;Programm&lt;/a&gt; zum rumspielen kann &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_18_Stokes.rar&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt; heruntergeladen werden, Code im Paket. Steuerung ist ziemlich einfach, Maus dr&amp;uuml;cken erstellt Rauch (erh&amp;ouml;ht Dichte), Maus bewegen erzeugt Geschwindigkeit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Wasser:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Und nun zum versprochenen Wasser. Wer sich an meine &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/?page=2#2001&quot; target=&quot;_blank&quot;&gt;ersten Eintr&amp;auml;ge&lt;/a&gt; erinnert, mag sich vielleicht auch an meine partikelbasierte Wassersimulation erinnern. Die meisten werden wahrscheinlich auch &lt;a href=&quot;https://www.blitzforum.de/worklogs/304/&quot; target=&quot;_blank&quot;&gt;Noobodys Worklog&lt;/a&gt; verfolgen und von seiner &lt;a href=&quot;http://de.wikipedia.org/wiki/Smoothed_Particle_Hydrodynamics&quot; target=&quot;_blank&quot;&gt;SPH&lt;/a&gt;-Implementation wissen.&lt;br /&gt;Ich habe mich mittlerweilen davon gel&amp;ouml;st, meine Variante war mir zu instabil, zu unruhig etc.&lt;br /&gt;Ich habe deshalb beschlossen, einen festen Bereich f&amp;uuml;r das Wasser zu definieren, ich stecke das Wasser in eine Box und definiere eine Wasseroberfl&amp;auml;che aus Punkten. Danach kann ich die Punkte beliebig auslenken und sie werden wieder ausgeglichen, bis sich eine ruhige Oberfl&amp;auml;che wieder eingestellt hat. Das funktioniert relativ gut, hier ein Beispiel:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_18_Water.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Der Code ist 3D-basiert, ben&amp;ouml;tigt also eine Kamera. Ich bin mir noch nicht ganz schl&amp;uuml;ssig, wie ich das System l&amp;ouml;sen soll. Im Moment mache ich es so, dass die Koordinate im Wasser der Bildschirm-Koordinate entspricht (d.h die Meshposition ist im Ecken oben links und die Kamera ist entsprechend gedreht). Aber vielleicht w&amp;auml;re es kl&amp;uuml;ger, es so zu machen, dass ich es relativ zu einer gegebenen Wasserposition mache, wird sich noch herausstellen, die &amp;Auml;nderung w&amp;auml;re nur eine kleine Anpassung.&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * Welle&lt;br /&gt;; *&lt;br /&gt;; *		MAX_WAVE_COUNT&lt;br /&gt;; *			Anzahl der maximal m&amp;ouml;glichen Wellenpunkte&lt;br /&gt;; *&lt;br /&gt;; *		WATERCAM&lt;br /&gt;; *			die Kamera f&amp;uuml;r die Darstellung des Wassers in 2D&lt;br /&gt;; *&lt;br /&gt;; *		initWaterCam()&lt;br /&gt;; *			erstellt die Wasserkamera (inkl. Drehung)&lt;br /&gt;; *&lt;br /&gt;; *		TWave&lt;br /&gt;; *			pList[]			Liste der Wellenpunkte&lt;br /&gt;; *			pCount			Anzahl der Wellenpunkte&lt;br /&gt;; *			segmentSize		L&amp;auml;nge der einzelnen Segmente&lt;br /&gt;; *			xStart			X-Wert der linken Seite&lt;br /&gt;; *			xStop			X-Wert der rechten Seite&lt;br /&gt;; *			ySurface		Y-Wert der Oberfl&amp;auml;che&lt;br /&gt;; *			yBottom			Y-Wert des Untergrunds&lt;br /&gt;; *			mesh			Mesh der Welle&lt;br /&gt;; *			surf			Surface der Welle&lt;br /&gt;; *&lt;br /&gt;; *		TWavePoint&lt;br /&gt;; *			x		X-Koordinate&lt;br /&gt;; *			y		Y-Koordinate&lt;br /&gt;; *			vx		X-Geschwindigkeit&lt;br /&gt;; *			vy		Y-Geschwindigkeit&lt;br /&gt;; *			fix		Festsetzung eines Punktes&lt;br /&gt;; *&lt;br /&gt;; *		newWavePoint(x, y)&lt;br /&gt;; *			erstellt einen neuen Wellenpunkt&lt;br /&gt;; *&lt;br /&gt;; *		newWave(xStart, xEnd, y, yBottom, size)&lt;br /&gt;; *			erstellt eine neue Welle nach angegebenen Parametern&lt;br /&gt;; *&lt;br /&gt;; *		addWavePoint(w, p)&lt;br /&gt;; *			f&amp;uuml;gt der Welle einen neuen Punkt hinzu&lt;br /&gt;; *&lt;br /&gt;; *		addNewWavePoint(w, x, y)&lt;br /&gt;; *			erstellt einen neuen Wellenpunkt und f&amp;uuml;gt ihn der Welle hinzu&lt;br /&gt;; *&lt;br /&gt;; *		updateWave(w)&lt;br /&gt;; *			erneuert die Wellenpunkte und die Wellen-Mesh&lt;br /&gt;; *&lt;br /&gt;; *		addWaveSource(w, x, width, height)&lt;br /&gt;; *			verschiebt die Wellenpunkte in einer Breite um x um eine gewisse H&amp;ouml;he&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Global WATERCAM&lt;br /&gt;&lt;br /&gt;Function initWaterCam()&lt;br /&gt;	WATERCAM=CreateCamera()&lt;br /&gt;	&lt;br /&gt;	TurnEntity WATERCAM, 180, 0, 0&lt;br /&gt;	PositionEntity WATERCAM, 0, 0, GraphicsWidth()/2&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Const MAX_WAVE_COUNT=128&lt;br /&gt;&lt;br /&gt;Type TWave&lt;br /&gt;	Field pList.TWavePoint[MAX_WAVE_COUNT]&lt;br /&gt;	Field pCount&lt;br /&gt;	&lt;br /&gt;	Field segmentSize#&lt;br /&gt;	&lt;br /&gt;	Field xStart#&lt;br /&gt;	Field xStop#&lt;br /&gt;	Field ySurface#&lt;br /&gt;	Field yBottom#&lt;br /&gt;	&lt;br /&gt;	Field mesh&lt;br /&gt;	Field surf&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Type TWavePoint&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;	&lt;br /&gt;	Field vx#&lt;br /&gt;	Field vy#&lt;br /&gt;	&lt;br /&gt;	Field fix&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newWavePoint.TWavePoint(x#, y#)&lt;br /&gt;	Local w.TWavePoint=New TWavePoint&lt;br /&gt;	&lt;br /&gt;	w\x=x&lt;br /&gt;	w\y=y&lt;br /&gt;	&lt;br /&gt;	Return w&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function newWave.TWave(xStart#, xEnd#, y#, yBottom#, size#)&lt;br /&gt;	Local w.TWave=New TWave&lt;br /&gt;	&lt;br /&gt;	w\segmentSize=size&lt;br /&gt;	&lt;br /&gt;	Local p1.TWavePoint, p2.TWavePoint&lt;br /&gt;	Local x#=xStart&lt;br /&gt;	&lt;br /&gt;	w\xStart=xStart&lt;br /&gt;	w\xStop=xEnd&lt;br /&gt;	w\ySurface=y&lt;br /&gt;	w\yBottom=yBottom&lt;br /&gt;	&lt;br /&gt;	While x&amp;lt;=xEnd&lt;br /&gt;		addNewWavePoint(w, x, y)&lt;br /&gt;		&lt;br /&gt;		x=x+size&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	w\pList[0]\fix=True&lt;br /&gt;	w\pList[w\pCount-1]\fix=True&lt;br /&gt;	&lt;br /&gt;	w\mesh=CreateMesh()&lt;br /&gt;	w\surf=CreateSurface(w\mesh)&lt;br /&gt;	&lt;br /&gt;	PositionEntity w\mesh, -GraphicsWidth()/2, -GraphicsHeight()/2, 0&lt;br /&gt;	EntityFX w\mesh,16&lt;br /&gt;	&lt;br /&gt;	Return w&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addWavePoint(w.TWave, p.TWavePoint)&lt;br /&gt;	w\pList[w\pCount]=p&lt;br /&gt;	w\pCount=w\pCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addNewWavePoint(w.TWave, x#, y#)&lt;br /&gt;	w\pList[w\pCount]=newWavePoint(x, y)&lt;br /&gt;	w\pCount=w\pCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function updateWave(w.TWave)&lt;br /&gt;	Local wpAct.TWavePoint, wpPre.TWavePoint, wpSuc.TWavePoint&lt;br /&gt;	Local mY#&lt;br /&gt;	&lt;br /&gt;	For i=1 To w\pCount-2&lt;br /&gt;		wpPre=w\pList[i-1]&lt;br /&gt;		wpAct=w\pList[i]&lt;br /&gt;		wpSuc=w\pList[i+1]&lt;br /&gt;		&lt;br /&gt;		mY=(wpPre\y+wpSuc\y)/2&lt;br /&gt;		&lt;br /&gt;		wpAct\vy=(mY-wpAct\y+wpAct\vy)*0.98&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For i=0 To w\pCount-1&lt;br /&gt;		If Not w\pList[i]\fix&lt;br /&gt;			w\pList[i]\y=w\pList[i]\y+w\pList[i]\vy&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	ClearSurface w\surf, True, True&lt;br /&gt;	&lt;br /&gt;	Local v1, v2, v3, v4&lt;br /&gt;	Local stp#=1./w\pCount&lt;br /&gt;	&lt;br /&gt;	v1=AddVertex(w\surf, w\pList[0]\x, w\pList[0]\y, 0, stp*i, 0)&lt;br /&gt;	v2=AddVertex(w\surf, w\pList[0]\x, w\yBottom, 0, stp*i, 1)&lt;br /&gt;	&lt;br /&gt;	For i=1 To w\pCount-1&lt;br /&gt;		v3=AddVertex(w\surf, w\pList[i]\x, w\pList[i]\y, 0, stp*i, 0)&lt;br /&gt;		v4=AddVertex(w\surf, w\pList[i]\x, w\yBottom, 0, stp*i, 1)&lt;br /&gt;		&lt;br /&gt;		AddTriangle(w\surf, v1, v2, v3)&lt;br /&gt;		AddTriangle(w\surf, v3, v4, v2)&lt;br /&gt;		&lt;br /&gt;		v1=v3&lt;br /&gt;		v2=v4&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addWaveSource(w.TWave, x#, height#, width#)&lt;br /&gt;	Local dist#&lt;br /&gt;	&lt;br /&gt;	For i=0 To w\pCount-1&lt;br /&gt;		If Not w\pList[i]\fix&lt;br /&gt;			dist=Abs(x-w\pList[i]\x)&lt;br /&gt;			&lt;br /&gt;			If dist&amp;lt;width/2&lt;br /&gt;				w\pList[i]\y=w\pList[i]\y-height&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Testprogramm&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Graphics3D 800,600,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;initWaterCam()&lt;br /&gt;&lt;br /&gt;Local w.TWave=newWave(0, 800, 300, 600, 10)&lt;br /&gt;EntityColor w\mesh, 0, 150, 255&lt;br /&gt;&lt;br /&gt;;Local waveTex=LoadTexture(&amp;quot;water.png&amp;quot;)&lt;br /&gt;;ScaleTexture waveTex,.25,.25&lt;br /&gt;;EntityTexture w\mesh, waveTex&lt;br /&gt;;EntityAlpha w\mesh, 0.75&lt;br /&gt;&lt;br /&gt;Local timer=CreateTimer(60)&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	RenderWorld&lt;br /&gt;	&lt;br /&gt;	updateWave(w)&lt;br /&gt;	&lt;br /&gt;	If MouseHit(1)&lt;br /&gt;		addWaveSource(w, MouseX(), 50, 30)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	fps=fps+1&lt;br /&gt;	If MilliSecs()-fpsTime&amp;gt;999&lt;br /&gt;		fpsCur=fps&lt;br /&gt;		fpsTime=MilliSecs()&lt;br /&gt;		fps=0&lt;br /&gt;	EndIf&lt;br /&gt;	Text 10,10,fpsCur&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	Cls&lt;br /&gt;	WaitTimer(timer)&lt;br /&gt;Wend&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Intermezzo:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, was jetzt folgt, wird vielleicht einige Leute ver&amp;auml;rgern, aber ich nehme mir die Freiheit es trotzdem zu tun. Der folgende Teil des Worklogs wird in Englisch gehalten sein. Der Grund dazu ist einfach, Deutsch ist eine Sprache, die eigentlich nur in Deutschland (und n&amp;auml;herer Umgebung) gesprochen wird, Englisch ist weitl&amp;auml;ufiger verbreitet und auch grossfl&amp;auml;chiger akzeptiert. Wenn ihr einmal eine akademische Laufbahn einschlagen werdet, dann m&amp;uuml;sst ihr euch mit hoher Wahrscheinlichkeit mit Englisch auseinandersetzen (ist bei mir jedenfalls so). Und ich m&amp;ouml;chte gewisse Aspekte meines Worklogs einfach allgemeiner zug&amp;auml;nglich gestalten. Soweit zu meinen Gr&amp;uuml;nden, die Entscheidung steht nicht weiter zur Diskussion (es sei denn die Moderation verbietet es &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt;).&lt;br /&gt;&lt;br /&gt;-----&lt;br /&gt;&lt;br /&gt;&lt;b&gt;DaDaPhysics:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In the last days I restructured my DaDaPhysics engine a little, which means, I changed some function names and some type-names. I did not change much in the way the engine works. Furthermore I stripped it to the &amp;quot;bare minimum&amp;quot; - it now works an a 2D basis only (I excluded the 2.5D part in a separate file, which has to be included to use). I also got rid of my first implementation of the particle based water (reason will follow in a sec). The reason for these changes was, that the File kept getting longer and I completely lost the oversight. I also did not have any naming consistency whatsoever, which made it all the more confusing, that's why I decided to invest a little time to change that, so I could continue to work with it in the future. I am currently working on a documentation, but as lazy as I tend to be, this could take while, so you have to be patient :&amp;gt;.&lt;br /&gt;In further news I am currently adding a &amp;quot;new&amp;quot; (as in renewed) feature: As you may have seen above, I started a box-based water, which is actually just a surface simulation. At the moment I do handle them separately, which means, that the water part uses the physics engine and manipulates the body-data, aside the normal physical update. Of course this means, that I just buried my attempt of ridding the system of it's 3D component (which has proven to be unstable on some modern machines), oh well, no matter. The first result is shown below:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_18_WaterPhysics.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The objects float or sink, depending on their density. I made certain simplifications to the collision detection. At the moment, I only check the flat surface, no waves are taken into consideration. I think this will be changed in the near future, to make it seem more realistic. Also, the body is just pushed upwards, but it will start to rotate, if it has not sunken evenly. I take the center of the overlapping area and add the hydrostatic force from there (which results in said rotation).&lt;br /&gt;&lt;br /&gt;The demo of the new feature can be found &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_18_WaterPhys.rar&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;, by &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_18_WaterPhys.rar&quot; target=&quot;_blank&quot;&gt;klicking&lt;/a&gt; on the &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_18_WaterPhys.rar&quot; target=&quot;_blank&quot;&gt;link&lt;/a&gt;.&lt;br /&gt;The controls are pretty basic, [i]Left Mouse&lt;/i&gt; spawns a new Box, &lt;i&gt;Right Mouse&lt;/i&gt; makes the box breakable (it will basically explode whenever it is in contact with water..).&lt;br /&gt;&lt;br /&gt;That's it for tonight, I wish you all a pleasant evening and a good night of sleep,&lt;br /&gt;Yours sincerely,&lt;br /&gt;Darth&lt;br /&gt;&lt;br /&gt;-----&lt;br /&gt;&lt;br /&gt;Das w&amp;auml;rs heute, ich w&amp;uuml;nsche allen einen sch&amp;ouml;nen Abend und eine gute M&amp;uuml;tze voll Schlaf,&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Fri, 28 May 2010 23:51:51 +0200</pubDate>
		</item>

		<item>
			<title>Squad..</title>
			<link>https://www.blitzforum.de/worklogs/292/#2381</link>
			<guid>https://www.blitzforum.de/worklogs/292/#2381</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;heute ist mal wieder so ein Tag, da hab ich keine Lust mehr. Also schreib ich einen Worklogeintrag, um mich ein wenig abzulenken. Das wird wieder ein ziemlich unstrukturierter Mischmasch von Dingen die ich versucht habe, einfach um ein wenig Vorarbeit f&amp;uuml;r das zu schaffen, was mir die Laune verdorben hat.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;LSysteme:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Oh ja, das ist was ganz Neues, wurde noch nie gemacht. Hihi, nein, &lt;a href=&quot;http://de.wikipedia.org/wiki/Lindenmayer-System&quot; target=&quot;_blank&quot;&gt;LSysteme&lt;/a&gt; sind wahrscheinlich die etwa &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=31581&amp;amp;highlight=system&quot; target=&quot;_blank&quot;&gt;bekanntesten&lt;/a&gt; Fraktale, neben ganzen Strukturen wie das &lt;a href=&quot;http://de.wikipedia.org/wiki/Sierpinski-Dreieck&quot; target=&quot;_blank&quot;&gt;Sierpinskydreieck&lt;/a&gt;. Eigentlich ist es ziemlich einfach:&lt;br /&gt;Gegeben ist String &lt;i&gt;A&lt;/i&gt;, und die Ersetzungsregeln &lt;i&gt;M_i -&amp;gt; R_i&lt;/i&gt;, suche in &lt;i&gt;A&lt;/i&gt; das Muster &lt;i&gt;M_i&lt;/i&gt; und ersetze es durch &lt;i&gt;R_i&lt;/i&gt;, und das f&amp;uuml;r jede Iteration.&lt;br /&gt;Zuerst dachte ich, dass ich daf&amp;uuml;r einen wirklich tollen Algorithmus brauche, Boyer-Moore oder Knuth-Morris-Pratt, &amp;ouml;hm, ja.. dann fiel mir ein, dass BB ja sowas lustiges wie &lt;a href=&quot;https://www.blitzforum.de/help/Instr&quot; target=&quot;_blank&quot;&gt;Instr()&lt;/a&gt; hat, das macht die Algorithmen nat&amp;uuml;rlich obsolet &lt;img src=&quot;/forum/images/smiles/icon_biggrin.gif&quot; alt=&quot;Very Happy&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_17_LSystem.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ziel war es urspr&amp;uuml;nglich, aus den LSystemen B&amp;auml;ume zu basteln, und die als Hintergrund in mein Spiel einzubauen. Allerdings habe ich zwei Probleme damit. Erstens sind die B&amp;auml;ume doch ziemlich regelm&amp;auml;ssig und &amp;quot;unnat&amp;uuml;rlich&amp;quot; (naja, &amp;uuml;ber den Punkt kann man diskutieren), und zweitens ist es meines Wissens unm&amp;ouml;glich, von einer gegebenen Struktur auf ihr LSystem zur&amp;uuml;ckzuschliessen, ich m&amp;uuml;sste also rumprobieren, bis ich einen eigenen Baum finde, oder einfach die gegebenen Beispiele nehmen, die man so im Internet findet.&lt;br /&gt;Nat&amp;uuml;rlich k&amp;ouml;nnte man die Darstellungsart noch &amp;auml;ndern, dickere Linien machen f&amp;uuml;r die St&amp;auml;mme, dann sieht es nochmal etwas sch&amp;ouml;ner aus, allerdings kann man aus dem String nicht direkt rauslesen, WO in der Struktur man ist, da m&amp;uuml;sste man noch etwas Gedanken investieren, und dazu gef&amp;auml;llt mir das Prinzip nicht genug. Um trotzdem nicht mit leeren H&amp;auml;nden dazustehen, habe ich einen kleinen &amp;quot;automatisch scrollenden&amp;quot; Wald gebastelt, Codes dazu gibt es eigentlich genug im Codearchiv/Internet, deshalb hier nur einen &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_17_LSystem.rar&quot; target=&quot;_blank&quot;&gt;Download&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pattern Recognition:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, nun zur &amp;quot;Hauptattraktion&amp;quot;. Ich habe ein lustiges Fach, das nennt sich &lt;i&gt;Computational Biology&lt;/i&gt;, worum es geht weiss keiner so wirklich, es hat irgendwas mit Biologie zu tun und ganz viel Wahrscheinlichkeitstheorie. In der Vorlesung wurde u.a auch Pattern-Recognition diskutiert.&lt;br /&gt;Die einfachste Methode ist, das ganze Muster in einem gegebenen String zu suchen, dazu gibt es (wie im LSystem Teil erw&amp;auml;hnt) einige Algorithmen, der mir beste bekannte ist KMP, den zu implementieren ist nicht wirklich schwer, ich habe das mal gemacht (inkl. Beispiel):&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * KMP&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const MAX_LENGTH=128&lt;br /&gt;&lt;br /&gt;Function KMP_Analyze(m$, jump[MAX_LENGTH])&lt;br /&gt;	Local mLen=Len(m)&lt;br /&gt;	&lt;br /&gt;	Local i=1, j=0&lt;br /&gt;	&lt;br /&gt;	While i&amp;lt;mLen&lt;br /&gt;		If Mid(m, i+1, 1)=Mid(m, j+1, 1)&lt;br /&gt;			jump&lt;i&gt;=j+1&lt;br /&gt;			&lt;br /&gt;			i=i+1&lt;br /&gt;			j=j+1&lt;br /&gt;		Else&lt;br /&gt;			If j&amp;gt;0&lt;br /&gt;				j=jump[j-1]&lt;br /&gt;			Else&lt;br /&gt;				jump[i]=0&lt;br /&gt;				i=i+1&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function KMP(txt$, muster$, i0=0)&lt;br /&gt;	Local jump[MAX_LENGTH]&lt;br /&gt;	KMP_Analyze(muster, jump)&lt;br /&gt;	&lt;br /&gt;	Local n=Len(txt)&lt;br /&gt;	Local m=Len(muster)&lt;br /&gt;	&lt;br /&gt;	Local i=i0, j=0&lt;br /&gt;	&lt;br /&gt;	While i&amp;lt;n&lt;br /&gt;		If Mid(txt, i+1, 1)=Mid(muster, j+1, 1)&lt;br /&gt;			If j=m-1&lt;br /&gt;				Return i-m+1&lt;br /&gt;			EndIf&lt;br /&gt;			&lt;br /&gt;			i=i+1&lt;br /&gt;			j=j+1&lt;br /&gt;		Else&lt;br /&gt;			If j&amp;gt;0&lt;br /&gt;				j=jump[j-1]&lt;br /&gt;			Else&lt;br /&gt;				i=i+1&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	Return -1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Local muster$=&amp;quot;abrakadabra&amp;quot;&lt;br /&gt;Local txt$=&amp;quot;er sprach abrakadabra, aber abrakadabra&amp;quot;&lt;br /&gt;&lt;br /&gt;Local i=KMP(txt, muster)&lt;br /&gt;&lt;br /&gt;Print i+&amp;quot;:&amp;quot;&lt;br /&gt;Print txt&lt;br /&gt;Print String(&amp;quot; &amp;quot;,i)+muster&lt;br /&gt;&lt;br /&gt;Local j=KMP(txt, muster, i+1)&lt;br /&gt;&lt;br /&gt;Print j+&amp;quot;:&amp;quot;&lt;br /&gt;Print txt&lt;br /&gt;Print String(&amp;quot; &amp;quot;,j)+muster&lt;br /&gt;&lt;br /&gt;WaitKey()[/syntax]&lt;br /&gt;&lt;br /&gt;Das dient nat&amp;uuml;rlich nur dazu, eine Sequenz zu finden, von der man weiss, dass sie vorhanden ist. Allgemein interessiert man sich aber eher f&amp;uuml;r &amp;quot;Fuzzy-Suchen&amp;quot;, also man sucht etwas, das ungef&amp;auml;hr &amp;auml;hnlich ist, aber nur gering abweicht. Und hier fangen die (=meine) Schwierigkeiten an.&lt;br /&gt;Ich kenne ein paar Verfahren die mir theoretisch helfen k&amp;ouml;nnten, da w&amp;auml;re die &lt;a href=&quot;http://en.wikipedia.org/wiki/Levenshtein_distance&quot; target=&quot;_blank&quot;&gt;Levenshtein Distanz&lt;/a&gt;, der die &amp;quot;Un&amp;auml;hnlichkeit&amp;quot; zweier Strings berechnet und das &lt;a href=&quot;http://en.wikipedia.org/wiki/Sequence_alignment&quot; target=&quot;_blank&quot;&gt;Sequence Alignment&lt;/a&gt;. Levenshtein hat das Problem, dass er [i]O(n^2)&lt;/i&gt; ist, das ist f&amp;uuml;r kleine Strings kein Ding, mehr dazu sp&amp;auml;ter. SA hat auch seine Probleme, daf&amp;uuml;r braucht man eine Matrix, die ist im Speicher &lt;i&gt;O(n^2)&lt;/i&gt;, und mit BBs Verhalten gegen&amp;uuml;ber langen Blitz-Arrays ist das ziemlich unsch&amp;ouml;n. Aber das hat mich nicht daran gehindert, die beiden mal zu programmieren und zu testen:&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * Definitionen&lt;br /&gt;; *		d sind die Kosten f&amp;uuml;r eine L&amp;uuml;cke&lt;br /&gt;; *		simularity sind die Kosten f&amp;uuml;r den Nachfolger&lt;br /&gt;; *		MAX_LENGTH ist die maximale L&amp;auml;nge eines Strings&lt;br /&gt;; *			(wird ben&amp;ouml;tigt weil B-Arrays mit Konstanten initialisiert werden m&amp;uuml;ssen)&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const d=-5&lt;br /&gt;&lt;br /&gt;;  A G C T&lt;br /&gt;; A&lt;br /&gt;; G  *&lt;br /&gt;; C    *&lt;br /&gt;; T&lt;br /&gt;&lt;br /&gt;Global simularity[16]&lt;br /&gt;simularity[ 0]=10 : simularity[ 1]=-1 : simularity[ 2]=-3 : simularity[3]=-4&lt;br /&gt;simularity[ 4]=-1 : simularity[ 5]=7  : simularity[ 6]=-5 : simularity[7]=-3&lt;br /&gt;simularity[ 8]=-3 : simularity[ 9]=-5 : simularity[10]=9  : simularity[11]=0&lt;br /&gt;simularity[12]=-4 : simularity[13]=-3 : simularity[14]=0  : simularity[15]=8&lt;br /&gt;&lt;br /&gt;Const MAX_LENGTH=64&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Vorberechnungen&lt;br /&gt;; *		calculateMatrix berechnet die Traversierungsmatrize f&amp;uuml;r das Problem&lt;br /&gt;; *		convertStringToArray wandelt den String in einen Array um&lt;br /&gt;; *			A=0, G=1, C=2, T=3&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Function min(a, b)&lt;br /&gt;	If a&amp;lt;b&lt;br /&gt;		Return a&lt;br /&gt;	Else&lt;br /&gt;		Return b&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function max(a, b)&lt;br /&gt;	If a&amp;gt;b&lt;br /&gt;		Return a&lt;br /&gt;	Else&lt;br /&gt;		Return b&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function calculateMatrix(source[MAX_LENGTH], sLength, dest[MAX_LENGTH], dLength, res[(MAX_LENGTH+1)*(MAX_LENGTH+1)])&lt;br /&gt;	For y=0 To sLength-1&lt;br /&gt;		res[y]=d*y&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For x=0 To dLength-1&lt;br /&gt;		res[x*(MAX_LENGTH+1)]=d*x&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Local k, l, m&lt;br /&gt;	&lt;br /&gt;	For y=1 To sLength&lt;br /&gt;		For x=1 To dLength&lt;br /&gt;			k=res[(y-1) + (x-1)*(MAX_LENGTH+1)] + simularity[source[y-1]*4 + dest[x-1]]&lt;br /&gt;			l=res[(y-1) + x*(MAX_LENGTH+1)] + d&lt;br /&gt;			m=res[y + (x-1)*(MAX_LENGTH+1)] + d&lt;br /&gt;			&lt;br /&gt;			res[y + x*(MAX_LENGTH+1)]=max(max(k, l),m)&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function convertStringToArray(s$, ar[MAX_LENGTH])&lt;br /&gt;	Local n&lt;br /&gt;	&lt;br /&gt;	For i=1 To Len(s)&lt;br /&gt;		Select Mid(s, i, 1)&lt;br /&gt;			Case &amp;quot;A&amp;quot;&lt;br /&gt;				n=0&lt;br /&gt;			Case &amp;quot;G&amp;quot;&lt;br /&gt;				n=1&lt;br /&gt;			Case &amp;quot;C&amp;quot;&lt;br /&gt;				n=2&lt;br /&gt;			Case &amp;quot;T&amp;quot;&lt;br /&gt;				n=3&lt;br /&gt;			Default&lt;br /&gt;				n=-1&lt;br /&gt;		End Select&lt;br /&gt;		&lt;br /&gt;		ar[i-1]=n&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Alignment Berechnung&lt;br /&gt;; *		die beiden resultierenden Strings werden in result1 bzw result2 gespeichert&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Global result1$, result2$&lt;br /&gt;&lt;br /&gt;Function getAlignment(ar[(MAX_LENGTH+1)*(MAX_LENGTH+1)], A[MAX_LENGTH], B[MAX_LENGTH], sA$, sB$)&lt;br /&gt;	Local alA$=&amp;quot;&amp;quot;&lt;br /&gt;	Local alB$=&amp;quot;&amp;quot;&lt;br /&gt;	&lt;br /&gt;	Local i=Len(sA)&lt;br /&gt;	Local j=Len(sB)&lt;br /&gt;	&lt;br /&gt;	Local score, scorediag, scoreup, scoreleft&lt;br /&gt;	&lt;br /&gt;	While i&amp;gt;0 And j&amp;gt;0&lt;br /&gt;		score=ar[i + j*(MAX_LENGTH+1)]&lt;br /&gt;		scorediag=ar[(i-1) + (j-1)*(MAX_LENGTH+1)]&lt;br /&gt;		scoreup=ar[i + (j-1)*(MAX_LENGTH+1)]&lt;br /&gt;		scoreleft=ar[(i-1) + j*(MAX_LENGTH+1)]&lt;br /&gt;		&lt;br /&gt;		If score=scorediag+simularity[A[i-1]*4+B[j-1]]&lt;br /&gt;			alA=Mid(sA, i, 1)+alA&lt;br /&gt;			alB=Mid(sB, j, 1)+alB&lt;br /&gt;			&lt;br /&gt;			i=i-1&lt;br /&gt;			j=j-1&lt;br /&gt;		ElseIf score=scoreleft+d&lt;br /&gt;			alA=Mid(sA, i, 1)+alA&lt;br /&gt;			alB=&amp;quot;-&amp;quot;+alB&lt;br /&gt;			&lt;br /&gt;			i=i-1&lt;br /&gt;		ElseIf score=scoreup+d&lt;br /&gt;			alA=&amp;quot;-&amp;quot;+alA&lt;br /&gt;			alB=Mid(sB, j, 1)+alB&lt;br /&gt;			&lt;br /&gt;			j=j-1&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	While i&amp;gt;0&lt;br /&gt;		alA=Mid(sA, i, 1)+alA&lt;br /&gt;		alB=&amp;quot;-&amp;quot;+alB&lt;br /&gt;		&lt;br /&gt;		i=i-1&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	While j&amp;gt;0&lt;br /&gt;		alA=&amp;quot;-&amp;quot;+alA&lt;br /&gt;		alB=Mid(sB, j, 1)+alB&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	result1=alA&lt;br /&gt;	result2=alB&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Levenshtein Distan&lt;br /&gt;; *		berechnet die Un&amp;auml;hnlichkeit zweier Strings&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Function getLevenshteinDistance(s$, t$)&lt;br /&gt;	Local n=Len(s)&lt;br /&gt;	Local m=Len(t)&lt;br /&gt;	&lt;br /&gt;	If n=0&lt;br /&gt;		Return m&lt;br /&gt;	ElseIf m=0&lt;br /&gt;		Return n&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local p[100], plen=n+1&lt;br /&gt;	Local d[100], dLen=n+1&lt;br /&gt;	Local tmp&lt;br /&gt;	&lt;br /&gt;	Local i, j&lt;br /&gt;	Local tj$&lt;br /&gt;	Local cost&lt;br /&gt;	&lt;br /&gt;	For i=0 To n&lt;br /&gt;		p&lt;i&gt;=i&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For j=1 To m&lt;br /&gt;		tj=Mid(t, j, 1)&lt;br /&gt;		d[0]=j&lt;br /&gt;		&lt;br /&gt;		For i=1 To n&lt;br /&gt;			If Mid(s, i, 1)=tj&lt;br /&gt;				cost=0&lt;br /&gt;			Else&lt;br /&gt;				cost=1&lt;br /&gt;			EndIf&lt;br /&gt;			&lt;br /&gt;			d[i]=min(min(d[i-1]+1, p[i]+1), p[i-1]+cost)&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		For i=0 To n ;array swap&lt;br /&gt;			tmp=p[i]&lt;br /&gt;			p[i]=d[i]&lt;br /&gt;			d[i]=tmp&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return p[n]&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Local s1$=&amp;quot;AGACTAGTTAC&amp;quot;;+&amp;quot;ACAGTACGTAAGATATGATAGATAGCTCAT&amp;quot;&lt;br /&gt;Local s2$=&amp;quot;AGCAAGTAG&amp;quot;;+&amp;quot;GTACTAGTAATACTGCATCTAGCTA&amp;quot;&lt;br /&gt;&lt;br /&gt;Local ar1[MAX_LENGTH]&lt;br /&gt;Local ar2[MAX_LENGTH]&lt;br /&gt;&lt;br /&gt;convertStringToArray(s1, ar1)&lt;br /&gt;convertStringToArray(s2, ar2)&lt;br /&gt;&lt;br /&gt;Local arr[(MAX_LENGTH+1)*(MAX_LENGTH+1)]&lt;br /&gt;&lt;br /&gt;calculateMatrix(ar1, Len(s1), ar2, Len(s2), arr)&lt;br /&gt;&lt;br /&gt;getAlignment(arr, ar1, ar2, s1, s2)&lt;br /&gt;&lt;br /&gt;Print result1&lt;br /&gt;Print result2&lt;br /&gt;&lt;br /&gt;Print &amp;quot;Distanz: &amp;quot;+getLevenshteinDistance(result1, result2)&lt;br /&gt;Print &amp;quot;Normal: &amp;quot;+getLevenshteinDistance(s1, s2)&lt;br /&gt;&lt;br /&gt;WaitKey()[/syntax]&lt;br /&gt;&lt;br /&gt;Es stellt sich heraus, die Levenshtein Distanz f&amp;uuml;r das aneinander angepasste genau gleich ist, wie f&amp;uuml;r die Strings separat. Ausserdem ist das SeqAl f&amp;uuml;r Gensequenzen optimiert, f&amp;uuml;r andere Suchen m&amp;uuml;sste man die Matrix anpassen. Darauf k&amp;ouml;nnte man den Computer theoretisch trainieren (evol. Algorithms o.&amp;Auml;.).&lt;br /&gt;Aber wozu das Ganze eigentlich? Ich wollte einen Algorithmus programmieren, der gezeichnete Eingaben mit einer Datenbank von bekannten Symbolen vergleicht und das &amp;auml;hnlichste Ausspuckt. So etwa in &lt;a href=&quot;http://detexify.kirelabs.org/classify.html&quot; target=&quot;_blank&quot;&gt;diese Richtung.&lt;/a&gt;&lt;br /&gt;Das Problem dabei ist, dass man schon bei einem Bild von 128x128 eine &amp;quot;String&amp;quot;l&amp;auml;nge von &amp;uuml;ber 16000 hat, Levenshtein ist wie gesagt [i]O(n^2)&lt;/i&gt;, das sind etwa 300Mio Operationen, und das f&amp;uuml;r jedes Bild der Datenbank. Ein weiteres Problem ist, dass die Zeichen unterschiedlich gross sein k&amp;ouml;nnen (wirklich ein Problem!) oder an einer anderen Stelle (theoretisch ein Problem). Die Stelle kann man mit einem Offset korrigieren, dazu m&amp;uuml;sste man aber auch wieder alle m&amp;ouml;glichen Verschiebungen vetrachten, das geht von -16k zu +16k, und sp&amp;auml;testens hier sagt einem BlitzBasic, dass es keine Lust mehr hat.&lt;br /&gt;Ich habe dann angefangen &amp;quot;abzuspecken&amp;quot;. Ich mache keinen Levenshtein, ich mache keine Offset-Optimierung, ich suche mir die Anfangspunkte der Bilder und nehme den als Offset, dann vergleiche ich die beiden Arrays &amp;uuml;ber ein &lt;i&gt;XOR&lt;/i&gt; und lasse das auswerten, dann gebe ich das beste Ergebnis aus. Das funktioniert aber nur beschr&amp;auml;nkt. Es kommen viel zu h&amp;auml;ufig falsche Zeichen raus, und ist &amp;uuml;berhaupt nicht so einsetzbar, wie ich das wollte :/&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_17_PatternRecognition.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Vielleicht kennt jemand einen besseren Algorithmus um Pattern-Recognition in Bildern zu machen. Ich kenne da noch die &lt;i&gt;Hough-Transformation&lt;/i&gt;, oder den &lt;i&gt;Hausdorff-Algorithmus&lt;/i&gt;, aber die sind eher dazu gedacht FORMEN zu finden, ich bin mir nicht sicher, inwiefern ich die auf mein Problem biegen k&amp;ouml;nnte. Allerdings habe ich mittlerweilen aufgegeben. Das &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_17_PatternRecognition.rar&quot; target=&quot;_blank&quot;&gt;Testprogram&lt;/a&gt; l&amp;auml;sst sich &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_17_PatternRecognition.rar&quot; target=&quot;_blank&quot;&gt;hier herunterladen&lt;/a&gt;, die Steuerung wird im Programm (teilweise) erkl&amp;auml;rt. Beim trainieren k&amp;ouml;nnt ihr noch zus&amp;auml;tzlich eine Zeichenfolge f&amp;uuml;r euer Bild geben (1, 2, 3, +, -, =,...). Wenn ihr dann die Erkennung startet, wird das Zeichen in einen String eingef&amp;uuml;gt, bei einem = wird dann das Ergebnis durch meinen Mathe-Parser geschickt und ausgegeben.&lt;br /&gt;&lt;br /&gt;Eigentlich wollte ich das f&amp;uuml;r die Steuerung benutzen, so &amp;auml;hnlich wie in Trine, wo der Zauberer mittels Maus eine Kiste zeichnet, die dann erscheint. Ich wollte ein Arsenal von magischen Zeichen kreieren, die der Spieler dann zeichnen musste, um einen Spruch zu wirken. Die Idee ist vorerst gestorben, ich werde mir etwas anderes einfallen lassen.&lt;br /&gt;&lt;br /&gt;So, das w&amp;auml;rs von mir, vielleicht kommt das Programm irgendwann mal auf einen gr&amp;uuml;nen Zweig, who knows.&lt;br /&gt;MfG,&lt;br /&gt;Darth&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Und weiter gehts..&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ich hatte eben ein kleineres Gespr&amp;auml;ch mit einem Studienkollegen. Er meinte ich sei doof, die Bildersuche mittels Stringvergleich anzugehen, ich solle lieber den Hausdorff-Algorithmus benutzen. Ich habe mal auf ihn geh&amp;ouml;rt und es versucht. Dazu muss man zuerst die wichtigen &lt;a href=&quot;http://de.wikipedia.org/wiki/Kantendetektion&quot; target=&quot;_blank&quot;&gt;Kanten&lt;/a&gt; des Bildes finden, dazu gibt es auch wieder mehrere Methoden, zum Beispiel &lt;a href=&quot;http://de.wikipedia.org/wiki/Laplace-Filter&quot; target=&quot;_blank&quot;&gt;Laplace&lt;/a&gt;, der liefert aber nicht gen&amp;uuml;gend exakte Ergebnisse, deshalb habe ich mir mal den Canny-Algorithmus angesehen, den ich anhand eines Tutorials mit Beispiel in BB nachgebaut habe. Ich glaube es ist mir gelungen :&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_17_Canny.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Die Frau da auf dem Bildschirm ist meine Freundin - oder irgend ein x-beliebiges Gesicht das ich &amp;uuml;ber Google gefunden habe, ich bin mir da nichtmehr ganz sicher. Der Algorithmus kann Bilder von maximal 256x256 behandeln (wieder wegen den BlitzArrays die ich verwende), und braucht f&amp;uuml;r ein solches etwa um die 150ms, also nicht sonderlich schnell. Allerdings ist mein Ziel ja auch, das nur einmal auszuwerten am Anfang der Transformation (Bild -&amp;gt; Muster). Da der Code auf einem Tutorial basiert und nicht wirklich von mir selber erarbeitet wurde, bin ich mir nicht sicher ob ich ihn posten soll, von daher lass ich es mal bleiben.&lt;br /&gt;&lt;br /&gt;So, nun weiter zu Hausdorff, dazu gibt es auf &lt;a href=&quot;http://www.youtube.com/DarthPhyrra&quot; target=&quot;_blank&quot;&gt;Youtube&lt;/a&gt; ein ziemlich gutes &lt;a href=&quot;http://www.youtube.com/watch?v=sY4KyCJh45Y&quot; target=&quot;_blank&quot;&gt;Erkl&amp;auml;rungsvideo&lt;/a&gt;. Das Problem ist, dass der Algorithmus &lt;i&gt;O(n^2*m^2)&lt;/i&gt; ist (hier: &lt;i&gt;O(n^4)&lt;/i&gt;), und damit ziemlich langsam. Allerdings dennoch halbwegs zumutbar. Aber auch der liefert meist komische Ergebnisse auf meine Eingabe. Also ist auch der Versuch gescheitert. Ich bin gerade am Ende meiner Weisheit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Und noch ein Versuch..&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ich wurde in den Comments auf &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=20312&quot; target=&quot;_blank&quot;&gt;diesen Thread&lt;/a&gt; aufmerksam gemacht. Da wird das Symbol nicht mittels Bildvergleich gesucht, sondern &amp;uuml;ber die Richtung der gezogenen Linie. Es eignet sich f&amp;uuml;r Gestenerkennung zur Steuerung wahrscheinlich besser als mein Ansatz des Bildvergleichs, deshalb habe ich es mal etwas &amp;Auml;hnliches (naja, ziemlich genau gleich &lt;img src=&quot;/forum/images/smiles/icon_razz.gif&quot; alt=&quot;Razz&quot; /&gt;) in BB geschrieben. Das System ist relativ wacklig (eine &amp;quot;gerade&amp;quot; Linie nach rechts oben artet schnell mal in einen Wechsel zwischen Up und Right aus), aber wenn ich das noch stabiler kriege, dann wird das sicher brauchbar.&lt;br /&gt;&lt;br /&gt;Also, bis zum n&amp;auml;chsten mal,&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Fri, 14 May 2010 17:00:34 +0200</pubDate>
		</item>

		<item>
			<title>Der Graph von MonteChristo</title>
			<link>https://www.blitzforum.de/worklogs/292/#2342</link>
			<guid>https://www.blitzforum.de/worklogs/292/#2342</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;diese und letzte Woche haben wir in einer lustigen Vorlesung ein paar interessante Dinge geh&amp;ouml;rt. Dabei ging es vor allem um Graphen und irgendwelche Theorien dazu. Um es grob zusammenzufassen: Ein paar komische Kauze haben sich jahrelang hingesetzt um herauszufinden, wie man einen Graphen am besten optimiert, oder so, ich bin in der H&amp;auml;lfte eingeschlafen.. Deshalb musste ich mich dann hinsetzen um das Zeug doch noch zu verstehen. Weil die Vorlesung &amp;quot;Algorithmen und Datenstrukturen&amp;quot; heisst, dachte ich, dass ich mir den Krempel mal programmiere um zu sehen wie es funktioniert. Und weil ich nichts besseres zu tun habe, teile ich meine Ergebnisse mit der breiten &amp;Ouml;ffentlichkeit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Splines:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Zuerst aber etwas anderes. Vor einigen Tagen fragte jemand im Channel nach einer Funktion f&amp;uuml;r &lt;a href=&quot;http://en.wikipedia.org/wiki/Spline_(mathematics)&quot; target=&quot;_blank&quot;&gt;Splines&lt;/a&gt;. Falls jemand nicht weiss was eine Spline ist dann hier eine kurze Erkl&amp;auml;rung: Es sind Kurven, die sich (&amp;auml;hnlich wie &lt;a href=&quot;http://en.wikipedia.org/wiki/B&amp;eacute;zier_curve&quot; target=&quot;_blank&quot;&gt;Bezierkurven&lt;/a&gt;) an einer Reihe von Punkten orientieren, die Splines gehen garantiert durch die gesetzten Kontrollpunkte (ungleich Bezier), sie dienen deshalb zur Interpolation von z.B Bewegungsabl&amp;auml;ufen und &amp;Auml;hnlichem.&lt;br /&gt;Ich erinnerte mich da an meine heissgeliebte Numerik Vorlesung (diesmal nicht sarkastisch, im Nachhinein war das wohl die n&amp;uuml;tzlichste Vorlesung bisher :/ Meh!) wo wir die lustigen Dinger von Hand berechnen durften. Allerdings hatte der Professor ein einsehen und schrieb eine &amp;Uuml;bung, wo wir das Prinzip in Matlab umsetzen sollten, nach vorgegebenem Pseudocode. Ich habe diesen wieder ausgegraben und nach BlitzBasic portiert. Das Ergebnis ist hier zu finden:&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Type Vector2&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function cVector2.Vector2(x#, y#)&lt;br /&gt;	Local v.Vector2=New Vector2&lt;br /&gt;	&lt;br /&gt;	v\x=x&lt;br /&gt;	v\y=y&lt;br /&gt;	&lt;br /&gt;	Return v&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Const MAX_SPLINE_POINTS=128&lt;br /&gt;&lt;br /&gt;Type TSpline&lt;br /&gt;	Field p.Vector2[MAX_SPLINE_POINTS]&lt;br /&gt;	Field count&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function cTSpline.TSpline()&lt;br /&gt;	Return New TSpline&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addPointToSpline(s.TSpline, p.Vector2)&lt;br /&gt;	If s\count&amp;gt;=MAX_SPLINE_POINTS&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	s\p[s\count]=p&lt;br /&gt;	s\count=s\count+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function removePointFromSpline(s.TSpline, i)&lt;br /&gt;	If s\count&amp;lt;1&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Delete s\p&lt;i&gt;&lt;br /&gt;	&lt;br /&gt;	For j=i+1 To s\count-1&lt;br /&gt;		s\p[j-1]=s\p[j]&lt;br /&gt;	Next&lt;br /&gt;	s\p[s\count-1]=Null&lt;br /&gt;	&lt;br /&gt;	s\count=s\count-1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Type CubicPolynom&lt;br /&gt;	Field a#&lt;br /&gt;	Field b#&lt;br /&gt;	Field c#&lt;br /&gt;	Field d#&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function cCubicPolynom.CubicPolynom(a#, b#, c#, d#)&lt;br /&gt;	Local cp.CubicPolynom=New CubicPolynom&lt;br /&gt;	&lt;br /&gt;	cp\a=a&lt;br /&gt;	cp\b=b&lt;br /&gt;	cp\c=c&lt;br /&gt;	cp\d=d&lt;br /&gt;	&lt;br /&gt;	Return cp&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function valueCP#(cp.CubicPolynom, x#)&lt;br /&gt;	Return (((cp\d*x)+cp\c)*x+cp\b)*x+cp\a&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// x wird gef&amp;uuml;llt&lt;br /&gt;Function fillXCoordinates(s.TSpline, x[MAX_SPLINE_POINTS])&lt;br /&gt;	For i=0 To s\count-1&lt;br /&gt;		x[i]=s\p[i]\x&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// y wird gef&amp;uuml;llt&lt;br /&gt;Function fillYCoordinates(s.TSpline, y[MAX_SPLINE_POINTS])&lt;br /&gt;	For i=0 To s\count-1&lt;br /&gt;		y[i]=s\p[i]\y&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// cp wird gef&amp;uuml;llt&lt;br /&gt;Function calcNatSpline(n, x[MAX_SPLINE_POINTS], cp.CubicPolynom[MAX_SPLINE_POINTS])&lt;br /&gt;	Local gamma#[MAX_SPLINE_POINTS]&lt;br /&gt;	Local delta#[MAX_SPLINE_POINTS]&lt;br /&gt;	Local d#[MAX_SPLINE_POINTS]&lt;br /&gt;	&lt;br /&gt;	gamma[0]=0.5&lt;br /&gt;	For i=1 To n-1&lt;br /&gt;		gamma[i]=1./(4-gamma[i-1])&lt;br /&gt;	Next&lt;br /&gt;	gamma[n]=1./(2-gamma[n-1])&lt;br /&gt;	&lt;br /&gt;	delta[0]=3*(x[1]-x[0])*gamma[0]&lt;br /&gt;	For i=1 To n-1&lt;br /&gt;		delta[i]=(3*(x[i+1]-x[i-1])-delta[i-1])*gamma[i]&lt;br /&gt;	Next&lt;br /&gt;	delta[n]=(3*(x[n]-x[n-1])-delta[n-1])*gamma[n]&lt;br /&gt;	&lt;br /&gt;	d[n]=delta[n]&lt;br /&gt;	For i=n-1 To 0 Step -1&lt;br /&gt;		d[i]=delta[i]-gamma[i]*d[i+1]&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For i=0 To n-1&lt;br /&gt;		cp[i]=cCubicPolynom(x[i], d[i], 3*(x[i+1]-x[i])-2*d[i]-d[i+1], 2*(x[i]-x[i+1])+d[i]+d[i+1])&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Global STEPS=10&lt;br /&gt;Global fSTEPS#=STEPS&lt;br /&gt;&lt;br /&gt;Function drawSpline(s.TSpline)&lt;br /&gt;	LockBuffer BackBuffer()&lt;br /&gt;	&lt;br /&gt;	If s\count&amp;gt;1&lt;br /&gt;		Local x[MAX_SPLINE_POINTS]&lt;br /&gt;		Local y[MAX_SPLINE_POINTS]&lt;br /&gt;		&lt;br /&gt;		fillXCoordinates(s, x)&lt;br /&gt;		fillYCoordinates(s, y)&lt;br /&gt;		&lt;br /&gt;		Local cx.CubicPolynom[MAX_SPLINE_POINTS]&lt;br /&gt;		Local cy.CubicPolynom[MAX_SPLINE_POINTS]&lt;br /&gt;		&lt;br /&gt;		calcNatSpline(s\count-1, x, cx)&lt;br /&gt;		calcNatSpline(s\count-1, y, cy)&lt;br /&gt;		&lt;br /&gt;		Local px1, py1, px2, py2&lt;br /&gt;		Local u#&lt;br /&gt;		&lt;br /&gt;		For i=0 To s\count-2&lt;br /&gt;			px1=valueCP(cx[i], 0)&lt;br /&gt;			py1=valueCP(cy[i], 0)&lt;br /&gt;			&lt;br /&gt;			For j=1 To STEPS&lt;br /&gt;				u=j/fSTEPS&lt;br /&gt;				&lt;br /&gt;				px2=valueCP(cx[i], u)&lt;br /&gt;				py2=valueCP(cy[i], u)&lt;br /&gt;				&lt;br /&gt;				Line px1, py1, px2, py2&lt;br /&gt;				&lt;br /&gt;				px1=px2&lt;br /&gt;				py1=py2&lt;br /&gt;			Next&lt;br /&gt;		Next&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	UnlockBuffer BackBuffer()&lt;br /&gt;	&lt;br /&gt;	;// remove if used&lt;br /&gt;	For i=0 To s\count-1&lt;br /&gt;		Oval s\p[i]\x-2, s\p[i]\y-2, 4, 4&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function getPointByMouse.Vector2(s.TSpline)&lt;br /&gt;	Local minDist#=1000000&lt;br /&gt;	Local dist#&lt;br /&gt;	Local pSel.Vector2&lt;br /&gt;	&lt;br /&gt;	For i=0 To s\count-1&lt;br /&gt;		dist=Sqr((MouseX()-s\p[i]\x)^2+(MouseY()-s\p[i]\y)^2)&lt;br /&gt;		&lt;br /&gt;		If dist&amp;lt;minDist&lt;br /&gt;			minDist=dist&lt;br /&gt;			pSel=s\p[i]&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return pSel&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test Program&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Graphics 640,480,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;Local s.TSpline=New TSpline&lt;br /&gt;addPointToSpline(s, cVector2(10,10))&lt;br /&gt;addPointToSpline(s, cVector2(50,30))&lt;br /&gt;addPointToSpline(s, cVector2(102,120))&lt;br /&gt;addPointToSpline(s, cVector2(236,236))&lt;br /&gt;addPointToSpline(s, cVector2(300,40))&lt;br /&gt;&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	Color 255,255,255&lt;br /&gt;	&lt;br /&gt;	drawSpline(s)&lt;br /&gt;	&lt;br /&gt;	Text 10,10,s\count&lt;br /&gt;	&lt;br /&gt;	If MouseDown(1)&lt;br /&gt;		pSel.Vector2=getPointByMouse(s)&lt;br /&gt;		If pSel&amp;lt;&amp;gt;Null&lt;br /&gt;			pSel\x=MouseX()&lt;br /&gt;			pSel\y=MouseY()&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If MouseHit(2)&lt;br /&gt;		addPointToSpline(s, cVector2(MouseX(), MouseY()))&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	fpsCount=fpsCount+1&lt;br /&gt;	If MilliSecs()-fpsTime&amp;gt;999&lt;br /&gt;		fpsCur=fpsCount&lt;br /&gt;		fpsCount=0&lt;br /&gt;		fpsTime=MilliSecs()&lt;br /&gt;	EndIf&lt;br /&gt;	Text 600,460,fpsCur&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	Cls&lt;br /&gt;Wend&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;br /&gt;Ein Bild gibt es nicht, es ist nicht ziemlich aussagekr&amp;auml;ftig, es ist halt einfach eine geschwungene Linie, die durch ein paar Punkte gef&amp;uuml;hrt wird. Steuerung ist eigentlich im Code ersichtlich, linke Maustaste dr&amp;uuml;cken verschiebt einen Punkt, rechte Maustaste setzt einen neuen.&lt;br /&gt;Man k&amp;ouml;nnte das Verfahren wohl noch etwas beschleunigen (man spart sich das F&amp;uuml;llen der Arrays), allerdings w&amp;uuml;rde das zu doppeltem Code f&amp;uuml;hren, was von schlechter Programmierarbeit zeugt, deshalb mache ich das nicht. Es ist auch so schnell genug &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt; .&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bin&amp;auml;re B&amp;auml;ume:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Das erste Thema war der allgemeine &lt;a href=&quot;http://de.wikipedia.org/wiki/Bin&amp;auml;rbaum&quot; target=&quot;_blank&quot;&gt;Bin&amp;auml;rbaum&lt;/a&gt;. Ein Knoten hat zwei Kinder, je eins links und eines rechts. Das kann man benutzen um z.b MorseCodes zu interpretieren (Punkt links, Strich rechts), oder um Zahlen zu sortieren. Ist ein Wert kleiner geht er nach links, ist er gr&amp;ouml;sser, dann nach rechts. Nat&amp;uuml;rlich kann dies zu h&amp;ouml;chst einseitigen B&amp;auml;umen f&amp;uuml;hren, wenn man die Wurzel zu klein w&amp;auml;hlt und alle Zahlen der Gr&amp;ouml;sse nach sortiert einf&amp;uuml;llt, dann hat man sowas wie eine LinkedList. Um dies zu verhindern, haben sich ein paar Leute hingesetzt und B&amp;auml;ume entwickelt. So gibt es heute den &lt;a href=&quot;http://en.wikipedia.org/wiki/AVL_tree&quot; target=&quot;_blank&quot;&gt;AVL-Baum&lt;/a&gt;, den &lt;a href=&quot;http://de.wikipedia.org/wiki/Rot-Schwarz-Baum&quot; target=&quot;_blank&quot;&gt;Rot-Schwarz-Baum&lt;/a&gt;, &lt;a href=&quot;http://de.wikipedia.org/wiki/B-Baum&quot; target=&quot;_blank&quot;&gt;B-B&amp;auml;ume&lt;/a&gt;, &lt;a href=&quot;http://www.youtube.com/watch?v=6guVKTsmmBs&quot; target=&quot;_blank&quot;&gt;Tannenb&amp;auml;ume&lt;/a&gt;, &lt;a href=&quot;http://www.minimax.ch/media/bilder/Logos/weihnachtsbaum.gif&quot; target=&quot;_blank&quot;&gt;Weihnachtsb&amp;auml;ume&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Leo_Obstbaum&quot; target=&quot;_blank&quot;&gt;Obstb&amp;auml;ume&lt;/a&gt; usw.&lt;br /&gt;Den Rot-Schwarz-Baum verstehe ich nicht, den muss ich mir nochmal ansehen. Da geht es irgendwie darum, dass man Knoten umf&amp;auml;rbt und je nach F&amp;auml;rbung verschiebt, aber wie genau man das macht weiss ich nicht. B-B&amp;auml;ume halte ich f&amp;uuml;r absolut bescheuert und sehe nicht ein, wof&amp;uuml;r man die braucht. Ausserdem werden sie eh generell nur als &amp;Uuml;bergangsstruktur benutzt, wozu also die M&amp;uuml;he -.- ?&lt;br /&gt;AVL-B&amp;auml;ume fand ich allerdings interessant. Wenn ein Ast zu schwer wird, dann &amp;quot;dreht&amp;quot; man den Baum, das ist ziemlich einfach (es gibt nur 4 F&amp;auml;lle die auftreten k&amp;ouml;nnen, und 4 Reaktionen darauf) und effizient. Ein Beispiel:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_16_AVLTree.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wof&amp;uuml;r man so etwas brauchen kann war mir zuerst nicht wirklich klar. Aber als Beispiel k&amp;ouml;nnte ich hier vielleicht [i]Highscores&lt;/i&gt; erw&amp;auml;hnen. Die Funktion &lt;i&gt;printTree(root)&lt;/i&gt; gibt den Baum sortiert aus. Das Einf&amp;uuml;gen ist ebenfalls ziemlich einfach, so k&amp;ouml;nnte man also ganz gem&amp;uuml;tlich einen neuen Wert in seinen Highscore Baum eintragen, der automatisch sortiert wird.&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * AVL Tree&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TreeNode&lt;br /&gt;	Field value&lt;br /&gt;	&lt;br /&gt;	Field cLeft.TreeNode&lt;br /&gt;	Field cRight.TreeNode&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTreeNode.TreeNode(x)&lt;br /&gt;	Local n.TreeNode=New TreeNode&lt;br /&gt;	&lt;br /&gt;	n\value=x&lt;br /&gt;	&lt;br /&gt;	Return n&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function hasLeft(n.TreeNode)&lt;br /&gt;	Return Not n\cLeft=Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function hasRight(n.TreeNode)&lt;br /&gt;	Return Not n\cRight=Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function isLeaf(n.TreeNode)&lt;br /&gt;	Return hasLeft(n)=False And hasRight(n)=False&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function insertToTree.TreeNode(n.TreeNode, x)&lt;br /&gt;	If n=Null&lt;br /&gt;		n=newTreeNode(x)&lt;br /&gt;	Else&lt;br /&gt;		If x&amp;lt;n\value&lt;br /&gt;			n\cLeft=insertToTree(n\cLeft, x)&lt;br /&gt;			&lt;br /&gt;			If treeDepth(n\cLeft)-treeDepth(n\cRight)=2&lt;br /&gt;				If x&amp;lt;n\cLeft\value&amp;lt;0&lt;br /&gt;					n=rotateWithLeftChild(n)&lt;br /&gt;				Else&lt;br /&gt;					n=doubleRotateWithLeftChild(n)&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		ElseIf x&amp;gt;n\value&lt;br /&gt;			n\cRight=insertToTree(n\cRight, x)&lt;br /&gt;			&lt;br /&gt;			If treeDepth(n\cRight)-treeDepth(n\cLeft)=2&lt;br /&gt;				If x&amp;gt;n\cRight\value&lt;br /&gt;					n=rotateWithRightChild(n)&lt;br /&gt;				Else&lt;br /&gt;					n=doubleRotateWithRightChild(n)&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Else&lt;br /&gt;			;doppelter Wert&lt;br /&gt;			;	hier wird er ignoriert&lt;br /&gt;			;	man k&amp;ouml;nnte ihn theoretisch auch einf&amp;uuml;gen..&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return n&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function rotateWithLeftChild.TreeNode(n.TreeNode)&lt;br /&gt;	Local n2.TreeNode=n\cLeft&lt;br /&gt;	&lt;br /&gt;	n\cLeft=n2\cRight&lt;br /&gt;	n2\cRight=n&lt;br /&gt;	&lt;br /&gt;	Return n2&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function rotateWithRightChild.TreeNode(n.TreeNode)&lt;br /&gt;	Local n2.TreeNode=n\cRight&lt;br /&gt;	&lt;br /&gt;	n\cRight=n2\cLeft&lt;br /&gt;	n2\cLeft=n&lt;br /&gt;	&lt;br /&gt;	Return n2&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function doubleRotateWithLeftChild.TreeNode(n.TreeNode)&lt;br /&gt;	n\cLeft=rotateWithRightChild(n\cLeft)&lt;br /&gt;	Return rotateWithLeftChild(n)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function doubleRotateWithRightChild.TreeNode(n.TreeNode)&lt;br /&gt;	n\cRight=rotateWithLeftChild(n\cRight)&lt;br /&gt;	Return rotateWithRightChild(n)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function removeFromTree.TreeNode(root.TreeNode, x)&lt;br /&gt;	;eine sinnvolle Implementation ist nervig&lt;br /&gt;	;	ich entferne den Knoten&lt;br /&gt;	;	und f&amp;uuml;ge nachher all seine Kinder wieder ein&lt;br /&gt;	;&lt;br /&gt;	;	kann mit grosser Wahrscheinlichkeit effizienter gel&amp;ouml;st werden&lt;br /&gt;	;	aber das ist mir egal &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt;&lt;br /&gt;	&lt;br /&gt;	Local rem.TreeNode=findInTree(root, x)&lt;br /&gt;	Local remParent.TreeNode=findParentinTree(root, rem)&lt;br /&gt;	&lt;br /&gt;	If remParent\cLeft=rem&lt;br /&gt;		remParent\cLeft=Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If remParent\cRight=rem&lt;br /&gt;		remParent\cRight=Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	root=insertBranchToTree(root, rem\cLeft)&lt;br /&gt;	root=insertBranchToTree(root, rem\cRight)&lt;br /&gt;	&lt;br /&gt;	Return root&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function findInTree.TreeNode(n.TreeNode, x)&lt;br /&gt;	While n&amp;lt;&amp;gt;Null&lt;br /&gt;		If x=n\value&lt;br /&gt;			Return n&lt;br /&gt;		Else&lt;br /&gt;			If x&amp;gt;n\value&lt;br /&gt;				n=n\cRight&lt;br /&gt;			Else&lt;br /&gt;				n=n\cLeft&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	Return Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function findParentinTree.TreeNode(n.TreeNode, c.TreeNode)&lt;br /&gt;	While n&amp;lt;&amp;gt;Null&lt;br /&gt;		If hasLeft(n)&lt;br /&gt;			If c\value=n\cLeft\value&lt;br /&gt;				Return n&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		If hasRight(n)&lt;br /&gt;			If c\value=n\cRight\value&lt;br /&gt;				Return n&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		If c\value&amp;gt;n\value&lt;br /&gt;			n=n\cRight&lt;br /&gt;		Else&lt;br /&gt;			n=n\cLeft&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	Return Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function insertBranchToTree.TreeNode(root.TreeNode, n.TreeNode)&lt;br /&gt;	If n=Null&lt;br /&gt;		Return root&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	insertToTree(root, n\value)&lt;br /&gt;	&lt;br /&gt;	root=insertBranchToTree(root, n\cLeft)&lt;br /&gt;	root=insertBranchToTree(root, n\cRight)&lt;br /&gt;	&lt;br /&gt;	Return root&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function treeDepth(n.TreeNode, d=0, max=0)&lt;br /&gt;	If n=Null&lt;br /&gt;		If d&amp;gt;max&lt;br /&gt;			Return d&lt;br /&gt;		Else&lt;br /&gt;			Return max&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	max1=treeDepth(n\cLeft, d+1, max)&lt;br /&gt;	max2=treeDepth(n\cRight, d+1, max)&lt;br /&gt;	&lt;br /&gt;	If max1&amp;gt;max&lt;br /&gt;		max=max1&lt;br /&gt;	EndIf&lt;br /&gt;	If max2&amp;gt;max&lt;br /&gt;		max=max2&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return max&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function printTree(n.TreeNode)&lt;br /&gt;	If n=Null&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	printTree(n\cLeft)&lt;br /&gt;	Print n\value&lt;br /&gt;	printTree(n\cRight)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function dispTree(n.TreeNode, x, y)&lt;br /&gt;	If n=Null&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local maxDepth=treeDepth(n)&lt;br /&gt;	Local b#=5, h#=50&lt;br /&gt;	&lt;br /&gt;	Text x, y, n\value&lt;br /&gt;	&lt;br /&gt;	If hasLeft(n)&lt;br /&gt;		Line x+Len(n\value)*4, y+14, x-b*2^maxDepth+Len(n\cLeft\value)*4, y+h-2&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If hasRight(n)&lt;br /&gt;		Line x+Len(n\value)*4, y+14, x+b*2^maxDepth+Len(n\cRight\value)*4, y+h-2&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	dispTree(n\cLeft, x-b*2^maxDepth, y+h)&lt;br /&gt;	dispTree(n\cRight, x+b*2^maxDepth, y+h)&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Local root.TreeNode&lt;br /&gt;root=insertToTree(root, 5)&lt;br /&gt;root=insertToTree(root, 7)&lt;br /&gt;root=insertToTree(root, 9)&lt;br /&gt;root=insertToTree(root, 6)&lt;br /&gt;root=insertToTree(root, 11)&lt;br /&gt;root=insertToTree(root, 2)&lt;br /&gt;root=insertToTree(root, 1)&lt;br /&gt;root=insertToTree(root, 25)&lt;br /&gt;root=insertToTree(root, 46)&lt;br /&gt;root=insertToTree(root, 52)&lt;br /&gt;root=insertToTree(root, 63)&lt;br /&gt;root=insertToTree(root, 98)&lt;br /&gt;&lt;br /&gt;root=removeFromTree(root, 46)&lt;br /&gt;&lt;br /&gt;Graphics 800,600,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;printTree(root)&lt;br /&gt;&lt;br /&gt;dispTree(root, 400, 50)&lt;br /&gt;&lt;br /&gt;Flip 0&lt;br /&gt;WaitKey()[/syntax]&lt;br /&gt;&lt;br /&gt;Die L&amp;ouml;schfunktion ist ziemlich m&amp;uuml;hsam, deshalb habe ich es mir &amp;quot;einfach&amp;quot; gemacht. Ich h&amp;auml;nge den Ast ab und f&amp;uuml;ge alle Werte (ausser den zu l&amp;ouml;schenden) wieder ein. Doppelte Werte ignoriere ich in dem Beispiel.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dijikstra:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Dann kamen Graphen-Netze dran. Gesucht war ein minimal spannender Graph (d.h ein einzelner (k&amp;uuml;rzester) Weg durch alle Knoten). Daf&amp;uuml;r gibt es den disch.. dsch.. dschaka.. discha.. [url=http://en.wikipedia.org/wiki/Dijkstra's_algorithm]Dingsda-Algorithmus[/url]. Er geh&amp;ouml;rt zu der Klasse der &lt;i&gt;Greedy-Algorithm&lt;/i&gt;, d.h er macht keine Fehler. Ein gemachter Schritt ist absolut, und richtig (also kein Backtracking), soweit ich mich erinnere ist das Laufzeitverhalten mit&lt;i&gt;n^2*log(n)&lt;/i&gt; angegeben. Hier das Beispiel, andem es uns erkl&amp;auml;rt wurde:&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_16_Dijkstra.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Generell geht es so, dass man eine Liste mit Distanzen zu den Knoten mitf&amp;uuml;hrt (nicht erreichbare Knoten werden auf unendlich distanziert) und sich dann den n&amp;auml;chsten Knoten ausw&amp;auml;hlt, dann wird die Distanzliste aktualisiert. So geht man vor, bis man alle Knoten erreicht hat, oder keine mehr erreichbar sind.&lt;br /&gt;Wof&amp;uuml;r man das brauchen kann weiss ich nicht genau :/ Vielleicht f&amp;uuml;r ein Waypoint-System, aber auch das ist heikel, weil man eigentlich nur den Startpunkt, nicht aber das Ziel angeben kann. Allerdings k&amp;ouml;nnte man es etwas umschustern, indem man zum Beispiel eine Waypoint-Map baut, die Knoten entsprechend ihrer Erreichbarkeit untereinander vernetzt und den Algorithmus abbricht, sobald der Zielknoten erreicht wurde, das garantiert den K&amp;uuml;rzesten Weg durch das Waypoint Wirrwarr.&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * Weighted Graph&lt;br /&gt;; *  Dijkstra Example&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TVertex&lt;br /&gt;	Field value$&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTVertex.TVertex(value$)&lt;br /&gt;	Local v.TVertex=New TVertex&lt;br /&gt;	&lt;br /&gt;	v\value=value&lt;br /&gt;	&lt;br /&gt;	Return v&lt;br /&gt;End Function&lt;br /&gt;	&lt;br /&gt;Type TEdge&lt;br /&gt;	Field n1.TVertex&lt;br /&gt;	Field n2.TVertex&lt;br /&gt;	&lt;br /&gt;	Field cost&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTEdge.TEdge(n1.TVertex, n2.TVertex, cost)&lt;br /&gt;	Local e.TEdge=New TEdge&lt;br /&gt;	&lt;br /&gt;	e\n1=n1&lt;br /&gt;	e\n2=n2&lt;br /&gt;	&lt;br /&gt;	e\cost=cost&lt;br /&gt;	&lt;br /&gt;	Return e&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Const MAX_NODES=128&lt;br /&gt;Const MAX_EDGES=128&lt;br /&gt;&lt;br /&gt;Type TGraph&lt;br /&gt;	Field v.TVertex[MAX_NODES]&lt;br /&gt;	Field vCount&lt;br /&gt;	&lt;br /&gt;	Field e.TEdge[MAX_EDGES]&lt;br /&gt;	Field eCount&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function addTVertexToGraph(g.TGraph, v.TVertex)&lt;br /&gt;	g\v[g\vCount]=v&lt;br /&gt;	g\vCount=g\vCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addTEdgeToGraph(g.TGraph, e.TEdge)&lt;br /&gt;	g\e[g\eCount]=e&lt;br /&gt;	g\eCount=g\eCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Type TGraphPathNode&lt;br /&gt;	Field v.TVertex&lt;br /&gt;	Field succ.TGraphPathNode&lt;br /&gt;	Field prev.TGraphPathNode&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTGraphPathNode.TGraphPathNode(v.TVertex)&lt;br /&gt;	Local gpn.TGraphPathNode=New TGraphPathNode&lt;br /&gt;	&lt;br /&gt;	gpn\v=v&lt;br /&gt;	&lt;br /&gt;	gpn\succ=Null&lt;br /&gt;	gpn\prev=Null&lt;br /&gt;	&lt;br /&gt;	Return gpn&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Const INF=1000000&lt;br /&gt;Function dijkstra.TGraphPathNode(g.TGraph, source.TVertex)&lt;br /&gt;	Local dist#[MAX_NODES]&lt;br /&gt;	&lt;br /&gt;	Local Q.TVertex[MAX_NODES]&lt;br /&gt;	Local qCount=0&lt;br /&gt;	&lt;br /&gt;	For i=0 To g\vCount-1&lt;br /&gt;		dist&lt;i&gt;=INF+1 ;TO INFINITY, AND BEYOND!&lt;br /&gt;		&lt;br /&gt;		Q[i]=g\v[i]&lt;br /&gt;	Next&lt;br /&gt;	qCount=g\vCount&lt;br /&gt;	&lt;br /&gt;	Local sourceID&lt;br /&gt;	&lt;br /&gt;	For i=0 To g\vCount-1&lt;br /&gt;		If g\v[i]=source&lt;br /&gt;			sourceID=i&lt;br /&gt;			Exit&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	dist[sourceID]=0&lt;br /&gt;	&lt;br /&gt;	Local s.TGraphPathNode&lt;br /&gt;	Local pStart.TGraphPathNode&lt;br /&gt;	&lt;br /&gt;	Local u.TVertex, uId&lt;br /&gt;	Local smallest#, alt#&lt;br /&gt;	&lt;br /&gt;	While qCount&amp;gt;0&lt;br /&gt;		&lt;br /&gt;		;suche den n&amp;auml;chsten Nachbarn&lt;br /&gt;		smallest=INF+1&lt;br /&gt;		For i=0 To qCount-1&lt;br /&gt;			If dist[i]&amp;lt;smallest&lt;br /&gt;				smallest=dist[i]&lt;br /&gt;				&lt;br /&gt;				u=Q[i]&lt;br /&gt;				uId=i&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		;kein Nachbar erreichbar&lt;br /&gt;		;	abbruch, oder zur&amp;uuml;ckliefern der bisherigen Liste&lt;br /&gt;		If smallest&amp;gt;=INF&lt;br /&gt;			;Return Null&lt;br /&gt;			Exit&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		;entfernt u von der Liste&lt;br /&gt;		For i=uId To qCount-2&lt;br /&gt;			Q[i]=Q[i+1]&lt;br /&gt;			dist[i]=dist[i+1]&lt;br /&gt;		Next&lt;br /&gt;		qCount=qCount-1&lt;br /&gt;		&lt;br /&gt;		;Erneuern der Distanzen/Pfadkosten&lt;br /&gt;		For i=0 To qCount-1&lt;br /&gt;			alt=getEdgeCost(g, u, Q[i])&lt;br /&gt;			If alt&amp;gt;=0&lt;br /&gt;				If alt&amp;lt;dist[i]&lt;br /&gt;					dist[i]=alt&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		;Generieren des neuen Pfadknotens&lt;br /&gt;		If s=Null&lt;br /&gt;			s=newTGraphPathNode(u)&lt;br /&gt;			&lt;br /&gt;			pStart=s ;damit ich den pfad nicht &amp;quot;zur&amp;uuml;ckspulen&amp;quot; muss&lt;br /&gt;		Else&lt;br /&gt;			s\succ=newTGraphPathNode(u)&lt;br /&gt;			s\succ\prev=s&lt;br /&gt;			&lt;br /&gt;			s=s\succ&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	Return pStart&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function getEdgeCost#(g.TGraph, v.TVertex, u.TVertex)&lt;br /&gt;	For i=0 To g\eCount-1&lt;br /&gt;		If (g\e[i]\n1=v And g\e[i]\n2=u) Or (g\e[i]\n1=u And g\e[i]\n2=v)&lt;br /&gt;			Return g\e[i]\cost&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return -1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test program&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;g.TGraph=New TGraph&lt;br /&gt;&lt;br /&gt;v1.TVertex=newTVertex(&amp;quot;a&amp;quot;)&lt;br /&gt;v2.TVertex=newTVertex(&amp;quot;b&amp;quot;)&lt;br /&gt;v3.TVertex=newTVertex(&amp;quot;c&amp;quot;)&lt;br /&gt;v4.TVertex=newTVertex(&amp;quot;d&amp;quot;)&lt;br /&gt;v5.TVertex=newTVertex(&amp;quot;e&amp;quot;)&lt;br /&gt;v6.TVertex=newTVertex(&amp;quot;f&amp;quot;)&lt;br /&gt;&lt;br /&gt;addTVertexToGraph(g, v1)&lt;br /&gt;addTVertexToGraph(g, v2)&lt;br /&gt;addTVertexToGraph(g, v3)&lt;br /&gt;addTVertexToGraph(g, v4)&lt;br /&gt;addTVertexToGraph(g, v5)&lt;br /&gt;addTVertexToGraph(g, v6)&lt;br /&gt;&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v1, v2, 5))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v1, v3, 10))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v2, v3, 4))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v2, v5, 30))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v2, v6, 46))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v3, v4, 20))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v4, v5, 10))&lt;br /&gt;addTEdgeToGraph(g, newTEdge(v5, v6, 10))&lt;br /&gt;&lt;br /&gt;s.TGraphPathNode=dijkstra(g, v1)&lt;br /&gt;&lt;br /&gt;While s&amp;lt;&amp;gt;Null&lt;br /&gt;	Print s\v\value&lt;br /&gt;	&lt;br /&gt;	s=s\succ&lt;br /&gt;Wend&lt;br /&gt;&lt;br /&gt;WaitKey()[/syntax]&lt;br /&gt;&lt;br /&gt;Der Graph besteht aus einer Ansammlung von Vertice (Knoten) und Edges (Kanten), die jeweils ein Gewicht haben (&amp;uuml;blicherweis Kosten/Distanz die ben&amp;ouml;tigt wird die Kante zu beschreiten). Die Funktion [i]dijkstra(graph, start)&lt;/i&gt; liefert eine Instanz von &lt;i&gt;TGraphPathNode&lt;/i&gt; zur&amp;uuml;ck, diese ist in einer LinkedList stets zum n&amp;auml;chsten Knoten verbunden (siehe Print-Beispiel). Der &lt;i&gt;value&lt;/i&gt; Eintrag ist hier zu Testzwecken ein String, kann allerdings gef&amp;uuml;llt werden mit was auch immer man will.&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Mir ist aufgefallen, dass ich mich in der Entfernung eines Vertex aus der Liste vertippt habe, ebenso bei der Abbruchsbedingung. Ist nun korrigiert.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bump Mapping:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Wenn ihr euch an meinen &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/#2289&quot; target=&quot;_blank&quot;&gt;vorletzten Eintrag&lt;/a&gt;  zur&amp;uuml;ckerinnern m&amp;ouml;gt, dann k&amp;ouml;nnt ihr euch vielleicht noch an meine Rendermethode f&amp;uuml;r Dreiecke erinnern. Ich hatte vor, diese zu erweitern und ihr mittels BumpMapping zu pseudo-Tiefe zu verhelfen. Zuerst habe ich die Gr&amp;ouml;ssenbeschr&amp;auml;nkung von 64x64 gekippt, man kann nun variable (quadratische!) Texturen laden, 2^k muss nicht sein, ist aber &amp;uuml;blich, maximal Gr&amp;ouml;sse ist jetzt 256x256 (sonst wird das Array viel zu gross). Die Renderung allein sieht schon einiges besser aus (weniger verschwommen), und mittels BumpMap (auch 256x256 maximal) kommt es eigentlich noch besser.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_16_BumpMapping.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Nun die Ern&amp;uuml;chterung: Es ist generell zu langsam. F&amp;uuml;r 2 Trigs kriege ich 140FPS, das ist ansich nicht schlecht, aber wenn man bedenkt, dass ich das in meine DaDaPhysik einbauen wollte, dann kann ich damit vielleicht etwa 3 Kisten darstellen, bevor die Schnecke ihre F&amp;uuml;hler streckt. Ich musste auch meine Interpolationsmethode wieder rausnehmen, weil es damit auf etwa 60FPS sinkt (f&amp;uuml;r 2 Dreiecke), es s&amp;auml;he zwar etwas sch&amp;ouml;ner aus, ist die Rechenleistung aber nicht wirklich wert. Ich muss mir nun &amp;Uuml;berlegen ob ich da noch irgendwo etwas rausholen kann um das Ganze schnell genug f&amp;uuml;r den Echteinsatz zu machen.&lt;br /&gt;Wer es mal in Aktion sehen m&amp;ouml;chte, kann sich &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_16_BumpMap.rar&quot; target=&quot;_blank&quot;&gt;hier&lt;/a&gt; das Paket mitsamt Source herunterladen.&lt;br /&gt;Anm: Die Funktion &lt;i&gt;fillTrig_HC(trig)&lt;/i&gt; ist (ziemlich h&amp;auml;sslich ich weiss) die gleiche Funktion wie &lt;i&gt;fillTrig(trig)&lt;/i&gt;, allerdings ist in der HardCode Methode (daher HC, hat nichts mit HolzChopf zu tun), allerdings ist da alles direkt eingef&amp;uuml;gt und wird (v&amp;ouml;llig undynamisch und un&amp;uuml;bersichtlich) nicht in andere Funktionen ausgelagert. Wer sich den Code ansehen will, soll sich also besser die nicht-HC Funktion ansehen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Ich wusste nicht genau wohin ich das stecken soll, aber da das mein eigener Worklog ist und ich entscheiden kann was ich damit mache, habe ich es hierhin gepackt. Ich habe einen Ansatz f&amp;uuml;r einen ziemlich flinken Trig-Filler gefunden, den ich mal fix implementiert habe. Das einzige &amp;quot;Problem&amp;quot; dabei ist, dass man die Punkte sortieren muss, aber das wird in der Funktion direkt gemacht (3 einfache If-Schachteln). Code dazu:&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Function fillTrig(x1#, y1#, x2#, y2#, x3#, y3#)&lt;br /&gt;	Local aX#, aY#, bX#, bY#, cX#, cY#&lt;br /&gt;	&lt;br /&gt;	If y1&amp;lt;=y2 And y1&amp;lt;=y3&lt;br /&gt;		aX=x1&lt;br /&gt;		aY=y1&lt;br /&gt;		&lt;br /&gt;		If y2&amp;lt;y3&lt;br /&gt;			bX=x2&lt;br /&gt;			bY=y2&lt;br /&gt;			&lt;br /&gt;			cX=x3&lt;br /&gt;			cY=y3&lt;br /&gt;		Else&lt;br /&gt;			bX=x3&lt;br /&gt;			bY=y3&lt;br /&gt;			&lt;br /&gt;			cX=x2&lt;br /&gt;			cY=y2&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If y2&amp;lt;=y1 And y2&amp;lt;=y3&lt;br /&gt;		aX=x2&lt;br /&gt;		aY=y2&lt;br /&gt;		&lt;br /&gt;		If y1&amp;lt;y3&lt;br /&gt;			bX=x1&lt;br /&gt;			bY=y1&lt;br /&gt;			&lt;br /&gt;			cX=x3&lt;br /&gt;			cY=y3&lt;br /&gt;		Else&lt;br /&gt;			bX=x3&lt;br /&gt;			bY=y3&lt;br /&gt;			&lt;br /&gt;			cX=x1&lt;br /&gt;			cY=y1&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If y3&amp;lt;=y1 And y3&amp;lt;=y2&lt;br /&gt;		aX=x3&lt;br /&gt;		aY=y3&lt;br /&gt;		&lt;br /&gt;		If y1&amp;lt;y2&lt;br /&gt;			bX=x1&lt;br /&gt;			bY=y1&lt;br /&gt;			&lt;br /&gt;			cX=x2&lt;br /&gt;			cY=y2&lt;br /&gt;		Else&lt;br /&gt;			bX=x2&lt;br /&gt;			bY=y2&lt;br /&gt;			&lt;br /&gt;			cX=x1&lt;br /&gt;			cY=y1&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local dx1#, dx2#, dx3#&lt;br /&gt;	&lt;br /&gt;	If bY-aY&amp;gt;0&lt;br /&gt;		dx1=(bX-aX)/(bY-aY)&lt;br /&gt;	Else&lt;br /&gt;		dx1=0&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If cY-aY&amp;gt;0&lt;br /&gt;		dx2=(cX-aX)/(cY-aY)&lt;br /&gt;	Else&lt;br /&gt;		dx2=0&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If cY-bY&amp;gt;0&lt;br /&gt;		dx3=(cX-bX)/(cY-bY)&lt;br /&gt;	Else&lt;br /&gt;		dx3=0&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local sX#, sY#, eX#&lt;br /&gt;	&lt;br /&gt;	sX=aX&lt;br /&gt;	sY=aY&lt;br /&gt;	&lt;br /&gt;	eX=aX&lt;br /&gt;	&lt;br /&gt;	If dx1&amp;gt;dx2&lt;br /&gt;		While sY&amp;lt;=bY&lt;br /&gt;			Line sX, sY, eX, sY&lt;br /&gt;			&lt;br /&gt;			sY=sY+1&lt;br /&gt;			&lt;br /&gt;			sX=sX+dx2&lt;br /&gt;			eX=eX+dx1&lt;br /&gt;		Wend&lt;br /&gt;		&lt;br /&gt;		eX=bX&lt;br /&gt;		&lt;br /&gt;		While sY&amp;lt;=cY&lt;br /&gt;			Line sX, sY, eX, sY&lt;br /&gt;			&lt;br /&gt;			sY=sY+1&lt;br /&gt;			&lt;br /&gt;			sX=sX+dx2&lt;br /&gt;			eX=eX+dx3&lt;br /&gt;		Wend&lt;br /&gt;	Else&lt;br /&gt;		While sY&amp;lt;=bY&lt;br /&gt;			Line sX, sY, eX, sY&lt;br /&gt;			&lt;br /&gt;			sY=sY+1&lt;br /&gt;			&lt;br /&gt;			sX=sX+dx1&lt;br /&gt;			eX=eX+dx2&lt;br /&gt;		Wend&lt;br /&gt;		&lt;br /&gt;		sX=bX&lt;br /&gt;		sY=bY&lt;br /&gt;		&lt;br /&gt;		While sY&amp;lt;=cY&lt;br /&gt;			Line sX, sY, eX, sY&lt;br /&gt;			&lt;br /&gt;			sY=sY+1&lt;br /&gt;			&lt;br /&gt;			sX=sX+dx3&lt;br /&gt;			eX=eX+dx2&lt;br /&gt;		Wend&lt;br /&gt;	EndIf&lt;br /&gt;End Function[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ende&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, das wars mal wieder von meiner Seite, ich hoffe es hatte etwas N&amp;uuml;tzliches f&amp;uuml;r den einen oder anderen dabei. Sollte es (aus welchem Grund auch immer) irgendwelche W&amp;uuml;nsche f&amp;uuml;r kommende Eintr&amp;auml;ge haben werde ich sehen, was ich umsetzen kann.&lt;br /&gt;&lt;br /&gt;Dann bis zum n&amp;auml;chsten Mal,&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Sat, 01 May 2010 17:33:53 +0200</pubDate>
		</item>

		<item>
			<title>Meh!</title>
			<link>https://www.blitzforum.de/worklogs/292/#2316</link>
			<guid>https://www.blitzforum.de/worklogs/292/#2316</guid>
			<author>darth</author>
			<description>Hallo,&lt;br /&gt;&lt;br /&gt;nachdem mir ein Kollege auf &lt;a href=&quot;http://www.youtube.com/watch?v=YI1fLFEc-A4&amp;amp;feature=fvsr&quot; target=&quot;_blank&quot;&gt;Trine&lt;/a&gt; aufmerksam gemacht hat, sitze ich in einem Motivationsloch. Ich habe mir die Demo (und einige Videos) mal angesehen und muss sagen, das Spiel ist toll. Das Spiel bringt allerdings ein Motivationsloch mit sich, erstens weil ich das Spiel gerne durchspielen w&amp;uuml;rde (das braucht Zeit) und zweitens .. wieso etwas programmieren, das andere schon besser gemacht haben? &lt;img src=&quot;/forum/images/smiles/icon_sad.gif&quot; alt=&quot;Sad&quot; /&gt; Ich muss mir nun &amp;uuml;berlegen, wohin ich mit meiner Physikengine und meiner Spielidee noch will, Trine hat alles was ich einbauen wollte, und mehr, und sch&amp;ouml;ner, und besser.&lt;br /&gt;&lt;i&gt;Ich mag die Leute nicht&lt;/i&gt;.&lt;br /&gt;Also dachte ich, ich grab mal weiter in meinen &amp;auml;lteren Dateien und bin auf einige lustige Dinge gestossen. Falls ihr euch an meinen &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/#2289&quot; target=&quot;_blank&quot;&gt;letzten Eintrag&lt;/a&gt; erinnert, schrieb ich gegen Ende etwas von alten Spielen, die ich gerne vorgestellt h&amp;auml;tte, das tue ich nun (auf eigene Gefahr).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Trubadur&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Hach, Trubadur. Das einzige Spiel, das ich etwa 4mal geschrieben habe. Einmal als blutiger Anf&amp;auml;nger, da ging gar nichts, aber die Spielidee war da. Dann als etwas erfahrener Rookie, diesmal funktionierte das Spiel in den Grundz&amp;uuml;gen, war aber unhandlich und ziemlich langsam (da schlecht programmiert). Ein weiteres mal in 3D, ein ziemliches Desaster muss ich sagen, die Animationsart war schrecklich und das Spielprinzip liess sich, v.a wegen fehlenden Lichteinstellungen (oder ich kenne die einfach nicht), fast nicht umsetzen. Und dann noch einmal, diesmal in einem ziemlich &amp;quot;Klassen&amp;quot;-&amp;auml;nlichen Stil, der das Ausbauen und weitermachen erleichtern sollte. Das Spiel scheiterte eigentlich jedesmal an sowas wie &amp;quot;Story&amp;quot; oder &amp;quot;Script&amp;quot; oder ganz einfach &amp;quot;Leveldesign&amp;quot;. Nunja, Hyde war meist da um mir ein oder zwei Levels zu zeichnen, aber es war mir nie genug f&amp;uuml;r ein richtiges Release, also mache ich das hier im Kleinen.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_15_Trubadur.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Der Stand ist, soweit ich mich erinnere, bei etwa 3 Leveln im Story Mode (das Intro hab ich entfernt, das war mir zu.. doof :&amp;gt; und das muss was heissen, siehe &amp;quot;Spiderman in Space&amp;quot;), und einem Testlevel von Hyde (danke daf&amp;uuml;r!).&lt;br /&gt;&lt;br /&gt;Zur Bedienung: Im Men&amp;uuml; sollten ein paar Kn&amp;ouml;pfe sein, die m&amp;uuml;sste man mit der Maus anklicken k&amp;ouml;nnen. Wenn die Kn&amp;ouml;pfe NICHT da sind, dann ist es irgend ein Grafikfehler, das ist mir bei einigen Tests vorgekommen (bei anderen Leuten) afaik liegt das irgendwie an den Grafikkarten die M&amp;uuml;he mit gewissen Sprites haben, in dem Fall: Tough Luck!&lt;br /&gt;Wenn ihr im Spiel mit der Maus an den oberen Bereich fahrt, kommt son ausfahr Men&amp;uuml;, das ist eigentlich selbsterkl&amp;auml;rend (ich weiss nichtmehr wie weit Save/Load sind..). Laufen tut man mit Pfeiltasten, Hoch/Runter sind vor und zur&amp;uuml;ck, links und rechts sind Drehen. Mit der Leertaste kann man die Stacheln (schwarze Punkte am Boden) deaktivieren, w&amp;uuml;rdet ihr einfach dr&amp;uuml;ber laufen, sterbt ihr. Dazu muss man aber den richtigen Schalter (grauer Kasten am Boden) finden.&lt;br /&gt;&lt;br /&gt;Der Leveleditor ist mit der Maus steuerbar, sollte ziemlich selbsterkl&amp;auml;rend sein. Ich habe so schwammig in Erinnerung, irgend einen Kniff eingebaut zu haben, mit dem man eigene Level von Spielleveln unterscheiden kann, aber ich habe vergessen wie das ging und ob er aktiviert ist, und falls nicht, wie man es tut &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt; Nunja, kommt Zeit geht Erinnerung.&lt;br /&gt;&lt;br /&gt;Hier der &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_15_Trubadur.rar&quot; target=&quot;_blank&quot;&gt;Download Link&lt;/a&gt; (~1MB)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What da Fock?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&amp;Ouml;hm, ja. Der Titel kommt eigentlich von Tobi. Ich habe mich mal als &amp;quot;Let's Player&amp;quot; versucht, war ein Desaster, aber Tobi fand meine Aussprache ziemlich lustig, darum hat er davon mal ein Remix (oder sowas in der Art) gemacht, und ich habe dann ein &lt;a href=&quot;http://www.youtube.com/watch?v=MjE3e2fo5Qw&quot; target=&quot;_blank&quot;&gt;Video&lt;/a&gt; mit meinem damaligen Spiel gemacht (hihi, billiger Trick um Views zu kriegen!). Falls ihr &amp;quot;I wanna be the Guy&amp;quot; kennt, spielt das - es ist besser, und es ist eigentlich genau das gleiche. Es ist ein Spiel, das darauf ausgelegt ist, euch zuerst etwa 25mal zu t&amp;ouml;ten, bevor ihr das Ende erreicht.&lt;br /&gt;Die Struktur des Spiels ist ziemlich miserabel, es ist so ziemlich alles hardcoded, was ging. Ich habe auch keinen &amp;Uuml;berblick mehr, was ich alles f&amp;uuml;r Dateien beilegen m&amp;uuml;sste, und was nur Hilfsdateien waren, ich habe einfach mal aussortiert und geschaut, dass das Spiel immerhin startet. Falls es also MAVs geben sollte, liegt es wahrscheinlich daran. Zudem kann es sein, dass die Kollision nicht in 100% der F&amp;auml;llen richtig funktioniert, vor allem bewegende Plattformen k&amp;ouml;nnten heikel sein, wenn ich mich richtig entsinne. Das Spiel sollte eigentlich mal eine Geschichte kriegen, die einzelnen Level-Gruppen haben deshalb auch ein &amp;uuml;bergeordnetes Thema und Endbosse, die theoretisch eine Bedeutung haben, allerdings war ich stets zu faul irgendwelche Scripts zu schreiben.&lt;br /&gt;Ich weiss nicht, ob ich das Spiel &amp;uuml;berhaupt vorstellen darf, so ziemlich s&amp;auml;mtliche Grafiken sind geklaut und unterstehen h&amp;ouml;chstwahrscheinlich einem Copyright von irgendeiner Seite :/ Falls es ein Problem sein sollte, werde ich das Spiel wieder l&amp;ouml;schen.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_15_JnR.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Steuerung ist eigentlich relativ simpel: Mit den Pfeiltasten kann man links und rechts bewegen, und mit der Hoch Taste kann man springen. Man kann einen Doppelsprung machen, wenn man in der Luft nochmal die Hochtaste dr&amp;uuml;ckt. Speichern kann man, wenn man in die leeren Rechtecke (auf dem Screen ganz links) springt, das sollte eigentlich in das &amp;quot;state&amp;quot; File schreiben, und euern Fortschritt speichern (keine Garantie darauf :&amp;gt;). Es sind ALLE Level schaffbar, ich habe jedes getestet (wenn auch nicht vor Kurzem *hust*). Aber ich w&amp;uuml;rde mich ernsthaft wundern, wenn es jemand bis nach dem ersten Schirm aush&amp;auml;lt &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt; .&lt;br /&gt;&lt;br /&gt;Der &lt;a href=&quot;http://www.phyrra.net63.net/Worklog/WL_15_JnR.rar&quot; target=&quot;_blank&quot;&gt;Download&lt;/a&gt; ist etwas gr&amp;ouml;sser (~4.5MB), weil ziemlich viele Bild Dateien in v&amp;ouml;llig verschiedenen Formaten enthalten sind und zus&amp;auml;tzlich noch einige Musikfiles. Um zu starten, sucht euch die Datei &amp;quot;Start.exe&amp;quot; in dem Gew&amp;uuml;hl von Dateien.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Evolution&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, nun muss ich eine &amp;Uuml;berleitung von den Dinosauriern zu Neuzeitlicheren Entwicklungen bringen. &lt;a href=&quot;http://www.youtube.com/watch?v=SRH-Ywpz1_I#t=0m11s&quot; target=&quot;_blank&quot;&gt;What killed the dinosaurs?&lt;/a&gt;. Naja, eigentlich liegt der gute Mr. Freeze ja falsch, es war die Evolution (jedenfalls behaupte ich das, um einen Grund zu haben das Nachfolgende als &amp;Uuml;berleitung zu verwenden).&lt;br /&gt;Ich wollte mal eine (f&amp;uuml;r mich) neue Art der KI ausprobieren. Ich versuchte mich also an &lt;a href=&quot;http://en.wikipedia.org/wiki/Evolutionary_algorithm&quot; target=&quot;_blank&quot;&gt;evolution&amp;auml;ren Algorithmen&lt;/a&gt;. Testgel&amp;auml;nde sollte ein TicTacToe Spiel sein, wie ihr vllt wisst, gibt es 9^2=81 M&amp;ouml;glichkeiten f&amp;uuml;r Feldkombinationen, auf die es richtige und falsche Antworten gibt. Nat&amp;uuml;rlich k&amp;ouml;nnte man nun all diese 81 hinschreiben und scripten, wie die KI reagieren soll, aber das wollte ich nicht. Ich habe meinen Spielern zwei Listen gegeben, eine von bekannten Feldpositionen und eine von folgenden Reaktionen. Dann habe ich sie spielen lassen, bei unbekannten Konstellationen wird zuf&amp;auml;llig gesetzt und das Ergebnis gespeichert. Nach einer gewissen Anzahl an Spielen sortiere ich (erinnert ihr euch an den &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/#2289&quot; target=&quot;_blank&quot;&gt;letzten Eintrag&lt;/a&gt;? :&amp;gt; ) nach Erfolg, und die besseren d&amp;uuml;rfen sich fortpflanzen, die Verlierer sterben. Zus&amp;auml;tzlich f&amp;uuml;ge ich noch ein zuf&amp;auml;lliges Element ein (neuer Spieler).&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_15_TicTacToeKI.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Das Ergebnis ist relativ ern&amp;uuml;chternd. Zum Teil zeigt die KI Anwandlungen von relativer Genialit&amp;auml;t (oder ich bin einfach nicht geeignet f&amp;uuml;r diese Art von Spiel) und &amp;uuml;berrumpelt mich total, und dann wiederum kann ich nacheinander drei Steine auf die obere Gerade Setzen und gewinnen. Meh! Lohnt sich meiner Meinung nach nicht wirklich. Eigentlich wollte ich dieses System nutzen, um eine sich steigernde KI in meinem Spiel zu haben (sie kommt nichts-ahnend ins Spiel, und lernt durch den Spieler dazu). Allerdings fehlt mir daf&amp;uuml;r noch ein objektiveres Wertungssystem und sowas, mal sehn was daraus wird.&lt;br /&gt;&lt;br /&gt;Der Code im Anhang. Nach einer Aufw&amp;auml;rmphase f&amp;uuml;r die KI kann man selber spielen. Dabei wird bei einem Gewinn sofort das Feld f&amp;uuml;r ein neues Spiel vorbereitet - der Gewinner ist, wer den letzen Zug hatte &lt;img src=&quot;/forum/images/smiles/icon_smile.gif&quot; alt=&quot;Smile&quot; /&gt;&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;];/*&lt;br /&gt;; * Spieler Verwaltung&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const MAX_MEM=100&lt;br /&gt;&lt;br /&gt;Global pList.TPlayer[100]&lt;br /&gt;Global plCount=0&lt;br /&gt;&lt;br /&gt;Type TPlayer&lt;br /&gt;	Field fieldState$[MAX_MEM]&lt;br /&gt;	Field reaction[MAX_MEM]&lt;br /&gt;	&lt;br /&gt;	Field stone$&lt;br /&gt;	&lt;br /&gt;	Field sCount&lt;br /&gt;	&lt;br /&gt;	Field victories&lt;br /&gt;	Field defeats&lt;br /&gt;	Field ties&lt;br /&gt;	&lt;br /&gt;	Field age&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function cTPlayer.TPlayer(stone$)&lt;br /&gt;	Local p.TPlayer=New TPlayer&lt;br /&gt;	&lt;br /&gt;	p\stone=stone&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addPlayer(p.TPlayer)&lt;br /&gt;	pList[plCount]=p&lt;br /&gt;	plCount=plCount+1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function addRndPlayers(anz)&lt;br /&gt;	Local s&lt;br /&gt;&lt;br /&gt;	For i=1 To anz&lt;br /&gt;		s=Rand(1,2)&lt;br /&gt;		&lt;br /&gt;		If s=1&lt;br /&gt;			pList[plCount]=cTPlayer(&amp;quot;X&amp;quot;)&lt;br /&gt;		Else&lt;br /&gt;			pList[plCount]=cTPlayer(&amp;quot;O&amp;quot;)&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		plCount=plCount+1&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function removePlayer(p.TPlayer)&lt;br /&gt;	For i=0 To plCount-1&lt;br /&gt;		If pList[i]=p&lt;br /&gt;			removePlayerByIndex(i)&lt;br /&gt;			Return&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function removePlayerByIndex(i)&lt;br /&gt;	If plCount=0&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Delete pList[i]&lt;br /&gt;	&lt;br /&gt;	For j=i+1 To plCount-1&lt;br /&gt;		pList[j-1]=pList[j]&lt;br /&gt;	Next&lt;br /&gt;	pList[plCount-1]=Null&lt;br /&gt;	&lt;br /&gt;	plCount=plCount-1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * KI Verwaltung&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Function playerMove(p.TPlayer)&lt;br /&gt;	Local s$=getFieldState()&lt;br /&gt;	Local i=stateKnown(p, s)&lt;br /&gt;	Local iNeu&lt;br /&gt;	&lt;br /&gt;	If i&amp;lt;&amp;gt;-1&lt;br /&gt;		If tField[p\reaction[i]]=&amp;quot;-&amp;quot;&lt;br /&gt;			tField[p\reaction[i]]=p\stone&lt;br /&gt;		Else&lt;br /&gt;			While True&lt;br /&gt;				set=setRandom()&lt;br /&gt;				If tField[set]=&amp;quot;-&amp;quot;&lt;br /&gt;					tField[set]=p\stone&lt;br /&gt;					&lt;br /&gt;					Exit&lt;br /&gt;				EndIf&lt;br /&gt;			Wend&lt;br /&gt;		EndIf&lt;br /&gt;	Else&lt;br /&gt;		While True&lt;br /&gt;			set=setRandom()&lt;br /&gt;			&lt;br /&gt;			If tField[set]=&amp;quot;-&amp;quot;&lt;br /&gt;				tField[set]=p\stone&lt;br /&gt;				saveState(p, s, set)&lt;br /&gt;				&lt;br /&gt;				Exit&lt;br /&gt;			EndIf&lt;br /&gt;		Wend&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function setRandom()&lt;br /&gt;	Local poss[9]&lt;br /&gt;	Local pCount=0&lt;br /&gt;	&lt;br /&gt;	For i=0 To 8&lt;br /&gt;		If tField[i]=&amp;quot;-&amp;quot;&lt;br /&gt;			poss[pCount]=i&lt;br /&gt;			pCount=pCount+1&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return poss[Rand(0,pCount-1)]&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function getFieldState$()&lt;br /&gt;	Local s$=&amp;quot;&amp;quot;&lt;br /&gt;	&lt;br /&gt;	For i=0 To 8&lt;br /&gt;		If tField[i]=&amp;quot;&amp;quot;&lt;br /&gt;			tField[i]=&amp;quot;-&amp;quot;&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		s=s+tField[i]&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return s&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function stateKnown(p.TPlayer, state$)&lt;br /&gt;	For i=0 To p\sCount-1&lt;br /&gt;		If p\fieldState[i]=state&lt;br /&gt;			Return i&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return -1&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function saveState(p.TPlayer, state$, reaction)&lt;br /&gt;	If p\sCount&amp;gt;=MAX_MEM&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If stateKnown(p, state)=-1&lt;br /&gt;		p\fieldState[p\sCount]=state&lt;br /&gt;		p\reaction[p\sCount]=reaction&lt;br /&gt;		&lt;br /&gt;		p\sCount=p\sCount+1&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Evolution&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Function nextGeneration(games)&lt;br /&gt;	For i=0 To games&lt;br /&gt;		startGame()&lt;br /&gt;		&lt;br /&gt;		While Not checkVictory()&lt;br /&gt;			gameRoutine()&lt;br /&gt;		Wend&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	quickSort(pList, 0, plCount-1)&lt;br /&gt;	&lt;br /&gt;	Local oldCount=plCount&lt;br /&gt;	Local halfCount=plCount/2&lt;br /&gt;	&lt;br /&gt;	For i=plCount-1 To plCount-halfCount Step -1&lt;br /&gt;		addPlayer(giveBirth(pList[i], pList[i-1]))&lt;br /&gt;		addPlayer(giveBirth(pList[i], pList[Rand(0,plCount-1)]))&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For i=0 To halfCount-1&lt;br /&gt;		removePlayerByIndex(0)&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	removePlayerByIndex(Rand(0, halfCount-1))&lt;br /&gt;	addRndPlayers(1)&lt;br /&gt;	&lt;br /&gt;	If plCount&amp;lt;oldCount&lt;br /&gt;		For i=plCount To oldCount-1&lt;br /&gt;			addRndPlayers(1)&lt;br /&gt;		Next&lt;br /&gt;	ElseIf plCount&amp;gt;oldCount&lt;br /&gt;		While plCount&amp;lt;&amp;gt;oldCount&lt;br /&gt;			removePlayerByIndex(Rand(0, Rand(0, plCount-1)))&lt;br /&gt;		Wend&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function giveBirth.TPlayer(p1.TPlayer, p2.TPlayer)&lt;br /&gt;	Local count=(p1\sCount+p2\sCount)/2&lt;br /&gt;	Local p.TPlayer&lt;br /&gt;	&lt;br /&gt;	If Rand(0,1)=0&lt;br /&gt;		p=cTPlayer(&amp;quot;O&amp;quot;)&lt;br /&gt;	Else&lt;br /&gt;		p=cTPlayer(&amp;quot;X&amp;quot;)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	For i=0 To count-1&lt;br /&gt;		If Rand(0,1)=0&lt;br /&gt;			If i&amp;lt;p1\sCount&lt;br /&gt;				saveState(p, p1\fieldState[i], p1\reaction[i])&lt;br /&gt;			Else&lt;br /&gt;				saveState(p, p2\fieldState[i], p2\reaction[i])&lt;br /&gt;			EndIf&lt;br /&gt;		Else&lt;br /&gt;			If i&amp;lt;p2\sCount&lt;br /&gt;				saveState(p, p2\fieldState[i], p2\reaction[i])&lt;br /&gt;			Else&lt;br /&gt;				saveState(p, p1\fieldState[i], p1\reaction[i])&lt;br /&gt;			EndIf&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function quickSort(list.TPlayer[100], le, ri)&lt;br /&gt;	Local l_tmp, r_tmp, piv, pivEl.TPlayer&lt;br /&gt;	&lt;br /&gt;	l_tmp=le&lt;br /&gt;	r_tmp=ri&lt;br /&gt;	piv=list[le]\victories&lt;br /&gt;	pivEl=list[le]&lt;br /&gt;	&lt;br /&gt;	While le&amp;lt;ri&lt;br /&gt;		While list[ri]\victories&amp;gt;=piv And le&amp;lt;ri&lt;br /&gt;			ri=ri-1&lt;br /&gt;		Wend&lt;br /&gt;		If le&amp;lt;&amp;gt;ri&lt;br /&gt;			list[le]=list[ri]&lt;br /&gt;			le=le+1&lt;br /&gt;		EndIf&lt;br /&gt;		While list[le]\victories&amp;lt;=piv And le&amp;lt;ri&lt;br /&gt;			le=le+1&lt;br /&gt;		Wend&lt;br /&gt;		If le&amp;lt;&amp;gt;ri&lt;br /&gt;			list[ri]=list[le]&lt;br /&gt;			ri=ri-1&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;	&lt;br /&gt;	list[le]=pivEl&lt;br /&gt;	piv=le&lt;br /&gt;	le=l_tmp&lt;br /&gt;	ri=r_tmp&lt;br /&gt;	&lt;br /&gt;	If le&amp;lt;piv&lt;br /&gt;		quickSort(list, le, piv-1)&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If ri&amp;gt;piv&lt;br /&gt;		quickSort(list, piv+1, ri)&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function savePlayers()&lt;br /&gt;	Local stream=WriteFile(&amp;quot;TTT_AI.txt&amp;quot;)&lt;br /&gt;	Local p.TPlayer&lt;br /&gt;	&lt;br /&gt;	quickSort(pList, 0, plCount-1)&lt;br /&gt;	&lt;br /&gt;	For j=0 To plCount-1&lt;br /&gt;		p=pList[j]&lt;br /&gt;		&lt;br /&gt;		If p\sCount&amp;gt;0&lt;br /&gt;			WriteLine stream, &amp;quot;Player &amp;quot;+p\stone&lt;br /&gt;			WriteLine stream, p\sCount&lt;br /&gt;			&lt;br /&gt;			For i=0 To p\sCount-1&lt;br /&gt;				WriteLine stream, p\fieldState[i]+&amp;quot; &amp;quot;+p\reaction[i]&lt;br /&gt;			Next&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function loadPlayers()&lt;br /&gt;	Local stream=ReadFile(&amp;quot;TTT_AI.txt&amp;quot;)&lt;br /&gt;	Local p.TPlayer, s$&lt;br /&gt;	&lt;br /&gt;	While Not Eof(stream)&lt;br /&gt;		s=ReadLine(stream)&lt;br /&gt;		&lt;br /&gt;		If s=Left(s, 6)=&amp;quot;Player&amp;quot;&lt;br /&gt;			p=New TPlayer&lt;br /&gt;			&lt;br /&gt;			p\stone=Right(s,1)&lt;br /&gt;			p\sCount=Int(ReadLine(stream))&lt;br /&gt;			&lt;br /&gt;			For i=0 To p\sCount-1&lt;br /&gt;				s=ReadLine(stream)&lt;br /&gt;				&lt;br /&gt;				p\fieldState[i]=Left(s, 9)&lt;br /&gt;				p\reaction[i]=Right(s, 1)&lt;br /&gt;			Next&lt;br /&gt;			&lt;br /&gt;			pList[plCount]=p&lt;br /&gt;			plCount=plCount+1&lt;br /&gt;		EndIf&lt;br /&gt;	Wend&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Spiel Verwaltung&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const FIELD_SIZE=50&lt;br /&gt;Global tField$[9]&lt;br /&gt;&lt;br /&gt;Global player1.TPlayer&lt;br /&gt;Global player2.TPlayer&lt;br /&gt;Global victor.TPlayer&lt;br /&gt;&lt;br /&gt;Global human=True&lt;br /&gt;Global turn=0&lt;br /&gt;&lt;br /&gt;Function startGame()&lt;br /&gt;	For i=0 To 8&lt;br /&gt;		tField[i]=&amp;quot;-&amp;quot;&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	If human&lt;br /&gt;		If player1=Null&lt;br /&gt;			player1=cTPlayer(&amp;quot;O&amp;quot;)&lt;br /&gt;		EndIf&lt;br /&gt;	Else&lt;br /&gt;		If plCount=0&lt;br /&gt;			player1=cTPlayer(&amp;quot;O&amp;quot;)&lt;br /&gt;			&lt;br /&gt;			pList[0]=player1&lt;br /&gt;			plCount=plCount+1&lt;br /&gt;		Else&lt;br /&gt;			player1=pList[Rand(0, plCount-1)]&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If plCount=0 Or (plCount=1 And human=False)&lt;br /&gt;		player2=cTPlayer(&amp;quot;X&amp;quot;)&lt;br /&gt;		&lt;br /&gt;		pList[plCount]=player2&lt;br /&gt;		plCount=plCount+1&lt;br /&gt;	Else&lt;br /&gt;		While True&lt;br /&gt;			player2=pList[Rand(0, plCount-1)]&lt;br /&gt;			&lt;br /&gt;			If player2&amp;lt;&amp;gt;player1&lt;br /&gt;				If player2\stone&amp;lt;&amp;gt;player1\stone&lt;br /&gt;					Exit&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Wend&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	turn=0&lt;br /&gt;	&lt;br /&gt;	victor=Null&lt;br /&gt;	&lt;br /&gt;	player1\age=player1\age+1&lt;br /&gt;	player2\age=player2\age+1&lt;br /&gt;	&lt;br /&gt;	SeedRnd(MilliSecs())&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function gameRoutine()&lt;br /&gt;	If checkVictory()=True&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If player1=Null Or player2=Null&lt;br /&gt;		Return&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If turn=0&lt;br /&gt;		If human&lt;br /&gt;			If MouseHit(1)&lt;br /&gt;				If setStone(player1\stone, MouseX(), MouseY())&lt;br /&gt;					turn=1-turn&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Else&lt;br /&gt;			playerMove(player1)&lt;br /&gt;			turn=1-turn&lt;br /&gt;		EndIf&lt;br /&gt;	Else&lt;br /&gt;		playerMove(player2)&lt;br /&gt;		turn=1-turn&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function setStone(stone$, sx, sy)&lt;br /&gt;	Local x=sx/FIELD_SIZE&lt;br /&gt;	Local y=sy/FIELD_SIZE&lt;br /&gt;	&lt;br /&gt;	If tField[x+y*3]=&amp;quot;-&amp;quot;&lt;br /&gt;		saveState(player1, getFieldState(), x+y*3)&lt;br /&gt;		&lt;br /&gt;		tField[x+y*3]=stone$&lt;br /&gt;		Return True&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return False&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function checkVictory()&lt;br /&gt;	If player1=Null Or player2=Null&lt;br /&gt;		Return True&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local vic$&lt;br /&gt;	&lt;br /&gt;	For i=0 To 2&lt;br /&gt;		vic=tField[i*3]&lt;br /&gt;		For x=0 To 2&lt;br /&gt;			If tField[i*3+x]&amp;lt;&amp;gt;vic&lt;br /&gt;				vic=&amp;quot;-&amp;quot;&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		If vic&amp;lt;&amp;gt;&amp;quot;-&amp;quot;&lt;br /&gt;			Exit&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		vic=tField[i]&lt;br /&gt;		For y=0 To 2&lt;br /&gt;			If tField[i+y*3]&amp;lt;&amp;gt;vic&lt;br /&gt;				vic=&amp;quot;-&amp;quot;&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		If vic&amp;lt;&amp;gt;&amp;quot;-&amp;quot;&lt;br /&gt;			Exit&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		vic=&amp;quot;-&amp;quot;&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	If tField[0]=tField[4] And tField[4]=tField[8]&lt;br /&gt;		If tField[0]&amp;lt;&amp;gt;&amp;quot;-&amp;quot;&lt;br /&gt;			vic=tField[0]&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If tField[2]=tField[4] And tField[4]=tField[6]&lt;br /&gt;		If tField[2]&amp;lt;&amp;gt;&amp;quot;-&amp;quot;&lt;br /&gt;			vic=tField[2]&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If vic=&amp;quot;O&amp;quot;&lt;br /&gt;		victor=player1&lt;br /&gt;		player1\victories=player1\victories+1&lt;br /&gt;		player2\defeats=player2\defeats+1&lt;br /&gt;		&lt;br /&gt;		Return True&lt;br /&gt;	ElseIf vic=&amp;quot;X&amp;quot;&lt;br /&gt;		victor=player2&lt;br /&gt;		player2\victories=player2\victories+1&lt;br /&gt;		player1\defeats=player1\defeats+1&lt;br /&gt;		&lt;br /&gt;		Return True&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	For i=0 To 8&lt;br /&gt;		If tField[i]=&amp;quot;-&amp;quot;&lt;br /&gt;			Return False&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	victor=Null&lt;br /&gt;	player1\ties=player1\ties+1&lt;br /&gt;	player2\ties=player2\ties+1&lt;br /&gt;	&lt;br /&gt;	Return True&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawField()&lt;br /&gt;	Local y=0&lt;br /&gt;	Local x=0&lt;br /&gt;	&lt;br /&gt;	For i=0 To 8&lt;br /&gt;		If tField[i]&amp;lt;&amp;gt;&amp;quot;-&amp;quot;&lt;br /&gt;			Text x*FIELD_SIZE, y*FIELD_SIZE, tField[i]&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		x=x+1&lt;br /&gt;		&lt;br /&gt;		If x Mod 3=0&lt;br /&gt;			y=y+1&lt;br /&gt;			x=0&lt;br /&gt;		EndIf&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For x=1 To 2&lt;br /&gt;		Line x*FIELD_SIZE, 0, x*FIELD_SIZE, FIELD_SIZE*3&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For y=1 To 2&lt;br /&gt;		Line 0, y*FIELD_SIZE, FIELD_SIZE*3, y*FIELD_SIZE&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Testumgebung&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Graphics 640,480,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;human=False&lt;br /&gt;addRndPlayers(20)&lt;br /&gt;&lt;br /&gt;For i=0 To 500&lt;br /&gt;	nextGeneration(10)&lt;br /&gt;Next&lt;br /&gt;&lt;br /&gt;quickSort(pList, 0, plCount-1)&lt;br /&gt;human=True&lt;br /&gt;&lt;br /&gt;Local timer=CreateTimer(60)&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	&lt;br /&gt;	gameRoutine()&lt;br /&gt;	drawField()&lt;br /&gt;	&lt;br /&gt;	If checkVictory()&lt;br /&gt;		startGame()&lt;br /&gt;		&lt;br /&gt;		player2=pList[plCount-1]&lt;br /&gt;		player1=cTPlayer(&amp;quot;&amp;quot;)&lt;br /&gt;		&lt;br /&gt;		If player2\stone=&amp;quot;X&amp;quot;&lt;br /&gt;			player1\stone=&amp;quot;O&amp;quot;&lt;br /&gt;		Else&lt;br /&gt;			player1\stone=&amp;quot;X&amp;quot;&lt;br /&gt;		EndIf&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	WaitTimer(timer)&lt;br /&gt;	Cls&lt;br /&gt;Wend&lt;br /&gt;&lt;br /&gt;;savePlayers()&lt;br /&gt;&lt;br /&gt;End[/syntax]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bakterien und so&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Naja, eigentlich eher Metaballs, aber wieso ich es Bakterien nenne, kommt in K&amp;uuml;rze. Falls ihr euch an meine (mittlerweilen) uralte &lt;a href=&quot;https://www.blitzforum.de/worklogs/292/?page=2#2001&quot; target=&quot;_blank&quot;&gt;Wassersimulation&lt;/a&gt; erinnert, wisst ihr vielleicht noch, dass ich das (u.a) damals mit Metaballs gerendert habe. Die Methode dazu war von Noobody und das wurmte mich, ich wollte den Krempel selber schreiben. Aber ich hatte keine Zeit und liess es liegen (v.a weil ich irgendwann auf blosse Pixel umgestiegen bin..). Aber ich habe es vor Kurzem wieder aufgenommen und weitergemacht.&lt;br /&gt;&lt;br /&gt;Der erste Ansatz war, einen &lt;a href=&quot;http://en.wikipedia.org/wiki/Quadtree&quot; target=&quot;_blank&quot;&gt;Quadtree&lt;/a&gt; zu verwenden, um nicht immer alle B&amp;auml;lle ber&amp;uuml;cksichtigen zu m&amp;uuml;ssen, sondern nur diejenigen, die auch Einfluss haben. Das Ergebnis war - falsch.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_15_QuadTreeFail.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Es kommt zu Fehlern an Grenzen. Das liegt daran, dass der zweite Metaball nicht ber&amp;uuml;cksichtigt wird, da er in einem anderen Quadrat liegt, allerdings hat er dennoch Einfluss auf das Feld. Ausserdem ist die Methode nicht wirklich viel schneller, als ohne QT Optimierung (.. 5 B&amp;auml;lle, ob ich jetzt 2 oder 5 durchlaufe macht den Braten auch nicht fetter). Darum wurde diese Idee aufgegeben.&lt;br /&gt;Da ich im Moment nicht weiss, wof&amp;uuml;r man einen QuadTree brauchen k&amp;ouml;nnte, spare ich es mir, den Code zu posten. Ich hatte ihn darauf ausgelegt, m&amp;ouml;glichst universell einsetzbar zu sein, man muss halt nur gewisse Type-Namen &amp;auml;ndern (von MetaBall zu MyType), und die &amp;Uuml;berlappfunktion anpassen. Sobald mir was Kluges einf&amp;auml;llt, kommt ein Beispiel dazu.&lt;br /&gt;&lt;br /&gt;Dann erinnerte ich mich an &lt;a href=&quot;https://www.blitzforum.de/forum/viewtopic.php?t=31608&amp;amp;highlight=metaball&quot; target=&quot;_blank&quot;&gt;diesen Eintrag&lt;/a&gt; im Codearchiv, wo das Prinzip der Marching Cubes in 3D implementiert wurde (f&amp;uuml;r ein Voxelgitter iirc). Das Gleiche m&amp;uuml;sste sich eigentlich in 2D auch machen lassen, und siehe da, es gibt den &lt;a href=&quot;http://en.wikipedia.org/wiki/Marching_squares&quot; target=&quot;_blank&quot;&gt;Marching Squares Algorithm&lt;/a&gt;. Wer vor einigen Tagen ins Forum schaute, sah vielleicht, dass diese Auswahlregeln nicht ausreichen, es braucht noch die alte Richtung bei den Querf&amp;auml;llen.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;img onload=&quot;resize_image(this)&quot; src=&quot;http://www.phyrra.net63.net/Worklog/WL_15_MSWater.png&quot; alt=&quot;user posted image&quot; /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(Sieht das nicht voll nach Bakterien aus die herumwuseln? Nein? ... Wie auch immer, mein Beitrag, meine Vergleiche!)&lt;br /&gt;Durch diese Methode der Randfindung, l&amp;auml;sst sich das Zeichnen ziemlich beschleunigen, da ich zun&amp;auml;chst einmal ein Gitter habe (hier: 80x60), was einige Berechnungen spart. Zudem muss ich eigentlich nur die Felder des Randes berechnen (und einige Startpunkte suchen), das ist ansich kein grosser Aufwand.&lt;br /&gt;Was schon etwas langsamer wird, ist das F&amp;uuml;llen. Ich kam nicht umhin, einen FloodFill zu integrieren, weil mein ScanLine wieder das alte Problem hatte &amp;quot;wo zeichne ich, und wo nicht&amp;quot;, vor allem bei Anf&amp;auml;ngen von Linien, die horizontal sind und das Feld abschliessen. (Die Funktion ist noch im Code enthalten, k&amp;ouml;nnt euch das Resultat ja mal ansehen).&lt;br /&gt;Der FloodFill benutzt kein ReadPixel, sondern ein Raster, dieses wird beim Zeichnen des Randes mittels des Bresenham-Algorithmus (letzer Eintrag, mann war der n&amp;uuml;tzlich!) gesetzt, und danach wird vom Startpunkt des Randes aus gef&amp;uuml;llt. Das ist zwar etwas riskant, funktioniert aber in den meisten F&amp;auml;llen (in gewissen Ausnahmen f&amp;uuml;llt es das Bild ringsherum :&amp;gt; ).&lt;br /&gt;&lt;br /&gt;Code hier (es sind noch einige Debugelemente drin, die man getrost entfernen kann):&lt;br /&gt;&lt;br /&gt;[syntax=&amp;quot;bb&amp;quot;]Graphics 800,600,0,2&lt;br /&gt;SetBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * MetaBall&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Const threshold#=0.004&lt;br /&gt;&lt;br /&gt;Type MetaBall&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;	&lt;br /&gt;	Field vx#&lt;br /&gt;	Field vy#&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function drawMetaBalls()&lt;br /&gt;	Dim screenMap(GraphicsWidth(), GraphicsHeight())&lt;br /&gt;	;Dim peakValues(2, GraphicsHeight())&lt;br /&gt;	&lt;br /&gt;	;For y=0 To GraphicsHeight()-1&lt;br /&gt;	;	peakValues(0, y)=GraphicsWidth()&lt;br /&gt;	;Next&lt;br /&gt;	&lt;br /&gt;	Dim fieldData(gridWidth,gridHeight)&lt;br /&gt;	Dim fieldDone(gridWidth,gridHeight)&lt;br /&gt;	Dim fieldRendered(gridWidth,gridHeight)&lt;br /&gt;	&lt;br /&gt;	Local hull.Path&lt;br /&gt;	&lt;br /&gt;	Local MX&lt;br /&gt;	Local MY&lt;br /&gt;	&lt;br /&gt;	Local count=0&lt;br /&gt;	LockBuffer BackBuffer()&lt;br /&gt;	&lt;br /&gt;	For m.metaBall=Each MetaBall&lt;br /&gt;		MX=m\x*gridWidth/GraphicsWidth()+1&lt;br /&gt;		MY=m\y*gridHeight/GraphicsHeight()+1&lt;br /&gt;		&lt;br /&gt;		For yi=MY To 1 Step -1&lt;br /&gt;			If Not fieldDone(MX,yi)&lt;br /&gt;				fieldData(MX,yi)=getDataField(MX, yi)&lt;br /&gt;			EndIf&lt;br /&gt;			&lt;br /&gt;			If yi&amp;lt;MY&lt;br /&gt;				If fieldData(MX, yi)=0&lt;br /&gt;					If fieldData(MX, yi+1)=1 And fieldRendered(MX, yi+1)=False&lt;br /&gt;						hull=identifyPerimeter(MX, yi+1)&lt;br /&gt;						&lt;br /&gt;						If hull=Null&lt;br /&gt;							stopped=True&lt;br /&gt;						Else&lt;br /&gt;							hull\parent=m&lt;br /&gt;							drawPath(hull)&lt;br /&gt;							&lt;br /&gt;							count=count+1&lt;br /&gt;						EndIf&lt;br /&gt;					EndIf&lt;br /&gt;					&lt;br /&gt;					Exit&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	fillHulls()&lt;br /&gt;	&lt;br /&gt;	UnlockBuffer BackBuffer()&lt;br /&gt;&lt;br /&gt;	Text 10,10,count&lt;br /&gt;	&lt;br /&gt;	Delete Each Point&lt;br /&gt;	Delete Each Direction&lt;br /&gt;	Delete Each Path&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// MetaBall&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Flood Fill&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Type TPixel&lt;br /&gt;	Field x&lt;br /&gt;	Field y&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newTPixel.TPixel(x, y)&lt;br /&gt;	Local p.TPixel=New TPixel&lt;br /&gt;	&lt;br /&gt;	p\x=x&lt;br /&gt;	p\y=y&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Dim screenMap(GraphicsWidth(), GraphicsHeight())&lt;br /&gt;;Dim peakValues(2, GraphicsHeight())&lt;br /&gt;&lt;br /&gt;Function sBLine(x0, y0, x1, y1)&lt;br /&gt;	;Local col=ColorRed()*$10000+ColorGreen()*$100+ColorBlue()&lt;br /&gt;	&lt;br /&gt;	Local steep&lt;br /&gt;	Local tmp, dX, dY, err, yStep, y&lt;br /&gt;	&lt;br /&gt;	If Abs(y1-y0)&amp;gt;Abs(x1-x0)&lt;br /&gt;		steep=True&lt;br /&gt;		&lt;br /&gt;		tmp=x0&lt;br /&gt;		x0=y0&lt;br /&gt;		y0=tmp&lt;br /&gt;		&lt;br /&gt;		tmp=x1&lt;br /&gt;		x1=y1&lt;br /&gt;		y1=tmp&lt;br /&gt;	Else&lt;br /&gt;		steep=False&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If x0&amp;gt;x1&lt;br /&gt;		tmp=x0&lt;br /&gt;		x0=x1&lt;br /&gt;		x1=tmp&lt;br /&gt;		&lt;br /&gt;		tmp=y0&lt;br /&gt;		y0=y1&lt;br /&gt;		y1=tmp&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	dX=x1-x0&lt;br /&gt;	dY=Abs(y1-y0)&lt;br /&gt;	err=dX/2&lt;br /&gt;	y=y0&lt;br /&gt;	&lt;br /&gt;	If y0&amp;lt;y1&lt;br /&gt;		yStep=1&lt;br /&gt;	Else&lt;br /&gt;		yStep=-1&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If steep&lt;br /&gt;		For x=x0 To x1&lt;br /&gt;			;WritePixelFast y,x,col&lt;br /&gt;			&lt;br /&gt;			screenMap(y, x)=True&lt;br /&gt;			;If y&amp;lt;peakValues(0, x)&lt;br /&gt;			;	peakValues(0, x)=y&lt;br /&gt;			;EndIf&lt;br /&gt;			;If y&amp;gt;peakValues(1, x)&lt;br /&gt;			;	peakValues(1, x)=y&lt;br /&gt;			;EndIf&lt;br /&gt;			&lt;br /&gt;			err=err-dY&lt;br /&gt;			&lt;br /&gt;			If err&amp;lt;0&lt;br /&gt;				y=y+yStep&lt;br /&gt;				&lt;br /&gt;				err=err+dX&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;	Else&lt;br /&gt;		For x=x0 To x1&lt;br /&gt;			;WritePixelFast x,y,col&lt;br /&gt;			&lt;br /&gt;			screenMap(x, y)=True&lt;br /&gt;			;If x&amp;lt;peakValues(0, y)&lt;br /&gt;			;	peakValues(0, y)=x&lt;br /&gt;			;EndIf&lt;br /&gt;			;If x&amp;gt;peakValues(1, y)&lt;br /&gt;			;	peakValues(1, y)=x&lt;br /&gt;			;EndIf&lt;br /&gt;			&lt;br /&gt;			err=err-dY&lt;br /&gt;			&lt;br /&gt;			If err&amp;lt;0&lt;br /&gt;				y=y+yStep&lt;br /&gt;				&lt;br /&gt;				err=err+dX&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function fillHull(hull.Path)&lt;br /&gt;	Local factorX#=GraphicsWidth()/gridWidth&lt;br /&gt;	Local factorY#=GraphicsHeight()/gridHeight&lt;br /&gt;	&lt;br /&gt;	Local col=0*$10000+55*$100+255&lt;br /&gt;	Local startX, startY, newX, newY&lt;br /&gt;	Local p.TPixel, n.TPixel&lt;br /&gt;	&lt;br /&gt;	startX=hull\parent\x&lt;br /&gt;	startY=hull\parent\y&lt;br /&gt;	&lt;br /&gt;	p=newTPixel(startX, startY)&lt;br /&gt;	WritePixelFast startX, startY, col&lt;br /&gt;	screenMap(startX, startY)=True&lt;br /&gt;	&lt;br /&gt;	For p=Each TPixel&lt;br /&gt;		For dir=0 To 3&lt;br /&gt;			newX=p\x+(dir=0)-(dir=2)&lt;br /&gt;			newY=p\y+(dir=1)-(dir=3)&lt;br /&gt;			&lt;br /&gt;			If newX&amp;gt;=0 And newY&amp;gt;=0 And newX&amp;lt;GraphicsWidth() And newY&amp;lt;GraphicsHeight()&lt;br /&gt;				If screenMap(newX, newY)=0&lt;br /&gt;					If Not screenMap(newX, newY)&lt;br /&gt;						n=newTPixel(newX, newY)&lt;br /&gt;						&lt;br /&gt;						WritePixelFast newX, newY, col&lt;br /&gt;						screenMap(newX, newY)=True&lt;br /&gt;					EndIf&lt;br /&gt;					;Else&lt;br /&gt;					;	WritePixelFast newX, newY, col&lt;br /&gt;				EndIf&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;		&lt;br /&gt;		Delete p&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;	&lt;br /&gt;Function fillHulls()&lt;br /&gt;	Local factorX#=GraphicsWidth()/gridWidth&lt;br /&gt;	Local factorY#=GraphicsHeight()/gridHeight&lt;br /&gt;	&lt;br /&gt;	Local col=0*$10000+55*$100+255&lt;br /&gt;	Local hull.Path&lt;br /&gt;	Local startX, startY, newX, newY&lt;br /&gt;	Local p.TPixel, n.TPixel&lt;br /&gt;	&lt;br /&gt;	For hull=Each Path&lt;br /&gt;		;Hmm, Start ist etwas riskant&lt;br /&gt;		; nach M&amp;ouml;glichkeit ist der Punkt ausserhalb des Pfads&lt;br /&gt;		; (oder auf der Linie)&lt;br /&gt;		&lt;br /&gt;		startX=hull\parent\x;hull\originX*factorX+1&lt;br /&gt;		startY=hull\parent\y;hull\originY*factorY+1&lt;br /&gt;		&lt;br /&gt;		p=newTPixel(startX, startY)&lt;br /&gt;		WritePixelFast startX, startY, col&lt;br /&gt;		screenMap(startX, startY)=True&lt;br /&gt;		&lt;br /&gt;		For p=Each TPixel&lt;br /&gt;			For dir=0 To 3&lt;br /&gt;				newX=p\x+(dir=0)-(dir=2)&lt;br /&gt;				newY=p\y+(dir=1)-(dir=3)&lt;br /&gt;				&lt;br /&gt;				If newX&amp;gt;=0 And newY&amp;gt;=0 And newX&amp;lt;GraphicsWidth() And newY&amp;lt;GraphicsHeight()&lt;br /&gt;					If screenMap(newX, newY)=0&lt;br /&gt;						If Not screenMap(newX, newY)&lt;br /&gt;							n=newTPixel(newX, newY)&lt;br /&gt;							&lt;br /&gt;							WritePixelFast newX, newY, col&lt;br /&gt;							screenMap(newX, newY)=True&lt;br /&gt;						EndIf&lt;br /&gt;					;Else&lt;br /&gt;					;	WritePixelFast newX, newY, col&lt;br /&gt;					EndIf&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;			&lt;br /&gt;			Delete p&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;Function fillHulls_wrong()&lt;br /&gt;;	Local fill, col&lt;br /&gt;;	&lt;br /&gt;;	col=255*$10000+255*$100+0&lt;br /&gt;;	&lt;br /&gt;;	For y=0 To GraphicsHeight()&lt;br /&gt;;		If peakValues(0, y)&amp;lt;peakValues(1, y)&lt;br /&gt;;			fill=True&lt;br /&gt;;			&lt;br /&gt;;			While screenMap(peakValues(0, y), y)=True&lt;br /&gt;;				peakValues(0, y)=peakValues(0, y)+1&lt;br /&gt;;			Wend&lt;br /&gt;;			&lt;br /&gt;;			For x=peakValues(0, y) To peakValues(1, y)&lt;br /&gt;;				If screenMap(x, y)&lt;br /&gt;;					While screenMap(x, y)&lt;br /&gt;;						x=x+1&lt;br /&gt;;					Wend&lt;br /&gt;;					&lt;br /&gt;;					fill=1-fill&lt;br /&gt;;				EndIf&lt;br /&gt;;				&lt;br /&gt;;				If fill&lt;br /&gt;;					WritePixelFast x, y, col&lt;br /&gt;;				EndIf&lt;br /&gt;;			Next&lt;br /&gt;;		EndIf&lt;br /&gt;;	Next&lt;br /&gt;;End Function&lt;br /&gt;&lt;br /&gt;;// FloodFill&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Marching Squares Algorithm&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;Global gridWidth=80&lt;br /&gt;Global gridHeight=60&lt;br /&gt;&lt;br /&gt;Dim fieldData(0,0)&lt;br /&gt;Dim fieldDone(0,0)&lt;br /&gt;Dim fieldRendered(0,0)&lt;br /&gt;&lt;br /&gt;Type Point&lt;br /&gt;	Field x#&lt;br /&gt;	Field y#&lt;br /&gt;	&lt;br /&gt;	Field prev.Point&lt;br /&gt;	Field succ.Point&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newPoint.Point(x#, y#)&lt;br /&gt;	Local p.Point=New Point&lt;br /&gt;	&lt;br /&gt;	p\x=x&lt;br /&gt;	p\y=y&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Global North[2]	: North[1]=-1&lt;br /&gt;Global East[2]	: East[0]=1&lt;br /&gt;Global South[2]	: South[1]=1&lt;br /&gt;Global West[2]	: West[0]=-1&lt;br /&gt;&lt;br /&gt;Type Direction&lt;br /&gt;	Field dirX&lt;br /&gt;	Field dirY&lt;br /&gt;	&lt;br /&gt;	Field succ.Direction&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newDirection.Direction(dir[2])&lt;br /&gt;	d.direction=New Direction&lt;br /&gt;	&lt;br /&gt;	d\dirX=dir[0]&lt;br /&gt;	d\dirY=dir[1]&lt;br /&gt;	&lt;br /&gt;	Return d&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Type Path&lt;br /&gt;	Field originX&lt;br /&gt;	Field originY&lt;br /&gt;	&lt;br /&gt;	Field pList.Point&lt;br /&gt;	Field count&lt;br /&gt;	&lt;br /&gt;	Field parent.MetaBall&lt;br /&gt;End Type&lt;br /&gt;&lt;br /&gt;Function newPath.Path(startX, startY, directions.Direction)&lt;br /&gt;	Local p.Path=New Path&lt;br /&gt;	&lt;br /&gt;	p\originX=startX&lt;br /&gt;	p\originY=startY&lt;br /&gt;	&lt;br /&gt;	p\pList=New Point&lt;br /&gt;	p\pList\x=startX&lt;br /&gt;	p\pList\y=startY&lt;br /&gt;	&lt;br /&gt;	fieldRendered(startX,startY)=True&lt;br /&gt;	&lt;br /&gt;	Local pList.Point=p\pList&lt;br /&gt;	&lt;br /&gt;	Repeat&lt;br /&gt;		pList\succ=New Point&lt;br /&gt;		pList\succ\prev=pList&lt;br /&gt;		&lt;br /&gt;		pList\succ\x=pList\x+directions\dirX&lt;br /&gt;		pList\succ\y=pList\y+directions\dirY&lt;br /&gt;		&lt;br /&gt;		pList=pList\succ&lt;br /&gt;		directions=directions\succ&lt;br /&gt;		&lt;br /&gt;		fieldRendered(pList\x,pList\y)=True&lt;br /&gt;		&lt;br /&gt;		p\count=p\count+1&lt;br /&gt;	Until directions=Null&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// can be used to find the path around one speciffic connected field&lt;br /&gt;Function identifyPerimeterStart.Path()&lt;br /&gt;	Dim fieldData(gridWidth, gridHeight)&lt;br /&gt;	Dim fieldDone(gridWidth, gridHeight)&lt;br /&gt;	Dim fieldRendered(gridWidth,gridHeight)&lt;br /&gt;	&lt;br /&gt;	For x=0 To gridWidth-1&lt;br /&gt;		For y=0 To gridHeight-1&lt;br /&gt;			fieldData(x,y)=getDataPoint(GraphicsWidth()/gridWidth*x,GraphicsHeight()/gridHeight*y)&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	For x=0 To gridWidth-1&lt;br /&gt;		For y=0 To gridHeight-1&lt;br /&gt;			If fieldData(x,y)&amp;lt;&amp;gt;0&lt;br /&gt;				Return identifyPerimeter(x,y)&lt;br /&gt;			EndIf&lt;br /&gt;		Next&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	Return Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function identifyPerimeter.Path(initialX, initialY)&lt;br /&gt;	Local initialValue=getDirection(initialX,initialY, Null)&lt;br /&gt;	If initialValue=-1&lt;br /&gt;		DebugLog &amp;quot;Wrong start Point&amp;quot;&lt;br /&gt;		stopped=True&lt;br /&gt;		Return Null&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Local dir.Direction&lt;br /&gt;	&lt;br /&gt;	Local X=initialX&lt;br /&gt;	Local Y=initialY&lt;br /&gt;	&lt;br /&gt;	Local maxIter=1000&lt;br /&gt;	Local iter=0&lt;br /&gt;	&lt;br /&gt;	Local p.Path=New Path&lt;br /&gt;	&lt;br /&gt;	p\originX=initialX&lt;br /&gt;	p\originY=initialY&lt;br /&gt;	&lt;br /&gt;	p\pList=newPoint(initialX, initialY)&lt;br /&gt;	fieldRendered(initialX, initialY)=True&lt;br /&gt;	&lt;br /&gt;	Local pList.Point=p\pList&lt;br /&gt;	&lt;br /&gt;	Repeat&lt;br /&gt;		iter=iter+1&lt;br /&gt;		If iter&amp;gt;maxIter&lt;br /&gt;			;Wenn es hierzu kommt, ist irgendwo ein Fehler passiert&lt;br /&gt;			; ich weiss nicht wie es dazu kommt :/&lt;br /&gt;			; das Ergebnis sind Linien durch das Objekt&lt;br /&gt;			&lt;br /&gt;			stopped=True&lt;br /&gt;			DebugLog &amp;quot;overflow&amp;quot;&lt;br /&gt;			Exit&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		Select getDirection(X, Y, dir)&lt;br /&gt;			Case 1&lt;br /&gt;				dir=newDirection(North)&lt;br /&gt;			Case 2&lt;br /&gt;				dir=newDirection(East)&lt;br /&gt;			Case 3&lt;br /&gt;				dir=newDirection(South)&lt;br /&gt;			Case 4&lt;br /&gt;				dir=newDirection(West)&lt;br /&gt;			Default&lt;br /&gt;				stopped=True&lt;br /&gt;				DebugLog &amp;quot;wrong direction&amp;quot;&lt;br /&gt;				Return Null&lt;br /&gt;		End Select&lt;br /&gt;		&lt;br /&gt;		X=X+dir\dirX&lt;br /&gt;		Y=Y+dir\dirY&lt;br /&gt;		&lt;br /&gt;		pList\succ=New Point&lt;br /&gt;		pList\succ\prev=pList&lt;br /&gt;		&lt;br /&gt;		pList\succ\x=pList\x+dir\dirX&lt;br /&gt;		pList\succ\y=pList\y+dir\dirY&lt;br /&gt;		&lt;br /&gt;		pList=pList\succ&lt;br /&gt;		&lt;br /&gt;		fieldRendered(pList\x, pList\y)=True&lt;br /&gt;		&lt;br /&gt;		p\count=p\count+1&lt;br /&gt;	Until X=initialX And Y=initialY&lt;br /&gt;	&lt;br /&gt;	Return p&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function getDirection(x, y, lastDir.Direction)&lt;br /&gt;	Local d1, d2, d3, d4&lt;br /&gt;	&lt;br /&gt;	d1=getDataField(x-1,y-1)&lt;br /&gt;	d2=getDataField(x,y-1)&lt;br /&gt;	d3=getDataField(x-1,y)&lt;br /&gt;	d4=getDataField(x,y)&lt;br /&gt;	&lt;br /&gt;	Local sum=d1+d2+d3+d4&lt;br /&gt;	&lt;br /&gt;	Local N=1 ; NORTH&lt;br /&gt;	Local E=2 ; EAST&lt;br /&gt;	Local S=3 ; SOUTH&lt;br /&gt;	Local W=4 ; WEST&lt;br /&gt;	&lt;br /&gt;	Select sum&lt;br /&gt;		Case 0&lt;br /&gt;			Return E&lt;br /&gt;		Case 1&lt;br /&gt;			If d2&lt;br /&gt;				Return E&lt;br /&gt;			ElseIf d4&lt;br /&gt;				Return S&lt;br /&gt;			ElseIf d1&lt;br /&gt;				Return N&lt;br /&gt;			ElseIf d3&lt;br /&gt;				Return W&lt;br /&gt;			EndIf&lt;br /&gt;		Case 2&lt;br /&gt;			If d2 And d4&lt;br /&gt;				Return S&lt;br /&gt;			ElseIf d1 And d2&lt;br /&gt;				Return E&lt;br /&gt;			ElseIf d1 And d3&lt;br /&gt;				Return N&lt;br /&gt;			ElseIf d3 And d4&lt;br /&gt;				Return W&lt;br /&gt;			ElseIf d1 And d4&lt;br /&gt;				If lastDir=Null&lt;br /&gt;					Return N&lt;br /&gt;				Else&lt;br /&gt;					If lastDir\dirX=1&lt;br /&gt;						Return N&lt;br /&gt;					Else&lt;br /&gt;						Return S&lt;br /&gt;					EndIf&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				;Return N ;Original Line&lt;br /&gt;			ElseIf d2 And d3&lt;br /&gt;				If lastDir=Null&lt;br /&gt;					Return W&lt;br /&gt;				Else&lt;br /&gt;					If lastDir\dirY=1&lt;br /&gt;						Return W&lt;br /&gt;					Else&lt;br /&gt;						Return E&lt;br /&gt;					EndIf&lt;br /&gt;				EndIf&lt;br /&gt;				&lt;br /&gt;				;Return W ;Original Line&lt;br /&gt;			EndIf&lt;br /&gt;		Case 3&lt;br /&gt;			If Not d2&lt;br /&gt;				Return N&lt;br /&gt;			ElseIf Not d1&lt;br /&gt;				Return W&lt;br /&gt;			ElseIf Not d3&lt;br /&gt;				Return S&lt;br /&gt;			ElseIf Not d4&lt;br /&gt;				Return E&lt;br /&gt;			EndIf&lt;br /&gt;		Default&lt;br /&gt;			Return -1&lt;br /&gt;	End Select&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function getDataField(x,y)&lt;br /&gt;	If x&amp;lt;=0 Or x&amp;gt;gridWidth Or y&amp;lt;=0 Or y&amp;gt;gridHeight&lt;br /&gt;		Return 0&lt;br /&gt;	Else&lt;br /&gt;		If Not fieldDone(x,y)&lt;br /&gt;			fieldData(x,y)=getDataPoint(GraphicsWidth()/gridWidth*x,GraphicsHeight()/gridHeight*y)&lt;br /&gt;			fieldDone(x,y)=True&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		Return fieldData(x,y)&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// this function should be overwritten if used elsewhere&lt;br /&gt;Function getDataPoint(x,y)&lt;br /&gt;	Local strength#=0&lt;br /&gt;	&lt;br /&gt;	For m.metaBall=Each MetaBall&lt;br /&gt;		strength=strength+1./((x-m\x)^2+(y-m\y)^2)&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	If strength&amp;gt;threshold&lt;br /&gt;		Return True&lt;br /&gt;	Else&lt;br /&gt;		Return False&lt;br /&gt;	EndIf&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function normalDrawPath(hull.Path)&lt;br /&gt;	Local factorX#=GraphicsWidth()/gridWidth&lt;br /&gt;	Local factorY#=GraphicsHeight()/gridHeight&lt;br /&gt;	&lt;br /&gt;	Local pIter.Point&lt;br /&gt;	Local pMiddle.Point&lt;br /&gt;	Local pLeft.Point&lt;br /&gt;	Local pRight.Point&lt;br /&gt;	&lt;br /&gt;	pIter=hull\pList&lt;br /&gt;	&lt;br /&gt;	Local x1#,y1#&lt;br /&gt;	Local x2#,y2#&lt;br /&gt;	&lt;br /&gt;	pMiddle=pIter&lt;br /&gt;	pLeft=prevPoint(hull,pMiddle)&lt;br /&gt;	pRight=succPoint(hull,pMiddle)&lt;br /&gt;	&lt;br /&gt;	x1=pMiddle\x*0.5+pLeft\x*0.25+pRight\x*0.25&lt;br /&gt;	y1=pMiddle\y*0.5+pLeft\y*0.25+pRight\y*0.25&lt;br /&gt;	&lt;br /&gt;	Repeat ;the points are counter clockwise&lt;br /&gt;		pMiddle=succPoint(hull,pIter)&lt;br /&gt;		pLeft=pIter&lt;br /&gt;		pRight=succPoint(hull,pMiddle)&lt;br /&gt;		&lt;br /&gt;		x2=pMiddle\x*0.5+pLeft\x*0.25+pRight\x*0.25&lt;br /&gt;		y2=pMiddle\y*0.5+pLeft\y*0.25+pRight\y*0.25&lt;br /&gt;		&lt;br /&gt;		Line x1*factorX,y1*factorY,x2*factorX,y2*factorY&lt;br /&gt;		&lt;br /&gt;		pIter=pIter\succ&lt;br /&gt;		&lt;br /&gt;		x1=x2&lt;br /&gt;		y1=y2&lt;br /&gt;	Until pIter=Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function drawPath(hull.Path)&lt;br /&gt;	Local factorX#=GraphicsWidth()/gridWidth&lt;br /&gt;	Local factorY#=GraphicsHeight()/gridHeight&lt;br /&gt;	&lt;br /&gt;	Local pIter.Point&lt;br /&gt;	Local pMiddle.Point&lt;br /&gt;	Local pLeft.Point&lt;br /&gt;	Local pRight.Point&lt;br /&gt;	&lt;br /&gt;	pIter=hull\pList&lt;br /&gt;	&lt;br /&gt;	Local x1#,y1#&lt;br /&gt;	Local x2#,y2#&lt;br /&gt;	&lt;br /&gt;	pMiddle=pIter&lt;br /&gt;	pLeft=prevPoint(hull,pMiddle)&lt;br /&gt;	pRight=succPoint(hull,pMiddle)&lt;br /&gt;	&lt;br /&gt;	x1=pMiddle\x*0.5+pLeft\x*0.25+pRight\x*0.25&lt;br /&gt;	y1=pMiddle\y*0.5+pLeft\y*0.25+pRight\y*0.25&lt;br /&gt;	&lt;br /&gt;	Repeat ;the points are counter clockwise&lt;br /&gt;		pMiddle=succPoint(hull,pIter)&lt;br /&gt;		pLeft=pIter&lt;br /&gt;		pRight=succPoint(hull,pMiddle)&lt;br /&gt;		&lt;br /&gt;		x2=pMiddle\x*0.5+pLeft\x*0.25+pRight\x*0.25&lt;br /&gt;		y2=pMiddle\y*0.5+pLeft\y*0.25+pRight\y*0.25&lt;br /&gt;		&lt;br /&gt;		sBLine x1*factorX,y1*factorY,x2*factorX,y2*factorY&lt;br /&gt;		&lt;br /&gt;		pIter=pIter\succ&lt;br /&gt;		&lt;br /&gt;		x1=x2&lt;br /&gt;		y1=y2&lt;br /&gt;	Until pIter=Null&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function prevPoint.Point(hull.Path,p.Point)&lt;br /&gt;	Local prev.Point&lt;br /&gt;	Local pIter.Point&lt;br /&gt;	&lt;br /&gt;	prev=p\prev&lt;br /&gt;	&lt;br /&gt;	If prev=Null&lt;br /&gt;		pIter=hull\pList&lt;br /&gt;		&lt;br /&gt;		Repeat&lt;br /&gt;			pIter=pIter\succ&lt;br /&gt;		Until pIter\succ=Null&lt;br /&gt;		&lt;br /&gt;		prev=pIter&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return prev&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function succPoint.Point(hull.Path,p.Point)&lt;br /&gt;	Local succ.Point&lt;br /&gt;	Local pIter.Point&lt;br /&gt;	&lt;br /&gt;	succ=p\succ&lt;br /&gt;	&lt;br /&gt;	If succ=Null&lt;br /&gt;		succ=hull\pList&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Return succ&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;Function lRect(x, y, w, h)&lt;br /&gt;	Line x, y, x+w, y&lt;br /&gt;	Line x+w, y, x+w, y+h&lt;br /&gt;	Line x+w, y+h, x, y+h&lt;br /&gt;	Line x, y+h, x, y&lt;br /&gt;End Function&lt;br /&gt;&lt;br /&gt;;// Marching Squares Algorithm&lt;br /&gt;&lt;br /&gt;;/*&lt;br /&gt;; * Test Program&lt;br /&gt;; */&lt;br /&gt;&lt;br /&gt;;SeedRnd(MilliSecs())&lt;br /&gt;&lt;br /&gt;For k=1 To 50&lt;br /&gt;	m.metaBall=New MetaBall&lt;br /&gt;	&lt;br /&gt;	m\x=Rnd(200,500)&lt;br /&gt;	m\y=Rnd(200,400)&lt;br /&gt;	&lt;br /&gt;	m\vx=Rnd(-1.5,1.5)&lt;br /&gt;	m\vy=Rnd(-1.5,1.5)&lt;br /&gt;Next&lt;br /&gt;&lt;br /&gt;Global stopped=False&lt;br /&gt;&lt;br /&gt;timer=CreateTimer(60)&lt;br /&gt;While Not KeyHit(1)&lt;br /&gt;	If MouseHit(2)&lt;br /&gt;		stopped=Not stopped&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	If stopped&lt;br /&gt;		Color 125,125,125&lt;br /&gt;		Text 50,10,&amp;quot;Stopped&amp;quot;&lt;br /&gt;		&lt;br /&gt;		For xn=0 To gridWidth&lt;br /&gt;			For yn=0 To gridHeight&lt;br /&gt;				fieldData(xn,yn)=getDataField(xn,yn)&lt;br /&gt;				If fieldData(xn,yn)&lt;br /&gt;					Rect xn*10,yn*10,10,10&lt;br /&gt;				EndIf&lt;br /&gt;			Next&lt;br /&gt;		Next&lt;br /&gt;	EndIf&lt;br /&gt;	&lt;br /&gt;	Color 255,255,255&lt;br /&gt;	drawMetaBalls()&lt;br /&gt;	&lt;br /&gt;	For m.metaBall=Each MetaBall&lt;br /&gt;		If Not stopped&lt;br /&gt;			m\x=m\x+m\vx&lt;br /&gt;			m\y=m\y+m\vy&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		If m\y&amp;lt;100 Or m\y&amp;gt;500&lt;br /&gt;			m\vy=-m\vy&lt;br /&gt;		EndIf&lt;br /&gt;		If m\x&amp;lt;100 Or m\x&amp;gt;700&lt;br /&gt;			m\vx=-m\vx&lt;br /&gt;		EndIf&lt;br /&gt;		&lt;br /&gt;		WritePixel m\x, m\y, 255*$10000+255*$100+255&lt;br /&gt;	Next&lt;br /&gt;	&lt;br /&gt;	fps=fps+1&lt;br /&gt;	If MilliSecs()-fpsTime&amp;gt;999&lt;br /&gt;		fpsCur=fps&lt;br /&gt;		fpsTime=MilliSecs()&lt;br /&gt;		fps=0&lt;br /&gt;	EndIf&lt;br /&gt;	Text 780,580,fpsCur&lt;br /&gt;	&lt;br /&gt;	Flip 0&lt;br /&gt;	Cls&lt;br /&gt;	WaitTimer(timer)&lt;br /&gt;Wend[/syntax]&lt;br /&gt;&lt;b&gt;Edit:&lt;/b&gt; Ich habe den Vorgang nochmal etwas beschleunigt, fr&amp;uuml;her wurde der Pfad (theoretisch) zweimal berechnet, das geschieht nun direkt. Die Beschleunigung ist zwar eher gering. Ausserdem habe ich einige Versuchswerte von fr&amp;uuml;heren Tests rausgenommen, die noch drin waren. Und die Zeichenfunktion wurde etwas angepasst, damit er die Punkte nicht immer doppelt berechnet. Neu wird auch im Pfad der Ausgangspunkt gespeichert, das sorgt daf&amp;uuml;r, dass ich einen Startpunkt f&amp;uuml;r die F&amp;uuml;llroutine habe, der garantiert innerhalb des geschlossenen Pfades liegt, es sollte nun also nichtmehr zur F&amp;uuml;llung des Bildschirms kommen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ende&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So, das wars mal wieder von mir. Ich bin sicher, ich habe wieder eine Menge von dem vergessen, was ich eigentlich vorstellen oder erw&amp;auml;hnen wollte. Aber daf&amp;uuml;r habe ich ja Zeit in den n&amp;auml;chsten Eintr&amp;auml;gen. Bis dahin werde ich mir &amp;uuml;berlegen, was ich mit meinem Spiel mache, wie ich mein Wasser restrukturieren k&amp;ouml;nnte (das hat immernoch arge Probleme mit W&amp;auml;nden -&amp;gt; es diffundiert), und wie ich es mit geringem Aufwand schaffe, interessante grafische Effekte (Feuer u.&amp;Auml;) zu erzeugen. Man kann sich also zur&amp;uuml;cklehnen und warten.&lt;br /&gt;&lt;br /&gt;Bis zum n&amp;auml;chsten Mal,&lt;br /&gt;MfG,&lt;br /&gt;Darth</description>
			<pubDate>Thu, 22 Apr 2010 21:22:03 +0200</pubDate>
		</item>


	</channel>
</rss>
