Java MVC Pattern richtig anwenden

NicoBec

Mitglied
Hey,
ich befasse mich gerade mit der korrekten Anwendung des MVC Patterns für das Spiel Breakout.

Ein paar Fragen dazu bleiben bei mir aber ungelöst.
Bricks, Ball und Panel werden im View angezeigt und ausgegeben und die Koordinaten dafür berechne ich im Model. Wo werden aber die Objekte generell erstellt?
Und was geschieht in der Console? Mehr Userinput als die Bewegung des Panels habe ich ja nicht.
Und dann bleibt bei mir noch die Frage, wie och alles so "offen" wie möglich verknüpfen kann, sodass z.B. die View auf die Daten Model zugreifen kann.

Bin für ein bisschen Aufklärung sehr dankbar!
LG
 

MoxxiManagarm

Top Contributor
Die View erhält eine Referenz auf das Model. Aber die View sollte nur lesend auf das Model zugreifen.
Model und View werden vom Controller erstellt.
Die Benutzereingabe sollte ebenfalls vom Controller verwaltet werden. Der Kontroller kann z.B. KeyListener implementieren. Viele Implementieren die Usereingabe aber auch in der View und senden mit einem KeyEvent einen Funktionsaufruf an den Controller. Das ist ebenfalls ok. Letztendlich unterscheidet sich das nur in der Darstellung, ob der Benutzer mit dem Controller oder der View interargiert. Die Interaktion mit dem Controller entspricht eher dm MVC-Konzept, jedoch ist die Interaktion mit der View flexibler in Bezug auf verschiedene Plattformen. So ist z.B. die Bewegung nach Links anders auf einem Smartphone ausgelöst als auf dem Desktop-PC. Aus Controllersicht ist jedoch beides eine Bewegung nach Links.

Java:
BrickModel model = new BrickModel();
BrickView view = new BrickView(model);
 
Zuletzt bearbeitet:

NicoBec

Mitglied
@MoxxiManagarm Hey, ich danke dir für die schnelle Antwort!
Mir ist leider nicht 100% klar, was genau in welches Pattern kommt.
Ich würde jetzt folgendermaßen vorgehen:
den MouseListener in der Control implementieren, damit er die Signale an die Model weitergibt. Hier würde ich Berechnungen für die Ballgeschwindigkeit, die Collisions und weitere Spielphysik einbauen.
In die View würde ich letztlich nur die Objekte via GraphicsProgram einfügen.
Aber wo kommen z.B. die Methoden rein, die einen Brick bei einer Collision verschwinden lassen und wie bzw. in welchem Fenster (M,V oder C) wird das gesamte Game gestartet?
 

MoxxiManagarm

Top Contributor
Der MVC-Part wird im Controller gestartet, also der Controller existiert zuerst. Der Controller erstellt Model und View in der Reihenfolge. Der Controller kann z.B. von der main gestarted werden oder eben durch irgendwas anderes.

Das Model sollte keine große Logik erhalten. Im einfachsten Fall hat das nur getter und setters. Die Kollision sollte m.E. im Controller passieren und der Controller sagt dem Model, dass der Brick entfernt werden muss. In der Regel sind View und Model recht übersichtlich, wo hingegen der Controller den größten Umfang besitzt.
 

mrBrown

Super-Moderator
Mitarbeiter
den MouseListener in der Control implementieren, damit er die Signale an die Model weitergibt. Hier würde ich Berechnungen für die Ballgeschwindigkeit, die Collisions und weitere Spielphysik einbauen.
Die Berechnungen gehören in das Model - da gehört alles Darstellungs-Unabhängige zu. Das Model hat eine Schnittstelle für Aktionen, die der Nutzer tätigen kann - und nur diese übermittelt der Controller.

In die View würde ich letztlich nur die Objekte via GraphicsProgram einfügen.
Richtig.

Aber wo kommen z.B. die Methoden rein, die einen Brick bei einer Collision verschwinden lassen und wie bzw. in welchem Fenster (M,V oder C) wird das gesamte Game gestartet?
Das der Brick bei einer Kollision verschwindet, gehört doch zur "Domäne" des Spiels und nicht zur Umsetzung für deinen Bildschirm -> also Model ;)
Die Initialisierung läuft einfach in einer davon getrennten Methode/Klasse, zB einfach in der Main.
Was meinst du mit "in welchem Fenster"? Das Fenster ist ja eben die View.


