Dynamisches auslesen von Bildern (mit INI Dateien)
Übersicht

![]() |
M0rgensternBetreff: Dynamisches auslesen von Bildern (mit INI Dateien) |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo Leute.
Ich hab mich heute mal dazu durchgerungen mein erstes Tutorial zu schreiben. Die Vorraussetzungen die man mitbringen sollte: Man sollte einigermaßen mit dem schreiben und lesen von Dateien umgehen können und somit auch Befehle wie Readline ![]() ![]() Aber alles in allem versuche ich das Tutorial so zu schreiben, dass auch Neulinge gut damit klar kommen, vor allem die Types werde ich ausführlich behandeln, da es nur einer ist. Zu erstmal: Worum gehts? Ich weiß, dass der Titel wohl zuersteinmal verwirrend wirkt. Also hier erstmal eine Erklärung: Ich hab neulich mal drüber nachgedacht, wie folgendes zu realisieren wäre: Wenn man ein Spiel programmiert und dem Spieler die Möglichkeit geben will selbst Objekte hinzuzufügen oder es sich selbst einfach machen will, ohne jede Grafik einzeln laden zu müssen. Im vorraus einfach mal zig TImage Instanzen zu deklarieren fand ich zu undynamisch. Also hab ich mir folgendes überlegt: Die Bilder werden nach einem bestimmten Schema benannt. Danach kann man den Namen auseinandernehmen und entsprechend in einer INI Datei speichern. Dann kann man das ganze schon ganz schön auslesen. Zusätzlich hab ich noch einen kleinen Type zur Bildverwaltung geschrieben, damit man alle Informationen auf einmal hat. Das Tutorial ist aufgespalten in 3 Teile. Da die Bilder, und in diesem Fall auch der Type der sie hier verwaltet, grundlegend sind werden wir heute damit anfangen. In den nächsten Tagen wird folgen: 2. Teil: Bilderordner durchsuchen, die Namen auseinanderschneiden und alle Infos in einer INI Datei speichern. 3. Teil: Die INI Datei auslesen und entsprechend die Bilder laden Also, los gehts mit Teil 1: Die Bilddateien und der zugehörige Type Zuerst sollte man sich für die Bilddateien eine anständige und einheitliche Notation überlegen, die man genau so bei allen Bildern die man so bearbeiten möchte nutzt. Ich hab folgende Notation gewählt: Bildname ! BreiteProFrame x HöheproFrame % FrameAnzahl & AnimationsTimer . png Die Leerzeichen hab ich nur zur Verdeutlichung eingefügt. Kleine Erklärung: BreiteProFrame, Höheproframe, FrameAnzahl und Animationstimer sind einfach Zahlen. BreiteProFrame gibt die Breite eines einzelnen Frames in Pixeln an. HöheProFrame gibt die Höhe eines einzelnen Frames in Pixeln an. FrameAnzahl gibt die Gesamtzahl aller Frames im Bild an. Animationstimer gibt die Zeit in Millisekunden zwischen zwei Frames an. Als konkretes Beispiel hier mal zwei Namen meiner Bilddateien: Bild1: Zitat: bullet!16x16%4&200.png
Bild2: Zitat: kleinerGrabstein_grau!32x32%0&0.png
Wie ihr sehen könnt hat Bild1 folgende Eigenschaften: Bildname = bullet BreiteProFrame = 16 HöheProFrame = 16 FrameAnzahl = 4 Animationstimer = 200 Und Bild2 hat folgende Eigenschaften: Bildname = kleinerGrabstein_grau BreiteProFrame = 32 HöheProFrame = 32 FrameAnzahl = 0 (Also, es ist ein Einzelbild und somit keine Animation vorhanden) Animationstimer = 0 (Da es hier kein Animationsbild ist, ist das ja nur logisch) Damit wäre der Aufbau der Dateien geklärt. Jetzt folgt der zugehörige Type. Bevor wir einen neuen Type anlegen, müssen wir uns im klaren darüber sein, welche Attribute (Felder) er haben muss. Also, erstmal brauchen wir eine Liste in der alle Einträge gespeichert werden. Dann brauchen wir eine Variable in der das Bild gespeichert werden kann (Timage). Zusätzlich brauchen wir für jede Information aus den Bildern noch eine Variable, also: Maximale Frameanzahl, der Name, der Pfad, Breite eines Einzelbildes, Höhe eines Einzelbildes und die Animationszeit. Zusätzlich brauchen wir noch eine Variable die aussagt welcher Frame im Moment angezeigt wird und eine die uns sagt wann die letzte Animation stattgefunden hat. Daraus ergiebt sich erstmal folgender Type: BlitzMax: [AUSKLAPPEN] Type TMyMainIMage Dann brauchen wir einen sogenannten Konstruktor, der uns eine neue Typeinstanz erstellt. Diesem Konstruktor müssen wir die wichtigsten Dinge übergeben. Er muss den Pfad kennen, aus dem das Bild geladen wird. Im Prinzip müssen wir dem Konstruktor alles übergeben, was wir aus der Bilddatei auslesen können. Daraus ergiebt sich folgende Grundstruktur: BlitzMax: [AUSKLAPPEN] Function Create:TMyMainImage(pPath:String, pMaxFrames:Int = 0, pCellWidth:Float = 0, pCellHeight:Float = 0, PTimer:Int = 0, pName:String = "") Das ganze muss noch erweitert werden, so dass Werte zugewiesen werden. Damit komment wie auf folgende Funktion: BlitzMax: [AUSKLAPPEN]
So, kleine Zwischenbilanz. Was kenne wir nun? Den Aufbau der Bilddateien. UNd die Grundlagen des Verwaltungstypes. Wir haben aber noch keine Möglichkeit die Typeinstanzen in die Liste zu bekommen, bzw sie da wieder raus zu bekommen. Dazu gibt es zwei Funktionen. Die erste heißt BlitzMax: [AUSKLAPPEN] New
Und vielleicht fällt euch auf, dass sie in der ersten Zeile unseres Konstruktors steckt: BlitzMax: [AUSKLAPPEN] Local MyIMage:TMyMainImage = New TMyMainImage Nun brauchen wir noch die Funktion dazu, welche wie folgt aussieht: BlitzMax: [AUSKLAPPEN] Method New() Die Instanz die wir im Konstruktor erstellt haben, wird hier in die Liste eingefügt. Schön und gut, aber, wie bekommen wir sie da wieder raus, wenn die INstanz vielleicht nicht mehr benötigt wird? Ganz einfach, mit einem Destruktor: BlitzMax: [AUSKLAPPEN] Method Destroy() Dieser entfernt den zugehörigen Listeneintrag einfach. Aufgerufen wird der Destruktor wie folgt: BlitzMax: [AUSKLAPPEN] Global MeinBild:TMyMainImage = TMyMainImage.Create(hier die Parameter) Kleiner Zwischenstopp um den bisherigen Type anzuschauen: BlitzMax: [AUSKLAPPEN] Type TMyMainIMage Weiter gehts. "Von Hand" animieren ist out. Das kann der Type schön selbst machen. Also, hier der Code, die Beschreibung gibts als Kommentar: BlitzMax: [AUSKLAPPEN] Method Animate() Natürlich ist es auch ab und zu nötig ein Bild manuell zu animieren. Also, wenn man zum Beispiel eine Animation nur bei einem bestimmten Ereigniss wünscht. Dann ist die Animationszeit nicht relevant und fällt somit weg. Was noch übrig bleibt ist folgende Funktion, welche wie ich denke selbsterklärend ist: BlitzMax: [AUSKLAPPEN] Method AnimateManual() Unser Type sieht also nun so aus: BlitzMax: [AUSKLAPPEN] Type TMyMainIMage Aus persönlichen Gründen hab ich noch eine Methode gebraucht, die mir alle Frames nebeneinander aufgereiht anzeigt. Da diese Methode aber nicht für dieses Thema relevant ist werde ich sie nicht weiter kommentieren und einfach nur einfügen: BlitzMax: [AUSKLAPPEN] Method DrawAllFramesInARow(px:Int, py:Int) Somit sieht unser Type endgültig so aus: BlitzMax: [AUSKLAPPEN] Type TMyMainIMage Uff... Wenn ihr bis hier her gelant seit: Grautlation. Ihr habt den ersten Teil schadlos (hoffe ich doch) überstanden. Teil 2 und 3 folgen in den nächsten Tagen. Bis dahin wäre ich über Kritik oder Kommentare wirklich sehr froh, da ich sicher bin, dass ich einiges verbessern könnte (leider weiß ich selbst nicht was). UNd das möchte ich dann auch tun. Es soll ja schließlich helfen. Liebe Grüße, M0rgenstern. |
||
![]() |
M0rgensternBetreff: Teil2 |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo Leute.
Heute gehts dann weiter mit: 2. Teil: Bilderordner durchsuchen, die Namen auseinanderschneiden und alle Infos in einer INI Datei speichern. Im ersten Teil haben wir alle vorbereitungen getroffen, eine bestimmte auslesbare Bilddatei zu erstellen. Heute geht es dann damit weiter diese Dateien auch auszulesen und schön sortiert in eienr Datai zu speichern. Los gehts: Zuersteinmal brauchen wir eine Funktion, die in einem bestimmten Ordner nach allen Dateien sucht und diese dann temporär speichert. Später wird diese FUnktion auch die INI Datei schreiben, aber wir gehen wieder schrittweise vor. Zuersteinmal deklarieren wir wieder einige benötigte Variablen. Wir brauchen den Ordnerpfad in dem die Bilder stecken (als relativer Pfad), eine Variable für das ausgelesene Verzeichnis, eine Variable für die Datei die momentan gelesen wird, ein Array in dem alle relevanten Bilddateien gespeichert werden und eine Variable die die Größe des Arrays angiebt. Somit sieht unsere Funktion anfangs so aus: BlitzMax: [AUSKLAPPEN] Function GetObjectImages() Nun gehen wir erst einmal durch das Verzeichnis und zählen wie viele relevante Dateien überhaupt in diesem Verzeichnis liegen. Die Erklärung gibts hier anhand von Kommentaren: BlitzMax: [AUSKLAPPEN] iDir = ReadDir(spath) 'Wir öffnen den angegebenen Pfad zum auslesen der Dateien Somit sieht unsere Funktion nun so aus: BlitzMax: [AUSKLAPPEN] Function GetObjectImages() Jetzt wiederholen wir das ganze, nur mit dem Unterschied, dass wir alle relevanten Dateien in einem Array speichern. Dazu geben wir unserem vorher deklarierten Array erstmal seine Größe mit: BlitzMax: [AUSKLAPPEN] sAllFiles = New String[iAmount] 'Ein neues Stringarray mit einer bestimmten Größe erstellen Und nun folgt fast die gleiche Schleife wie vorher. Ich werde nur noch die neuen Teile kommentieren: BlitzMax: [AUSKLAPPEN] iDir = ReadDir(sPath) Unsere Funktion sieht jetzt folgendermaßen aus: BlitzMax: [AUSKLAPPEN] Function GetObjectImages() Nun, das ist wieder ein gutes Stück gewesen. Kleine Zwischenbilanz. Was haben wir bis jetzt? 1. Bilddateien die in einem bestimmten Muster benannt sind 2. Einen Type der unsere Bilder verwalten kann 3. Wir haben schonmal alle gültigen Bilddateien ausgelsen und die Namen in einem Array gespeichert. Jetzt folgt das Auseinanderschneiden der Dateinamen und das Speichern. Das Problem ist, dass hier beides immer pro Datei einmal passiert. Wie schneiden sie auseinander und speichern das direkt ab um dann die nächste Datei in Bearbeitung zu nehmen. Also gibts jetzt erstmal ein paar Hilfsfunktionen, die uns die Dateien entsprechen schneiden. Zuerst die einfachste und kürzeste Funktion dieser drei Funktionen: Wie bekommen wir den Namen des Bildes? (Ihr erinnert euch: Alles was vor dem ! steht.) BlitzMax: [AUSKLAPPEN] Function GetNameFromImage:String(pImageFile:String, pName:String Var) Kleine Erklärung zu der Function: GetNameFromImage:STRING bedeutet, dass diese Funktion einen String zurückliefert. pImageFile:String ist der komplette Name der Bilddatei den man der Funktion übergiebt. Und pName ist kein eigentlicher Parameter, sondern ein Rückgabewert. Das erkennt man, daran, dass dahinter noch ein Var steht. Durch solche Parameter kann man der Funktion sagen, welche Variablen sie zurückgeben soll. Warum braucht man sowas? Nun, normalerweise können wir der Funktion mit Return sagen, welche Werte sie zurückgeben soll. Mit Return kann man aber nur jeweils einen Wert zurückgeben. Ihr werdet gleich sehen, dass wir zwei Funktionen dieser Art haben, die zwei Parameter zurückgeben müssen. Dann hilft uns Return nicht weiter. Man gibt der Funktion also beim Aufruf eine vorher deklarierte Variable mit. Nach dem Aufruf der Funktion hat die Variable dann den Wert der ihr in der Funktion zugeteilt wurde (Später nochmal im Code zu sehen). Nun die Funktion, die uns die Höhe und Breite des Bildes leifert: BlitzMax: [AUSKLAPPEN] Function GetSizeFromImage:String(pImageFile:String, pWidth:String Var, pHeight:String Var) Wie ihr sehen könnt hat diese Funktion sogar zwei Rückgabewerte: pWidth und pHeight Logisch, sie gibt ja auch die Breite UND die Höhe zurück. Und zu guter letzt die Funktion, die uns die Frameanzahl und die Animationszeit ausgiebt. Dazu brauche ich eigentlich nichts mehr zu sagen, da sie genauso wie die vorhergegangene Funktion funktioniert, nur dass nach anderen Anhaltspunkten gesucht wird: BlitzMax: [AUSKLAPPEN] Function GetFramesFromImage:String(pImageFile:String, pFrames:String Var, pTimer:String Var) Jetzt haben wir die Funktionen die und die Dateiinfos aus den Dateinamen geben. Nun müssen wir alles zusammen speichern. Dazu machen wir in unsere Funktion vom Anfang weiter, also in Zitat: GetObjectImages()
Zuersteinmal legen wir eine neue INI Datei an. Das geht so (dabei bitte darauf achten, dass alle angegebenen Ordner im Pfad vorhanden sind. Gegebenenfalls bitte abändern): BlitzMax: [AUSKLAPPEN] Local sIniPath:String = "Bin\Objects.ini" 'Der Pfad Dann müssen wir uns erstmal im Klaren sein wie unsere INI datei aussehen soll. Ich habe folgende Anordnung gewählt: Zitat: [Global]
Anzahl = (Variable) Namen der Bilder.... [Bildname1] Pfad = (Pfad) Breite = (Breite) Höhe = (Höhe) Frames = (Frames) Zeit = (Time) [Bildname2] . . . Ich denke, der Aufbau sollte damit klar sein. Jetzt schreiben wir erstmal unsere Sektion, also das in den Eckigen Klammern und die Anzahl, sowie alle Bildnamen in die INI Datei. Also: BlitzMax: [AUSKLAPPEN] WriteLine(sIniFile, "[Global]") 'Die Sektion schreiben Und jetzt folgt der ganze Rest der in die Datei gehört. Das sieht dann so aus: BlitzMax: [AUSKLAPPEN] For Local i:Int = 0 Until iAmount 'Für alle Bilder im Array Und zum schluss schließen wir die Datei wieder: BlitzMax: [AUSKLAPPEN] CloseStream(sIniFile)
Unsere Funktion sieht jetzt folgendermaßen aus: BlitzMax: [AUSKLAPPEN] Function GetObjectImages() Sooo... Jetzt wieder eine Zusammenfassung: Wir haben die Bilder die wir benötigen entsprechend genannt. Wir haben unseren Verwaltungstype. Wir haben Funktionen die uns ganz spezielle Infos aus dem Dateinamen herausfiltern. Und wir haben Die Funktion, die uns alles in einer INI Datei speichert. In Teil 3 werden wir dann noch eine Funktion schreiben, die uns die INI Datei ausliest und entsprechende Bilder in den Speicher läd. Lg, M0rgenstern |
||
- Zuletzt bearbeitet von M0rgenstern am Sa, Sep 04, 2010 12:24, insgesamt 2-mal bearbeitet
![]() |
M0rgensternBetreff: Teil 3 |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo an alle.
Heute kommen wir endgültig zum 3. und letzten Teil des Tutorials. 3. Teil: Die INI Datei auslesen und entsprechend die Bilder laden Zuerst benötigen wir einen INI Parser. Meinen habe ich mir nach dem Lesen von Midimasters Tutorial zusammengebastelt und stelle ihn jetzt hier einfach als festen Code ein. Wer mehr über INI Parser wissen will, den verweise ich auf Midimasters Tutorial: https://www.blitzforum.de/foru...hp?t=33651 Hier der Parser: BlitzMax: [AUSKLAPPEN]
So, weiter gehts. Wir brauchen eine Funktion die unsere INI Datei automatisch ausließt. Hört sich vielleicht ein wenig komplizierter an als es ist. Die komplette Funktion sieht so aus: BlitzMax: [AUSKLAPPEN] Function MakeImagesFromIni() So. Das wars auch schon. Ich hab natürlich noch ein Anwendungsbeispiel: BlitzMax: [AUSKLAPPEN] Import brl.timer Und nochmal: Ihr müsst natürlich im Code die richtigen Ordner angeben, sonst funktioniert das nicht. So. Ich hoffe dass das Tutorial irgendjemandem hilft. Und bitte: Wenn ihrs lest, dann gebt mit hier in dem Thread bitte ne Rückmeldung. Was ihr gut fandet, oder was scheiße war. Würd mir echt viel helfen. Lg, M0rgenstern |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group