Punktezähler

F4ckHanoi

Mitglied
Yo da bin ich mal wieder mit neue Probleme :D

Diesmal möchte ich, dass wenn man einen Block berührt, sich der Punktezähler um eins erhöht. Dies macht das Programm aber unendlich. Also es wird die ganze Zeit hochgezählt. Ich habe es mal mit boolean variablen probiert, die das ganze steuern soll, hat aber irgendwie nicht geklappt.

So sieht es momentan aus:
Java:
if(block[0].Coin() == true){
                scoreKontrolle = true;
            }
            if(scoreKontrolle){
                coin_score++;
                f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                scoreKontrolle = false;
            }

Das Block wird berührt. Dann wird die Variable auf true gesetzt. Wenn es auf true gesetzt wird, dann zähle ein Punkt hoch und zeichne mir ein anderes image. Setze danach die Variable auf false und tue nichts. (War meine Gedanke)

Vielen dank im Voraus! :)
 

VfL_Freak

Top Contributor
Moin,

und was soll dabei jetzt unendlich laufen ??? :confused:
Mal so ins Blaue geraten: ist da vlt. noch eine weitere Schleife drum herum und dabei in jedem Durchlauf "block[0].Coin() == true" ??

Mehr Infos bitte :rolleyes:

BTW: "hat aber irgendwie nicht geklappt" ist KEINE Fehlermeldung :mad:

Gruß Klaus
 

Henne079

Aktives Mitglied
Gibt es einen Grund, wieso in der ersten Abfrage die Variable auf "true" gesetzt wird und diese Variable direkt in der nächsten Abfrage genutzt wird.
Also wieso die Bedingung bei der ersten Abfrage nicht gleich die Bedingung der zweiten Abfrage ist?
Dann würde eine Abfrage rausfallen.
 

VfL_Freak

Top Contributor
Moin,
Gibt es einen Grund, wieso in der ersten Abfrage die Variable auf "true" gesetzt wird und diese Variable direkt in der nächsten Abfrage genutzt wird.
Also wieso die Bedingung bei der ersten Abfrage nicht gleich die Bedingung der zweiten Abfrage ist?
Dann würde eine Abfrage rausfallen
Auch hierfür gilt: Bissl mehr Einsicht in den Code wäre super :rolleyes:
Aber um mal wieder ins Blaue zu raten: vermutlich wird "scoreKontrolle" noch an anderen Stellen im Code genutzt!
Wenn es wirklich nur in dem geposteten Schnipsel verwendet würde, hättest Du Recht !

Gruß Klaus
 

F4ckHanoi

Mitglied
Also was unendlich läuft ist "coin_score". Und nein, da ist keine Schleife drum herum. Naja etwas mehr zum code:

Die eigentliche Klasse (wo es ausgeführt wird):

Java:
//Variablen
boolean scoreKontrolle = false;
int coin_score = 0;



//Anlegen von Block
block[0] = new Block((blockPosX*randomPosX),80,50,50);



//Block zeichnen
f2.drawImage(coin, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);



//Kollision von Figur und Block
block[0].kollisionsabfrage(block[0].getX_Block()-getXBild(), block[0].getY_Block() + block[0].getHeight(),figur_posX + (74-12), figur_posY);



//Wenn Block berührt wird, erhält man Punkte
            if(block[0].Coin() == true){
                scoreKontrolle = true;
            }
            if(scoreKontrolle){
                coin_score++;
                f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                scoreKontrolle = false;
            }

"coin_score++" --> Es soll einfach die Punkteanzahl um 1 erhöhen. Aber es läuft halt unendlich. Also es wird unendlich lang hochgezählt.



Block Klasse:

Java:
package HNProduction;


public class Block {

    int X;
    int Y;
    int WIDTH;
    int HEIGHT;
    boolean coin = false;
  
  
    /*
     * Konstruktor
     */
    public Block(int x, int y, int width, int height){
        this.X = x;
        this.Y = y;
        this.WIDTH = width;
        this.HEIGHT = height;  
    }
  
  
    /*
     * Kollision
     */
    public boolean kollisionsabfrage(int x_block, int y_block,int x_figur,int y_figur){
        if( x_figur >= x_block && y_figur >= y_block && y_figur <= y_block + HEIGHT){
            if(x_figur <= x_block+WIDTH){
                coin = true;
                return true;
            }
        }else{
            return false;
        }
        return false;
      
    }
  
  
  
    /*
     *Zurückliefern von Variablen
     */
  
    public int getX_Block(){
        return this.X;
    }
  
    public void setX_Block(int x){
        this.X = x;
    }
  
    public int getY_Block(){
        return this.Y;
    }
  
    public int getWidth(){
        return this.WIDTH;
    }
  
    public int getHeight(){
        return this.HEIGHT;
    }
  
    public boolean Coin(){
        return this.coin;
    }
  
}
 

Blender3D

Top Contributor
Also so wie ich das sehe willst Du mit der Variable scoreKontrolle verhindern, dass die Berührung nur einmal gezählt wird.
if(block[0].Coin() == true){
scoreKontrolle = true;
}
if(scoreKontrolle){
coin_score++;
f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
scoreKontrolle = false;
}
Wie meine Vorredner bereits bemerkt haben: Dass kann nicht funktionieren! Weil die Abfrage auf block[0].Coin() scoreKontrolle immer auf true setzen wird, sofern du die Positionen des Blocks und des Coins nicht veränderst.
 

F4ckHanoi