Model und View werden vom Controller erstellt.
[...]
Die Interaktion mit dem Controller entspricht eher dm MVC-Konzept, jedoch ist die Interaktion mit der View flexibler in Bezug auf verschiedene Plattformen. So ist z.B. die Bewegung nach Links anders auf einem Smartphone ausgelöst als auf dem Desktop-PC. Aus Controllersicht ist jedoch beides eine Bewegung nach Links.
Im eigentlichen Pattern werden UI und Model getrennt initialisiert, und in ersterer initialisiert die View den Controller.
Es geht auch nicht darum, den Controller wieder zu verwenden, der darf auch ruhig von der View abhängig sein. Für ein anderes Frontend würde man beides gemeinsam ersetzen ;)
 

MoxxiManagarm

Top Contributor
Ich hab mich wegen gerade wegen mrBrown nochmal belesen und merke ich habe was falsches gelehrt bekommen... Hör mal lieber auf ihn mein Anschauungsbild stellt sich gerade auf den Kopf x) Aber ich bin nachwievor der Meinung Controller war zuerst und Controller erstellt View und Model.
 

NicoBec

Mitglied
Klar, wollte damit nur nicht jeden nerven. Er ist Im Moment noch durcheinander, weil ich gerade anfange das Pattern umzubauen (Ich hatte Breakout bereit fertig und es hat top funktioniert und dann wurde mir gesagt, dass das Pattern das Falsche ist:/ )
 

NicoBec

Mitglied
Einmal die Model:
Java:
package brickBracker;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.util.Observable;

import acm.graphics.GLabel;
import acm.graphics.GObject;
import acm.graphics.GOval;
import acm.graphics.GRect;
import acm.program.ConsoleProgram;
import acm.util.RandomGenerator;

public class Model extends Observable {

    protected static final int WIDTH = 1600;
    protected static final int PADDLE_WIDTH = 60;
    protected static final int PADDLE_HEIGHT = 10;
    protected static final int PADDLE_Y_OFFSET = 30;
    protected static final int NBRICK_ROWS = 10;
    protected static final int NBRICKS_PER_ROW = 10;
    protected static final int BRICK_HEIGHT = 8;
    protected static final int BRICK_SEP = 4;
    protected static final int BRICK_WIDTH = (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;
    protected static final int BALL_RADIUS = 10;
    protected static final int DELAY = 10;

    protected static final int BRICK_Y_OFFSET = 70;
    protected double vx;
    protected double vy;
    protected RandomGenerator rgen = RandomGenerator.getInstance();
    protected static int brickCounter = 30;
    int scoreToShow = 0;
    protected GOval ballToG;
    protected GRect panel;
    protected GRect brick;
    protected GLabel score;
    protected GLabel scoreBoard;

    protected static GOval ballToGo;

    private void getBallVelocity() {
        vy = -4.0;
        vx = rgen.nextDouble(1.0, 3.0);
        if (rgen.nextBoolean(0.5)) {
            vx = -vx;
        }
    }

    public static void moveBall() {

        if (1 < 2) {
            try {
                Thread.sleep(10);
                ballToGo.move(vx, vy);
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }

        }

        GObject collider = getCollidingObject();

        if ((ballToGo.getX() - vx <= 0 && vx < 0)
                || (ballToGo.getX() + vx >= (getWidth() - BALL_RADIUS * 2) && vx > 0)) {
            vx = -vx;
        }
        if ((ballToGo.getY() - vy <= 0 && vy < 0)) {
            vy = -vy;
        }

        if (collider == panel) {

            if (ballToGo.getY() >= ((getHeight() - PADDLE_Y_OFFSET - PADDLE_HEIGHT - BALL_RADIUS * 2) - 8)) {
                vy = -vy;
            }
        }

        else if (collider != null) {
            remove(collider);
            brickCounter--;
            remove(scoreBoard);
            this.scoreToShow++;
            GLabel scoreBoard = new GLabel("SCORE: " + scoreToShow, 10, 750);
            scoreBoard.setColor(Color.WHITE);
            scoreBoard.setFont(Font.MONOSPACED);
            add(scoreBoard);
            vy = -vy;
        }
        pause(DELAY);

    }

    protected GObject getCollidingObject() {

        if ((getElementAt(ballToGo.getX(), ballToGo.getY())) != null) {
            return getElementAt(ballToGo.getX(), ballToGo.getY());
        } else if (getElementAt((ballToGo.getX() + BALL_RADIUS * 2), ballToGo.getY()) != null) {
            return getElementAt(ballToGo.getX() + BALL_RADIUS * 2, ballToGo.getY());
        } else if (getElementAt(ballToGo.getX(), (ballToGo.getY() + BALL_RADIUS * 2)) != null) {
            return getElementAt(ballToGo.getX(), ballToGo.getY() + BALL_RADIUS * 2);
        } else if (getElementAt((ballToGo.getX() + BALL_RADIUS * 2), (ballToGo.getY() + BALL_RADIUS * 2)) != null) {
            return getElementAt(ballToGo.getX() + BALL_RADIUS * 2, ballToGo.getY() + BALL_RADIUS * 2);
        } else {
            return null;
        }
    }

}

Die Control:

Java:
package brickBracker;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;

import acm.graphics.GLabel;
import acm.graphics.GObject;

public abstract class Control implements ActionListener {

