Java Grundlagen? Lebensanzeige - Greenfoot

Pneismneis

Newbie
Registriert
Dez. 2010
Beiträge
5
Hallo ;-)

Ich arbeite momentan an einem Spiel für die Schule, habe mich für Super Mario World entschieden. Es funktioniert soweit ganz gut, hatte paar Probleme bei der Kollisionsabfrage, aber konnte die auch lösen. Hab jetzt allerdings ein neues Problem. Es geht um die Lebensanzeige, die ich eigentlich für ziemlich simpel gehalten hätte.

Ich habe einen Actor - Mario, in dem habe ich die Variable "Lives" deklariert und ihr den Wert "3" zugewiesen. Dann habe ich einen neuen Actor "Lives" erstellt:

Code:
public class Lives  extends Text {
    
    Mario M = new Mario();

    public Lives() {
        GreenfootImage img = new GreenfootImage(100, 30);
        img.drawString ("Lives: "+M.getLives(), 2, 20);
        setImage(img);
    }

    public void act() {
            setText(M.getLives());
    }
    
    public void setText(int text){
        GreenfootImage img = getImage();
        img.clear();
        img.drawString("Lives: " +text, 2, 20);
    }
}

Die Funktion getLives aus der Klasse Mario sieht wie folgt aus:

Code:
public int getLives(){
        return Lives;
    }

In der Unterklasse "Marioworld" von "World" habe ich:

Code:
public Marioworld()
    {
        addObject(new Mario(), 10, 253);
        Lives lives = new Lives();
        addObject(lives, 60, 20);
    }

--Habe die unwichtigen Dinge mal aus dem Code genommen, nur das wesentliche geposted.--


Außerdem habe ich zu der Methode "Jump" von Mario, die ausgelöst wird wenn man die Pfeiltaste hoch drückt, ein "Lives--;" hinzugefügt, so dass immer wenn er springt ein Leben abgezogen wird (nur zum Test natürlich).

Das ganze habe ich getestet, wenn Mario springt, dann geht die Variable "Lives" eins runter, kann ich ja mit Inspizieren nachschauen, funktioniert. ALLERDINGS ändert sich der Text in der links oberen Ecke nicht.

Habe also bisschen gegooglet und rumprobiert, und denke, dass es daran liegt, dass ich nur ganz am Anfang einmal "Mario M = new Mario();" stehen habe, und das ja einfach nur bedeutet, dass "M" wie ein neuer Mario (NICHT der Mario auf dem Spielfeld) gehandhabt wird und deshalb auch kein Leben verliert. Soweit so gut. Hatte dann keine Idee, also wieder gegooglet. Dann habe ich folgendes gelesen:

Code:
public Mario(){
        //unwichtiger Code
    }

ändern in:

Code:
private Mario myMario;

public Mario(Mario mario){
//unwichtiger Code
myMario = mario;
}

dann in Marioworld:

Code:
public Marioworld()
    {
        Mario mario = new Mario();
        addObject(mario, 10, 253);
        Lives lives = new Lives();
        addObject(lives, 60, 18);
    }

Dann kann ich es aber garnicht mehr compilen, da "Mario()" kein Konstruktor ist? oO


Hat jemand eine andere Idee? =)

MfG
Pneismneis
 
Mario mario = new Mario();

und

private Mario myMario;

public Mario(Mario mario){
//unwichtiger Code
myMario = mario;
}

siehste was?

Mario() ist wirklich kein constructor ;)
das wäre Mario(dein jetziger Mario);

und wozu ist Lives lives = new Lives(); !?
gib der Mario Klasse eine int variable namens lives und die hält dann den gegenwärtigen lebensstand.
 
Zuletzt bearbeitet:
Ich weiß nicht, um ehrlich zu sein habe ich ein bisschen den Überblick verloren :D
Der zweite Code war ein Vorschlag, wie ich ihn im Internet gefunden habe - den ich aber leider nicht nachvollziehen kann udn der auch nicht funktioniert. Ich nehme an, dass deni Post sich darauf bezieht, deshalb kann ich da nicht wirklich viele Informationen rausziehen :D

Hast du evtl eine Idee warum mein Code oben nicht funktioniert und wie ich den verbessern kann?

Bzw: Den Teil
Mario() ist wirklich kein constructor
das wäre Mario(dein jetziger Mario);
habe ich verstanden, allerdings weiß ich nicht, wie ich in den Klammern den jetzigen Mario auswählen kann. :/
 
kannst du mal dein ganzes projekt hochladen?
mit codeausschnitten ist das ein wenig schwierig.

deine analyse im 1. Post klingt schon sehr zielführend.
Ergänzung ()

Pneismneis schrieb:
Bzw: Den Teil habe ich verstanden, allerdings weiß ich nicht, wie ich in den Klammern den jetzigen Mario auswählen kann. :/

Deinen jetzigen Mario speicherst du dir irgendwo als statische Variable. Dann musst du auch nicht jedesmal einen neuen erzeugen. Du brauchst schließlich nur einen Mario.