Mitglied
Also die Position des Blocks wird verändert: (habe ich vergessen mit zu posten)

Java:
//Wenn Block außerhalb des Frames gelangt
           
            if(block[0].getX_Block()-getXBild() < -50){
                ausserGrenze = true;
            }
           
            if(ausserGrenze){
                randomPosX = 3000 + (int) Math.floor(Math.random()*2000);
                block[0].setX_Block(getXBild()+randomPosX);
                ausserGrenze = false;
            }

Das funktioniert prima und das gleiche habe ich bei den Punktezähler (coin_score) versucht und naja. Du sagtest das es immer auf true gesetzt wird und ich kann es mir halt nicht erklären.


Was wäre denn eine andere alternative, so dass der Punktezähler nur um 1 erhöht wird, nachdem man eine Kollision mit einen Block hatte.
 

Blender3D

Top Contributor

F4ckHanoi

Mitglied
Ah ich sehe warum es immer auf true gesetzt wird. Wenn block berührt wird, ist es auf true gesetzt und so bleibt es dann auch. Ich muss es doch wieder dann auf false setzen oder nicht?
 

F4ckHanoi

Mitglied
Edit: Ich habs ausprobiert, klappt immer noch nicht. Leute ich muss das ding endlich lösen, muss dadurch auf vieles verzichten. Bitte hilft mir doch!

Ich nehme auch gerne Codeverbesserungen an!
 

Meniskusschaden

Top Contributor
Also meines Erachtens kann man anhand des bisher gezeigten Codes nicht viel dazu sagen. Man sieht nur ein Codefragment indem coin_score einmal inkrementiert wird. Man sieht aber nicht, ob das die vollständige Methode ist und auch nicht, wie der Code aufgerufen wird. Wie stellst du denn überhaupt fest, dass coin_score mehrfach erhöht wird? Vielleicht gibt es im Programm mehrere Variablen mit demselben Namen und das Problem liegt ausserhalb des gezeigten Codes.
 

F4ckHanoi

Mitglied
Wenn das mir weiter hilft:

Die komplette Spielklasse:
Java:
package HNProduction;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.RescaleOp;
import java.util.Date;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;


public class Spiel extends JPanel implements ActionListener {
   
   
    //Boolean variable für bestimmte Abfragen
    boolean gegnerFigurKollision = false;
    boolean gegnerWurdeBesiegt = false;
    boolean ausserGrenze = false;
    boolean scoreKontrolle = false;
    boolean lebenKontrolle = false;
   
   
    //Timer
    Timer time;
   
   
    //Hintergrund
    Image background;
    int backgroundZeichnenX,backgroundZeichnenX_zwei;
    int background_aktuelle_posX;
    static int background_posX;
    int anzahl = 0;
    int anzahl_zwei= 0;
   
   
    //Taste
    int gedrueckteTaste;   
   
   
    //Charakter   
    Image figur;
    int figur_posX = 75;
    int figur_posY = 300;
    int leben = 3;

   
    //Blöcke
    Image coin;
    Image usedBlock;
    Block block[] = new Block[5];
    int blockPosX = 500;
    int randomPosX = 1 + (int) Math.floor(Math.random()*3);
    int coin_score = 0;

   
    //Gegner
    Gegner enemy;
    int gegnerPosX = 1000;
    int randomGegnerPosX = 1 + (int) Math.floor(Math.random()*3);
    Image gegner;
    int kills = 0;
   

   
   
   
    /*******************************************************/
    /********************* KONSTRUKTOR *********************/
    /*******************************************************/
    public Spiel(){

       
        /*
         * Inizialisieren
         */
        backgroundZeichnenX = 0;
        backgroundZeichnenX_zwei = 1120;//1120
        gedrueckteTaste = 0;
        background_posX = 0;
        setFocusable(true);
       
       
       
       
        /*
         * Bilder von Charakter und Hintergrund
         */
        ImageIcon u = new ImageIcon((getClass().getResource("background_game.png")));
        background = u.getImage();
       
        ImageIcon s = new ImageIcon((getClass().getResource("char.png")));
        figur = s.getImage();
       
        ImageIcon c = new ImageIcon(getClass().getResource("coin.png"));
        coin = c.getImage();
       
        ImageIcon b = new ImageIcon(getClass().getResource("blockUsed.png"));
        usedBlock = b.getImage();
       
        ImageIcon g = new ImageIcon(getClass().getResource("enemy.png"));
        gegner = g.getImage();
       
       
       
        /*
         * KeyListener
         */
        addKeyListener(new AL());
       
       
       
       
        /*
         * Blöcke
         */
        block[0] = new Block((blockPosX*randomPosX),80,50,50);
        //block[1] = new Block((blockPosX*randomPosX),80,50,50);
        //block[2] = new Block((blockPosX*randomPosX),80,50,50);
           
       
       
       
        /*
         * Gegner
         */
            enemy = new Gegner((gegnerPosX*randomGegnerPosX), 300, 74, 74);
       
       
       
       
        /*
         * Springen
         */
        Springen sprung = new Springen();
   
       
       
       
        /*
         * Alternative zu "update - Methode" die sich alle 5 Millisekunden wiederholt
         */
        time = new Timer(5,this);
        time.start();
       
    }
    /*****************************************************************************************************************************************/
   
   

   
   
   
   
   
   