    private Model model;
    private View view;

    public Control() {
        this.model = new Model();

        this.view = new View();

        this.model.addObserver(this.view);

        // Erzeuge das Fenster
        new Frame(this, view);

    }

    public void run() {

        for (int i = 0; i < 1; i++) {

            Game.setUpGame();
            Game.playGame();
            if (ObjectsToGo.brickCounter == 0) {
                ballToGo.setVisible(false);
                printWinner();
                break;
            }

            if (brickCounter > 0) {
                removeAll();
            }
        }
        if (brickCounter > 0) {
            printGameOver();
        }

    }

    public void actionPerformed(MouseEvent e) {
        panel.setLocation(e.getX(),
                getHeight() - PADDLE_Y_OFFSET - ObjectsToGo.PADDLE_HEIGHT - ObjectsToGo.BALL_RADIUS * 2 + 2);

    }

    public static void setUpGame() {
        drawBricks(getWidth() / 2, BRICK_Y_OFFSET);
        drawPanel();
        drawBall();
    }

    public static void playGame() {
        waitForClick();
        getBallVelocity();
        while (true) {
            moveBall();
            if (ballToGo.getY() >= getHeight()) {
                break;
            }
            if (brickCounter == 0) {
                break;
            }
        }
    }
}

und die View:

Java:
package brickBracker;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.*;
import java.util.Observer;

import acm.graphics.*;
import acm.program.*;
import acm.util.RandomGenerator;

public class View extends GraphicsProgram implements Observer {

    protected static final int WIDTH = 1600;
    protected static final int PADDLE_WIDTH = 60;
    protected static final int PADDLE_HEIGHT = 10;
    protected static final int PADDLE_Y_OFFSET = 30;
    protected static final int NBRICK_ROWS = 10;
    protected static final int NBRICKS_PER_ROW = 10;
    protected static final int BRICK_HEIGHT = 8;
    protected static final int BRICK_SEP = 4;
    protected static final int BRICK_WIDTH = (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;
    protected static final int BALL_RADIUS = 10;
    protected static final int DELAY = 10;

    protected static final int BRICK_Y_OFFSET = 70;
    protected double vx;
    protected double vy;
    protected RandomGenerator rgen = RandomGenerator.getInstance();
    protected static int brickCounter = 30;
    int scoreToShow = 0;
    protected GOval ballToG;
    protected GRect panel;
    protected GRect brick;
    protected GLabel score;
    protected GLabel scoreBoard;

    public void drawBall() {
        double x = (getWidth() / 2 - BALL_RADIUS) + 200;
        double y = (getHeight() / 2 - BALL_RADIUS) + 300;
        ballToGo = new GOval(x, y, BALL_RADIUS, BALL_RADIUS);
        ballToGo.setFilled(true);
        ballToGo.setColor(Color.white);
        add(ballToGo);
    }

    protected void drawBricks(double cx, double cy) {

        for (int row = 0; row < NBRICK_ROWS; row++) {

            for (int column = 0; column < NBRICKS_PER_ROW - 7; column++) {

                double x = (cx - (NBRICKS_PER_ROW * BRICK_WIDTH) / 2 - ((NBRICKS_PER_ROW - 1) * BRICK_SEP) / 2
                        + column * BRICK_WIDTH + column * BRICK_SEP) + 755;

                double y = cy + row * BRICK_HEIGHT + row * BRICK_SEP;

                brick = new GRect(x, y, BRICK_WIDTH, BRICK_HEIGHT);
                add(brick);
                brick.setFilled(true);

                if (row < 2) {
                    brick.setColor(Color.RED);
                }
                if (row == 2 || row == 3) {
                    brick.setColor(Color.ORANGE);
                }
                if (row == 4 || row == 5) {
                    brick.setColor(Color.YELLOW);
                }
                if (row == 6 || row == 7) {
                    brick.setColor(Color.GREEN);
                }
                if (row == 8 || row == 9) {
                    brick.setColor(Color.CYAN);

                }

            }

        }
    }

    protected void drawPanel() {

        double x = (getWidth() / 2 - PADDLE_WIDTH / 2) + 190;

        double y = (getHeight() - PADDLE_Y_OFFSET - PADDLE_HEIGHT) + 530;
        panel = new GRect(x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
        panel.setFilled(true);
        panel.setFillColor(Color.white);
        panel.setColor(Color.white);
        add(panel);
        addMouseListeners();
    }

    protected void printGameOver() {
        GLabel gameOver = new GLabel("Game Over", getWidth() / 2, getHeight() / 2);
        gameOver.move(-gameOver.getWidth() / 2, -gameOver.getHeight());
        gameOver.setColor(Color.RED);
        add(gameOver);
    }

    protected void printWinner() {
        GLabel Winner = new GLabel("Winner!!", getWidth() / 2, getHeight() / 2);
        Winner.move(-Winner.getWidth() / 2, -Winner.getHeight());
        Winner.setColor(Color.GREEN);
        add(Winner);
    }

}
 

mrBrown

Super-Moderator
Mitarbeiter
Das Problem ist eher, dass das Model zig Grafik-Objekte enthält ;)

uU kann MVC für so etwas auch ungeeignet sein - eben weil man bei einem solchen Spiel keine klare Trennung von Logik und Darstellung erreichen kann
 

mrBrown

Super-Moderator
Mitarbeiter
Aber dann bleiben meiner Meinung nach nur noch die Ball- Panel- und Brickkoordinaten in dem Model.
Ja, aus denen kannst du natürlich sinnvolle Objekte machen ;)


Und wenn ich es richtig sehe, kommen Methoden, wie moveBall() in den Controller oder?
Naja, der Ball ist Teil des Models, also sollten auch die Methoden zum Bewegen des Models dahin ;)

