Spielball bewegt sich nicht richtig, prallt falsch ab

Alex2013

Bekanntes Mitglied
hey leute,

ich habe versucht mal ein kleines pong spiel zu schreiben.
Soweit passt auch fast alles. Aber der Ball prallt am oberen Rand nicht richtig ab (auf höhe des schlägers). Am linken rand mit weitem Abstand und am unteren Rand erst, wenn er verschwunden ist.

Ich habe schon einige Varianten in den Klassen ausprobiert. Ich kann den Fehler aber leider nicht ausmerzen.

Ich hoffe ihr habt einen Tipp, wo ich was falsch gemacht habe.
Hier die in frage kommenden Klassen:
PingPong:
Java:
public class Pingpong extends JComponent implements ActionListener, MouseMotionListener, KeyListener
{
    //Anfangs X und Y Position
    public static int ballX=0;
    public static int ballY=0;
   
    //X und Y Geschwindigkeit
    public static int ballXSpeed=1;
    public static int ballYSpeed=-1;
   
    //Anfangsposition des Schlägers
    static int schlaegerSpielerX=0;
    static int schlaegerGegnerX=0;
   
    //Höhe und breite
    static int hoehe=800;
    static int breite=1200;
    //Schrift für die Punkte
    static Font font=new Font("Arial", Font.PLAIN, 20);
    static int spielerpoints=0;
    static int gegnerpoint=0;
   
   
    public Pingpong() {

        JFrame frame=new JFrame("Ping Pong");
        Draw draw=new Draw();
        Move move=new Move();
        Kollision kollision=new Kollision();
        Gegnermove gm=new Gegnermove();
        frame.add(draw);
        frame.addMouseMotionListener(this);
        frame.setSize(1200, 800);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   
    }

//Hier sind noch eininge Methoden der Listener vorhanden. Diese habe ich jetzt weggelassen, da sie nicht relevant sind.

Move:
Java:
import java.util.Timer;
import java.util.TimerTask;


public class Move {
Timer timer;
    public Move() {
    timer=new Timer();
    TimerTask TimerTask;
    timer.scheduleAtFixedRate(TimerTask=new TimerTask() {
       
        @Override
        public void run() {

            //Festlegen der Geschwindigkeit in x und y richtung
            Pingpong.ballX=Pingpong.ballX+Pingpong.ballXSpeed*2;
            Pingpong.ballY=Pingpong.ballY+Pingpong.ballYSpeed*2;
                       
            //wenn die position des balls an den rechten bildschirmrand schlägt springt er zurück
            if(Pingpong.ballX>=(1170))
            {
                Pingpong.ballXSpeed=-1;
            }
            //wenn die position des balls kleiner der des linken Randes ist
            if(Pingpong.ballX<=0)
            {
                Pingpong.ballXSpeed=1;
            }
            //wenn die position des balls größer als des Frames ist
            if(Pingpong.ballY>=(Pingpong.hoehe-15))//770)
            {
                Pingpong.ballYSpeed=-1;
            }
        }
    }, 0, 5);
    }
}

Kollision:
Java:
import java.util.Timer;
import java.util.TimerTask;


public class Kollision {
Timer timer;
    public Kollision() {
    timer=new Timer();
    TimerTask TimerTask;
    timer.scheduleAtFixedRate(TimerTask=new TimerTask() {
        @Override
        public void run() {
           
            if(Pingpong.ballY<=(Pingpong.hoehe-Pingpong.hoehe)+30)
            {
                Pingpong.ballYSpeed=1;
                Pingpong.spielerpoints+=1;
            }
            if(Pingpong.ballY>=(Pingpong.hoehe-30))
            {
                Pingpong.ballYSpeed=-1;
                Pingpong.gegnerpoint+=1;
            }
            if(Pingpong.ballX<=(Pingpong.breite-Pingpong.breite)+30)
            {
                Pingpong.ballXSpeed=1;
            }
            if(Pingpong.ballX>=(Pingpong.breite)-30)
            {
                Pingpong.ballXSpeed=-1;
            }
               
           
            //Der 3 Fall wurde verändert, damit der ball vom schläger und nicht mitten im Bildschirm abprallt
            //wenn die horizontale des balls größer ist als die länge des Spieler schlägers und
            //wenn die hörizontale des balls kleiner ist als die Länge des spieler schläger +150 und
            //wenn die vertikale des balls größer als der obere Rand ist
            if(Pingpong.ballX>=Pingpong.schlaegerSpielerX&&Pingpong.ballX<=Pingpong.schlaegerSpielerX-150&&Pingpong.ballY>=20)
            {
                //dann wird die geschwindigkeit positiv;
                Pingpong.ballYSpeed=1;   
            }

        }
       
    }, 0, 6);
    }

}

und gegnermove:
Java:
import java.util.Timer;
import java.util.TimerTask;


public class Gegnermove {
Timer timer;
    public Gegnermove() {
    timer=new Timer();
    TimerTask TimerTask;
    timer.scheduleAtFixedRate(TimerTask=new TimerTask() {
        @Override
        public void run() {
           
            //Gegnermove
            //wenn der ball in der oberen Hälfte ist und er in der horizontalen kleiner ist als der Gegner schläger +75
            if(Pingpong.ballY<Pingpong.hoehe/2&&Pingpong.ballX<=Pingpong.schlaegerGegnerX+75)
            {//und wenn der ball in der oberen hälfte in der horizontalen kleiner als die hälfte der breite ist
                //und wenn der gegner schläger in der horiz. größer als die hälfte der breite ist
                if(Pingpong.ballX<=Pingpong.breite/2 && Pingpong.schlaegerGegnerX>=Pingpong.breite/2)
                {//dann wandert der gegnerschläger nach links
                    Pingpong.schlaegerGegnerX-=1;
                }
            }
            //wenn der ball in der horizontalen größer als die breite des Spielfelds ist
            //und der gegner schläger kleiner als die hälfte des felds
            if(Pingpong.ballX>=Pingpong.breite/2 && Pingpong.schlaegerGegnerX<=Pingpong.breite/2)
                {//dann wandert der gegnerschläger nach rechts
                    Pingpong.schlaegerGegnerX+=1;
                }

//            //wenn die horizontale des balls größer gleich das ende des Gegner Schlägers ist
//            if(Pingpong.ballX>=Pingpong.schlaegerGegnerX+75)
//            {
//                Pingpong.schlaegerGegnerX=5;
//            }
//            //wenn die horizontale des balls kleiner oder gleich der des gegner schlägers ist
//            if(Pingpong.ballX<=Pingpong.schlaegerGegnerX+75)
//            {
//                Pingpong.schlaegerGegnerX=-5;
//            }
//            //Wenn der ball am oberen Rand anschlägt
//            if(Pingpong.ballY<=(Pingpong.hoehe-Pingpong.hoehe)+30)
//            {
//                //fliegt er zurück
//                Pingpong.ballYSpeed=1;
//                //und der spieler bekommt einen punkt
//                Pingpong.spielerpoints+=1;
//            }
//       
//
////        //Wenn der Ball in der unteren Hälfte ist
//        if(Pingpong.ballY>=Pingpong.hoehe/2)
//        //wenn der ball am unteren rand anschlägt
//        if(Pingpong.ballY>=(Pingpong.hoehe-30))//770)
//        {
//            //fliegt er zurück
//            Pingpong.ballYSpeed=-1;
//            //und der gegner bekommt einen Punkt
//            Pingpong.gegnerpoint+=1;
//        }
           
        }
    }, 0, 5);
    }

}

Ich hoffe mir kann jemand die schwachstelle aufzeigen. anschließend würde ich dann mit dem abprallen am unteren und oberen balken weiter machen.
 
So den ersten Teil habe ich jetzt. Die Punkte werden gezählt und die Bewegungen laufen auch recht sauber.

Aber der Ball reagiert noch nicht auf die Kollision mit den jeweiligen Balken und springt dann zurück...

Hat hier zufällig jemand einen Tipp? @Meniskusschaden oder @Robat wisst ihr zufällig weiter?

Mein aktueller Code für die Kollisionsklasse ist wie folgt:
Java:
import java.util.Timer;
import java.util.TimerTask;


public class Kollision {
Timer timer;
    public Kollision() {
    timer=new Timer();
    TimerTask TimerTask;
    timer.scheduleAtFixedRate(TimerTask=new TimerTask() {
        @Override
        public void run() {
           
            if(Variablen.ballX+30>=Variablen.breite)
            {
                Variablen.ballXSpeed=-1;
            }
            if(Variablen.ballX+15<=0)
            {
                Variablen.ballXSpeed=1;
            }
            if(Variablen.ballY+50>=Variablen.hoehe)
            {
               
                Variablen.ballYSpeed=-1;Variablen.gegnerpoint+=1;
            }
            if(Variablen.ballY+15<=0)
            {
           
                Variablen.ballYSpeed=1;    Variablen.spielerpoints+=1;
            }
            if(Variablen.ballX==Variablen.schlaegerSpielerX&&Variablen.ballY==Variablen.schlaegerSpielerY&&Variablen.ballX<=Variablen.schlaegerSpielerX+150&&Variablen.ballY==Variablen.hoehe)
            {
                Variablen.ballYSpeed=-1;
            }
            if(Variablen.ballX==Variablen.schlaegerGegnerX&&Variablen.ballY==Variablen.schlaegerGegnerX&&Variablen.ballX<=Variablen.schlaegerGegnerX+150&&Variablen.ballY==0)
            {
                Variablen.ballYSpeed=1;
            }
               
        }
       
    }, 0, 6);
    }

}
 
Wie hast du denn dein Spieler / Schläger aufgebaut?
Würde dir hjier zu der Rect Klasse raten.
Dann kannst du die Kollision recht einfach aufbauen:

Java:
    publicvoid checkCollision(){
        if(game.getPanel().getPlayer().getBounds().intersects(ball.getBounds()) || game.getPanel().getEnemyPlayer().getBounds().intersects(ball.getBounds()))
            xa =-xa;
    }
 
Ich habe das gesamte etwas einfacher gehalten. Ich hoffe ich muss den gesamten Code nicht umschreiben, wenn ich mit der Rect Klasse arbeite.
Mein Code siehe wie folgt:
Java:
protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d=(Graphics2D) g;
        //Rendern der Grafiken
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
       