    /************************************************************************/
    /********************* Wiederholende Methodenaufruf *********************/
    /************************************************************************/
    public void actionPerformed(ActionEvent e){
        //(Wird immer wieder neu gezeichnet sowohl die Bewegungen als auch die Bilder)
        bewegen();
        repaint();
        figur_posY = Springen.sprungposition;
    }
    /*****************************************************************************************************************************************/
   
   
   
   
   
   
   
   
    /*********************************************************/
    /********************* PAINT METHODE *********************/
    /*********************************************************/
    public void paint(Graphics g){
       
        super.paint(g);
        Graphics2D f2 =(Graphics2D)g;
       
       
       
        /*
         * Hintergrund wiederholt sich
         */
        if (getXBild() == 20 + (anzahl * 2380)){
            anzahl += 1;
            backgroundZeichnenX = 0;
        }
       
        if (getXBild() == 1210 + (anzahl_zwei*2380)){
            anzahl_zwei += 1;
            backgroundZeichnenX_zwei = 0;
        }
       
        if (getXBild() >= 20){
            f2.drawImage(background,1115-backgroundZeichnenX,0,null);
        }
       
       
       
       
        //Hintergrund
        f2.drawImage(background,1115-backgroundZeichnenX_zwei,0,null);

       
       
       
       
       
        /*
         * Blöcke
         */
        f2.drawImage(coin, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
        /*f2.drawImage(coin, block[1].getX_Block()-getXBild(), block[1].getY_Block(), block[1].getWidth(), block[1].getHeight(), null);
        f2.drawImage(coin, block[2].getX_Block()-getXBild(), block[2].getY_Block(), block[2].getWidth(), block[2].getHeight(), null);
        */
       
       
   
        //Kollisionsabfrage
            //74 -12 (Größe des Charakters also die X Position minus den Abstand zu den Rand)
        block[0].kollisionsabfrage(block[0].getX_Block()-getXBild(), block[0].getY_Block() + block[0].getHeight(),figur_posX + (74-12), figur_posY);
        /*block[1].kollisionsabfrage(block[1].getX_Block()-getXBild(), block[1].getY_Block() + block[1].getHeight(),figur_posX + (74-12), figur_posY);
        block[2].kollisionsabfrage(block[2].getX_Block()-getXBild(), block[2].getY_Block() + block[2].getHeight(),figur_posX + (74-12), figur_posY);
        */
       
           
       
       
           
            //Wenn Block berührt wird, erhält man Punkte
            if(block[0].Coin() == true){
                coin_score++;
                f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                Block.coin = false;
            }
            /*if(block[1].Coin() == true){
                coin_score++;
                f2.drawImage(usedBlock, block[1].getX_Block()-getXBild(), block[1].getY_Block(), block[1].getWidth(), block[1].getHeight(), null);
            }
            if(block[2].Coin() == true){
                coin_score++;
                f2.drawImage(usedBlock, block[2].getX_Block()-getXBild(), block[2].getY_Block(), block[2].getWidth(), block[2].getHeight(), null);
            }
            }*/
           
           
           
           
           
            //Wenn Block außerhalb des Frames gelangt
            //if(block[0].getX_Block()-getXBild() < -50 || block[1].getX_Block()-getXBild() < -50 || block[2].getX_Block()-getXBild() < -50){
            //    ausserGrenze = true;
            //}
            if(block[0].getX_Block()-getXBild() < -50){
                ausserGrenze = true;
            }
           
           
            if(ausserGrenze){
                randomPosX = 3000 + (int) Math.floor(Math.random()*2000);
                //int randomPosX_One = 1000 + (int) Math.floor(Math.random()*2000);
                //int randomPosX_Two = 5000 + (int) Math.floor(Math.random()*2000);
               
                block[0].setX_Block(getXBild()+randomPosX);
                //block[1].setX_Block(getXBild()+randomPosX_One);
                //block[2].setX_Block(getXBild()+randomPosX_Four);
                ausserGrenze = false;
            }
               
           
           
           
        /*
         * Gegner
         */
            f2.drawImage(gegner, (int) enemy.getXGegner(), enemy.getYGegner(), null);
            enemy.bewegenVonGegner();
            enemy.kollisionsabrageVonGegner((int) (enemy.getXGegner()), enemy.getYGegner(), figur_posX, figur_posY);
           
           
           
           
            //Gegner Kollision
            if(enemy.getGegnerTrifftFigur() == true){
                gegnerFigurKollision = true;
                if(gegnerFigurKollision){
                    leben--;
                    gegnerFigurKollision = false;
                }
            }
            if(enemy.getGegnerTrifftFigur() == false){gegnerFigurKollision = false;}
           
           
           
           
           
            //Gegner killen
            if(enemy.getGegnerStirbt() == true){
                gegnerWurdeBesiegt = true;
            }
           
            if(gegnerWurdeBesiegt){
                coin_score += 5;
                kills++;
                gegnerWurdeBesiegt = false;
            }
           
           
           
           
            //Wenn Gegner außerhalb der Framebreite ist
            if(enemy.getXGegner() < -50){
                randomGegnerPosX = 100 + (int) Math.floor(Math.random()*1000);
                enemy.setXGegner((figur_posX+randomGegnerPosX));
            }
       
           
           
           
            //Wenn kein Leben mehr vorhanden ist
            if(leben == 0){
                lebenKontrolle = true;
           
            }
            if(lebenKontrolle && enemy.getGegnerTrifftFigur() == true){
                lebenKontrolle = false;
                leben = 0;
            }
       
           
           
       
        //Charakter
        f2.drawImage(figur,figur_posX,figur_posY,null);
           
       
       
       
        //Punktestand
        f2.setColor(Color.WHITE);
        f2.drawString("Score :" + coin_score, 10, 15);
       
       
       
       
        //Leben
        f2.setColor(Color.WHITE);
        f2.drawString("Leben :" + leben, 70, 15);

       
       
        //Kills
        f2.setColor(Color.WHITE);
        f2.drawString("Kills :" + kills, 130, 15);
       
       
       
       
       
        /*
         * Inventar
         */
        f2.setColor(Color.decode("#BEF781"));
        f2.fillRect(0, 520, 1100, 279);
        f2.setColor(Color.BLACK);
        f2.setFont(new Font("Tekton Pro Ext", Font.BOLD, 99));
        f2.drawString("Inventar", 350, 675);
       
       
        //Achievements
        if(kills == 100){
            System.out.println("Achievement unlocked: 100 Gegner getötet!");
        }
           
    }
    /***************************************************************************************************************************************************/
   
   
   
   
   
   
   
   
    /***********************************************************************************************/
    /********************* akutelle X Position des Hintergrunds zurückliefern  *********************/
    /***********************************************************************************************/
    private int getXBild() {
        return background_aktuelle_posX;
    }
    /*****************************************************************************************************************************************************/
   
   
   
   
   
   
   
   
   

    /***********************************************************************************************/
    /********************* ANIMATION DES BACKGROUNDS UND CHARAKTERS ********************************/
    /***********************************************************************************************/
    public void bewegen(){
       
        if (background_posX != -2) {
            if (figur_posX + background_posX <= 75) {
                figur_posX += background_posX;
            } else {
                background_aktuelle_posX += background_posX;
                backgroundZeichnenX += background_posX;
                backgroundZeichnenX_zwei += background_posX;
            }
        }else {
            if (figur_posX + background_posX > 0) {
                figur_posX += background_posX;
            }
        }

    }
    /*****************************************************************************************************************************************************/
   
   
   
   
   
   
   
   
   
    /****************************************************************/
    /********************* KEYEVENTS ********************************/
    /****************************************************************/
    private class AL extends KeyAdapter{
            public AL(){}
           
           
            public void keyPressed(KeyEvent e){
                gedrueckteTaste = e.getKeyCode();
               
                if(gedrueckteTaste == KeyEvent.VK_LEFT){
                    background_posX = -2;
                }
               
                if(gedrueckteTaste == KeyEvent.VK_RIGHT){
                    background_posX = 2;
                    figur_posX += 4;
                }
           
                if(gedrueckteTaste == KeyEvent.VK_ESCAPE){
                    //Menü öffnen
                }
   
                if(gedrueckteTaste == KeyEvent.VK_SPACE){
                    if(Springen.springenAnimationFertig == true)
                    Sprung();
                }
   
            }
           
           
   
            public void keyReleased(KeyEvent e){
                gedrueckteTaste = e.getKeyCode();
                if(gedrueckteTaste == KeyEvent.VK_LEFT || gedrueckteTaste == KeyEvent.VK_RIGHT){
                    background_posX = 0;
                }
            }
           
           
           
            //Springen Methode
            public void Sprung(){
                Springen SprungAnimation = new Springen();
                SprungAnimation.start();
            }
           
        }
        /*****************************************************************************************************************************************************/

    
}//Klasse Spiel ende




Die Blockklasse habe ich ja schonmal gepostet. Coin_score wird ansonsten nirgendswo aufgerufen.
Ich hoffe das du mir weiter helfen kannst! :)
 

