Speedoptimierung
Während meiner Bundeswehrzeit konnte ich nur einen vernünftigen Spruch hören:

"Geschwindigkeit ist keine Hexerei".

Ich muss sagen, dieser Spruch ist tatsächlich korrekt. Natürlich kann man schnelle Programme schreiben, wenn die Programmiersprache selbst schnell ist. Nur es gibt einige Sachen, die die Programme nochmals beschleunigen können...


#1 - Sinnloses meiden
Jeder Mensch macht immer nur das was am einfachsten geht. Niemandem würde in den Sinn kommen etwas sinnlosen ständig und immer wieder zu machen. Merkwürdigerweise wird das bei der Programmierung schnell vergessen. So werden ständig irgendwelche Befehle ausgeführt die überhaupt nicht notwendig sind. Darum empfehle ich euch: Setzt viele IF-THEN-Bedingungen und führt nur die Befehle aus die tatsächlich benötigt werden.


#2 - Integer benutzen
BlitzBasic hat drei Variablentypen: Integer, Float und String. Integer ist die schnellste Variante. Float ist wesentlich langsamer. Strings sind am langsamsten.


#3 - Float meiden
Kommt bei Berechnungen ein Wert mit Kommazahl vor, dann wird intern nicht mit Integern gerechnet, sondern mit Floatwerten. Dadurch wird die Berechnung stark verlangsamt.


#4 - Wenig Daten
Reserviere und Benutze möglichst wenig Daten (in Feldern, Types, Banks...). Lade möglichst wenig Multimediadateien (Bilder, Sounds). Wird der Speicher knapp, dann werden einige Daten von Ram auf wesentlich langsamere Festplatte verschoben. Dadurch kann das Programm so langsam werden, dass es unbrauchbar wird.


#5 - Werte merken
Einige Funktionsaufrufe können eingespart werden. So kann man ImageWidth und ImageHeight vor einer Schleife ausführen und die Werte zwischenspeichern:

FOR y=0 to IMAGEHEIGHT(bild)-1
   FOR z=0 to IMAGEWIDTH(bild)-1
      ...
   NEXT
NEXT


das ist schneller:

grx=IMAGEWIDTH(bild)-1
gry=IMAGEHEIGHT(bild)-1
FOR y=0 to gry
   FOR z=0 to grx
      ...
   NEXT
NEXT


#6 - Teilergebnisse
Manche Formeln sind sehr ähnlich. So kann man einen Teil der Formel rausnehmen und separat berechnen. Danach dieses Ergebnis in den anderen Formeln verwenden.


#7 - Vorberechnen
Einige Daten werden ständig gebraucht und berechnet, obwohl das total unnötig ist. Erstelle ein Feld und speichere alle vorberechnete Werte. Dies kann z.B. mit Sqr, Cos und Sin erfolgen:

DIM feld#(359)
FOR i=0 TO 359
   feld#(i)=SIN(i)
NEXT




#8 - Vorberechnen 2
Meistens wird ein Sin- oder Coswert mit einer Zahl multipliziert. Dies kann man in einigen Fällen auch vorberechnen. Zudem kann man in solchen Fällen oft auf die Floatvariable verzichten:

radius=100
DIM feld(359)
FOR i=0 TO 359
   feld(i)=SIN(i)*radius
NEXT


#9 - Berechnungen auslassen
Bei sehr kritischen Berechnungen kann man einige Funktionen auslassen. So z.B. bei Ermittlung von einem Radius:

IF SQR((x1-x2)^2+(y1-y2)^2)=10 THEN...

das ist schneller:

IF (x1-x2)^2+(y1-y2)^2=100 THEN...


#10 - Const
Benutze möglichst Konstanten. Konstanten sind schneller als globale oder lokale Variablen. Da eine Konstante nie geändert wird, weiß BlitzBasic den Wert immer sofort.


#11 - Umschaltung 0/1
Soll ein Wert ständig zwischen 0 und 1 geändert werden, dann ist das die schnellste Möglichkeit:

aus=1-aus

ersetzt das:

IF aus=0 THEN aus=1 ELSE aus=0


#12 - Bit-Operationen
Benutze die Funktionen AND um zu ermitteln, ob ein Bit gesetzt ist. Benutze OR um ein Bit einzuschalten. Benutze XOR um ein Bit zwischen zwei Zuständen umzuschalten. Durch diese Möglichkeiten kann man mehrere Daten in eine Variable packen - dadurch kann die Speicherbelastung enorm gesenkt werden:

auslesen=SGN(wert AND 1)
einschalten=wert OR 1
umschalten=wert XOR 1


#13 - Multitasking
Starte möglichst wenig Programme gleichzeitig. Besonders Programme die im Hintergrund arbeiten können BB verlangsamen.


#14 - Debug
Deaktiviere den Debug-Modus im BB-Editor. Das bringt eine enorme Geschwindigkeitssteigerung.


#15 - Sgn meiden
Sgn ist eine sehr simple Operation. Ersetze es durch eigene (nur bei Integer!):

x=SGN(wert)

das ist schneller:

x=(wert>0)-(wert<0)


#16 - Sgn meiden 2
Sgn liefert Werte -1, 0 und 1. Wie wäre es mit einer spezialisierten Funktion, die dadurch noch schneller ist:

x=SGN(wert)

das liefert nur 0 oder 1:

x=(wert>0)

das liefert nur 0 oder -1:

x=-(wert<0)


#17 - Zählungen
Bei ständigen konstanten Zählungen zwischen zwei Werten, kann man If-Then-Bedingungen durch schnellere Mod ersetzten (nur bei Integer!):

win=win+1
IF win=360 THEN win=0


das ist schneller:

win=(win+1) MOD 360


#18 - Schleifen meiden
Die Schleifen sind etwas langsam, deshalb sollte man auf die möglichst ganz verzichten (wie man sieht ist kürzerer Code nicht immer schneller!):

FOR i=1 TO 3
   IF spieler(i)=1 THEN ...
NEXT


diese Zeilen sind schneller:

IF spieler(1)=1 THEN ...
IF spieler(2)=1 THEN ...
IF spieler(3)=1 THEN ...


#19 - Schleifensprung
Manchmal sind Schleifen unumgänglich. Darum kann man manchmal mit einem Schleifensprung mehr erreichen:

FOR i=1 TO 100
   blub(i)=1
NEXT


diese Zeilen sind schneller:

FOR i=1 TO 100 STEP 2
   blub(i)=1
   blub(i+1)=1
NEXT


#20 - DIM
Nach Möglichkeit sollen statt Type-Felder normale Dim-Felder benutzt werden. Die einfachen Felder sind 100% schneller - zudem kann ein Zugriff sofort erfolgen - dies bringt nochmals mehr Speed.


#21 - Bedingungen
Die If-Then-Bedingungen können manchmal zusammengefasst werden. Dies beschleunigt das Programm leicht:

IF x=1 THEN
   IF y=1 THEN
      ...
   ENDIF
ENDIF


das ist schneller:

IF x=1 AND y=1 THEN ...


#22 - Bedingungen vereinfachen
Manchmal lassen sich die If-Then-Bedingungen vereinfachen. Dies kann so erfolgen:

IF x=1 and y=1 THEN...

das ist schneller:

IF x+y=2 THEN...


#23 - Bedingungen weglassen
Manchmal lassen sich die If-Then-Bedingungen entfernen. Dies kann so erfolgen:

IF x=>100 THEN dummy=1

das ist schneller:

dummy=(x=>100)


#24 - Select statt If
Bei vielen sehr einfachen Bedingungen genügt Select-Case-Konstruktion. Dies bringt auch mehr Geschwindigkeit.

IF x=1 THEN
ELSEIF x=2 THEN...
ELSEIF x=3 THEN...
ENDIF


das ist schneller:

SELECT x
CASE 1
CASE 2
CASE 3
END SELECT


#25 - Gosub statt Function
Der Befehl Gosub ist wesentlich schneller als Function. Der Unterschied ist sogar sehr gewaltig. Darum nehmt besser Gosub. Dies kann aber oft zu unübersichtlichen Programmen führen.


#26 - Programmsprung
Vermeide Programmsprünge mit Goto, Gosub und Function. Je weniger, desto besser lautet hier die Devise. Dadurch kann aber die Größe des Quellcodes steigen.


#27 - Daten laden
Vielfach ist es notwendig irgendwelche Daten zu laden. Manchmal kann man es sehr einfach und schnell mit den Banks erledigen. Benutzt dazu einfach CreateBank und ReadBytes. Speichern geht auch, mit WriteBytes.


