Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Java] Pong

Pagina: 1
Acties:
  • 746 views

  • GLaDOS
  • Registratie: December 2012
  • Laatst online: 15:54
Dag Tweakers,

ben voor school-projectje bezig het spel pong te maken. Ik heb een aantal tutorials gekeken/geprobeerd op het internet. Omdat de meeste tutorials op het internet niet of slechts gedeeltelijk OO werken heb ik geprobeerd de informatie die ik hier uit kreeg te gebruiken in een OO-benadering. Tot zover heb ik 5 klassen, namelijk een Main, een Ball, myFrame, Paddle en AL.


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Random;


public class Ball implements Runnable {
    // globale variabelen
    int x, y, xDirection, yDirection;
    Rectangle ball;
    static Paddle p1 = new Paddle(15, 140, 1);
    static Paddle p2 = new Paddle(370, 140, 2);

    static int p1Score;
    static int p2Score;

    public Ball(int x, int y) {
        p1Score = p2Score = 0;
        this.x = x;
        this.y = y;
        // set ball moving randomly
        Random r = new Random();
        int rDir = r.nextInt(2);
        if (rDir == 0) {
            rDir--;
        }
        int yDir = r.nextInt(2);
        if (yDir == 0) {
            yDir--;
        }
        setXDirection(rDir);
        setYDirection(yDir);
        // maakt een ball;
        ball = new Rectangle(this.x, this.y, 10, 10);

    }

    public void setXDirection(int xdir) {
        xDirection = xdir;
    }

    public void setYDirection(int ydir) {
        yDirection = ydir;
    }

    public void paint(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(ball.x, ball.y, ball.width, ball.height);

    }

    public static void draw(Graphics g) {
        Ball.draw(g);
        myFrame.rerepaint();
    }


    public void run() {
        try {
            while (true) {
                move();
                Thread.sleep(7);
            }
        }

        catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }

}


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyListener;

import javax.swing.JFrame;

public class myFrame extends JFrame {
    Image dbImage;
    Graphics dbg;
    
    public myFrame() {
        setTitle("Pong");
        setSize(400,300);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        setBackground(Color.DARK_GRAY);
        addKeyListener((KeyListener) new AL());
    }
    public void paint(Graphics g) {
        dbImage = createImage(getWidth(), getHeight());
        dbg = dbImage.getGraphics();
        draw(dbg);
        g.drawImage( dbImage, 0,0, this);
        
    }
    public void rerepaint() {
        repaint();
    }
    public void draw (Graphics g) {
        Ball.draw(g);
        Ball.p1.draw(g);
        Ball.p2.draw(g);
        
        g.setColor(Color.WHITE);
        g.drawString("" + Ball.p1Score, 15, 50);
        g.drawString("" + Ball.p2Score, 270, 50);
        repaint();
        
    }

}