Meniskusschaden

Top Contributor
Aha, der Code befindet sich also in der paint()-Methode. In der actionPerformed-Methode der Klasse Spiel wird repaint() aufgeruden. Ich sehe allerdings nicht, dass ein Spiel-Objekt irgendwo als Listener registriert wurde. Passiert das ausserhalb der Klasse, beispielsweise in der main-Methode einer Start-Klasse? Ich würde in der actionPerformed und/oder paint-Methode mal testweise bei jedem Aufruf etwas auf die Konsole ausgeben lassen. Vielleicht wird die Methode viel öfter aufgerufen, als du denkst.
 

F4ckHanoi

Mitglied
Also bei der actionPerformed Methode wird es ständig aufgerufen, es ist ja sozusagen eine alternative für ein "Update Methode". In der Paint Methode wird es aufgerufen, sobald ich den Block berühre. Jetzt habe ich das hier als Abfrage:

Java:
if(block[0].Coin() == true){
                coin_score++;
                f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                Block.coin = false;
                System.out.println("Block Kollision mit in der PAINT Methode");
            }

Ich habe keine extra boolean Variable. Ich habe bei der Block Klasse die boolean Variable auf static gesetzt und hier nachdem die Punkte gezählt worden sind etc. wir es auf false gesetzt.

Nun zählt es nicht mehr unendlich lang sondern nur noch solange ich den Block berühre. Also ich berühre den Block z.B 1 - 1,5 Sekunden lang und bis kein Kollision mehr stattfindet wird es hochgezählt.

Aber ich möchte das es nur um 1 erhöht, egal wie lange ich den Block berührte...
 

Bitfehler

Bekanntes Mitglied
Code:
Wenn
   Kollisionsabfrage gleich true und Block.coin gleich false
dann
   setze Block.Coin = true und erhöhe Punktezähler
sonst
    tue nichts

Das dargestellte Vorgehen sollte dafür sorgen, dass nur die erste Kollision zu einer Erhöhung des Punktestandes führt. Alle weiteren nicht, da coin gleich true
 

