Hi,
bin atm dabei einen kleinen Minesweeper clon zu schreiben.
Dies ist mein erstes swing projekt, und ich habe extreme probleme (bzw teilweise keine ahnung), wie ich spiellogik und GUI trennen könnte. ich poste hier mal den code, wäre nett wenn ihr eure meinung dazu schreiben könntet. kann man das in etwa so lassen, oder muss ich das ganz anders angehen?
sonstige momentane mängel im spiel:
- man kann beim ersten klick eine mine erwischen
- das programm macht nichts, wenn man gewonnen hat
- man kann die spielfeldgröße + minenanzahl nur im code ändern (main methode)
- einige menüpunkte habe noch keine funktion
- kein zeitCounter, highscore etc
klasse mineplacer, erzeugt ein Minenfeld (erst werden minen in einem boolean array erzeugt, dann die zugehörigen zahlen auf den feldern aussenrum in einem int array gespeichert.
die klasse Minesweeper ist die hauptklasse, hier sind mainmethode, gui und spiellogik
die klasse PlayButton ist eine ableitung von JButton, erweitert um koordinaten und um einen "buttonTyp" (mine, 0,1,2,3,...)
StaticStrings speichert momentan nur die Strings für die anzeige der nr auf einem feld, später werden wohl mehr dazuokommen (z.B. strings für helpfile etc)
danke für eure mühe
bin atm dabei einen kleinen Minesweeper clon zu schreiben.
Dies ist mein erstes swing projekt, und ich habe extreme probleme (bzw teilweise keine ahnung), wie ich spiellogik und GUI trennen könnte. ich poste hier mal den code, wäre nett wenn ihr eure meinung dazu schreiben könntet. kann man das in etwa so lassen, oder muss ich das ganz anders angehen?
sonstige momentane mängel im spiel:
- man kann beim ersten klick eine mine erwischen
- das programm macht nichts, wenn man gewonnen hat
- man kann die spielfeldgröße + minenanzahl nur im code ändern (main methode)
- einige menüpunkte habe noch keine funktion
- kein zeitCounter, highscore etc
klasse mineplacer, erzeugt ein Minenfeld (erst werden minen in einem boolean array erzeugt, dann die zugehörigen zahlen auf den feldern aussenrum in einem int array gespeichert.
Code:
import java.util.*;
class MinePlacer
{
//~ Constructors------------------------------------------------------------
public MinePlacer(int fieldXSize, int fieldYSize, int minesToPlace)
{
mineField = new boolean[fieldXSize][fieldYSize];
numberField = new int[fieldXSize][fieldYSize];
Random randomGen = new Random();
// seed mines randomly
while (minesToPlace > 0)
{
int randomNumber = randomGen.nextInt(fieldXSize*fieldYSize);
if (mineField[(randomNumber%fieldXSize)][randomNumber/fieldXSize] == false)
{
mineField[(randomNumber%fieldXSize)][randomNumber/fieldXSize] = true;
minesToPlace --;
}
}
// count mines around each field
for (int x = 0; x < fieldXSize; x ++)
{
for (int y = 0; y < fieldYSize; y++)
{
// no mine on field
if (mineField[x][y] == false)
{
int mineCounter = 0;
if(x > 0)
{
if (y < (fieldYSize-1))
{
// north-west
if (mineField[x-1][y+1])
mineCounter ++;
}
// west
if (mineField[x-1][y])
mineCounter ++;
if (y > 0)
{
// south-west
if (mineField[x-1][y-1])
mineCounter ++;
}
}
if (y < (fieldYSize-1))
{
// north
if (mineField[x][y+1])
mineCounter ++;
}
if (y > 0)
{
// south
if (mineField[x][y-1])
mineCounter ++;
}
if (x < (fieldXSize-1))
{
if (y < (fieldYSize-1))
{
// north-east
if (mineField[x+1][y+1])
mineCounter ++;
}
// east
if (mineField[x+1][y])
mineCounter ++;
if (y > 0)
{
// south-east
if (mineField[x+1][y-1])
mineCounter ++;
}
}
numberField[x][y] = mineCounter;
}
// mine on field
else
numberField[x][y] = -1;
}
}
}
//~ Methods-----------------------------------------------------------------
public int getMines(int x, int y)
{
return numberField[x][y];
}
//~ Fields------------------------------------------------------------------
boolean[][] mineField;
int[][] numberField;
}
die klasse Minesweeper ist die hauptklasse, hier sind mainmethode, gui und spiellogik
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Minesweeper implements MouseListener, ActionListener
{
//~ Private GUI-Methods-----------------------------------------------------
private JMenuBar createMenuBar()
{
//Create the menu bar.
menuBar = new JMenuBar();
//----Build the game menu------
menuGame = new JMenu("Game");
menuBar.add(menuGame);
//Gamemenu Items
gameNew = new JMenuItem("New Game",KeyEvent.VK_N);
gameNew.addActionListener(this);
menuGame.add(gameNew);
gameLevel = new JMenuItem("Set Level...",KeyEvent.VK_L);
menuGame.add(gameLevel);
gameLevel.addActionListener(this);
gameScores = new JMenuItem("Highscores",KeyEvent.VK_H);
menuGame.add(gameScores);
gameScores.addActionListener(this);
gameExit = new JMenuItem("Exit Program",KeyEvent.VK_E);
menuGame.add(gameExit);
gameExit.addActionListener(this);
//----Buil the Help menu-----
menuHelp = new JMenu("Help");
menuBar.add(menuHelp);
// Helpmenu Items
helpRules = new JMenuItem("Rules...",KeyEvent.VK_R);
menuHelp.add(helpRules);
helpRules.addActionListener(this);
helpAbout = new JMenuItem("About",KeyEvent.VK_A);
menuHelp.add(helpAbout);
helpAbout.addActionListener(this);
return menuBar;
}
private Container createContentPane()
{
// Create Icons
flag = new ImageIcon("img/mineFlag.jpg");
flagWrong = new ImageIcon("img/mineFlagWrong.jpg");
quest = new ImageIcon("img/questFlag.jpg");
nothing = new ImageIcon("img/null.jpg");
// Create Top-area
newGame = new JButton(new ImageIcon("img/newGame.jpg"));
newGame.setPreferredSize(new Dimension(25,25));
newGame.addMouseListener(this);
counterDisplay = new JTextField(""+minen);
topArea = new JPanel();
topArea.setPreferredSize(new Dimension(fieldXSize*25,40));
topArea.add(newGame);
topArea.add(counterDisplay);
// Create PlayButton-area
buttonArea = new JPanel();
buttonArea.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
buttonArea.setPreferredSize(new Dimension(fieldXSize*25,fieldYSize*25));
createButtonField();
contentPane = new JPanel();
contentPane.setOpaque(true);
contentPane.add(topArea);
contentPane.add(buttonArea);
return contentPane;
}
/** called from within createContentPane(), actionPerformed() for gameNew,
* mouseListener for newGame
*/
private void createButtonField()
{
minen = numberOfMines;
counterDisplay.setText(""+minen);
lost = false;
mines = new MinePlacer(fieldXSize,fieldYSize,minen);
// Array to remember PlayButtons
buttonArray = new PlayButton[fieldXSize][fieldYSize];
buttonArea.removeAll();
for (int y=0; y<fieldYSize; y++)
{
for (int x=0; x<fieldXSize; x++)
{
int buttonType = mines.getMines(x,y);
PlayButton button1 = new PlayButton(x,y,buttonType);
button1.addMouseListener(this);
buttonArea.add(button1);
buttonArray[x][y] = button1;
}
}
}
/** Create the GUI and show it.
*/
private static void createAndShowGUI()
{
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("Minesweeper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
Minesweeper demo = new Minesweeper();
frame.setJMenuBar(demo.createMenuBar());
frame.setContentPane(demo.createContentPane());
//Display the window.
frame.setSize(25*fieldXSize +25, 25*fieldYSize +150);
frame.setLocation(250,250);
frame.setVisible(true);
}
//~ Private Game-Methods----------------------------------------------------
private void buttonPressed(PlayButton butt)
{
int temp = butt.getButtonType();
// clicked on mine
if (temp == -1)
this.lost();
else
{
buttonNoMinePressed(butt);
}
butt.setOpened();
}
private void buttonNoMinePressed(PlayButton butt)
{
int temp = butt.getButtonType();
if (temp == 0)
{
butt.setOpened();
butt.setIcon(nothing);
this.openAroundNull(butt.getXPos(),butt.getYPos());
}
else
{
butt.setOpened();
butt.setText(StaticStrings.coloredNumber(temp));
}
buttonArea.validate();
}
private void openAroundNull(int x, int y)
{
PlayButton tempButton;
if (y>0)
{
if (x>0)
{
// north-west
tempButton = buttonArray[x-1][y-1];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
}
// west
tempButton = buttonArray[x][y-1];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
if (x<(fieldXSize-1))
{
// south-west
tempButton = buttonArray[x+1][y-1];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
}
}
if (x>0)
{
// north
tempButton = buttonArray[x-1][y];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
}
if (x<(fieldXSize-1))
{
// south
tempButton = buttonArray[x+1][y];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
}
if (y<(fieldYSize-1))
{
if (x>0)
{
// north-east
tempButton = buttonArray[x-1][y+1];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
}
// east
tempButton = buttonArray[x][y+1];
buttonNoMinePressed(tempButton);
if (x<(fieldXSize-1))
{
// south-east
tempButton = buttonArray[x+1][y+1];
if (tempButton.getOpened() == false)
buttonNoMinePressed(tempButton);
}
}
buttonArea.validate();
}
private void lost()
{
lost = true;
for (int i=0; i<fieldXSize; i++)
{
for (int j=0; j<fieldYSize; j++)
{
PlayButton butt = buttonArray[i][j];
// reveal all not marked mines
if (butt.getMarked() != 1 && butt.getButtonType() == -1)
{
butt.setIcon(new ImageIcon(""));
butt.setText("<html><font color=#ED3415>*</font></html>");
}
// show wrongly mine-marked buttons
else if (butt.getMarked() == 1 && butt.getButtonType() != -1)
{
butt.setIcon(flagWrong);
}
}
}
buttonArea.validate();
}
//~ Eventlistener-----------------------------------------------------------
public void actionPerformed(ActionEvent ae)
{
Object eventQuelle = ae.getSource();
// gameMenu
if (eventQuelle == gameNew)
{
createButtonField();
contentPane.validate();
}
}
public void mouseClicked(MouseEvent me)
{
Object mouseQuelle = me.getSource();
if ((mouseQuelle instanceof PlayButton) && !lost)
{
PlayButton butt = (PlayButton)me.getSource();
// leftClick
if ((me.getButton() == 1) && (butt.getMarked() == 0))
{
buttonPressed(butt);
buttonArea.validate();
}
// rightClick to mark/unmark as mine
if ((me.getButton() == 3) && (butt.getOpened() == false))
{
// button not yet marked
if (butt.getMarked() == 0)
{
butt.setIcon(flag);
butt.setMarked(1);
minen--;
counterDisplay.setText(""+minen);
}
// button marked as mine
else if (butt.getMarked() == 1)
{
butt.setIcon(quest);
butt.setMarked(2);
minen++;
counterDisplay.setText(""+minen);
}
// button marked as quest
else if (butt.getMarked() == 2)
{
butt.setIcon(new ImageIcon(""));
butt.setMarked(0);
}
buttonArea.validate();
}
}
// start new game
else if (mouseQuelle == newGame || mouseQuelle == gameNew)
{
createButtonField();
contentPane.validate();
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
//~ Main-Method-------------------------------------------------------------
public static void main(String[] args)
{
minen = 15;
numberOfMines = 15;
fieldXSize = 12;
fieldYSize = 10;
lost = false;
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
//~ Fields------------------------------------------------------------------
static int fieldXSize;
static int fieldYSize;
static int numberOfMines;
static int minen;
static boolean lost;
MinePlacer mines;
JMenuBar menuBar;
JMenu menuGame;
JMenu menuHelp;
JMenuItem gameNew;
JMenuItem gameLevel;
JMenuItem gameScores;
JMenuItem gameExit;
JMenuItem helpRules;
JMenuItem helpAbout;
JPanel topArea;
JPanel buttonArea;
JPanel contentPane;
JTextField counterDisplay;
JButton newGame;
ImageIcon flag;
ImageIcon flagWrong;
ImageIcon quest;
ImageIcon nothing;
PlayButton[][] buttonArray;
}
die klasse PlayButton ist eine ableitung von JButton, erweitert um koordinaten und um einen "buttonTyp" (mine, 0,1,2,3,...)
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
public class PlayButton extends JButton
{
//~ Constructors------------------------------------------------------------
public PlayButton(int x, int y, int type)
{
super("");
xPos = x;
yPos = y;
buttonType = type;
this.setPreferredSize(new Dimension(25,25));
this.setMargin(new Insets(2,2,2,2));
clicked = false;
}
//~ Methods-----------------------------------------------------------------
public int getXPos()
{
return xPos;
}
public int getYPos()
{
return yPos;
}
public int getButtonType()
{
return buttonType;
}
public boolean getOpened()
{
return clicked;
}
public void setOpened()
{
clicked = true;
}
public int getMarked()
{
return mineMarked;
}
public void setMarked(int m)
{
mineMarked = m;
}
//~ Fields------------------------------------------------------------------
String mineNumbers;
int xPos;
int yPos;
boolean clicked;
int mineMarked;
int buttonType;
}
StaticStrings speichert momentan nur die Strings für die anzeige der nr auf einem feld, später werden wohl mehr dazuokommen (z.B. strings für helpfile etc)
Code:
public class StaticStrings
{
/** Colored Numbers for not mined buttons
*/
static String coloredNumber(int n)
{
switch (n)
{
case 1: return "<html><font color=#410BDB>1</font></html>";
case 2: return "<html><font color=#19EB3B>2</font></html>";
case 3: return "<html><font color=#EB4019>3</font></html>";
case 4: return "<html><font color=#070E68>4</font></html>";
case 5: return "<html><font color=#070E68>5</font></html>";
case 6: return "<html><font color=#070E68>6</font></html>";
case 7: return "<html><font color=#E6DF25>7</font></html>";
case 8: return "<html><font color=#E23ED8>8</font></html>";
default: return "";
}
}
}
danke für eure mühe