Im Controller gibts nur die Funktion, die aus einem Tastendruck das "Ball nach Rechts" macht, und die dazu gehörende Methode im Model aufruft
 

MoxxiManagarm

Top Contributor
Habe noch ein paar Anmerkungen:
1. Das if-Konstrukt bei den Farben für die Rows würde ich zu else-ifs machen. Anderenfalls fragt er unnötiger weise alle anderen if's ab, obwohl er beim ersten bereits fündig wurde.
2. Ich bin kein Fan von diesen Threads und Sleeps! Ich werde immer wieder Timer predigen für diese Anwendungsfälle. acm hat auch einen Timer, welcher von javax.swing.timer erbt.
https://cs.stanford.edu/people/eroberts/jtf/javadoc/complete/index.html?acm/util/SwingTimer.html
Du hättest dann kein while(true) mehr. Alles was dort passiert, passiert dann im ActionEvent. Du hättest kein Thread.sleep() mehr was ohnehin vermutlich nicht ins Model gehört, kein try-catch und kein break. Anstatt break stoppst du deinen Timer dann.
3.
Java:
 for (int i = 0; i < 1; i++)
Das wird genau 1x ausgeführt. Wozu dann die Schleife?
 

MoxxiManagarm

Top Contributor
Anmerkung zu meiner Anmerkung mit dem Timer:

https://cs.stanford.edu/people/eroberts/jtf/tutorial/AnimationAndInteractivity.html

Das Tutorials schlägt pause() vor unter 3-2
https://cs.stanford.edu/people/eroberts/jtf/javadoc/student/acm/program/Program.html#pause(double)

Aber unter 3-10 ist auch die Variante mit dem SwingTimer.

----

Das Tutorials erhebt aber den Eindruck, dass GraphicsProgramm nicht für MVC geeignet ist. Das ist so einer Eier Legende Wollmilchsau. Ist das Vorgabe? Eventuell wäre es sinnvoll auf GCanvas umzusteigen und das in einem Frame zu verpacken.
 
Zuletzt bearbeitet:

MoxxiManagarm

Top Contributor
Nein ich meinte nicht "normales" Java. Du kannst nachwievor bei ACM bleiben. Würde ich auch tun da doch viele Bewegung dabei ist. Aber wenn ich die Doku richtig verstehe, dann hat GraphicsProgram als solches schon alles was man auf die Schnelle brauch. Es hat sogar alle möglichen Listener bereits implementiert. Ich glaube es wird schwer ein vernünftiges MVC daherum zu bauen. GraphicsProgram ist bei ACM aber nicht Pflicht. Du kannst genauso JFrame verwenden. GCanvas erbt von JContainer. Füge deinem Frame einfach das GCanvas hinzu und dem GCanvas kannst du wie gewohnt die anderen Elemente ergänzen.
 

MoxxiManagarm