Meniskusschaden

Top Contributor
Du brauchst eine Möglichkeit, zu erkennen ob es sich beim mehrfachen Aufruf um dieselbe oder eine neue Kollision handelt. Du speicherst im Block-Objekt in der Variablen coin ja sowieso, ob der Block sich gerade in einer Kollision befindet oder nicht. Dort könntest du in der Kollisionsabfrage ja prüfen, ob sich coin gegenüber dem vorigen Aufruf ändert und nur beim Übergang false->true eine Zählung anstossen. Der Block könnte z.B. ein CollisionDetectedEvent auslösen, dass in Spiel verarbeitet wird. Falls gleichzeitig mehrere Kollisionen mit unterschiedlichen Objekten möglich sein sollen, muß man das natürlich etwas verfeinern.

Generell würde ich überlegen, ob die paint-Methode nicht etwas überfrachtet ist. Die ist ja eigentlich zum Zeichnen gedacht. Da würde ich möglichst nicht so viel Logik rein packen.
 
K

kneitzel

Gast
Ich würde Spiellogik von der Anzeige trennen. Ich habe bei einem Spiel in der Vergangenheit in der Paint einfach nur ein Bild gezeigt und das dann in der Spiellogik immer angepasst. (Also ein Bild, das gerade gemalt werden könnte, ein Bild, das als nächstes gemalt werden soll, ein Bild, das gerade von der Logik erstellt wird - gesteuert über eine synchronized Klasse) um dann eben bei mehrfachem malen des Fensters nur eine minimale Logik ausführen zu müssen. Dies kann z.B. bei Verdeckungen des Fensters oder bei Verschiebungen massiv vorkommen)

Aber das ist nur meine pers. Sicht und bezüglich Spieleentwicklung bin ich auch kein großer Experte.
 

F4ckHanoi

Mitglied
Ich danke euch seeehr, dass Ihr euch die Zeit nimmt und mir hilft!

So langsam verstehe ich was gemeint ist, jedoch hatte ich das Problem auch bei der Kollisionsabfrage. Ich weiß was gemacht werden muss und die Logik habe ich auch verstanden. Jedoch ist es für mich gerade schwer, die ganze Logik zu integrieren. Also ich kann es nicht im Code umsetzen. Nun sitze ich schon stunden daran und bekomme eine billige Punktezähler nicht hin. So etwas ist echt unmotivierend. Alles läuft prima, die Datenbanken ist in Ordnung, die allgemeine Logik stimmt etc. Mir fehlt eigentlich nur noch der Punktezähler, damit würde ich auch weiter arbeiten können, da ich auch Achievements etc. reinbauen werde.


Könnt Ihr mir bitte Codeverbesserungen anbieten?
Das wäre echt sehr hilfreich und da könnte ich es auch besser vestehen.
 
K

kneitzel

Gast
Also es ist ja kein Problem von der Codequalität sondern es muss die Logik verbessert werden. (Mit sauberem Code geht es einfacher, aber das ist hier erst einmal nebensächlich.)

Was ich bisher verstanden habe, dann hast Du folgende Logik:
Check auf Kollision -> Variable "KollisionVorhanden" wird gesetzt.
Check "KollisionVorhanden" -> Score erhöhen.

Da diese Logik aber immer wieder neu aufgerufen wird, wird eine Kollision mehrfach gezählt. Daher muss die Kollision erweitert werden:
Check auf Kollision -> Ja: Variable "KollisionVorhanden" wird gesetzt. Nein: KollisionGezählt wird gelöscht.
Check "KollisionVorhanden" und nicht "KollisionGezählt" -> Score erhöhen, KollisionGezählt wird gesetzt.

Nun wird jede Kollision nur noch einmal gezählt. Problematisch könnte es erst werden, wenn du viele Objekte hast. Da wäre dann evtl. in der Spiellogik gut, eine Art "Objektwert" einzuführen. Dann wäre die Logik:
- Check auf Kollision -> Score wird um Wert des Objekts erhöht und Objektwert wird auf 0 gesetzt.
Beim zweiten Durchlauf, hat man immer noch die Kollision, aber es gibt keine Punkte mehr, da Wert = 0 ist.

Nur mal, um ein paar Ideen zu nennen.
 

F4ckHanoi

Mitglied
Vielen dank erstmal.

Gerade bin ich nicht Zuhause. Bin etwas frische Luft schnappen gegangen und werde erst später zuhause daran weiter arbeiten. Ich werde versuchen die Logik umzusetzen, die du aufgeschrieben hast.

Ich werde euch dann weiterhin informieren, ob es geklappt hat oder nicht.
 

F4ckHanoi

Mitglied
@kneitzel

Ich danke dir vielmals. Nun hat es geklappt aber es wird nur einmal um 1 erhöht. Vielleicht hat man es schon gesehen, dass ich nur EIN Objekt habe. Nachdem der Block die Grenze des Frames verlässt, wird die X-Position zufällig festgelegt.

Erstmal zum Code (wie es momentan nur einmal um 1 erhöht):

Java:
if(block[0].Coin() == true){
                //f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                scoreKontrolle = true;
            }
            if(block[0].Coin() == false){
                kollisionZaehler = false;
            }
         
            if(scoreKontrolle && !kollisionZaehler){
                coin_score++;
                kollisionZaehler = true;
            }


Pseudocode:

Code:
Wiederholend{

Wenn
            die Grenze verlassen wird, mache die Variable scoreKontrolle und kollisionZaehler rückgängig.

Wenn
             nochmal ein Kollision stattfindet, erhöhe den Punktestand um 1.

}


Das wäre zumindest meine Idee. Konnte es aber wieder nicht umsetzen...
 

Meniskusschaden

Top Contributor
So ungefähr könnte es funktionieren:

Ich würde alle direkten lesenden und schreibenden Zugriffe auf das Attribut Block.coin entfernen und es am besten als private oder protected deklarieren. Dann würde ich in der Methode Block.kollisionsabfrage je nach Ergebnis der Kollisionsprüfung entwedersetCoin(true); oder setCoin(false); aufrufen. Ausserdem würde ich den Rückgabetyp von boolean auf void ändern. Die Methode setCoin würde ich wie folgt implemetieren:
Java:
private void setCoin(boolean isCollided) {
    if (isCollided && !coin) {
        spiel.collisionDetected();
    }
    coin = b;
}
Dazu benötigst du in Block natürlich eine Klassenvariable Spiel spiel;, die du beim Erzeugen eines Blocks entsprechend setzen musst.

In der Spielklasse benötigst du dann noch folgende Methode:
Java:
public void collisionDetected() {
    coin_score++;
}
 
K

kneitzel

Gast
Deine If-Anweisung ist aber auch noch falsch. Das innere if wird nie wahr sein, denn wäre die Bedingung wahr, dann würde die äußere if Schleife ja unwahr sein. Statt dem inneren if müsste das äußere if ein else bekommen.
 

Meniskusschaden

Top Contributor
Da war noch ein Fehler in meinem Vorschlag. Korrigierte Version:

Java:
private void setCoin(boolean isCollided) {
    if (isCollided && !coin) {
        spiel.collisionDetected();
    }
    coin = isCollided;
}
 

Meniskusschaden

Top Contributor
@kneitzel:
Deine If-Anweisung ist aber auch noch falsch. Das innere if wird nie wahr sein, denn wäre die Bedingung wahr, dann würde die äußere if Schleife ja unwahr sein. Statt dem inneren if müsste das äußere if ein else bekommen.
Das bezieht sich doch auf folgenden Code, oder?
Java:
if(block[0].Coin() == true){
                //f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                scoreKontrolle = true;
            }
            if(block[0].Coin() == false){
                kollisionZaehler = false;
            }
        
            if(scoreKontrolle && !kollisionZaehler){
                coin_score++;
                kollisionZaehler = true;
            }

Ich glaube, da gibt es gar keine inneren und äußeren Bedingungen. Das ist nur falsch eingerückt.
 

F4ckHanoi

Mitglied
Ich liebe euch <3 #nohomo xD

Ich habs noch nicht ausgetestet, weil ich gerade andere wichtige Probleme bzw. bugs habe. Sobald ich diese gereinigt habe, werde ich es mal versuchen.

Wie immer informiere ich euch dann wieder..
 

F4ckHanoi

Mitglied
@Meniskusschaden

Ich habs ausprobiert, leider hat es bei mir nicht geklappt. Die Abgabe ist am Donnerstag und ich bin soweit mit allem fertig. Mir fehlt nur noch der Punktezähler. Dadurch werde ich auch vieles wie z.B Achievements einbauen.

Ich hoffe auf weitere Hilfe...!
Vielen dank!!!!
 

Meniskusschaden

Top Contributor
Dadurch werde ich auch vieles wie z.B Achievements einbauen.
Ist das eigentlich Bestandteil der Aufgabenstellung? Ansonsten würde ich die verbleibende Zeit lieber nutzen, um den Code noch mal hinsichtlich Lesbarkeit und Organisation zu überprüfen und zu verbessern. Das dürfte vermutlich für den Lerneffekt und auch für die Benotung mehr bringen. kneitzel hat ja in Post #18 schon einiges dazu vorgeschlagen.
 

Meniskusschaden

Top Contributor
Also aktuell wird es nur EINMAL um 1 erhöht und dann nicht mehr.
Ich vermute, dass du in der Methode Block.kollisionsabfrage nicht setCoin(false) aufrufst, falls die Abfrage keine Kollision feststellt. Ohne den aktuellen Code zu sehen ist das aber nur geraten. Das ist deine Kollisionsabfrage aus Post #6:
Java:
public boolean kollisionsabfrage(int x_block, int y_block,int x_figur,int y_figur){
        if( x_figur >= x_block && y_figur >= y_block && y_figur <= y_block + HEIGHT){
            if(x_figur <= x_block+WIDTH){
                coin = true;
                return true;
            }
        }else{
            return false;
        }
        return false;
     
    }
Meines Erachtens ist die Verschachtelung der if-Bedingung nicht nötig. Dadurch wird es etwas unübersichtlich. Wenn man das auflöst und meine Vorschläge aus Post #23 bzw. #25 einbaut, könnte es so aussehen:
Java:
public void kollisionsabfrage(int x_block, int y_block,int x_figur,int y_figur){
    if( x_figur >= x_block && y_figur >= y_block && y_figur <= y_block + HEIGHT && x_figur <= x_block+WIDTH){
        setCoin(true);
    }else{
        setCoin(false);
    }
}

Oder noch etwas kürzer:
Java:
public void kollisionsabfrage(int x_block, int y_block,int x_figur,int y_figur){
    setCoin( x_figur >= x_block && y_figur >= y_block && y_figur <= y_block + HEIGHT && x_figur <= x_block+WIDTH);
}
 