#28 - Grafik meiden
Die Grafik ist der Speedkiller Nummer 1. Während simple Berechnungen einem PC nur ein müdes lächeln zaubern, kann eine komplexe Grafik einen PC in die Knie zwingen. Zeichnet darum nur das ein, was auch geändert werden muss. Es muss nicht der komplette Bildschirmbereich sein - schon einige Teilbereiche zu aktualisieren kann Wunder wirken.


#29 - Farbtiefe
Die benutzte Farbtiefe hat enorme Einflüsse auf die Programmgeschwindigkeit. Bei 16 Bit Farbtiefe erreichen Programm die maximale Geschwindigkeit. 24 Bit sind langsamer. Bei 32 Bit ist die Grafik am langsamsten.


#30 - Auflösung
Je größer die Auflösung, desto langsamer erfolgt die Grafikausgabe. Das kommt daher, weil die Grafikkarte wesentlich mehr Daten schaufeln muss. Meine Empfehlung liegt bei 640x480. Zur Not geht 800x600 auch noch.


#31 - Vollbild
Starte dein Programm im Vollbild. Wenn ein Programm im Fenster läuft, dann übernimmt Windows eigenständig die Aktualisierung des Fensters. Laut FPS-Counter sieht es sogar schneller aus - in Wirklichkeit wird das Bild aber wesentlich seltener aktualisiert.


#32 - Pixelbild aus Dim
Nehmen wir mal an, du benutzt ReadPixelFast um die Farbe aus einem Image zu lesen und WritePixelFast um es dann einzuzeichnen. Dies kann mit spezieller Technik beschleunigt werden. Lese das Bild aus einem Image in ein Dim-Feld Pixel für Pixel mit ReadPixelFast ein. Nun kannst du die Daten ganz einfach ohne irgendwelche Befehle direkt auslesen und mit WritePixelFast einzeichnen.

Beachte, dass das Bild danach aus dem Video-Ram mit FreeImage gelöscht werden soll. Ein Dim-Feld wird dagegen im langsameren Ram-Speicher gespeichert - trotzdem ist diese Methode wesentlich schneller.


#33 - Line beschleunigen
Line funktioniert nur sehr langsam. Mit einem Trick kann es beschleunigt werden. Wendet den Befehl LOCKBUFFER bei vielen Linien an. LOCKBUFFER funktioniert ausnahmsweise zusätzlich noch mit Line. Dies bring etwa 10% mehr Speed - allerdings kann Line danach nicht außerhalb des Bildschirms erscheinen.


#34 - Rect statt Line
Sollen einfache waagerechte oder senkrechte Linien gezeichnet werden? Dann benutzt besser Rect statt Line. Dies bring enorm viel Speed (über 2000%). Das liegt daran, dass Rect besonders einfache Routinen enthält und von Grafikkarte maximal beschleunigt wird.


#35 - Rect beschleunigen
Rect ist schnell. Aber es kann noch schneller gemacht werden. Dies funktioniert nur bei einer Linienbreite von einem bis zwei Pixel. Dazu setzt den Parameter Füllen auf 1 (=Standard).


#36 - Plot meiden
Plot ist sehr langsam. Es gibt deshalb einen speziellen Pixelbefehl: WritePixel. WritePixel ist wesentlich schneller. Es hat nur einen Hacken: Die Farbe muss manuell berechnet werden. Bei einer großen einfarbigen Fläche bring das den meisten Geschwindigkeitsschub. Ach ja, erscheint die Grafik nicht außerhalb des Bildschirmbereichs, dann kann auch WritePixelFast benutzt werden - es ist das schnellste überhaupt.


#37 - GetColor meiden
Mit ReadPixel kann man den GetColor-Befehl nahezu ersetzen. Das bringt etwas mehr Geschwindigkeit. Die Farbanteile müssen dann aber manuell errechnet werden. Noch schneller ist ReadPixelFast - allerdings darf es nicht außerhalb des Bildschirms angewendet werden.


#38 - CopyPixel
Sollen nur Pixelfarben kopiert werden? Dann kann CopyPixel das Programm beschleunigen. CopyPixelFast ist sogar noch schneller - allerdings darf es nicht außerhalb des Bildschirms angewendet werden.


