Bild kann nicht geladen werden?

Übersicht BlitzBasic Beginners-Corner

Neue Antwort erstellen

 

Snowdragon

Betreff: Bild kann nicht geladen werden?

BeitragSa, Aug 23, 2014 21:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

vorab will ich mich für die sperrlichen Informationen entschuldigen. Mein Code ist mitlerweile recht umfangreich (es geht um ein Kartenspiel) und an jeder möglichen Stelle werden der Hintergrund, alle Karten usw. geladen (wenn ich z.B. in ein anderes "Unterprogramm springe, so müssen ja die Bilder erneut geladen werden).

An sich funktioniert alles, doch wenn ich länger Spiele taucht ab und an
an verschiedenen Stellen eine Fehlermeldung auf - das Bild kann nicht geladen
werden.

Liegt es daran, dass ich nicht mit FreeImage arbeite und der Speicher irgendwann volläuft?

DAK

BeitragSa, Aug 23, 2014 21:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Ok, als Erstes: du solltest Bilder nicht unnötig neu laden. Wenn du in ein "Unterprogramm springst" (ich nehme an, du redest von Funktionen?), dann sollst du Bilder auch nicht neuladen, sondern Dims oder globale Variablen für die Bilder verwenden, da sie eben global, also von überal zugreifbar sind.

Wenn du den Speicher dauerhaft vollmüllst und nie leerst, dann ist es ja wohl keine Hexerei, dass da bald nix mehr rein geht, oder?

Blitz speichert Bilder natürlich unkomprimiert im RAM. Das heißt, jedes Pixel verbraucht 3 Bytes. Ein 500x500-Pixel-Bild kommt also auf 750 KB. Wenn du so ein Bild jedes Frame neu lädst, dann schaft dein Programm gerade mal runde 100 Sekunden, bis es bei 60 FPS die 4-GB-Grenze knackt, die ein 32-Bit-Programm zur Verfügung hat.


Also:
1) FreeImage ist nicht etwas, mit dem man optional arbeiten kann oder nicht, sondern absolute Pflicht. Alles, was nicht unbedingt bis zum Ende des Programms benötigt wird, muss geFreed werden!
2) Bilder oder andere Ressourcen in einer Schleife laden ist ganz ganz böse! Macht dein Programm ewig lahm und bringt dir den Speichertod.
3) Um Variablen des Hauptprogramms in Funktionen nützen zu können, verwende globale Variablen oder Dims.
Gewinner der 6. und der 68. BlitzCodeCompo

Xeres

Moderator

BeitragSa, Aug 23, 2014 23:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Man braucht FreeImage nur dann, wenn man aus irgendeinem Grund Bilder erzeugt/lädt und dann nicht weiter benutzt. Üblicherweise lädt man aber alle Ressourcen für's Spiel und ändert die dann nicht mehr - der Speicher wird dann beim beenden automatisch frei gegeben.
Variablen enthalten das handle zu einem Bild, nicht das Bild selbst. D.h. du kannst das selbe Bild in mehreren Variablen haben. Wenn du aber die einzige Variable überschreibst, kannst du nicht mehr auf das Bild zugreifen und es auch nicht mehr durch FreeImage löschen.

Wenn du noch Fragen hast, poste die passende Abschnitte aus dem Code. Dann kann man dir sagen, ob und wie sinnvoll die sind.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
 

Snowdragon

BeitragSo, Aug 24, 2014 16:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay danke euch beiden. Ich verwende dann lieber mal Arrays (hab nicht daran gedacht ... hehe ) und teste dann wieder alles ausführlich.

Und das mit Ressourcen in einer Schleife laden ist mir auch schon aufgefallen und habe es deshalb immer unterbunden. Muss also wirklich damit zusammenhängen, dass ich den Speicher komplett vollgemült habe.
 

Sirrus

BeitragMo, Aug 25, 2014 11:17
Antworten mit Zitat
Benutzer-Profile anzeigen
Es ist auch sinnvoll, nicht alle Karten einzeln als Bilder abzuspeichern, sondern die Karten alle zusammen auf einem Bild unterzubringen. Von dort aus kannst du die dann mit DrawImageRect auf die jeweils angezeigten Karten kopieren. Das würde dir dann auch ermöglichen mit relativ wenig Aufwand verschiedene Kartensätze für dein Programm bereit zu stellen.
z.B.
Code: [AUSKLAPPEN]
Global Kartensatz ;Imagehandel des Kartensatz
Function LadeKartensatz(Dateiname$)
    ;Falls ein Kartensatz bereits geladen ist
    If Kartensatz<>0 Then Freeimage Kartensatz
    ;neuen Kartensatz laden
    Kartensatz=LoadImage(Dateiname)
    ;True zurückgeben wenn erfolgreich geladen
    Return (Kartensatz<>0)