F4ckHanoi

Mitglied
Ich habe es so übernommen und habe tausende von Fehlermeldungen bekommen.

Code:
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5219)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1572)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1495)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1265)
    at javax.swing.JComponent._paintImmediately(JComponent.java:5167)
    at javax.swing.JComponent.paintImmediately(JComponent.java:4978)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:824)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:807)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:807)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:782)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:731)
    at javax.swing.RepaintManager.access$1300(RepaintManager.java:64)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1720)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:749)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:702)
    at java.awt.EventQueue$3.run(EventQueue.java:696)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:719)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Den rest möchte ich jetzt nicht kopieren weil es einfach zu lang ist. Da sind jede menge NullPointer Fehlermeldungen dabei..
 

Meniskusschaden

Top Contributor
Also, mit dem Ausschnitt kann man jetzt nicht so viel anfangen. Wichtig wären die ersten Zeilen, damit man die Exception sieht und die Zeilen, die sich auf deine eigenen Klassen beziehen, sowie der zur Zeilennummer gehörende Quelltext.
 

F4ckHanoi

Mitglied
Also ich habe es jetzt hinbekommen, dass es sich um 1 erhöht. Das macht es jetzt jedes mal wenn ich eine Kollision mit dem Block habe. Ich möchte aber, dass wenn ich den Block nur EINMAL berührte es um 1 erhöht wird und auch wenn ich den Block danach nochmal berühre, das es dann nicht mehr hochzählt. Erst wenn der Block die Grenze verlassen hat, sollen die Variablen sich reinizialisieren und das ganze soll wieder von vorn anfangen.

Das ist die aktuelle Lösung:
Java:
if(block[0].Coin() == true){
                    //f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
                    scoreKontrolle = true;
               
                }else{
                    kollisionZaehler = false;
                }

           
                if(scoreKontrolle && !kollisionZaehler){
                    coin_score++;
                    Block.coin = false;
                    kollisionZaehler = true;
                }


und wenn man den Key loslässt:
Java:
public void keyReleased(KeyEvent e){
                gedrueckteTaste = e.getKeyCode();
                if(gedrueckteTaste == KeyEvent.VK_LEFT || gedrueckteTaste == KeyEvent.VK_RIGHT){
                    background_posX = 0;
                }
                if(gedrueckteTaste == KeyEvent.VK_SPACE){
                    Block.coin = false;
                    scoreKontrolle = false;
                    kollisionZaehler = false;
                }
            }


Pseudocode:
Code:
Block Kollision --> Erhöhe Punkt um 1.
Wenn Block wieder berührt wird --> Zähle nicht hoch.
Wenn Block die Grenze verlässt --> Reinizialisiere Variablen
 
K

kneitzel

Gast
Die Variable, die ein erneutes Zählen verhindert, darfst du dann erst zurücksetzen, wenn der Block die Grenze verlassen hat. (Sprich das kollisionZaehler=false muss an eine andere Stelle wandern.)
 

F4ckHanoi

Mitglied
Nein, wenn es an eine andere Stelle wandert, dann fängt wieder das mit dem unendlichen Punktezählerei an. Ich habe noch bis 15:15 Zeit, dann erfolgt die Abgabe.
 
K

kneitzel

Gast
Also da die Theorie relativ einfach ist und dort erst einmal keine logischen Fehler zu finden sind, dürfte bei der Implementation etwas falsch sein. Aber ohne den exakten Code, bei dem Du es versucht hast, es umzusetzen, werden wir Dir nicht helfen können.

Die Theorie noch einmal in kurzen Worten:
- Du fügst ein Flag ein. Wenn dieses Flag gesetzt ist, dann werden keine Punkte gezählt. Dieses Flag ist am Anfang nicht gesetzt.
- Wenn nun ein Event auftritt, dass ein Punkt gezählt werden könnte, prüfst Du auch das Flag. Wenn es gesetzt ist, wird kein Punkt gezählt. Ist es noch nicht gesetzt, setzt Du das Flag und zählst den Punkt.
- Wenn es soweit ist, dass wieder Punkte gezählt werden sollen, dann setzt Du das Flag wieder zurück.

Also da kann nicht unendlich gezählt werden. Das deutet schon klar auf einen Implementationsfehler hin. Mal mit dem Debugger geschaut, was schief läuft?

Konrad
 

F4ckHanoi

Mitglied
Hier ist nochmal alles, was mit Punkte zu tun hat:

Java:
static int coin_score = 0;

//Wenn Block berührt wird, erhält man Punkte
        if(block[0].Coin() == true){
            scoreKontrolle = true;
            f2.drawImage(usedBlock, block[0].getX_Block()-getXBild(), block[0].getY_Block(), block[0].getWidth(), block[0].getHeight(), null);
        }else{
            kollisionZaehler = false;
        }
           
        if(scoreKontrolle && !kollisionZaehler){
            coin_score++;
            Block.coin = false;
            kollisionZaehler = true;
        }


public void keyReleased(KeyEvent e){
                gedrueckteTaste = e.getKeyCode();
                if(gedrueckteTaste == KeyEvent.VK_LEFT || gedrueckteTaste == KeyEvent.VK_RIGHT){
                    background_posX = 0;
                }
                if(gedrueckteTaste == KeyEvent.VK_SPACE){
                    Block.coin = false;
                    scoreKontrolle = false;
                    kollisionZaehler = false;
                }
            }