Top Contributor
Ich habe, auch um mich selbst mit ACM ein wenig auseinanderzusetzen, ein Beispiel gemacht. Es kann nicht viel, es bewegt bisher nur die beiden Paddles, aber es legt denke ich meinen Grundgedanken dar.

Controller:
Java:
package javaforum.org.pingpong;


import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import acm.util.SwingTimer;

public class PingPongController implements KeyListener {

    private PingPongModel model;
    private PingPongView view;
 
    private SwingTimer ballTimer, paddleTimer1, paddleTimer2;
 
 
    public PingPongController() {
        model = new PingPongModel();
        view = new PingPongView(model);
    
        model.addObserver(view);
    
        view.addKeyListener(this);
    
        ballTimer = new SwingTimer(10, ae -> {
              // TODO: Ballbewegung
        });
    
        paddleTimer1 = new SwingTimer(10, ae -> {
              model.movePaddle(Player.ONE);
        });
    
        paddleTimer2 = new SwingTimer(10, ae -> {
              model.movePaddle(Player.TWO);
        });
      
        view.setVisible(true);
    }
 
    public static void main(String[] args) {
        new PingPongController();
    }

    @Override
    public void keyPressed(KeyEvent arg0) {
        switch (arg0.getKeyCode())  {
        case KeyEvent.VK_W:
            model.setDirection(Player.ONE, Direction.UP);
            if(!paddleTimer1.isRunning()) paddleTimer1.start();
            break;
        case KeyEvent.VK_S:
            model.setDirection(Player.ONE, Direction.DOWN);
            if(!paddleTimer1.isRunning()) paddleTimer1.start();
            break;
        case KeyEvent.VK_UP:
            model.setDirection(Player.TWO, Direction.UP);
            if(!paddleTimer2.isRunning()) paddleTimer2.start();
            break;
        case KeyEvent.VK_DOWN:
            model.setDirection(Player.TWO, Direction.DOWN);
            if(!paddleTimer2.isRunning()) paddleTimer2.start();
            break;
        default:
        }
    }

    @Override
    public void keyReleased(KeyEvent arg0) {
        switch (arg0.getKeyCode())  { // TODO: Verhalten bei up+down
        case KeyEvent.VK_W:
            if(paddleTimer1.isRunning()) paddleTimer1.stop();
            break;
        case KeyEvent.VK_S:
            if(paddleTimer1.isRunning()) paddleTimer1.stop();
            break;
        case KeyEvent.VK_UP:
            if(paddleTimer2.isRunning()) paddleTimer2.stop();
            break;
        case KeyEvent.VK_DOWN:
            if(paddleTimer2.isRunning()) paddleTimer2.stop();
            break;
        default:
        }
    }

    @Override
    public void keyTyped(KeyEvent arg0) {
        switch (arg0.getKeyCode())  {
        case KeyEvent.VK_ENTER:
        case KeyEvent.VK_SPACE:
            if(!ballTimer.isRunning()) { // TODO: nur wenn Spiel im Startzustand
                ballTimer.start();
            }
        default:
        }
    }
}

View:
Java:
package javaforum.org.pingpong;


import java.awt.Dimension;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFrame;

import acm.graphics.GCanvas;
import acm.graphics.GLine;
import acm.graphics.GObject;
import acm.graphics.GOval;
import acm.graphics.GRect;

@SuppressWarnings("serial")
public class PingPongView extends JFrame implements Observer {
    private HashMap<ObservableObject, GObject> observerObjects;
   
    public PingPongView(PingPongModel model) {
        setTitle("Ping Pong");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        GCanvas panel = new GCanvas();
        panel.setPreferredSize(new Dimension(Settings.PANEL_SIZE * 2, Settings.PANEL_SIZE));
        add(panel);
       
        GLine line = new GLine(Settings.PANEL_SIZE, 0, Settings.PANEL_SIZE, Settings.PANEL_SIZE);
        line.setColor(Settings.LINE_COLOR);
        panel.add(line);
       
        observerObjects = new HashMap<ObservableObject, GObject>();
       
        PaddleView paddle1 = new PaddleView(Settings.PADDLE_WIDTH, Settings.PADDLE_HEIGHT, model.getPaddle(Player.ONE).getX(), model.getPaddle(Player.ONE).getY());
        panel.add(paddle1);
        observerObjects.put(model.getPaddle(Player.ONE), paddle1);
       
        PaddleView paddle2 = new PaddleView(Settings.PADDLE_WIDTH, Settings.PADDLE_HEIGHT, model.getPaddle(Player.TWO).getX(), model.getPaddle(Player.TWO).getY());
        panel.add(paddle2);
        observerObjects.put(model.getPaddle(Player.TWO), paddle2);
       
        BallView ball = new BallView(Settings.BALL_RADIUS*2, Settings.BALL_RADIUS*2, model.getBall().getX(), model.getBall().getY());
        panel.add(ball);
        observerObjects.put(model.getBall(), ball);
       
        pack();
    }

