// Swarm control // // Author Matthew Caryl // Created 22.3.97 // // Although under copywrite to the author (Matthew Caryl) this code can be copied and modified for non-commercial // purposes as long as any derivatives contain this condition. package Swarm; import java.awt.Frame; import java.awt.Event; import java.awt.Color; import java.awt.Button; import java.awt.Choice; import java.awt.Panel; import java.awt.Label; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridLayout; import java.lang.Thread; import java.lang.Integer; final class Control extends Frame implements Runnable { // // Private interface // static String[] behaviourNames = {"Flocking", "Swarming", "Lonely", "Friendly", "Indifferent", "Frightened"}; static float[][][] behaviourValues = {{{0.0f, 0.2f, 0.15f, 0.1f, 0.0f}, // flocking {0.5f, 0.2f, 0.05f, 0.0f, 0.0f}, // avoidance to separation {0.0f, 0.1f, 0.2f, 0.3f, 0.4f}, {0.5f, 0.5f, 0.5f, 0.5f, 0.0f}, {0.5f, 0.4f, 0.3f, 0.2f, 0.0f}}, {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // swarming {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // avoidance to separation {0.0f, 0.7f, 0.85f, 0.95f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 0.95f, 0.85f, 0.7f, 0.0f}}, {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // lonely {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // avoidance to separation {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f, 1.0f}}, {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // friendly {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // avoidance to separation {1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}}, {{0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // indifferent {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // avoidance to separation {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}}, {{0.1f, 0.4f, 0.3f, 0.2f, 0.1f}, // frightened {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, // avoidance to separation {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}}}; private Thread animation; private Graph[] graphs; private static int WIDTH = 300; private static int HEIGHT = 300; private World owner; private Button behaviour; private Choice whatBehaviour; private Button number; private Choice whatNumber; private Button predator; private Button dismiss; private Button reset; private String predatorText(boolean on) { if (on) return "Predator on"; else return "Predator off"; } // // Public interface // public Control(World w) { super("Swarm Control"); owner = w; // Signiture at top of control panel Panel signiturePanel = new Panel(); signiturePanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10)); signiturePanel.add(new Label("Matthew Caryl 1997")); this.add("North", signiturePanel); // Graph controls below that Panel graphPanel = new Panel(); graphPanel.setBackground(Color.black); graphPanel.setLayout(new GridLayout(3, 2, 0, 5)); graphs = new Graph[5]; graphs[0] = new Graph(w, "Avoidance", Color.yellow, Sparrow.avoidance); graphs[1] = new Graph(w, "Evasion", Color.pink, Sparrow.evasion); graphs[2] = new Graph(w, "Cohesion", Color.green, Sparrow.cohesion); graphs[3] = new Graph(w, "Alignment", Color.blue, Sparrow.alignment); graphs[4] = new Graph(w, "Separation", Color.orange, Sparrow.separation); for (int i = 4; i >= 0; i--) { graphs[i].setBackground(Color.black); graphs[i].setForeground(Color.white); graphPanel.add(graphs[i]); } // Suround with black and then gray border Panel blackBorderPanel = new Panel(); blackBorderPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); blackBorderPanel.setBackground(Color.black); blackBorderPanel.add(graphPanel); Panel grayBorderPanel = new Panel(); grayBorderPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); grayBorderPanel.add(blackBorderPanel); this.add("Center", grayBorderPanel); // Behaviour, bot number, predator, and dismiss controls at bottom Panel controlPanel = new Panel(); controlPanel.setLayout(new GridLayout(3, 2, 5, 5)); behaviour = new Button("Set behaviour"); whatBehaviour = new Choice(); for (int i = 0; i < behaviourNames.length; i++) whatBehaviour.addItem(behaviourNames[i]); controlPanel.add(behaviour); controlPanel.add(whatBehaviour); number = new Button("Set number bots"); whatNumber = new Choice(); for (int i = 10; i <= 100; i += 10) whatNumber.addItem(Integer.toString(i)); try { whatNumber.select((int) (owner.numberBots() / 10) - 1); } catch (IllegalArgumentException e) { // just leave it on default selection } controlPanel.add(number); controlPanel.add(whatNumber); predator = new Button(predatorText(!owner.kestrelOn())); reset = new Button("Reset"); controlPanel.add(predator); controlPanel.add(reset); // Align controls in center with dismiss button dismiss = new Button("Dismiss"); Panel dismissAlignPanel = new Panel(); dismissAlignPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10)); dismissAlignPanel.add(dismiss); Panel controlAlignPanel = new Panel(); controlAlignPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); controlAlignPanel.add(controlPanel); Panel alignPanel = new Panel(); alignPanel.setLayout(new BorderLayout(0, 0)); alignPanel.add("North", controlAlignPanel); alignPanel.add("South", dismissAlignPanel); this.add("South", alignPanel); // Show controls this.setResizable(false); this.pack(); this.show(); } public boolean action(Event e, Object arg) { if (e.target == dismiss) { // Remove control panel this.hide(); this.dispose(); return true; } else if (e.target == reset) { // Send reset to simulation owner.reset(); return true; } else if (e.target == predator) { // Change predator state in simulation owner.kestrelOn(!owner.kestrelOn()); predator.setLabel(predatorText(!owner.kestrelOn())); return true; } else if (e.target == number) { // Reset simulation with new number of bots owner.numberBots((whatNumber.getSelectedIndex() + 1) * 10); return true; } else if (e.target == behaviour) { if (animation == null) { // Animate change of control panel owner.stop(); animation = new Thread(this); animation.start(); } return true; } else return false; } public void dispose() { super.dispose(); owner.controlOff(); } public void run() { boolean working = true; for (int i = graphs.length - 1; i >= 0; i--) graphs[i].disable(); while (working) { working = false; for (int i = graphs.length - 1; i >= 0; i--) working = working | graphs[i].slideTowards(behaviourValues[whatBehaviour.getSelectedIndex()][i]); // Wait for short time try { animation.sleep(100); } catch (InterruptedException e) { // do nothing } } animation = null; for (int i = graphs.length - 1; i >= 0; i--) graphs[i].enable(); owner.start(); } }