und die Block Klasse:
Java:
package HNGProduction;


public class Block {

    int X;
    int Y;
    int WIDTH;
    int HEIGHT;
    public static boolean coin = false;
   
   
    /*
     * Konstruktor
     */
    public Block(int x, int y, int width, int height){
        this.X = x;
        this.Y = y;
        this.WIDTH = width;
        this.HEIGHT = height;   
    }
   
   
    /*
     * Kollision
     */
    public boolean kollisionsabfrage(int x_block, int y_block,int x_figur,int y_figur){
        if( x_figur + WIDTH + 12 >= x_block && y_figur >= y_block && y_figur <= y_block + HEIGHT && x_figur <= x_block+WIDTH){
                coin = true;
                return true;
        }else{
            return false;
        }
       
    }
   
   
   
   
   
    /*
     *Zurückliefern von Variablen
     */
   
    public int getX_Block(){
        return this.X;
    }
   
    public void setX_Block(int x){
        this.X = x;
    }
   
    public int getY_Block(){
        return this.Y;
    }
   
    public int getWidth(){
        return this.WIDTH;
    }
   
    public int getHeight(){
        return this.HEIGHT;
    }
   
    public boolean Coin(){
        return this.coin;
    }
   
}
 
K

kneitzel

Gast
Also ich finde Deinen Code recht schwer zu lesen. Die Bedeutung der Variablen ist nicht aus den Namen erkennbar. Bestes Beispiel ist eine boolean Variable, die Zaehler heisst.

Und in der Klasse Block fällt auf, dass Du da eine statische Variable hast, deren Sinn nicht ganz nachvollziehbar ist. Diese Variable coin scheint in Wirklichkeit ein Kollisions-Flag zu sein. Also sowas wie ein istKollidiert. Und der Zugriff darauf ist teilweise direkt und teilweise über Funktionen. Hier solltest Du sauber arbeiten und es einheitlich machen. Und vor allem ist es extrem verwirrend, wenn Du eine statische Variable in einem Getter der Instanz zurück gibst.

Hier würde ich also ein Refactoring vorschlagen, so dass die Logik besser erkennbar wird, die Du umsetzt. Wenn coin ein "istKollidiert" Flag ist, ist die Frage, wieso Du dies zurück setzen kannst, wenn die Leertaste losgelassen wird.

Aus den Codeteilen erschliesst sich mir jetzt nicht das eigentliche Problem. Ein schnelles endlos hochzählen der Punkte würde ich jetzt hier nicht sehen, aber evtl. bei schnellem Drücken der Leertaste? Ist das das Fehlerbild?

Konrad
 

Meniskusschaden

Top Contributor
Die Variable, die ein erneutes Zählen verhindert, darfst du dann erst zurücksetzen, wenn der Block die Grenze verlassen hat. (Sprich das kollisionZaehler=false muss an eine andere Stelle wandern.)
Nein, wenn es an eine andere Stelle wandert, dann fängt wieder das mit dem unendlichen Punktezählerei an. Ich habe noch bis 15:15 Zeit, dann erfolgt die Abgabe.
Es leuchtet mir nicht ein, warum die Aussage von kneitzel falsch sein soll. Wenn die "unendliche Punktezählerei" bereits jetzt erfolgreich unterbunden wird, indem das Zählen erst durch "gelegentliches" Rücksetzen der Variablen wieder erlaubt wird, muß es doch bei "noch seltenerem" Rücksetzen erst recht funktionieren. Also muß das Rücksetzen dorthin verschoben werden, wo das "Verlassen des Bereichs" (was immer das heissen mag) erkannt wird.
 

Blender3D

Top Contributor
Also auf den 1ten Blick. Du hast Dir eine Klasse Block gebaut, die die Position X,Y und die Weite und Höhe des Blocks beinhaltet. Ich schließe daraus: Du möchtest verschiedene Blöcke an verschiedenen Positionen darstellen. So weit so gut. Aber warum machst Du Deine Variable coin static. --> Wenn Du die auf True setzt wird sie für alle anderen Blöcke auch auf True gesetzt.
Eine Klassenvariable ( static ) gilt immer für die gesamt Klasse ( Block ) und nicht für die einzelnen generierten Objekt.

Code:
Block blockA = new Block( 10,20, 10,10 );
Block blockB = new Block( 30,30, 10,10 );

..
// warning von Eclipse  -->  Block.coin = true
blockA.coin = true;
blockB.coin = false;
System.out.println( blockA.coin );
...
..

Auch die Funktion kollisionsabfrage sollte eigentlich eine static Funktion sein so wie du Sie gebaut hast.
Weil Du innerhalb nicht auf Objektvariablen zugreifst.

/*
* Kollision
*/

public boolean kollisionsabfrage(int x_block, int y_block,int x_figur,int y_figur){
if( x_figur + WIDTH + 12 >= x_block && y_figur >= y_block && y_figur <= y_block + HEIGHT && x_figur <= x_block+WIDTH){
coin = true;
return true;
}else{
return false;
}

}
 

Blender3D

Top Contributor
Sinnvoll wäre es so..
Code:
public class Block {

     int X;
     int Y;
     int WIDTH;
     int HEIGHT;
     boolean coin = false;
     ..
     public boolean getCoin(){ return coin; }
     public void setCoin( boolean ok ){ coin = ok }
     public boolean kollisionsabfrage( int x_figur, int y_figur, int w_figur, int  h_figur ){
  ..
}
 

Neue Themen


Oben