Als ik deze code run krijg ik een lijst met errors, vooral stack overflow errors

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problem: 
    Cannot make a static reference to the non-static method rerepaint() from the type myFrame

    at Ball.draw(Ball.java:54)
    at myFrame.draw(myFrame.java:32)
    at myFrame.paint(myFrame.java:24)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$700(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problem: 
    Cannot make a static reference to the non-static method rerepaint() from the type myFrame

    at Ball.draw(Ball.java:54)
    at myFrame.draw(myFrame.java:32)
    at myFrame.paint(myFrame.java:24)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$700(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)


Deze liggen aan de methode repaint() die wordt aangeroepen in de klasse ball. Ik heb ondervonden dat je deze methode alleen mag aanroepen in de klas met het frame. Ik heb hier geprobeerd omheen te werken door de methode rerepaint() te maken in klasse myFrame. Dit zorgde ook niet dat de errors gefixed werden en dat het programma ook maar enigszins werken werd.


Mijn voornaamste vraag is nu:
Hoe zorg ik dat ik repaint kan gebruiken in klasse Ball?

Eventueel andere suggesties die ten goede komen aan de code zijn uiteraard ook welkom!

[ Voor 20% gewijzigd door Creepy op 15-01-2013 22:28 . Reden: Wat code gesnipt ]


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23-11 22:23

Creepy

Tactical Espionage Splatterer

De errors die ik zie heb je omdat je het verschil tussen static en niet static simpelweg niet snapt.

Je kan niet een methode op een class aanroepen die niet static is, dat zul je op een instantie van een class moeten doen.

Je roept nu myFrame.rerepaint() aan, maar myFrame is een class (!) en geen instantie van een class. In java is het gebruikelijk om een class met een hoofdletter te laten beginnen en een gewone variabele met een kleine letter. Dan is ook in code gelijk duidelijk wat een class is, en wat niet.

Je zult dus eerst uberhaupt een instantie van myFrame moeten maken wil je deze kunnen gebruiken. Dus ergens moet je iets hebben als:

Java:
1
myFrame frame = new myFrame();


Ik weet niet wat voor tuturials e.d. je erbij hebt gemaakt maar iets als "Thinking in Java" (even googlen, deze is gratis online te vinden) leert je wel fatsoenlijk OO denken en ook hoe Java in elkaar steekt. Daar gaat het nu al mis en dan zie je al snel door de bomen het bos niet meer. Puur OO technisch gezien is het nogal gek dat de Ball moet gaan vragen aan het frame om zichzelf even opnieuw te tekenen. Waarom vraagt het frame aan de ball bijv. niet de positie op zodat het frame daarna op zichzelf de ball kan tekenen? Dan hoeft de bal ook geen repaint o.i.d. aan te gaan roepen. En waarom heeft een Ball twee paddles in zich? Een bal heeft toch geen paddles? En is de bal verantwoordelijk voor de paddles? Nee toch? En wie moet de scores bijhouden? Dat doet je Ball class nu!.

Zet eerst eens rustig op papier welke classes jij denkt te hebben en hoe die met elkaar moeten gaan communiceren voordat je gaat proggen. Met meer ervaring kan dat uiteindelijk ook vaak prima zonder dat je het op papier moet zetten. Of beter nog: start met een frame en teken daar eens wat op. Als dat lukt, teken er dan een bal op die je in het frame rond laat stuiteren, ga dan aan de gang met 2 paddels waar de ball ook op kan stuiteren etc. etc.

Je stack overflow is ook duidelijk:
Java:
1
2
3
4
public static void draw(Graphics g) { 
        Ball.draw(g); 
        myFrame.rerepaint(); 
    } 

Dit is Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), die roept dus weer Ball.draw(), ......StackOverflow ;)

