Konstruktor für "Vier Gewinnt"

francisca93

Mitglied
Hallo,

ich soll ein "Vier gewinnt"-Spiel in der Größe 8x8 programmieren. Die grundlegende Graphik für das Spielfeld hab ich schon hinbekommen (64 Kästchen mit drawRect in verschachtelter for-Schleife angelegt, darüber 8 Buttons); jetzt muss ich irgendwie die Funktionalität reinbekommen.
Mein Ansatz ist: Jedes Spielfeld ist eine Instanz der Klasse "Feld", Attribute sind die beiden Koordinaten und ein int "Zustand" (0=leer, 1=weiß, 2=schwarz). Nun überlege ich, wie ich den Konstruktor so hinbekomme, dass er am Anfang des Spiels ein Array von den 64 Feldern anlegt, jedes Feld mit den Koordinaten und Zustand auf 0. Bisher hab ich folgendes:
Code:
package praktikum_4;

public class Feld {
    int x,y;
    int zustand;
   
    public Feld(){
        Feld f[][] = new Feld[8][8];
        for(int i=1; i<9; i++)
            for (int j=1; j<9; j++){
                f[j][i].x=j ;f[j][i].y=i; f[j][i].zustand=0;            
            }
       }
}
Beschwert hat er sich nicht, aber ich hab keine Ahnung ob das dann so Sinn macht. Kann der Konstruktor sofort ein Array konstruieren? Oder soll ich ihn nur für ein einzelnes Feld machen, dem i und j als Parameter übergeben werden, und dann mit einer for-Schleife aufrufen und so die 64 Felder bilden?

Danke schonmal für die Hilfe
 
Warum sollte denn die Klasse Feld, welche wenn ich dich richtig verstanden habe ein einzigen Spielstein darstellen soll [Name mMn ungünstig gewählt], auch das gesamte Spielfeld beinhalten?

Gruß Robert
 
Naja, mit "Feld" meine ich so eine Stelle im Spielbrett, wo ein Spielstein liegen kann oder eben auch keiner. Und von diesen Feldern soll dann ein 8x8 - Array angelegt werden.

Jetzt hab ich den Konstruktor erstmal für ein einzelnes Feld geschrieben:
Code:
public class Feld {
    int x,y;
    int zustand;
   
    public Feld(int i, int j){
        x = j;
        y = i;
        zustand = 0;            
    }
}

Und in der init-Methode soll er dann das Array bilden und auffüllen:
Code:
Feld f[][] = new Feld[8][8];
        for(int i=1; i<9; i++)
            for (int j=1; j<9; j++) {
                f[i][j] = new Feld(i,j);
                }
Ich würde halt nur gern wissen, ob das im Prinzip so funktionieren könnte, bevor ich weitermache, oder ob da ein grober Denkfehler drin ist (testen kann ich ja jetzt noch nichts).
 
Ich denke schon, dass man das so machen könnte. Allerdings würde ich das Array mit den Feld-Objekten in einer eigenen Klasse packen. Diese könnte z.B. "SpielBrett" heissen. Nebenbei: die for-Schleifen sollten von 0 bis < 8 gehen. Die erste Position eines Arrays ist immer mit "0" anzusprechen.
 
O.k., ich versuch es dann mal so. Leider gibt es ein neues Problem: Ich will die Buttons mit einem actionListener ausrüsten, damit bei einem "Einwurf" eines Spielsteins die Reihe von unten nach oben aufgefüllt wird. Versuchsweise hab ich das für die linkeste Reihe so gemacht:
Code:
btn1 = new JButton("1");
        btn1.setBounds(18, 12, 40, 26);
        contentPane.add(btn1);
        btn1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {            
                 for(int i=8; i>0; i--){
                    if (f[i][1].zustand==0){
                        public void paint(Graphics g) {
                            super.paint(g);
                            g.fillOval(21+(1-1)*50, 81+(i-1)*50, 48, 48);
                        }
                    }               
                }
            }
        });