End Function

DAK

BeitragMo, Aug 25, 2014 11:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Da die Karten wohl alle gleich groß sind, könntest du auch AnimImage verwenden, da du dort nur beim Laden die Größen der einzelnen Karten angeben musst, und dann bei DrawAnimImage nur noch die Nummer der Karte angeben musst.
Gewinner der 6. und der 68. BlitzCodeCompo
 

funkmaster5000

BeitragDi, Aug 26, 2014 17:58
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich definiere meine Bilder immer als Global und kann sie so in den Functions benutzen. Generell besteht deine Hauptschleife ja aus mehreren Funktionsaufrufen. Ich lasse meine Bilder deswegen in einer Funktion darstellen, genauso wie die Eingaben des Spielers.

Also z. B.

Code: [AUSKLAPPEN]
Global card% = LoadImage("gfx\image.bmp")

While Not KeyHit(1)
   Cls
   DrawCards()
        PlayerInput()
   Flip
Wend

EndGraphics
End

Function DrawCards()
   DrawImage card,0,0
End Function

Function PlayerInput()
   If KeyDown(200) Then
      ....
   End If
End Function

TimBo

BeitragFr, Aug 29, 2014 14:07
Antworten mit Zitat
Benutzer-Profile anzeigen
du könntest dir auch eine Art Garbage Collector bauen, indem du trackst, zu welchem Zeitpunkt die Grafik das letzte mal gezeichnet worden ist. Wenn ein gewisser Zeitpunkt überschritten ist, dann wird die Grafik aus dem Speicher automatisch gelöscht.


Beispielsweise würde sich da eine Liste anbieten, bei der du jeden Frame 10 Einträge überprüfst und wenn ein Bild gezeichnet worden ist in einem Zeitintervall, dann schiebste das Element wieder ganz ans Ende.

Natürlich musst du beim Malen prüfen, ob das Bild noch geladen ist. Hier würde sich ein HashSet anbieten. Das müsstest du dir aber auch selbst basteln. Oder du nimmst dafür einfach global und setzt es auf true oder false, jenachdem ob das Bild noch geladen ist oder auch nicht.

Idee :

DrawImage ( getImage ("NameDesBildes") , x , y)

getImage schaut in dem Hashset (oder bei der global nach), ob das Bild geladen ist


deinen Collector lässt du einfach durchlaufen.


Ich weiß nicht, wie komplex dein Projekt und deine Motivation bzw. deine Kenntnisse sind. Den Aufwand würde ich nur machen, wenn ich mir sicher wäre, dass er unumgänglich ist.

Grüße
TimBo
mfg Tim Borowski // CPU: Ryzen 2700x GPU: Nvidia RTX 2070 OC (Gigabyte) Ram: 16GB DDR4 @ 3000MHz OS: Windows 10
Stolzer Gewinner des BCC 25 & BCC 31
hat einen ersten Preis in der 1. Runde beim BWInf 2010/2011 & 2011/12 mit BlitzBasic erreicht.

DAK

BeitragFr, Aug 29, 2014 14:30
Antworten mit Zitat
Benutzer-Profile anzeigen
@Timbo: Das ist dann aber schon wirklich was Höheres und macht in dem Fall wohl keinen Sinn. Das braucht man erst, wenn man wirklich annähernd 4 GB an Bildern hat. Hier wird es wohl reichen, wenn nur die Bilder alle je nur ein Mal geladen werden.
Gewinner der 6. und der 68. BlitzCodeCompo

TimBo

BeitragFr, Aug 29, 2014 14:31
Antworten mit Zitat
Benutzer-Profile anzeigen
dem möchte ich nicht widersprechen Wink
mfg Tim Borowski // CPU: Ryzen 2700x GPU: Nvidia RTX 2070 OC (Gigabyte) Ram: 16GB DDR4 @ 3000MHz OS: Windows 10
Stolzer Gewinner des BCC 25 & BCC 31
hat einen ersten Preis in der 1. Runde beim BWInf 2010/2011 & 2011/12 mit BlitzBasic erreicht.

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group