#39 - Images
Unterlasse die Erstellung und Löschung von Images. Durch diese Grafikbefehle wird ständig Speicher reserviert/freigegeben - dies kostet Geschwindigkeit. Besser am Anfang Images erstellen und am Ende löschen.


#40 - Löschen meiden
Benutzt du ein bildschirmfüllendes Hintergrundbild? Dann kann Cls ganz entfallen. Zeichne das Bild dann aber mit DrawBlock.


#41 - CopyRect
Mit CopyRect kann man einen Bildbereich gleichzeitig kopieren und einzeichnen. Dies ist wesentlich schneller als GrabImage und DrawBlock.


#42 - Bilder zeichnen
Bilder sollen vorzugsweise mit DrawImage gezeichnet werden. Im Vergleich zu DrawBlock wird eine bestimmte Farbe erst gar nicht eingezeichnet - dies entlastet die Grafikkarte. Allerdings kann dieser Befehl selten so eingesetzt werden - meistens bei einfarbigen Hintergründen und mit Verwendung von Cls.


#43 - Kollision
Die Kollision wird meist für einige Sachen missbraucht, für die es gar nicht gedacht ist. So wird es oft für Menüs genommen. Meine Empfehlung: Versucht eine Möglichkeit zu finden es ohne die Kollision hinzukriegen. Dies kann schon mit einfacher Prüfung der Koordinate erledigt werden. Auch Prüfungen, ob man einen Rechteck, einen Kreis oder eine Ellipse angeklickt hat sind schon mit simplen Berechnungen möglich.

Rechteck:
IF x=>x1 AND y=>y1 AND x<=x2 AND y<=y2 THEN...

Kreis:
IF SQR((x-mittex)^2+(y-mittey)^2)>=radius THEN...

Ellipse (radiusy=radiusx/2):
IF SQR((x-mittex)^2+((y-mittey)*2)^2)>=radius THEN...


Eine Kreis-/Ellipsenberechnung kann auch vereinfacht für Sechsecke benutzt werden, die "Fehlerquote" ist nur minimal...

Beachtet auch, dass die Kollisionsprüfung sehr langsam sein kann. Hier die Sortierung nach Geschwindigkeit:

-RectsOverlap
-ImageRectOverlap
-ImagesOverlap
-ImageRectCollide
-ImagesCollide


#44 - Bildergröße ändern
Die Größe der Bilder zu ändern ist ein sehr langsames Verfahren. Nach Möglichkeit sollte deshalb TFormFilter deaktiviert werden. Dadurch wird ein bi-linearer Filter ausgeschaltet.

Es gibt Möglichkeiten ein Bild manuell zu vergrößern/verkleinern. Das schnellste Verfahren: Das Bild wird über zwei Berechnungsstufen in der Größe geändert. Zuerst wird die X-Achse gestreckt/gestaucht, danach wird die Y-Achse gestreckt/gestaucht. Die Berechnung erfolgt in FOR-NEXT-Schleifen. Das Bild wird mit CopyRect ausgeschnitten und sofort kopiert. Prinzipbeispiel:

GRAPHICS 640,480,0,2
OVAL 50,50,540,380,1
verkleinern 100,50
WAITKEY()
END

FUNCTION verkleinern(grx,gry)
   FOR x=0 TO grx
      x2=x*(640/grx)
      COPYRECT x2,0,1,480,x,0
   NEXT
   FOR y=0 TO gry
      y2=y*(480/gry)
      COPYRECT 0,y2,grx,1,0,y
   NEXT
   COLOR 0,0,0
   RECT grx,0,640-grx,480,1
   RECT 0,gry,grx,480-gry,1
END FUNCTION


#45 - Bilder drehen
Das Drehen eines Bildes ist sehr zeitaufwendig. Die Deaktivierung von TFormFilter kann es etwas beschleunigen. Empfehlenswert ist eine Vorberechnung am Anfang des Programms.


#46 - Grafiken vorberechnen
Nach Möglichkeit sollen Grafiken nicht während des Spiels berechnet werden. Erstelle ein Image und zeichne dorthin das Bild ein. Nun braucht man nur dieses eine Bild mit nur einem Grafikbefehl einzuzeichnen - das bringt wesentlich mehr Geschwindigkeit. Natürlich sollte das bei komplexeren Bildern verwendet werden.