Ich arbeite gerade an einem Script für ein Memory und habe momentan ein großes Problem, mein Bild wird nicht angezeigt.
Das Debakel sieht bis nun so aus:
In den Variablen $x_1 und $y_2 stehen Werte. Eigentlich war es von mir angedacht damit das Bild richtig auf dem Screen zu platzieren. (Habe auch via Konsole geprüft ob in den Beiden was drin steht, tut es und auch der modus ist 0.)
Mein Versuch "Number" mitzuliefern sieht wie folgt aus:
Bekomme aber nur einen schwarzen Bildschirm geliefert.
Wenn ich das "rescue nil" wegnehme schmiert mir Spiel ab. So dann auch mal zwischendrin die Frage, was macht dieser Befehl überhaut. Habe ihn in anderen Scripten mit Bildern immer wieder gesehen.
Ein Bild wird mir zudem angezeigt wenn ich einfach sage:
Aber das ist ja nicht das was ich möchte. Dann ist das Bild stumpf oben links in der Ecke und zudem möchte ich ja auch mehrere anzeigen.
Natürlich kann man so ein Memory auch leicht ohne Script basteln, aber ich möchte es unbedingt mit hinbekommen.
Wäre super lieb wenn mir hier wer auf die Sprünge helfen könnte.
Mit der Position hat das Bitmap nichts am Hut, das wird über den Sprite geregelt. Die beiden zusammen kann man sich ein bisschen vorstellen wie eine Leinwand (Sprite) auf die eben was gemalt wird (Bitmap). Die Leinwand mit dem Gemalten wird dann irgendwo platziert.
Was du machen musst, ist also folgendes: Cache.picture holt einfach nur ein Bitmap aus dem Cache, wenn es da drin ist, ansonsten wird von der Festplatte geladen. Das spart Zeit und Speicher falls eben dieses Bitmap noch öfters gebraucht wird. Verschiedene Leinwände teilen sich dann quasi ein Gemälde. Wenn du hingegen fünf mal direkt Bitmap.new('Graphics/Pictures/meinbild.png') nutzt, hast du am Ende unnötigerweise fünf Mal ein identisches Bitmap im Speicher, das auch jedes Mal wieder neu von der Festplatte geladen werden muss.
rescue nil ist übrigens eine dumme Idee, weil du damit den Fehler dort unterdrückst wo er passiert und dann je nach Script ziemlich sicher später an anderer Stelle eine Fehlermeldung bekommst, deren Ursprung auf den ersten Blick nicht zu erkennen ist.
Edit: Achso, falsch verstanden. Du wolltest wissen, was es mit dem rescue auf sich hat, nicht mit dem Cache?
Wie gesagt, damit werden Fehler abgefangen.
In deinem Beispiel ist der Cache.picture-Aufruf fehlerhaft, deshalb wird stattdessen das getan, was hinter dem rescue steht, in deinem Fall einfach ein allein stehendes nil. Dem Sprite wird also nie ein Bitmap zugewiesen, deshalb bleibt der Bildschirm schwarz.
--
"Banjo, you're a BEAR... and I will teach you... THESE MOVES!"
Aber... wie bekomme ich jetzt mehrere Bilder auf einmal angezeigt?
Immer wieder einen neuen sprite[nummer] = Sprite.new erzeugen klappt ja nicht (ja ich habs versucht). Da wird nur ein Bild angezeigt und das Vorherige ausgeblendet.
Bin sowieso ein wenig verwundert, der Fehler liegt vermutlich weiter oben im Code, aber nach ein paar Sekunden verschwinden mein Bild auch einfach wieder.
Ich glaube ich brauche noch einen Schubser in die richtige Richtung
Sprites in RGSS haben keine Nummern. Du musst für jeden Sprite eine neue Variable verwenden, sonst wird der alte überschrieben. Was natürlich auch geht, ist ein Array, so werden auch die Pictures im Maker verwaltet. Das versuchst du scheinbar gerade.
Um genau sagen zu können warum dein Bild wieder verschwindet, fehlen Informationen. Hast du für dein Memory eine neue Szene erstellt oder versuchst du das irgendwo anders mit reinzuschreiben? Am besten wäre, wenn du mal dein komplettes Script zeigst.
Ein erster Tipp wäre, dass "sprite" nur eine lokale Variable ist, die wieder verfällt, sobald Ruby mit deiner Methode durch ist, in der der Sprite erstellt wird. (War in meinem Beispiel auch so, aber das war eigentlich nur zur Demonstration von Sprites^^)
--
"Banjo, you're a BEAR... and I will teach you... THESE MOVES!"
Aufgerufen wird es mit dem Befehl halt Bis jetzt noch seeeehr umständlich geschrieben, aber erstmal soll es ja laufen, verfeinern kann man ja immer noch :3
du musst die Sprites "am Leben halten". Wenn du sie in lokale Variablen abspeicherst, werden sie irgendwann vom GarbageCollector gelöscht und die Grafik wird nicht mehr angezeigt.
Hierfür verwendest du am besten Instanzvariablen (also die mit dem @).
Globale Variablen solltest du möglichst vermeiden. Nimm am besten die globalen Variablen die die RGGS selbst definiert und füge dort deine eigenen Attribute hinzu.
Überhaupt macht es Sinn deinen Code mehr in Klassen zu organisieren, sonst wirst du schnell den Überblick verlieren.
Hier mal ein Beispiel wie das aussehen könnte:
Das ist deine Game-Logik Klasse. Die verwaltet alle Attribute des Memory-Spiels sowie die Spiellogik dahinter. Was sie nicht macht ist das Anzeigen der Grafik und das entgegennehmen von Nutzereingaben. Das regelst du über die Scene. Als nächstes speicherst du dieses Memory-Objekt in ein bestehendes globales Objekt ab. z.B. Game_System
Jetzt kannst du ein neues Memory-Spiel mit
anlegen.
Als nächstes legst du deine Szene-Klasse an. Hier musst du dir klar machen das Grafiken in einer Szene einen Lebenszyklus haben: Jede Grafik muss angelegt, geupdatet und am Ende der Szene wieder gelöscht werden. Dafür legst du entsprechend drei Funktionen an:
Das updaten ist erstmal nicht so wichtig, solange du die Positionen der Karten nicht änderst. Wenn du aber neue Funktionen einfügst, wie z.B. das der Nutzer Karten entfernen kann, müssen diese Aktionen Auswirkungen auf das Anzeigen der Grafiken haben. Das regelst du in dem Update-Zyklus. Sprich: Wenn der Nutzer eine Karte abhebt änderst du die Variablen in $game_system.memory. Beim nächsten Updaten der Grafiken werden diese Änderungen dann sichtbar.
Ich hoffe ich hab dir nicht zu viel "vorgesagt". Aber ich denke es gibt noch genug zu tun. So ein Memory-Spiel ist eine gute Übung für das Scripten in der RGSS.
Ein paar Vorschläge was man noch bessern könnte:
- wenn du viele Grafiken verwalten musst, legt für diese eine neue Klasse Spriteset_Memory an. Dann musst du weniger Code in deine Szene-Klasse legen.
- genauso macht es evtl. Sinn die Logik hinter den Spielkarten in eine eigene Game_MemoryCard Klasse auszulagern. Die Klasse Game_Memory verwaltet dann einen Array von Game_MemoryCard Objekten, die Methoden zum Abfragen der Position etc. haben
- genauso kannst du eine Klasse Sprite_GameCard schreiben die eine Referenz auf Game_MemoryCard hat und weiß wie sie grafisch angezeigt werden
Danke euch Zwei so weit, aber ich glaube ich noch was an dem Code von -KD- falsch verstanden.
Zum Verständnis...
In das Array kommen alle Bilder rein die ich anzeigen möchte oder?
zum Beispiel sehe das dann so aus oder?
Sollte das so weit stimmen, anderes Verständnisproblem.
.
Muss ich das für jede Karte machen? Bis jetzt kam es mir so vor, als würde das der Code für alle schon regeln, glaube aber hier etwas arg falsch verstanden zu haben.
Momentan kommt mir der dumpfe Gedanke... dass die Zeile so aussehen müsste: Wobei ich mich dann natürlich auch wieder frage, wofür ich vorher und habe. Mir war so genau diese müssten dafür da sein.
Natürlich lagen die beiden Array in einer Klasse, wodurch das zusammenhängen kann das ich das noch einmal machen muss, dennoch bin ich momentan arg verwirrt, da ich stark davon ausgehe dass der Code von -KD- garantiert so funktioniert... unter Voraussetzung man setzt ihn richtig ein.
Kompelieren tut er... nur wie immer sehe nichts XD ... wegen weil falsche Bedienung meinerseits.
ich hab den Code nicht ausprobiert. Gut möglich das da was noch nicht funktioniert.
Zitat
In das Array kommen alle Bilder rein die ich anzeigen möchte oder?
...
Jap
Zitat
Muss ich das für jede Karte machen? Bis jetzt kam es mir so vor, als würde das der Code für alle schon regeln, glaube aber hier etwas arg falsch verstanden zu haben.
...
Nein, das macht es automatisch für alle Karten. Die map Funktion bildet einen Array (oder eine beliebige andere Collection) auf einen neuen Array ab, in dem es eine Funktion auf jedes Element des Arrays ausführt.
Beispiel: Du hast eine Liste von Zahlen [1,2,3,4,5] und wendest darauf ein map mit der Quadrat-Funktion an. Dann bekommst du eine Liste [1,4,9,16,25] zurück. Vom Code her würde das folgendermaßen aussehen:
Ob du geschweifte Klammern oder do...end benutzt ist egal. Was da zwischen den |...| steht sind die Parameter der Funktion, die du map übergibst.
In dem Beispielcode
sagst du: Lege einen Array an: für jede Karte, die $game_system.memory.get_cards zurückliefert, erzeuge einen Sprite, setze dessen x und y Koordinaten auf die Koordinaten der Karte, sowie seine Grafik auf die Grafik der Karte. Füge diesen Sprite dann in den Array ein. Setze am Ende die Variable @card_sprites auf diesen Array.
Der Code ist gleichbedeutend zu
map gehört zu den Iteratorfunktionen (in anderen Sprachen auch Funktoren genannt). Das sind Methoden, die eine Funktion (also ein Stück ausführbaren Code) als Parameter bekommen.
In meinen Codebeispielen sind noch zwei weitere Iteratorfunktionen: each führt eine Funktion für jedes Element des Arrays aus (ohne dabei aber einen neuen Array zu erzeugen).
each ist identisch mit der For-Schleife. n.times führt eine Funktion n Mal aus. Sie entspricht einer Zählerschleife in anderen Sprachen.
Das Tutorial ist sehr veraltet und bezieht sich noch auf Ruby 1.8 (und den RPGMaker XP), aber evtl. hilft dir die dortige Erklärung zum Verständnis von Iteratorfunktionen: http://www.rpg-studio.org/scientia/R...2_-_OOP_Teil_2
Ich befinde mich gerade auf Fehlersuche und bin schwerst verwirrt.
Der scheint nur in die erste Methode einer Klasse zu gehen. Muss ich die anderen Klassen wie in meinem alten Code noch mal alle extra aufrufen?
Jedenfalls... er geht soweit ich das sehe nur in die Methode "initialize" (immer und immer wieder) und in die Klasse "Game_System", genau einmal.
Edit:
Wie ich es im alten Code gemacht habe funktioniert es leider nicht... warum geht der denn nicht in die anderen Methoden rein Oo
... oder sehe ich das einfach nur nicht... der müsste mir doch mit:
den Wert von "irgendwas" in der Konsole ausgeben. Egal wo ich mich befinde.
Ja, vermutlich wird die Stelle im Code nicht erreicht. <initialize> wird immer dann aufgerufen, wenn ein neues Objekt der Klasse angelegt wird. Hast du beispielsweise die Klasse Auto und schreibst: auto = Auto.new, dann wird <initialize> von Auto einmal aufgerufen. Die anderen Methoden der Klasse werden dann aufgerufen, wenn du im Code explizit auto.[Name der Methode] schreibst.
Automatisch geht er in keine Methode rein. Wie Kelven schon gesagt hat: die initialize Methode wird aufgerufen sobald du Klasse.new schreibst.
Während das Spiel läuft wird ständig SceneManager.scene.main aufgerufen. Dadurch das du SceneManager.call(Memory) geschrieben hast, wird die Klasse Memory als aktive Szene gesetzt und zuerst die initialize Methode und danach die main Methode von Memory aufgerufen.
Da deine Memory Klasse von Scene_Base erbt, übernimmt sie deren main Methode. Wenn du also wissen willst, was main macht, musst du in die Klasse Scene_Base reinschauen. Dort siehst du, dass main erst die Methode start aufruft, und danach in einer Schleife die Methode update aufruft bis die Scene beendet wird. Danach wird die Methode terminate aufgerufen.
In der start-Methode hast du dann dein draw_graphic aufgerufen.
Du müsstest jetzt noch die update Methode überschreiben und dort update_graphics aufrufen, sowie die terminate Methode überschreiben und dort dispose_graphics aufrufen (und wichtig dabei: in den Methoden immer am Anfang das Schlüsselwort super schreiben, damit die gleichnamige Methode der Superklasse Scene_Base aufgerufen wird).