From cae72163a4e1fb23f07754ced23d124826766258 Mon Sep 17 00:00:00 2001 From: Enrico Fasoli Date: Wed, 5 Aug 2015 17:41:21 +0200 Subject: [PATCH] implemented saving and loading creatures --- README.md | 5 +- core/src/com/mygdx/game/Game.java | 92 ++++++++------ core/src/com/mygdx/game/Log.java | 1 + core/src/com/mygdx/game/Serializer.java | 111 ++++++++++++++++ core/src/logic/World.java | 6 +- core/src/logic/neural/Brain.java | 25 +--- core/src/logic/neural/Neuron.java | 1 + desktop/src/gui/GUI.form | 113 ++++++++++++----- desktop/src/gui/GUI.java | 160 +++++++++++++++++------- 9 files changed, 372 insertions(+), 142 deletions(-) create mode 100644 core/src/com/mygdx/game/Serializer.java diff --git a/README.md b/README.md index 12200b5..86bdaed 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,8 @@ Visis the [releases page](https://github.com/fazo96/AIrium/releases) to download ### Controls -- __+__ and __-__ control the zoom of the camera -- __arrow keys__ allow you to move the camera -- The __Configuration__ page in the GUI will let you tweak more! +- The __Configuration__ page in the GUI will let you tweak many parameters and pause the simulation +- You can drag with the mouse to move the camera and zoom with the mouse wheel ## Development diff --git a/core/src/com/mygdx/game/Game.java b/core/src/com/mygdx/game/Game.java index 35462dd..047dc84 100644 --- a/core/src/com/mygdx/game/Game.java +++ b/core/src/com/mygdx/game/Game.java @@ -3,6 +3,7 @@ package com.mygdx.game; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; +import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; @@ -20,10 +21,60 @@ public class Game extends ApplicationAdapter { private float cameraSpeed = 15; private BitmapFont font; private boolean paused = false; + private InputProcessor input; @Override public void create() { game = this; + input = new InputProcessor() { + + @Override + public boolean keyDown(int i) { + return true; + } + + @Override + public boolean keyUp(int i) { + return true; + } + + @Override + public boolean keyTyped(char c) { + return true; + } + + @Override + public boolean touchDown(int i, int i1, int i2, int i3) { + return true; + } + + @Override + public boolean touchUp(int i, int i1, int i2, int i3) { + return true; + } + + @Override + public boolean touchDragged(int i, int i1, int i2) { + renderer.translate(Gdx.input.getDeltaX(), -Gdx.input.getDeltaY(), 0); + return true; + } + + @Override + public boolean mouseMoved(int i, int i1) { + return true; + } + + @Override + public boolean scrolled(int i) { + if (i>0) { + renderer.scale(0.5f, 0.5f, 1); + } else { + renderer.scale(1.5f, 1.5f, 1); + } + return true; + } + }; + Gdx.input.setInputProcessor(input); renderer = new ShapeRenderer(); renderer.setAutoShapeType(true); overlayRenderer = new ShapeRenderer(); @@ -45,47 +96,6 @@ public class Game extends ApplicationAdapter { @Override public void render() { - // Controls - if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE)) { - world.launchNewGen(); - } - if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { - renderer.translate(-cameraSpeed, 0, 0); - } - if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) { - renderer.translate(cameraSpeed, 0, 0); - } - if (Gdx.input.isKeyPressed(Input.Keys.UP)) { - renderer.translate(0, -cameraSpeed, 0); - } - if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) { - renderer.translate(0, cameraSpeed, 0); - } - if (Gdx.input.isKeyJustPressed(Input.Keys.PLUS)) { - renderer.scale(0.5f, 0.5f, 1); - } - if (Gdx.input.isKeyJustPressed(Input.Keys.MINUS)) { - renderer.scale(1.5f, 1.5f, 1); - } - if (Gdx.input.isKeyJustPressed(Input.Keys.P)) { - paused = !paused; - } - if (Gdx.input.isKeyJustPressed(Input.Keys.L)) { - if (world.getFpsLimit() == 60) { - world.setFpsLimit(0); - } else { - world.setFpsLimit(60); - } - } - if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)) { - renderer.translate(Gdx.input.getDeltaX(), Gdx.input.getDeltaY() * -1, 0); - } - /* - // Broken for now - if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){ - // TODO: project coordinates to world - world.selectCreatureAt(Gdx.input.getX(), Gdx.input.getY()); - }*/ // Draw Gdx.gl.glClearColor(0, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); diff --git a/core/src/com/mygdx/game/Log.java b/core/src/com/mygdx/game/Log.java index c3222b1..3bbab07 100644 --- a/core/src/com/mygdx/game/Log.java +++ b/core/src/com/mygdx/game/Log.java @@ -28,6 +28,7 @@ public class Log { for (LogListener l : logListeners) { l.onLog(level, msg); } + System.out.println(msg); } } diff --git a/core/src/com/mygdx/game/Serializer.java b/core/src/com/mygdx/game/Serializer.java new file mode 100644 index 0000000..22ea4f2 --- /dev/null +++ b/core/src/com/mygdx/game/Serializer.java @@ -0,0 +1,111 @@ +package com.mygdx.game; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Hangles File I/O for AIrium components. + * + * @author fazo + */ +public class Serializer { + + public static void saveToFile(File f, String content) { + PrintWriter fw = null; + try { + fw = new PrintWriter(f); + } catch (IOException ex) { + Log.log(Log.ERROR, ex.getMessage()); + } + fw.print(content); + fw.flush(); + fw.close(); + } + + public static String loadFromFile(File f) { + String s, a = ""; + try { + BufferedReader bf = new BufferedReader(new FileReader(f)); + while ((s = bf.readLine()) != null) { + a += s+"\n"; + } + } catch (Exception e) { + Log.log(Log.ERROR, e.getMessage()); + System.out.println(e+""); + } + return a; + } + + public static String serializeBrain(float brainMap[][][]) { + String s = "# Neural Map for use with AIrium.\n" + + "# More information at http://github.com/fazo96/AIrium\n" + + "Layers: " + (brainMap.length+1); + s += "\nInput Neurons: " + brainMap[0][0].length; + s += "\n# Layer 1 Skipped because it's the input layer."; + // layers (input layer not included in brain map) + for (int i = 0; i < brainMap.length; i++) { + s += "\nLayer " + (i + 2) + " has " + brainMap[i].length + " neurons"; + for (int j = 0; j < brainMap[i].length; j++) { // neurons + s += "\nWeights for Layer " + (i + 2) + " Neuron " + (j + 1) + " = "; + for (int z = 0; z < brainMap[i][j].length; z++) { // connections + s += brainMap[i][j][z] + " "; + } + } + } + return s; + } + + public static float[][][] loadBrain(String s) { + float brainMap[][][] = null; + Log.log(Log.INFO,"Loading brain from String with "+s.split("\n").length+" lines:\n"+s); + for (String l : s.split("\n")) { + l = l.trim(); + if (l.isEmpty() || l.startsWith("#")) { + // Skip comment + } else if (l.startsWith("Layers: ")) { + // Set Layer number + int layers = Integer.parseInt(l.split(" ")[1]) - 1; + brainMap = new float[layers][][]; + Log.log(Log.INFO, "Loaded NLayers: " + layers); + } else if (l.startsWith("Input Neurons")) { + int in = Integer.parseInt(l.split(" ")[2]); + brainMap[0] = new float[in][0]; + Log.log(Log.INFO, "Loaded NInputNeurons: " + in); + } else if (l.startsWith("Layer ")) { + // Set neuron number for given layer + String ll[] = l.split(" "); + int layer = Integer.parseInt(ll[1]) - 2; + int n = Integer.parseInt(ll[3]); + brainMap[layer] = new float[n][];//[layer>0?brainMap[layer-1].length:0]; + } else if (l.startsWith("Weights ")) { + // Set weights + String ll[] = l.split(" "); + int layer = Integer.parseInt(ll[3]) - 2; + int neuron = Integer.parseInt(ll[5]) - 1; + int nWeights = ll.length - 7; + brainMap[layer][neuron] = new float[nWeights]; + if(layer == 0){ + Log.log(Log.INFO, "This weightmap is for brains with "+(nWeights)+" input neurons."); + } else if (nWeights != brainMap[layer - 1].length) { + Log.log(Log.ERROR, "WRONG WEIGHT NUMBER: prev layer has " + + brainMap[layer - 1].length + " neurons, but only " + + (nWeights) + + " weights are supplied to this neuron"); + } + for (int i = 7; i < ll.length; i++) { + brainMap[layer][neuron][i - 7] = Float.parseFloat(ll[i]); + Log.log(Log.INFO,"Loading L"+layer+"N"+neuron+"W"+(i-7)+" = "+brainMap[layer][neuron][i-7]); + } + Log.log(Log.INFO, "Loaded " + (nWeights) + " Weights for Layer " + layer + " Neuron " + neuron); + } + } + return brainMap; + } +} diff --git a/core/src/logic/World.java b/core/src/logic/World.java index 6fe3dbe..e42866a 100644 --- a/core/src/logic/World.java +++ b/core/src/logic/World.java @@ -348,15 +348,15 @@ public class World implements Runnable { } } - private void spawnVegetable() { + public void spawnVegetable() { spawn(false, null); } - private Creature spawnCreature() { + public Creature spawnCreature() { return (Creature) spawn(true, null); } - private Creature spawnCreature(float[][][] b) { + public Creature spawnCreature(float[][][] b) { return (Creature) spawn(true, b); } diff --git a/core/src/logic/neural/Brain.java b/core/src/logic/neural/Brain.java index d7b12b9..0df0a4d 100644 --- a/core/src/logic/neural/Brain.java +++ b/core/src/logic/neural/Brain.java @@ -34,28 +34,13 @@ public class Brain { initialize(); } - /** - * Create a new brain using given brain map (mind) - * - * @param brainMap the brain map (mind) to use - */ - public Brain(float[][][] brainMap) { - neurons = new Neuron[brainMap.length][]; - for (int i = 0; i < brainMap.length; i++) { // for each layer - neurons[i] = new Neuron[brainMap[i].length]; - for (int j = 0; j < brainMap[i].length; j++) { // for each neuron - neurons[i][j] = new Neuron(i, bias, this, brainMap[i][j]); - } - } - } - /** * Apply a new brain map (mind) to this brain * * @param brainMap the new brain map to apply */ public void remap(float[][][] brainMap) { - for (int i = 0; i < brainMap.length; i++) { // for each layer + for (int i = 0; i < brainMap.length; i++) { // for each layer (skip input) for (int j = 0; j < brainMap[i].length; j++) { // for each neuron // skip input layer if (neurons[i + 1][j] == null) { @@ -103,9 +88,11 @@ public class Brain { float nr = neurons[i][j].compute(); // Draw neuron links float[] links = neurons[i][j].getWeights(); - for (int f = 0; f < links.length; f++) { - s.setColor(links[f] < 0 ? links[f] / 2 * -1 : 0, links[f] > 0 ? links[f] / 2 : 0, 0, 1); - s.line(i * sepX + offset, j * sepY + offset, (i - 1) * sepX + offset, f * sepY + offset); + if (links != null) { + for (int f = 0; f < links.length; f++) { + s.setColor(links[f] < 0 ? links[f] / 2 * -1 : 0, links[f] > 0 ? links[f] / 2 : 0, 0, 1); + s.line(i * sepX + offset, j * sepY + offset, (i - 1) * sepX + offset, f * sepY + offset); + } } // Draw neuron s.setColor(1 - nr, nr, 0, 1); diff --git a/core/src/logic/neural/Neuron.java b/core/src/logic/neural/Neuron.java index ce390da..e56c204 100644 --- a/core/src/logic/neural/Neuron.java +++ b/core/src/logic/neural/Neuron.java @@ -76,6 +76,7 @@ public class Neuron { * @return the output of this neuron. */ public float compute() { + if(weights == null || weights.length == 0) isInputNeuron = true; if (isInputNeuron) { return output; } diff --git a/desktop/src/gui/GUI.form b/desktop/src/gui/GUI.form index eadfe07..a02b405 100644 --- a/desktop/src/gui/GUI.form +++ b/desktop/src/gui/GUI.form @@ -89,9 +89,6 @@ - - - @@ -174,7 +171,7 @@ - + @@ -228,35 +225,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -496,7 +464,7 @@ - + @@ -810,6 +778,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/desktop/src/gui/GUI.java b/desktop/src/gui/GUI.java index a621da3..f9df7d2 100644 --- a/desktop/src/gui/GUI.java +++ b/desktop/src/gui/GUI.java @@ -11,7 +11,9 @@ import com.mygdx.game.Game; import com.mygdx.game.Listener; import com.mygdx.game.Log; import com.mygdx.game.Log.LogListener; +import com.mygdx.game.Serializer; import java.awt.Desktop; +import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; @@ -19,7 +21,10 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import javafx.stage.FileChooser; +import javax.swing.JFileChooser; import javax.swing.JOptionPane; +import logic.Creature; /** * @@ -80,8 +85,6 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { logTextArea = new javax.swing.JTextArea(); jLabel1 = new javax.swing.JLabel(); logLevelBox = new javax.swing.JComboBox(); - jScrollPane2 = new javax.swing.JScrollPane(); - creatureList = new javax.swing.JList(); jPanel1 = new javax.swing.JPanel(); fpsLimitSlider = new javax.swing.JSlider(); jLabel3 = new javax.swing.JLabel(); @@ -129,6 +132,11 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { jLabel12 = new javax.swing.JLabel(); nMutatedConnectionsSlider = new javax.swing.JSlider(); currentNMutatedConnections = new javax.swing.JLabel(); + jPanel3 = new javax.swing.JPanel(); + jScrollPane2 = new javax.swing.JScrollPane(); + creatureList = new javax.swing.JList(); + saveBrainBtn = new javax.swing.JButton(); + loadBrainBtn = new javax.swing.JButton(); status = new javax.swing.JLabel(); menuBar = new javax.swing.JMenuBar(); jMenu1 = new javax.swing.JMenu(); @@ -143,7 +151,6 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("AIrium"); setMinimumSize(new java.awt.Dimension(700, 700)); - setPreferredSize(new java.awt.Dimension(700, 700)); logTextArea.setEditable(false); logTextArea.setColumns(20); @@ -178,7 +185,7 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { logPaneLayout.setVerticalGroup( logPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(logPaneLayout.createSequentialGroup() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 490, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 567, Short.MAX_VALUE) .addGap(10, 10, 10) .addGroup(logPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) @@ -188,21 +195,6 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { tabs.addTab("Log", logPane); - creatureList.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "No creatures" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } - }); - creatureList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - creatureList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { - public void valueChanged(javax.swing.event.ListSelectionEvent evt) { - creatureListValueChanged(evt); - } - }); - jScrollPane2.setViewportView(creatureList); - - tabs.addTab("Creatures", jScrollPane2); - fpsLimitSlider.setMinimum(1); fpsLimitSlider.setSnapToTicks(true); fpsLimitSlider.setToolTipText("The maximum amount of ticks per second the simulation is allowed to compute"); @@ -598,7 +590,7 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(drawViewCones) .addComponent(drawSightLines)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 41, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 71, Short.MAX_VALUE) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(pauseButton) .addComponent(jButton1)) @@ -607,6 +599,58 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { tabs.addTab("Settings", jPanel1); + creatureList.setModel(new javax.swing.AbstractListModel() { + String[] strings = { "No creatures" }; + public int getSize() { return strings.length; } + public Object getElementAt(int i) { return strings[i]; } + }); + creatureList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + creatureList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { + public void valueChanged(javax.swing.event.ListSelectionEvent evt) { + creatureListValueChanged(evt); + } + }); + jScrollPane2.setViewportView(creatureList); + + saveBrainBtn.setText("Save"); + saveBrainBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + saveBrainBtnActionPerformed(evt); + } + }); + + loadBrainBtn.setText("Load"); + loadBrainBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + loadBrainBtnActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane2) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(saveBrainBtn) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(loadBrainBtn) + .addContainerGap(587, Short.MAX_VALUE)) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 569, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(saveBrainBtn) + .addComponent(loadBrainBtn)) + .addContainerGap()) + ); + + tabs.addTab("Creatures", jPanel3); + status.setText("Simulation stopped"); javax.swing.GroupLayout containerLayout = new javax.swing.GroupLayout(container); @@ -816,14 +860,14 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { currentMaxTicks.setText(maxTicksSlider.getValue() + ""); currentHpDecay.setText(hpDecaySlider.getValue() / 1000f + ""); currentSightRange.setText(sightRangeSlider.getValue() + ""); - options.put("nMutatedBrains", (float) nMutatedBrainsSlider.getValue()/100); - currentNMutatedBrains.setText(String.format("%.2f", (float) nMutatedBrainsSlider.getValue()/100)+"%"); - options.put("nMutatedNeurons", (float) nMutatedNeuronsSlider.getValue()/100); - currentNMutatedNeurons.setText(String.format("%.2f", (float) nMutatedNeuronsSlider.getValue()/100)+"%"); - options.put("nMutatedConnections", (float) nMutatedConnectionsSlider.getValue()/100); - currentNMutatedConnections.setText(String.format("%.2f", (float) nMutatedConnectionsSlider.getValue()/100)+"%"); - options.put("mutationFactor", (float) mutationFactorSlider.getValue()/100); - currentMutationFactor.setText(String.format("%.2f", (float) mutationFactorSlider.getValue()/100)); + options.put("nMutatedBrains", (float) nMutatedBrainsSlider.getValue() / 100); + currentNMutatedBrains.setText(String.format("%.2f", (float) nMutatedBrainsSlider.getValue() / 100) + "%"); + options.put("nMutatedNeurons", (float) nMutatedNeuronsSlider.getValue() / 100); + currentNMutatedNeurons.setText(String.format("%.2f", (float) nMutatedNeuronsSlider.getValue() / 100) + "%"); + options.put("nMutatedConnections", (float) nMutatedConnectionsSlider.getValue() / 100); + currentNMutatedConnections.setText(String.format("%.2f", (float) nMutatedConnectionsSlider.getValue() / 100) + "%"); + options.put("mutationFactor", (float) mutationFactorSlider.getValue() / 100); + currentMutationFactor.setText(String.format("%.2f", (float) mutationFactorSlider.getValue() / 100)); if (game != null) { game.getWorld().reloadOptions(); } @@ -837,20 +881,6 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { Log.setLogLevel(logLevelBox.getSelectedIndex()); }//GEN-LAST:event_logLevelBoxItemStateChanged - private void creatureListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_creatureListValueChanged - if (game == null) { - creatureList.setSelectedIndex(-1); - } else { - try { - if (creatureList.getSelectedIndex() >= 0) { - Game.get().getWorld().selectCreature(Game.get().getWorld().getCreatures().get(creatureList.getSelectedIndex())); - } - } catch (IndexOutOfBoundsException ex) { - JOptionPane.showMessageDialog(this, "This creature is not available"); - } - } - }//GEN-LAST:event_creatureListValueChanged - private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; if (desktop != null) { @@ -957,6 +987,49 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { updateSettings(); }//GEN-LAST:event_nMutatedConnectionsSliderStateChanged + private void creatureListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_creatureListValueChanged + if (game == null) { + creatureList.setSelectedIndex(-1); + } else { + try { + if (creatureList.getSelectedIndex() >= 0) { + Game.get().getWorld().selectCreature(Game.get().getWorld().getCreatures().get(creatureList.getSelectedIndex())); + } + } catch (IndexOutOfBoundsException ex) { + JOptionPane.showMessageDialog(this, "This creature is not available"); + } + } + }//GEN-LAST:event_creatureListValueChanged + + private void saveBrainBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveBrainBtnActionPerformed + game.setPaused(true); + updateGUI(); + if (game.getWorld().getSelectedCreature() == null) { + JOptionPane.showMessageDialog(this, "Please select a creature first"); + return; + } + JFileChooser fc = new JFileChooser(); + File f = null; + if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { + f = fc.getSelectedFile(); + } else return; + Serializer.saveToFile(f, Serializer.serializeBrain(game.getWorld().getSelectedCreature().getBrain().getMap())); + }//GEN-LAST:event_saveBrainBtnActionPerformed + + private void loadBrainBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadBrainBtnActionPerformed + game.setPaused(true); + updateGUI(); + JFileChooser fc = new JFileChooser(); + File f = null; + if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + f = fc.getSelectedFile(); + } else return; + float map[][][] = Serializer.loadBrain(Serializer.loadFromFile(f)); + Creature c = (Creature) game.getWorld().spawnCreature(map); + game.getWorld().selectCreature(c); + updateGUI(); + }//GEN-LAST:event_loadBrainBtnActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel container; private javax.swing.JSlider corpseDecaySlider; @@ -1001,8 +1074,10 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { private javax.swing.JMenuItem jMenuItem1; private javax.swing.JMenuItem jMenuItem2; private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JButton loadBrainBtn; private javax.swing.JComboBox logLevelBox; private javax.swing.JPanel logPane; private javax.swing.JTextArea logTextArea; @@ -1017,6 +1092,7 @@ public class GUI extends javax.swing.JFrame implements LogListener, Listener { private javax.swing.JSlider nPlantsSlider; private javax.swing.JToggleButton pauseButton; private javax.swing.JMenuItem pauseMenuButton; + private javax.swing.JButton saveBrainBtn; private javax.swing.JSlider sightRangeSlider; private javax.swing.JMenuItem startButton; private javax.swing.JLabel status;