[ Voor 57% gewijzigd door Creepy op 15-01-2013 22:47 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • Mammon
  • Registratie: December 2006
  • Laatst online: 23-11 13:55
Ik zou ook overwegen om Ball niet de eigenaar te laten zijn van de paddles en de scores van de spelers. Ik zou hier toch een aparte class voor aanmaken.

Tevens mis ik de methode move() en zou ik niet een Exception afvangen maar een wat specifiekere exceptie.

  • GLaDOS
  • Registratie: December 2012
  • Laatst online: 15:54
Bedankt voor de hulp Creepy, Ik heb mijn ontwerp volledig weggegooid en ben opnieuw begonnen. Naar uren werk heb ik nu ook een werkend resultaat (is nog niet 100% perfect, maar het is te definieren als pong. Dit is het resultaat.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import javax.swing.JFrame;

//kort gezegd is de pong de main class. Is ook verantwoordelijk voor hte maken van een window. Er staan 2 final static waarden in. Als je deze aanpast zal het formaat van het window veranderen. De rest van de code hoeft dan niet aangepast te worden en is dus volledig compatibel
//nadat deze klasse een frame en een pong-object heeft gemaakt is deze klasse klaar (tenzij de window_width en height worden gebruikt)
@SuppressWarnings("serial")
public class Pong extends JFrame {
    final static int WINDOW_WIDTH = 407;
    final static int WINDOW_HEIGHT = 283;

    public Pong() {
        setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(new GamePanel());
        setVisible(true);
    }

    public static void main(String[] args) {
        new Pong();
    }
}


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JPanel;
import javax.swing.Timer;
//gamepanel is verantwoordelijk voor alle visuele output. Het is in staat met alle andere klassen te communiceren
@SuppressWarnings("serial")
public class GamePanel extends JPanel implements ActionListener, KeyListener {
    //hier maakt gamepanel dus de 3 objecten aan die in het spel van belang zijn
    Player player = new Player();
    Ball ball = new Ball();
    Computer computer = new Computer(this);

    public GamePanel() {
        //deze timer tim zorgt voor de interne logica van het spelletje
        Timer tim = new Timer(25, this);
        tim.start();
        // wijst deze klasse aan als klasse die moet reageren op keyevents
        this.addKeyListener(this);
        // zorgt dat de toetsaanslagen worden geregistreerd in het java
        // programma
        this.setFocusable(true);
    }
    //update wordt iedere keer uitgevoerd als de timer een event "creeert" Is alleen verantwoordelijk voor het updaten van de x/y waarden en het uitvoeren van de collision code
    public void update() {
        player.update();
        ball.update();
        computer.update();
        ball.checkCollisionWith(player);
        ball.checkCollisionWith(computer);
    }
    //is verantwoordelijk voor het tekenen van de objecten in het frame, iedere klass heeft zijn eigen paint-methode en deze wordt hier aangeroepen
    public void paintComponent(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, Pong.WINDOW_WIDTH, Pong.WINDOW_HEIGHT);
        player.paint(g);
        ball.paint(g);
        computer.paint(g);
        
    }
    //returned de naam van het ball object (die is nodig voor de klasse computer, anders kan deze niet de positie van de bal oproepen);
    public Ball getBall() {
        return ball;
    }
    //voert iedere timer-tick de methode update en repaint uit;
    public void actionPerformed(ActionEvent e) {
        update();
        repaint();
    }
//vanaf hier  luistert KeyEvent naar key-events om daarmee het player-object aka het paddle aan te sturen
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_UP) {
            player.setYVelocity(-4);
        }
        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            player.setYVelocity(4);
        }
    }

    public void keyReleased(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) {
            player.setYVelocity(0);
        }
    }

    public void keyTyped(KeyEvent e) {

    }

}


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import java.awt.Color;
import java.awt.Graphics;

//klasse bal is verantwoordelijk voor het bijhouden van alle data omtreft de bal
public class Ball {
    // als de bal getekend wordt worden x en y gebruikt om de startpositie van
    // de bal op te roepen. Deze is afhankelijk van de grootte van het frame en
    // hoeft dus niet te worden aangepast als de afmetingen van het frame worden
    // aangepast.
    private int x = Pong.WINDOW_WIDTH / 2;
    private int y = Pong.WINDOW_HEIGHT / 2;
    // de velocity geeft aan hoe snel de bal beweegt een positief of negatief
    // teken geeft de richting aan
    private int xVelocity = -4;
    private int yVelocity = -4;
    // de grootte van de bal
    private int size = 5;

    public void update() {
        // de update methode past de x en y posities aan als de update methode
        // wordt uitgevoerd
        x = x + xVelocity;
        y = y + yVelocity;
        // collision met de borders van het scherm
        if (x < 0) {
            xVelocity = 4;
        }
        if (x + size > Pong.WINDOW_WIDTH - 7) {
            xVelocity = -4;
        }
        if (y < 0) {
            yVelocity = 4;
        }
        // - 33 omdat hij anders bounced hij te "laat"
        if (y + size > Pong.WINDOW_HEIGHT - 33) {
            yVelocity = -4;
        }
    }

    // verteld hoe je een bal tekent
    public void paint(Graphics g) {
        g.setColor(Color.GREEN);
        g.fillOval(x, y, size, size);
    }

    // als bal tegen een paddle bounced reversed deze methode de richting van de
    // bal
    public void reverseDirection() {
        xVelocity = xVelocity * -1;

    }

    // deze code check of de bal in contact komt een paddle (zowel player als
    // computer)
    public void checkCollisionWith(Player player) {
        if (this.x > player.getX()
                && this.x < player.getX() + player.getWidth()) {
            if (this.y > player.getY()
                    && this.y < player.getY() + player.getHeight()) {
                // als beide true zijn heeft ball paddle geraakt en voert hij reverseDirection uit
                reverseDirection();
            }
        }

    }