    @Override
    public void update(Observable arg0, Object arg1) {
        ObservableObject observableObject = (ObservableObject)arg1;
        GObject observerObject = observerObjects.get(observableObject);
       
        observerObject.setLocation(observableObject.getX(), observableObject.getY());       
    }
   
    private class PaddleView extends GRect {
        public PaddleView(int sizeX, int sizeY, int posX, int posY) {
            super(sizeX, sizeY);
            setLocation(posX, posY);
           
            setFilled(true);
            setFillColor(Settings.PADDLE_COLOR);
            setColor(Settings.PADDLE_COLOR);
        }
       
        @Override
        public void setLocation(double x, double y) {
            super.setLocation(x - Settings.PADDLE_WIDTH/2, y - Settings.PADDLE_HEIGHT/2);
        }
    }
   
    private class BallView extends GOval {
        public BallView(int sizeX, int sizeY, int posX, int posY) {
            super(sizeX, sizeY);
            setLocation(posX, posY);
           
            setFilled(true);
            setFillColor(Settings.BALL_COLOR);
            setColor(Settings.BALL_COLOR);
        }
       
        @Override
        public void setLocation(double x, double y) {
            super.setLocation(x - Settings.BALL_RADIUS, y - Settings.BALL_RADIUS);
        }
    }
}

Model:
Java:
package javaforum.org.pingpong;

import java.util.Observable;

public class PingPongModel extends Observable {
 
    private PaddleModel paddle1, paddle2;
    private BallModel ball;

    public PingPongModel() {
        paddle1 = new PaddleModel(Settings.PADDLE_OFFSET);
        paddle2 = new PaddleModel(Settings.PANEL_SIZE * 2 - Settings.PADDLE_OFFSET);
    
        ball = new BallModel();
    }
 
    public void movePaddle(Player player) {
        setChanged();
        switch(player) {
        case ONE:
            paddle1.move();
            notifyObservers(paddle1);
            break;
        case TWO:
            paddle2.move();
            notifyObservers(paddle2);
            break;    
        }
    }
 
    public void setDirection(Player player, Direction direction) {
        switch(player) {
        case ONE:
            paddle1.setDirection(direction);
            break;
        case TWO:
            paddle2.setDirection(direction);
            break;    
        }
    }
 
    public PaddleModel getPaddle(Player player) {
        switch(player) {
        case ONE:
            return paddle1;
        case TWO:
            return paddle2;    
        }
        return null;
    }
 
    public BallModel getBall() {
        return ball;
    }
}
 
Zuletzt bearbeitet:

MoxxiManagarm

Top Contributor
Zum Verständnis noch:

Paddle
Java:
package javaforum.org.pingpong;

public class PaddleModel extends ObservableObject{

    private int speed;
    private Direction direction;
  
    public PaddleModel(int x) {
        this.x = x;
        y = Settings.PANEL_SIZE / 2;
      
        speed = Settings.PADDLE_SPEED;
    }  
  
    public int getSpeed() {
        return speed;
    }
  
    public void setDirection(Direction direction) {
        this.direction = direction;
    }
  
    public void move() {
        switch (direction) {
        case UP:
            y -= speed;
            break;
        case DOWN:
            y += speed;
            break;
        }
      
        if (y < (Settings.PADDLE_HEIGHT / 2))
            y = Settings.PADDLE_HEIGHT / 2;
        else if (y > (Settings.PANEL_SIZE - (Settings.PADDLE_HEIGHT / 2)))
            y = Settings.PANEL_SIZE - (Settings.PADDLE_HEIGHT / 2);
    }
}

ObservableObject
Java:
package javaforum.org.pingpong;

public abstract class ObservableObject {
    protected int x, y;
  
    public int getX() {
        return x;
    }
  
    public int getY() {
        return y;
    }
  
    public void setX(int x) {
        this.x = x;
    }
  