Er beschwert sich aber in der Zeile public void paint(Graphics g) { mit folgender Meldung:
- Syntax error on token "(", ; expected
- Syntax error on token ")", ; expected
Versteh ich nicht, weiter oben hab ich es genauso gemacht (mit "drawRect"), und da läuft es. Oder will er im actionListener keine Grafik haben?
 
Moin,

außerdem:
Java:
g.fillOval(21+(1-1)*50, 81+(i-1)*50, 48, 48);
Was soll '1-1' ergeben ???

VG Klaus
 
Aber wenn ich public void paint(Graphics g) und super.paint(g) weglasse, beschwert er sich mit "g cannot be resolved".

Dabei hab ich weiter oben (direkt in der Klassendefinition) schon mit paint das Spielfeld konstruiert, und da funktioniert es:
Code:
public void paint(Graphics g) {
        super.paint(g);
        g.drawRect(20,80,400,400);
       
        for(int i=1; i<9; i++)
            for (int j=1; j<9; j++){
                g.drawRect(21+(j-1)*50, 81+(i-1)*50, 48, 48);
            }
     }
Wie muss man das den machen, wenn man im actionListener etwas zeichnen lassen will?
 
Das was du da oben gemacht hast wird nicht funktionieren. Die paint(Graphics g) Methode gehört zu der JComponent Klasse und nicht zum ActionListener. Daher meckert er auch rum eben weil er keine Methode finden kann die so im ActionListener definiert ist.

Du gehst auch schon mit dem falschen Grundgedanken an die Sache heran. Du solltest nicht im ActionListener zeichnen. Gezeichnet wird nur in der paint Methode. (wobei ich dir empfehlen würde lieber die paintComponent(Graphics g) Methode zu überschreiben.. Wenn man sich den JavaDoc durchliest sieht man auch warum:
"This is invoked during a printing operation. This is implemented to invoke paintComponent on the component. Override this if you wish to add special painting behavior when printing.").

Im ActionListener sollte nur der State des gezeichneten verändert werden. Nehmen wir also folgendes Minimalbeispiel:
Java:
/**
 * Du hast eine Klasse welche dein JPanel repräsentiert auf dem du zeichnen möchtest.
 * Dort überschreibst du die paintComponent(Graphics g) Methode wo du alles zeichnen lässt, was du zeichnen willst.
 * Außerdem enthält die Klasse die Parameter die bestimmen was gezeichnet werden soll, wie gezeichnet werden soll, eventuell 
 * welche Farbe etc etc etc.
 * Außerdem enthält sie die passenden Methoden um das gezeichnete anzupassen wie in diesem Fall die Länge der Linie.
 * Jedesmal wenn du was angepasst hast (also die Linie verlängert wurde) muss das Panel via repaint() neugezeichnet werden.
 */
public class MyDrawyPanel extends JPanel
{
    private int lineLength;

    public MyDrawyPanel(int lineLength)
    {
        this.lineLength = lineLength;
    }

    public void incrementLineLength(int lineLength)
    {
        // Linienlänge anpassen und das Bild neuzeichnen.
        this.lineLength += lineLength;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
     
        // Farbe setzen und die Linie zeichnen
        g.setColor(Color.RED);
        g.drawLine(5, 5+lineLength, 5, 5);
    }
   
   /**
    * In der main Methode wird dann einfach nur ein Test-Frame angelegt mit einem Button der die Linienlänge ändern soll.
    * Im ActionListener des Buttons wird dann die incrementLineLength(int) Methode des MyDrawyPanel aufgerufen und
    * somit auf Knopfdruck die Länge verändert.
    */
    public static void main(String[] args)
    {
        JFrame frame = new JFrame();
        frame.setSize(500,500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
        JPanel contentPane = new JPanel(new BorderLayout());
       
        MyDrawyPanel drawContent = new MyDrawyPanel(30);
        drawContent.setBackground(Color.WHITE);
       
        JButton btnChangeLine = new JButton("Länge Ändern");
        btnChangeLine.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                drawContent.incrementLineLength(20);
            }
        });
       
        contentPane.add(drawContent, BorderLayout.CENTER);
        contentPane.add(btnChangeLine, BorderLayout.SOUTH);
        frame.add(contentPane);
        frame.setVisible(true);
    }


}

Das ganze ist wie gesagt nur ein Minimalbeispiel. Mit dem Prinzip solltest du dein Vorhaben aber ganz gut umsetzen können 🙂
Du könntest so bspw. dein Spielfeld zeichnen lassen und eine Methode anlegen mit der du ein überarbeitetes Spielfeld übergeben kannst.

Gruß Robert
 

Zurück
Oben