        //Erstellen des Spielfelds
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);
       
        //Erstellen des Balls
        g.setColor(Color.RED);
        g.fillOval(ballposX, ballposY, 30, 30);

        //Erstellen der Punkte
        g.setColor(Color.BLACK);
        g.setFont(schrift);
        g.drawString(""+spielerpunkte, 40, height/2);
       
        //Erstellen des Spielerschlägers
        g.setColor(Color.BLACK);
        g.fillRect(schlaegerSpielerX,schlaegerSpielerY-40 , 150, 20);
        repaint();
    }

Ich werde mal sehen wie ich das umsetze
 
Ach soo.. ein bisschen sehr vereinfacht 😛 Für das nächste mal würde ich dir raten ein eigenes Objekt für deinen Ball, Spieler und Gegner zu machen, mit x,y Koords, ySpeed, xSpeed, einer update Methode, einer checkCollisionMethode und einer paint Methode. Das macht vieles einfacher.

if(Variablen.ballX==Variablen.schlaegerSpielerX&&Variablen.ballY==Variablen.schlaegerSpielerY&&Variablen.ballX<=Variablen.schlaegerSpielerX+150&&Variablen.ballY==Variablen.hoehe)
{
Variablen.ballYSpeed=-1;
}
if(Variablen.ballX==Variablen.schlaegerGegnerX&&Variablen.ballY==Variablen.schlaegerGegnerX&&Variablen.ballX<=Variablen.schlaegerGegnerX+150&&Variablen.ballY==0)
{
Variablen.ballYSpeed=1;
}
Wenn ich das gerade richtig überflogen habe, dann ist deine Bedingung hier falsch.
Was du momentan prüfst ist in Worten ausgedrückt folgendes:

Code:
Wenn ( (der Ball die selbe X  Koordinate wie der Spieler hat) [B]UND [/B](der Ball die selbe Y Koordinate wie der Spieler hat) [B]und [/B](der Ball kleiner gleich der X Koordinate des Spielers ) [B]und [/B](der Ball gleichder Höhe) )

Was du eigentlich nur prüfen musst ist in Worten ausgedrückt folgendes:

Code:
Wenn ( (der Ball die selbe X Koordinate des Spielers hat) && (der Ball zwischen der oberen Y Koord. des Spielers und der unteren Y Koord. des Spielers ) ) dann..

Dabei könntest du die zweite BEdingung durch y + spieler.height / 2 und y - spieler.height/2 darstellen.

Gruß
Robert
 
Hey Robat, vielen Dank für deine schnelle Antwort 🙂
das werde ich gleich auch noch ausprobieren.

Ich habe jetzt folgenden Code. Mit diesem ist sowohl das Abprallen an allen Seiten als auch das Abprallen vom Schläger gesichert.
Was sagst du dazu?(Ist vlt. etwas lang aber klappt 🙂 ):
Java:
//Anstoß des Balls linker Rand
        if(PingPongEinzelspieler.ballposX<=0)
        {
            PingPongEinzelspieler.geschwindigkeitX=10;
        }
        //Anstoß des Balls an der linken Seite des Schlägers und linke seite des balls ist kleiner als die Länge des Schlägers und die untere Seite des Balls ist größer als die höhe des schlägers
        if(PingPongEinzelspieler.ballposX>=PingPongEinzelspieler.schlaegerSpielerX&&PingPongEinzelspieler.ballposX<=PingPongEinzelspieler.schlaegerSpielerX+150&&PingPongEinzelspieler.ballposY+30>=(PingPongEinzelspieler.height-60))
        {
            PingPongEinzelspieler.geschwindigkeitY=-10;
        }
        //Anstoß des Balls am rechten Rand
        if(PingPongEinzelspieler.ballposX+30>=PingPongEinzelspieler.width)
        {
            PingPongEinzelspieler.geschwindigkeitX=-10;
        }
        //Anstoß des Balls oberer Rand
        if(PingPongEinzelspieler.ballposY<=0)
        {
            PingPongEinzelspieler.geschwindigkeitY=10;
        }
        //Anstoß des Balls unterer Rand
        if(PingPongEinzelspieler.ballposY+50>=PingPongEinzelspieler.height)
        {
            PingPongEinzelspieler.geschwindigkeitY=-10;
        }
 
Ist vlt. etwas lang aber klappt 🙂

Das ist der springende Punkt 😛 - es gibt einen unterschied zwischen "so programmieren, dass es funktioniert" und "so programmieren, dass es funktioniert und performant" ist.

“Measuring programming progress by lines of code is like measuring aircraft building progress by weight.”
— Bill Gates

aber das soll ein anderes Thema sein 🙂

Wie gesagt, so wie dein Code aufgebaut ist wird das schon funktionieren.

Nimm dir vielleicht mal als nächste die Aufgabe ein Ping Pong Spiel mit versch. Klassen und Objekten zu schreiben, MVC zu trennen etc.
Dazu gehört auch die Namenskonventionen einzuahlten (das Variablennamen immer klein und in CammelCase geschrieben werden). Ist aber eher Off-Topic 😛
 

Zurück
Oben