    public void setY(int y) {
        this.y = y;
    }
}
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Compilerfehler bis in java.util.regex.Pattern... Allgemeine Java-Themen 2
L Erste Schritte Java Date Format Pattern bestimmten Allgemeine Java-Themen 2
M Java Garbage Collector Frage (Singleton Pattern) Allgemeine Java-Themen 13
M Java Pattern hilfe Allgemeine Java-Themen 6
F Composite Pattern in Java? Allgemeine Java-Themen 1
D Hat Java eine Library um JavaScript auszuwerten? Allgemeine Java-Themen 2
Zrebna Wieso sind eigentlich JUnit-Tests in src/test/java platziert - nur Konvention? Allgemeine Java-Themen 7
N LlaMA, KI, java-llama.cpp Allgemeine Java-Themen 39
V Java-Codierungsherausforderung: Navigieren durch die Macken der Datumsmanipulation Allgemeine Java-Themen 2
E Output Fehler (Java-Programm Kuchen) Allgemeine Java-Themen 11
M java: unexpected type Allgemeine Java-Themen 2
harrytut Java Input/Output Tests Junit Allgemeine Java-Themen 3
B Java Discord bot auf ein Root Server? Allgemeine Java-Themen 1
BetziTheRealOne Java PKIX path building failed as non Admin Allgemeine Java-Themen 15
D Linux, Java-Version wird nicht erkannt bzw. welche Einstellung fehlt noch? Allgemeine Java-Themen 19
KonradN Java 21 Release Allgemeine Java-Themen 5
V Umgang mit fehlenden Daten in einer Java-Datenanalyseanwendung Allgemeine Java-Themen 5
P Fehler: Hauptklasse Main konnte nicht gefunden oder geladen werden Ursache: java.lang.ClassNotFoundException: Main Allgemeine Java-Themen 24
K Java Anwendung machen Anleitung Allgemeine Java-Themen 5
G java.io.listFiles() Allgemeine Java-Themen 3
8u3631984 Frage zu Java Streams min / max Allgemeine Java-Themen 17
S Java Programm lässt sich vom USB-Stick starten, aber nicht von HDD Allgemeine Java-Themen 16
K Java-Projekt Allgemeine Java-Themen 11
K Java-Projekt Allgemeine Java-Themen 0
ruutaiokwu Welcher Browser unterstützt heutzutage noch Java Applets? Allgemeine Java-Themen 5
Jose05 Java-Klasse im extra cmd-Fenster ausführen Allgemeine Java-Themen 3
rode45e Java Threads Allgemeine Java-Themen 4
G java.io.listFiles() Allgemeine Java-Themen 2
N Java Dynamic Proxy Allgemeine Java-Themen 3
N Leichte Java Gegner Ki Allgemeine Java-Themen 10
A Java modul Problem Allgemeine Java-Themen 4
Thomasneuling Java Jar datei erstellen, von Projekt, dass auch Javafx Dateien, FXML Dateien und CSS Dateien, sowie Bilder enthält? Allgemeine Java-Themen 14
V Funktionale Schnittstelle in Java Allgemeine Java-Themen 3
OnDemand Java String in Hashmap als Key NULL Allgemeine Java-Themen 27
urmelausdemeis Exception in thread "main" java.lang.Error: Unresolved compilation problem: Allgemeine Java-Themen 7
berserkerdq2 Wenn ich bei Intelij javafx mit maven importieren will, muss ich das in die pom.xml reintun, aber warum noch in module-info.java? Allgemeine Java-Themen 3
KonradN Java 20 am 21. März Allgemeine Java-Themen 1
O Java Website Stock Bot Allgemeine Java-Themen 3
J Front-/Backend in Java Allgemeine Java-Themen 14
doopexxx JAVA Google Webcrawler Allgemeine Java-Themen 1
J JavaScript innerhalb eines Java Projekts ausführen Allgemeine Java-Themen 2
A Java Programm erstellen hilfe Allgemeine Java-Themen 10
G java.lang.NoClassDefFoundError: org/aspectj/lang/Signature Allgemeine Java-Themen 2
lalex1491 Java Aktienkurse nachfragen Allgemeine Java-Themen 4
J Class to link Java Allgemeine Java-Themen 4
V Wie funktioniert das Schlüsselwort "final" von Java? Allgemeine Java-Themen 19
mrStudent Inferenz JAVA Allgemeine Java-Themen 6
U URI Rechner (Java Script) Allgemeine Java-Themen 7
TheSkyRider Java Geburtsdatum Textfeld Allgemeine Java-Themen 7
mihe7 Java 19 JavaDocs: Browserintegration Allgemeine Java-Themen 0
Encera Gleichzeitiges Ausführen und verbinden von 2 Java-Klassen über die Eingabeaufforderung und Eclipse Allgemeine Java-Themen 21
H Java Rechner Programmierung der Mathematik Allgemeine Java-Themen 33
Lennox Schinkel Java Kara Auf einen Java Host laufen lassen Allgemeine Java-Themen 17
C Fußnoten von DocX mit Java Allgemeine Java-Themen 2
C Fußnoten in DocX mit Java Allgemeine Java-Themen 1
M Aussagenlogik in Java Programmieren Allgemeine Java-Themen 22
B Per Java Word Dokument schreiben? Allgemeine Java-Themen 8
krgewb Java-Bibliothek für ONVIF Allgemeine Java-Themen 1
KonradN Oracle übergibt (Java Teile der) GraalVM Community Edition an OpenJDK Community Allgemeine Java-Themen 2
Momo16 Brauche Hilfe - Java Projekt kann nicht erstellt werden Allgemeine Java-Themen 12
B Java mit command line und jars benutzen? Allgemeine Java-Themen 18
M Java Überprüfen ob .exe-Datei bereits ausgeführt wird Allgemeine Java-Themen 2
B HTTP Allgemeine Fragen über Suchmaschine nutzen mit Java Allgemeine Java-Themen 20
Mick P. F. Wie kriege ich die Fehlermeldung "java: symbol lookup error: ..." weg? Allgemeine Java-Themen 11
K Nachhilfe Java Allgemeine Java-Themen 11
KonradN Java 19 Allgemeine Java-Themen 11
F IDEA IntelliJ Java Songliste erstellen Allgemeine Java-Themen 6
TheSepp Java bestimmtes Array auf den Wert 0 setzen Allgemeine Java-Themen 32
B Java Reflection Probleme beim wehcselseitigen Referenzieren zweier Klassen/Objekte Allgemeine Java-Themen 14
Sachinbhatt Sind alle Methoden in Java implizit virtuell Allgemeine Java-Themen 2
E Java und integrierte Grafikkarten Allgemeine Java-Themen 18
Sachinbhatt Wie wird die Typumwandlung bei Mehrfachvererbung in Java implementiert? Allgemeine Java-Themen 3
Peterw73 Hilfe bei Java gesucht Allgemeine Java-Themen 3
A Java unter Win 10 Allgemeine Java-Themen 1
B Woher kommen die Bildschirmkoordinaten beim java Robot? Allgemeine Java-Themen 14
P9cman java.Lang Klassen fehlen in JRE System Library Allgemeine Java-Themen 1
T Java Robot Class - Bot Allgemeine Java-Themen 3
E Wie Java Heap Space vergrößern? Allgemeine Java-Themen 3
B Java Programm auf virutellem Desktop laufen lassen? Allgemeine Java-Themen 1
D VBA Code mit Java ausführen möglich? Allgemeine Java-Themen 10
berserkerdq2 Threads, wie genau läuft das in Java ab? (Ich kann Threads erstellen und nutzen, nur das Verständnis) Allgemeine Java-Themen 6
izoards Java Home Pfad unabhängig von der Version Allgemeine Java-Themen 7
N JAVA-Code mit Grafikfenster zeichnet in Windows, aber nicht Mac. Allgemeine Java-Themen 4
L Java überprüfen lassen, ob sich ein gegebener Pfad / das Programm an sich auf einer CD oder Festplatte befindet Allgemeine Java-Themen 14
KonradN CVE-2022-21449: Fehler in Java bei Signaturprüfung Allgemeine Java-Themen 20
berserkerdq2 Java sql Allgemeine Java-Themen 15
JordenJost Unverständlicher Java code? Allgemeine Java-Themen 21
LimDul XSD To Java - Überschreiben von Assoziationen Allgemeine Java-Themen 1
Aartiyadav Comparisons and Swapa in Bubble-sort Java Allgemeine Java-Themen 6
KonradN Java 18 Allgemeine Java-Themen 8
N Statistische Auswertung von Logfiles (Einlesen, auswerten und grafische Aufbereitung von logfiles) mit Java Allgemeine Java-Themen 9
ME2002 Fragen aus einer Java Klausur Allgemeine Java-Themen 67
Z Mit Java 8+ Streams Zeilen nummern zu Zeilen hinzufügen Allgemeine Java-Themen 17
M Verständnisfrage java.util.TimerTask Allgemeine Java-Themen 2
V Hilfe mit Java Code Allgemeine Java-Themen 4
S Processing Java Code verstehen Allgemeine Java-Themen 4
O Newton Algorithmus Java Allgemeine Java-Themen 1
P Java Quellen finden Allgemeine Java-Themen 3
M Java Analyse/ SWOT-Analyse Allgemeine Java-Themen 13
J c Programm läuft nicht in compilierter Version des Java Projektes Allgemeine Java-Themen 7

Ähnliche Java Themen

Neue Themen


Oben