/** * Moobreeder is a simple cow breeding game to illustrate the principles of * selective breeding to KS3 pupils. * * (c) Daniel Vedder 2018, Amano Christian School * Licensed under the terms of the MIT license. * https://git.synoikos.de/daniel/moobreeder */ /* * This is the main class with the GUI. */ //TODO Set breeding goal at beginning of game (dairy, meat, plowing) import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.filechooser.*; import java.util.HashMap; import java.io.File; public class MooBreeder extends JFrame implements MouseListener { private String goal; //TODO implement goal picking private JMenuBar menubar; private JMenu fileMenu, helpMenu; private JMenuItem select, save, load, reset, quit, help, about; private JPanel breedPanel; private JScrollPane herdScroller; private Box herdBox, motherBox, fatherBox, calf1Box, calf2Box; private JButton breedButton; private JFileChooser fileChooser; private HelpWindow helpWindow; public static void main(String[] args) { Herd.getInstance(); MooBreeder mb = new MooBreeder(); } public MooBreeder() { this.setTitle("MooBreeder"); this.setSize(900, 450); this.setDefaultCloseOperation(EXIT_ON_CLOSE); goal = "dairy"; helpWindow = new HelpWindow(); fileChooser = new JFileChooser(System.getProperty("user.dir")); FileFilter datFilter = new FileNameExtensionFilter("MooBreeder (.dat) files", "dat"); fileChooser.setFileFilter(datFilter); this.createMenu(); this.createLayout(); this.setVisible(true); chooseGoal(); } private void createMenu() { menubar = new JMenuBar(); fileMenu = new JMenu("File"); helpMenu = new JMenu("Help"); select = new JMenuItem("Select a goal"); save = new JMenuItem("Save"); load = new JMenuItem("Load"); reset = new JMenuItem("Reset"); quit = new JMenuItem("Quit"); help = new JMenuItem("Help"); about = new JMenuItem("About"); select.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { chooseGoal(); } }); save.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int saveConfirm = fileChooser.showSaveDialog(null); if (saveConfirm == JFileChooser.APPROVE_OPTION) { File saveFile = fileChooser.getSelectedFile(); if (!saveFile.getName().endsWith(".dat")) saveFile = new File(saveFile.getAbsolutePath()+".dat"); Herd.saveHerd(saveFile.getAbsolutePath()); JOptionPane.showMessageDialog(null, "Current herd saved to "+saveFile.getName(), "Game saved", JOptionPane.INFORMATION_MESSAGE); } } }); save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK)); load.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int loadConfirm = fileChooser.showOpenDialog(null); if (loadConfirm == JFileChooser.APPROVE_OPTION) { File loadFile = fileChooser.getSelectedFile(); int userConfirm = JOptionPane.showConfirmDialog(null, "Load herd from "+loadFile.getName()+"?", "Confirm", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (userConfirm == JOptionPane.OK_OPTION) { Herd.loadHerd(loadFile.getAbsolutePath()); updateGUI(); } } } }); load.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK)); reset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int restart = JOptionPane.showConfirmDialog(null, "Reset the game?", "Reset?", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (restart == JOptionPane.OK_OPTION) resetGame(); } }); reset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.ALT_MASK)); help.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { helpWindow.setVisible(true); } }); help.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, ActionEvent.ALT_MASK)); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int confirm = JOptionPane.showConfirmDialog(null, "Quit MooBreeder?", "Quit?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if(confirm == JOptionPane.YES_OPTION) System.exit(0); } }); quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.ALT_MASK)); about.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "MooBreeder - an educational breeding game"+ "\n\n(c) 2018 Daniel Vedder"+ ", Amano Christian School"+ "\nhttps://git.synoikos.de/daniel/moobreeder", "About", JOptionPane.INFORMATION_MESSAGE); } }); fileMenu.add(select); fileMenu.add(save); fileMenu.add(new JSeparator()); fileMenu.add(load); fileMenu.add(reset); fileMenu.add(new JSeparator()); fileMenu.add(quit); helpMenu.add(help); helpMenu.add(about); menubar.add(fileMenu); menubar.add(helpMenu); this.setJMenuBar(menubar); } private void createLayout() { this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.X_AXIS)); //Create the left half of the window with the herd box JPanel herdBorderPanel = new JPanel(new BorderLayout()); herdBox = new Box(BoxLayout.Y_AXIS); herdScroller = new JScrollPane(herdBox, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); herdScroller.setWheelScrollingEnabled(true); herdBorderPanel.add(herdScroller, BorderLayout.CENTER); //Take care of the layout herdBorderPanel.add(Box.createVerticalStrut(25), BorderLayout.NORTH); herdBorderPanel.add(Box.createVerticalStrut(25), BorderLayout.SOUTH); herdBorderPanel.add(Box.createHorizontalStrut(25), BorderLayout.EAST); herdBorderPanel.add(Box.createHorizontalStrut(25), BorderLayout.WEST); this.add(herdBorderPanel); //Create the right half of the window with the breeding interface JPanel breedBorderPanel = new JPanel(new BorderLayout()); Box breedBox = new Box(BoxLayout.Y_AXIS); breedPanel = new JPanel(new GridLayout(2,2)); fatherBox = new Box(BoxLayout.Y_AXIS); motherBox = new Box(BoxLayout.Y_AXIS); calf1Box = new Box(BoxLayout.Y_AXIS); calf2Box = new Box(BoxLayout.Y_AXIS); breedPanel.add(fatherBox); breedPanel.add(motherBox); breedPanel.add(calf1Box); breedPanel.add(calf2Box); breedBox.add(breedPanel); //Add the breed button breedButton = new JButton("Breed"); breedButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { breedAction(); } }); breedBox.add(Box.createVerticalStrut(10)); breedBox.add(breedButton); //Take care of the layout breedBorderPanel.add(breedBox, BorderLayout.CENTER); breedBorderPanel.add(Box.createVerticalStrut(25), BorderLayout.NORTH); breedBorderPanel.add(Box.createHorizontalStrut(25), BorderLayout.EAST); breedBorderPanel.add(Box.createVerticalStrut(25), BorderLayout.SOUTH); this.add(breedBorderPanel); updateGUI(); } private void updateGUI() { updateHerdBox(); updateParentBox(); updateOffspringBox(); //this.validate(); this.repaint(); } private void updateHerdBox() { //TODO It should be possible to choose just bulls or cows herdBox.removeAll(); for (int c = 0; c < Herd.getInstance().size(); c++) { Cow cow = Herd.getInstance().getNthCow(c); if (Herd.getInstance().isParent(cow.getID())) continue; Box cowBox = getCowBox(cow); herdBox.add(cowBox); herdBox.add(Box.createVerticalStrut(1)); } herdBox.validate(); } private void updateParentBox() { fatherBox.removeAll(); motherBox.removeAll(); //Label boxes JLabel dl = new JLabel("Father:"); JLabel ml = new JLabel("Mother:"); fatherBox.add(dl); motherBox.add(ml); //Include information boxes Cow[] parents = Herd.getInstance().getParents(); Box db = getCowBox(parents[0]); fatherBox.add(Box.createVerticalStrut(10)); fatherBox.add(db); Box mb = getCowBox(parents[1]); motherBox.add(Box.createVerticalStrut(10)); motherBox.add(mb); fatherBox.validate(); motherBox.validate(); } private void updateOffspringBox() { calf1Box.removeAll(); calf2Box.removeAll(); JLabel l1 = new JLabel("Calf 1:"); JLabel l2 = new JLabel("Calf 2:"); calf1Box.add(l1); calf2Box.add(l2); //Include information boxes Cow[] calves = Herd.getInstance().getCalves(); Box c1b = getCowBox(calves[0]); calf1Box.add(Box.createVerticalStrut(10)); calf1Box.add(c1b); Box c2b = getCowBox(calves[1]); calf2Box.add(Box.createVerticalStrut(10)); calf2Box.add(c2b); calf1Box.validate(); calf2Box.validate(); } private Box getCowBox(Cow c) { Box cowBox = new Box(BoxLayout.Y_AXIS); cowBox.setBorder(new BevelBorder(BevelBorder.RAISED)); cowBox.setMaximumSize(new Dimension(300, 110)); cowBox.setMinimumSize(new Dimension(300, 110)); cowBox.add(Box.createVerticalStrut(7)); //If there is no cow here, display an empty panel if (c == null) { cowBox.add(new JLabel(" <empty> ", JLabel.CENTER)); cowBox.add(Box.createVerticalStrut(9)); return cowBox; } //Genealogy labels cowBox.setName(String.valueOf(c.getID())); JLabel name = new JLabel(c.getName()); name.setFont(new Font(Font.SERIF, Font.BOLD, 14)); JLabel genealogy = new JLabel("Generation "+c.getGeneration()+ ", Father: "+c.getParents()[0]+ ", Mother: "+c.getParents()[1]); cowBox.add(name); cowBox.add(Box.createVerticalStrut(5)); cowBox.add(genealogy); cowBox.add(Box.createVerticalStrut(3)); //Trait and rating labels HashMap<String, Integer> t = c.getTraits(); JLabel tl1 = new JLabel("Milk: "+t.get("milk")+", Meat: "+t.get("meat")); JLabel tl2 = new JLabel("Strength: "+t.get("strength")+", Aggression: "+ t.get("aggression")); cowBox.add(tl1); cowBox.add(tl2); cowBox.add(Box.createVerticalStrut(5)); JLabel rl = new JLabel(c.rateCow(goal)); rl.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 12)); cowBox.add(rl); //Final stuff cowBox.add(Box.createVerticalStrut(5)); cowBox.addMouseListener(this); return cowBox; } private void breedAction() { String possible = Herd.getInstance().checkBreeding(); if (possible == "OK") { Herd.getInstance().breed(); updateGUI(); testWin(); } else { JOptionPane.showMessageDialog(null, possible, "Breeding failed", JOptionPane.WARNING_MESSAGE); } } private void testWin() { Cow[] calves = Herd.getInstance().getCalves(); if ((calves[0] != null && calves[0].rateCow(goal).indexOf("excellent") != -1) || (calves[1] != null && calves[1].rateCow(goal).indexOf("excellent") != -1)) JOptionPane.showMessageDialog(null, "You have bred an excellent cow for "+ goal+" in "+Cow.getMaxGen()+" generations.", "Congratulations!", JOptionPane.INFORMATION_MESSAGE); } private void chooseGoal() { String[] possible = {"dairy", "beef", "plowing"}; goal = (String) JOptionPane.showInputDialog(null, "What do you want to breed for?", "Select a goal", JOptionPane.QUESTION_MESSAGE, null, possible, possible[0]); updateGUI(); } private void resetGame() { Herd.getInstance().resetHerd(); updateGUI(); //FIXME ScrollPane disappears? - only until window is resized } /* * MouseListener methods * * FIXME Updating the GUI does not yet work as and when intended */ @Override public void mouseClicked(MouseEvent me) { System.out.println("Recognised a mouse event."); //DEBUG int selectionID = Integer.parseInt(me.getComponent().getName()); //Respond to the mouse click with an action or a context menu if (me.getButton() == MouseEvent.BUTTON3) { mouseSideAction(selectionID, me); } else if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) { mouseMainAction(selectionID); } } /* * The action launched by a double left click or the first context menu: * set/remove a parent or add a calf to the herd. */ private void mouseMainAction(int selection) { System.out.println("Carrying out mouse main action on animal #"+selection); //DEBUG if (Herd.getInstance().isParent(selection)) Herd.getInstance().removeParent(selection); else if (Herd.getInstance().isCalf(selection)) Herd.getInstance().keepCalf(selection); else Herd.getInstance().setParent(selection); updateGUI(); } /* * The context menu launched by a right click. Offers the main mouse action * (see above), or the option to discard/delete a calf or adult animal. */ private void mouseSideAction(int selection, MouseEvent me) { System.out.println("Carrying out mouse side action on animal #"+selection); //DEBUG //Initialise menu JPopupMenu contextMenu = new JPopupMenu(); JMenuItem item1 = new JMenuItem(); JMenuItem item2 = new JMenuItem(); //Change item labels and actions depending on context //FIXME Problem with animals occurring both in the herd list and the parent slots item1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { mouseMainAction(selection); //always the same } }); if (Herd.getInstance().isParent(selection)) { item1.setText("Remove as parent"); } else if (Herd.getInstance().isCalf(selection)) { item1.setText("Add calf to herd"); item2.setText("Discard calf"); item2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Herd.getInstance().discardCalf(selection); } }); } else { item1.setText("Select for breeding"); item2.setText("Remove from herd"); item2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String question = "Remove "+Herd.getInstance(). getCow(selection).getName()+" from herd?"; int confirm = JOptionPane.showConfirmDialog(null, question, "Remove animal?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if(confirm == JOptionPane.YES_OPTION) Herd.getInstance().removeCow(selection); } }); } //Add menu items and show menu contextMenu.add(item1); if (item2.getText() != "") contextMenu.add(item2); contextMenu.show(me.getComponent(), me.getX(), me.getY()); updateGUI(); } @Override public void mouseEntered(MouseEvent me) {} @Override public void mouseExited(MouseEvent me) {} @Override public void mousePressed(MouseEvent me) { Box tile = (Box) me.getComponent(); tile.setBorder(new BevelBorder(BevelBorder.LOWERED)); } @Override public void mouseReleased(MouseEvent me) { Box tile = (Box) me.getComponent(); tile.setBorder(new BevelBorder(BevelBorder.RAISED)); } }