    public void checkCollisionWith(Computer cpu) {
        if (this.x > cpu.getX() && this.x < cpu.getX() + cpu.getWidth()) {
            if (this.y > cpu.getY() && this.y < cpu.getY() + cpu.getHeight()) {
                // als beide true zijn heeft ball paddle geraakt
                reverseDirection();
            }
        }
    }
//geeft x terug als deze methode wordt gebruikt. Deze heeft klasse computer nodig om de bal te kunnen volgen
    public int getX() {
        return x;
    }
// zelfde als hierboven
    public int getY() {
        return y;
    }
}


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.awt.Color;
import java.awt.Graphics;

public class Player {
    //paddle staat net als bij computer bij de start van het spel in het midden;
    private int y = Pong.WINDOW_HEIGHT / 2;
    //paddle kan alleen omhoog/omlaag niet naar links/rechts; X is dus een fixed position;
    private int yVelocity = 0;
    private int width = 8;
    private int height = 40;
    //lege constructor, er zal in totaal toch maar 1 player object zijn
    public Player() {
        
    }
    //wordt aangeroepen door gamepanel en verteld hoe je een player-object update
    public void update() {
        y = y + yVelocity;
    }
    //word aangeroepen door gamepanel en verteld hoe je een player object update
    public void paint(Graphics g){
        g.setColor(Color.YELLOW);
        g.fillRect(15, y, width, height);
    }
    //krijgt vanuit de gamepanel een richting mee waarin deze moet bewegen
    public void setYVelocity(int speed) {
        yVelocity = speed;
    }
    //is voor de bal zodat deze collision kan bepalen (met behulp van onderstaande 4 methoden)
    public int getX() {
        return 15;
    }
    public int getY() {
        return y;
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    
}


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import java.awt.Color;
import java.awt.Graphics;

public class Computer {
    // klasse computer is een AI en heeft inzicht nodig in de positie van de
    // bal. De computer wordt volledig autonoom bestuurd
    private GamePanel field;
    // computer heeft alleen een y nodig omdat deze slechts omhoog en omlaag kan
    private int y = Pong.WINDOW_HEIGHT / 2;
    // velocity is 0 omdat de paddle in begin stil moet staan
    private int yVelocity = 0;
    // afmetingen van de paddle
    private int width = 8;
    private int height = 40;

    // computer object constructor met de klasse myframe er in
    public Computer(GamePanel game) {
        this.field = game;
    }

    // laat computer in richting van de bal bewegen
    public void update() {
        if (field.getBall().getY() < this.y + 20) {
            // bal is boven paddle
            yVelocity = -3;
        }
        // bal is onder de paddle
        if (field.getBall().getY() > this.y - 20) {
            yVelocity = 3;
        }
        y = y + yVelocity;
    }

    // deze methode verteld de gamepanel methode hoe je een paddle tekent
    public void paint(Graphics g) {
        g.setColor(Color.RED);
        g.fillRect(Pong.WINDOW_WIDTH - 7 - (35 - width), y, width, height);
    }

    // getX en getY zijn nodig voor de bal om collision te checken;
    public int getX() {
        return Pong.WINDOW_WIDTH - 7 - (35 - width);
    }

    public int getY() {
        return y;
    }

    // bal moet ook weten hoe breed / hoog een paddle is om te kunnen bepalen of
    // een bal hit
    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

}


deze code houd nog geen score oid bij maar dit is slechts een kleine toevoeging. Ook wordt de bal nog niet gereset als er een "punt" word gescoord en zal deze gewoon vrolijk terugkaatsen. Bedankt voor de hulp!

  • GLaDOS
  • Registratie: December 2012
  • Laatst online: 15:54
ow ja suggesties zijn altijd welkom

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23-11 22:23

Creepy

Tactical Espionage Splatterer

Hmmja, we zitten er hier niet om je code zomaar even te reviewen natuurlijk. Dat geld nog meer voor school projecten, jij moet worden beoordeeld op jouw werk, niet ons werk. Ik ga dit topic dan ook dicht doen. Mocht je weer ergens tegen aan lopen probeer dan alleen de relevante code te posten i.p.v. *alle*.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney

Pagina: 1

Dit topic is gesloten.