zocke jetzt ne runde fifa, bin um 12 wieder on^^
 
Zuletzt bearbeitet:
Du hast verschiedene Marios erstellt. einmal hier:

public class Lives extends Text {

Mario M = new Mario();
...

und dann nochmal hier:

public Marioworld()
{
addObject(new Mario(), 10, 253);
...

richtig wäre, einen Mario zu erstellen und ihn dann in beiden aufrufen zu benutzen:

public Marioworld()
{
Mario M = new Mario();
addObject(M, 10, 253);
Lives lives = new Lives(M); <--- Deinen Konstruktor müsstest du hier umschreiben!
addObject(lives, 60, 20);
}

Der Konstruktor von Lives könnte dann so aussehen:

public class Lives extends Text {

public Mario M;

public Lives(Mario Mar) {
this.M = Mar;
GreenfootImage img = new GreenfootImage(100, 30);
img.drawString ("Lives: "+M.getLives(), 2, 20);
setImage(img);
}
...
 
Lade das Projekt ungern hoch, denn dann besteht immer die Gefahr, dass der Lehrer sagt es wäre kopiert, auch wenns nicht der Fall ist.. Aber ok. Klick hier.

Vielleicht hat ja auch jemand ne Lösung für mein anderes Problem: Momentan kann Mario zwar auf nen Gumba springen, der "stirbt" dann auch korrekt, aber Mario "prallt" nicht am Gumba ab, sondern fällt normal weiter. Konnte dafür bisher auch keine Lösung finden, habe es mit einer Variable im Gumba probiert, die von 0 auf 1 gesetzt wird, wenn Mario ihn berührt - beim Mario wird die ganze Zeit überprüft ob diese Variable auf 1 ist, wenn ja springt er. Das passiert allerdings nicht. Der Code befindet sich noch in den Klassen Mario/Gumba.
Ergänzung ()

Shagg schrieb:
Du hast verschiedene Marios erstellt. einmal hier:

public class Lives extends Text {

Mario M = new Mario();
...

und dann nochmal hier:

public Marioworld()
{
addObject(new Mario(), 10, 253);
...

richtig wäre, einen Mario zu erstellen und ihn dann in beiden aufrufen zu benutzen:

public Marioworld()
{
Mario M = new Mario();
addObject(M, 10, 253);
Lives lives = new Lives(M); <--- Deinen Konstruktor müsstest du hier umschreiben!
addObject(lives, 60, 20);
}

Der Konstruktor von Lives könnte dann so aussehen:

public class Lives extends Text {

public Mario M;

public Lives(Mario Mar) {
this.M = Mar;
GreenfootImage img = new GreenfootImage(100, 30);
img.drawString ("Lives: "+M.getLives(), 2, 20);
setImage(img);
}
...


Ok, das funktioniert, danke!

Allerdings verstehe ich nicht ganz, was du da jetzt gemacht hast :-) Dass M in Marioworld der Mario den man steuert ist, verstehe ich noch. public Mario M heißt wohl, dass eine Variable des Typs Mario deklariert wird - diese heißt M. Aber sobald es zu dem public Lives(Mario Mar) kommt, muss ich wohl passen.

Heißt das, dass sobald ein Objekt der Klasse Lives erstellt wird, wird in ihr eine Variable Mar deklariert, der ein bestimmter Mario - in meinem Fall wegen Lives lives = new Lives(M) der Mario den man steuert - zugeordnet wird?

Wenn ja, komme ich nurnoch mit dem this.M = Mar; nicht klar - wofür das this.?

Danke schonmal ;-)
Pneismneis
 
Zuletzt bearbeitet:
Du hast eigentlich recht. es ist eine art variable die erstellt wird, eigentlich eher ein verweis auf das bereits bekannt mario objekt (hier also M). dieser verweis ist aber vorerst nur im konstruktor verwendbar. deshalb sorgen wir dafür, dass die gesamte klasse ihn kennt. dies tuen wir mit der zeile, die dir noch nichts gesagt hat, also die mit dem this.M .
Das heißt eigentlich nichts weiter als, diese Klasse kann einen Mario speichern, der soll dann M heißen. und im konstruktor sagst du dann, this.M = Mar, also im Mario M aus dieser Klasse soll der Mario aus Mar gespeichert sein.

das erstellte Lives-Objekt "kennt" also quasi den Mario den wir steuern wollen:

public Marioworld()
{
Mario M = new Mario(); // erstelle den Mario den wir steuern wollen
addObject(M, 10, 253); // da wir hier M verwenden, ist es der gleiche wie eine Zeile oben drüber
Lives lives = new Lives(M); <--- Hier verwenden wir wieder M, also immernoch der gleiche Mario
addObject(lives, 60, 20);
}

Nun weiter zu der Klasse Lives:

Der Konstruktor von Lives hat einen Parameter vom Typ Mario, den ich hier jetzt einfach Mar genannt habe, wie der heisst, ist aber eigentlich auch egal. Wichtig ist, das du der klasse beim erstellen, also dem aufruf new Lives(Mario) , ein existierendes Mario Objekt übergibst. In unserem Fall, war dies nun der Mario M, den wir steuern wollen.


public class Lives extends Text {

public Mario M; // da soll nachher M drinnen stehen

public Lives(Mario Mar) { // wir haben den Konstruktor so benutzt: Lives lives = new Lives(M);
// in Mar steht jetzt also M drinnen! Dein Lives Objekt kennt jetzt M!
this.M = Mar; // Diese Zeile bewirkt, dass M (welches in Mar steht) an das M in
// der Klasse Lives übergeben wird.
GreenfootImage img = new GreenfootImage(100, 30);
img.drawString ("Lives: "+M.getLives(), 2, 20);
setImage(img);
}

Der Vorteil des übergebens an this.M liegt darin, dass du jetzt belibig viele Funktionen in Lives schreiben kannst, und trotzdem kannst du nun mit this.M (oder nur mit M) immer auf den Mario zugreifen, den wir steuern wollen.

Denke es wäre ganz gut, wenn du dich mal damit auseinandersetzt, was es bedeutet, dass Java Objektorientiert ist. Wenn man das verstanden hagt, begreift man viel einfacher, warum man wo ein Objekt übergibt etc.

Ich gucke gleich nochmal in den Thread rein, also wenn du noch Fragen hast, oder ich irgendwas zu umständlich erklärt habe, dann frage gerne nochmal nach :)
 
Zuletzt bearbeitet:
Wow, die Erklärung war super, danke! ;-) Eigentlich ist jetzt alles klar - wenn ich noch Fragen habe, melde ich mich nochmal, aber konnte jetzt alles umsetzen.

Damit hat sich auch mein Problem mit dem Gumba geklärt!

Keine 2 Stunden und das Problem gelöst, wahnsinn!

Danke für die schnellen und vor allem hilfreichen Antworten!

MfG
Pneismneis
Ergänzung ()

Okay, ich hab wieder ne Frage ;-)

Die Lebensanzeige funktioniert jetzt sehr gut, jetzt sitze ich am Tod von Mario. Dazu habe ich in "Act" der Klasse Mario folgendes ergänzt:

Code:
if(death == 1){
        if(trigger==0){
            Lives--;
            trigger=1;
        }
        checkDeath();
    }

Es wird also zuerst ein Leben abgezogen, dann wird death z.B. wenn Mario einen Gumba an der Seite berührt auf 1 gesetzt. Dann wird checkDeath abgerufen:

Code:
public void checkDeath(){
        setImage("MarioDEAD.png");
        if(count < 15){
            setLocation(getX(), getY() -4);
            count++;
        }
        else if(getY() < 290 && count > 14){
            setLocation(getX(), getY() +2);
            count++;
        }
        else if(getY() > 290){
           getWorld().removeObject(this);
        }
    }

Das soll einfach die typische Mario-Todessequenz darstellen, bei der Mario zuerst ein Stück "hochspringt" und dann langsam den ganzen Bildschirm runterfällt. Das funktioniert soweit.

Nur jetzt stehe ich vor dem Problem, dass ein neuer Mario erstellt werden soll, undzwar mit Lives = 2, auf den trotzdem alle anderen Klassen zugreifen können, wie auf den ersten. Da muss ich zugeben, dass ich recht ideenlos bin, wie ich das umsetzen soll.

Zudem kommt, dass wenn Lives = 0, dann soll sich das Fenster schwarz färben - mit einem "Game Over" in der Mitte. Aber das werde ich wohl selbst hinbekommen - bleibt erstmal nur das Mario Problem!

Danke schonmal!:)

MfG
Pneismneis
 
Nur jetzt stehe ich vor dem Problem, dass ein neuer Mario erstellt werden soll, undzwar mit Lives = 2, auf den trotzdem alle anderen Klassen zugreifen können, wie auf den ersten. Da muss ich zugeben, dass ich recht ideenlos bin, wie ich das umsetzen soll.
Mach bei den anderen Klassen eine public-Methode, über die du den Klassen das neue Mario-Objekt bekanntmachen kannst.
Das könnte zB etwa so aussehen:
PHP:
public void changeMario(Mario m) {
    this.mario = m;

    // weitere Befehle, zwecks Neuinitialisierung der Daten
    // ...
}

Den anderen Klassen muss ja das Mario-Objekt irgendwie bekannt sein (zB über die Instanzvariable "mario"). Da kannst du einfach ein neues Objekt reinschreiben.


Kann ich eine aktuelle Version deines Projekts haben? Mich würden da persönlich einige Dinge interessieren. Auch klingt es für mich, dass du einige Sachen zu kompliziert umgesetzt hast. Keine Sorge, ich behalte das für mich. Du kannst es ja per PN schicken.
 
Danke für die Antwort, habe die erst eben gesehen ;-)

Ich hab das Ganze inzwischen anders umgesetzt, indem ich den Mario einfach zurücksetze wenn Lives--; eintritt.

Eine neuere Version kannst du selbstverständlich haben, hast eine PN!

MfG
Pneismneis
 

Ähnliche Themen

Zurück
Oben