public void draw() { background( theme.getColor(Types.BACKGROUND)); // Draws background, basically refreshes the screen win.setBackground(theme.getColor(Types.BACKGROUND)); sidePanel.setBackground(theme.getColor(Types.SIDEPANEL1)); for (int i = 0; i < SIM_TICKS; i++) { env.updateAllAgents(); // 'Ticks' for the new frame, sensors sense, networks network and // collisions are checked. env.updateCollisions(); // update the environment with the new collisions env.updateAgentsSight(); // update all the agents to everything they can see in their field // of view handleCollisions(); if (!env.fitnessOnly) { checkDeaths(); } updateUI(); autoSnapshot(); } // move drawn region if (arrowsPressed[0] && !arrowsPressed[1]) offsetY -= moveSpeed * zoomLevel; // UP if (arrowsPressed[1] && !arrowsPressed[0]) offsetY += moveSpeed * zoomLevel; // DOWN if (arrowsPressed[2] && !arrowsPressed[3]) offsetX -= moveSpeed * zoomLevel; // LEFT if (arrowsPressed[3] && !arrowsPressed[2]) offsetX += moveSpeed * zoomLevel; // RIGHT win.draw(); fill(255); text("FrameRate: " + frameRate, 10, 10); // Displays framerate in the top left hand corner text("Mouse X: " + mouseX + "Mouse Y: " + mouseY, 10, 30); text("Fish Generation: " + env.getFishGeneration(), 10, 50); text("Ticks to next fish generation: " + (1000 - (env.getTick() % 1000)), 10, 70); }
private void setupUI() { // Set colors of each element of simulation theme = new UITheme(); theme.setColor(Types.BACKGROUND, color(0)); theme.setColor(Types.SIDEPANEL1, color(50)); theme.setColor(Types.FOOD, color(0, 255, 0)); theme.setColor(Types.FISH, color(255, 127, 0)); theme.setColor(Types.SHARK, color(255, 0, 0)); theme.setColor(Types.WALL, color(255, 255, 0)); theme.setColor(Types.NEURON, color(200)); theme.setColor(Types.NEURON_FIRED, color(0, 255, 0)); // setup main window for UI elements win = new UIWindow(this, 0, 0, screen.width, screen.height); sideTabs = new UITab(this, 250, 0, 250, screen.height); sideTabs.setIsLeft(false); sideTabs.setBackground(50); sideTabs.setFixedBackground(true); sidePanel = sideTabs.addTab("Information"); // new UIWindow(this, 250, 0, 250, screen.height); neatParams = sideTabs.addTab("NEAT Params"); neatParams.setBackground(30); setupNEATParams(); // Simulation draw region UIDrawable sim = new UIDrawable(this, 0, 0, draw_width, draw_height); sim.setBackground(color(255)); sim.setFixedBackground(true); sim.setEventHandler( new UIAction() { public void draw(PApplet canvas) { drawSimulation(canvas); } }); win.addObject(sim); win.addObject(sideTabs); // Buttons to change the current mode btnGroupModes = new UIWindow(this, 0, 0, 250, 150); btnGroupModes.setBackground(30); btnGroupModes.setFixedBackground(true); sidePanel.addObject(btnGroupModes); btnSelectAgent = addModeButton(0, "Select", 2, 118, 255); btnAddFood = addModeButton(1, "Seaweed", 84, 255, 159); btnAddAgent = addModeButton(2, "Agent", 255, 127, 0); btnThrust = addModeButton(3, "Thrust", 0, 231, 125); btnAddWall = addModeButton(4, "Wall", 255, 255, 0); btnGroupModes.selectButton(btnSelectAgent); // Change number of ticks updated each frame sliderTPS = new UISlider(this, 10, 90, 170, 30); sliderTPS.setEventHandler( new UIAction() { public void change(UISlider slider) { SIM_TICKS = (int) (slider.getValue() * SIM_TPS_MAX); lblSimTPS.setText("Ticks: " + SIM_TICKS); } }); sliderTPS.setValue(1.0 / SIM_TPS_MAX); btnGroupModes.addObject(sliderTPS); lblSimTPS = new UILabel(this, 190, 92, "Ticks: " + SIM_TICKS); btnGroupModes.addObject(lblSimTPS); // Statistics window for the currently selected agent winStats = new UIWindow(this, 0, 165, 300, 500); winStats.setBackground(30); winStats.setFixedBackground(true); sidePanel.addObject(winStats); // control to change the selected agents heading agentHeading = new UIVision(this, 25, 270, 200); agentHeading.setTheme(theme); agentHeading.setEventHandler( new UIAction() { public void change(UIAngle ang) { if (selectedAgent != null) { selectedAgent.changeViewHeading(ang.getAngle() - selectedAgent.getViewHeading()); } } }); winStats.addObject(agentHeading); // progress bar of the selected agents current health progHealth = new UIProgress(this, 10, 93, 230, 10); winStats.addObject(progHealth); // sliders to move agents position sliderX = new UISlider(this, 10, 35, 230, 15); sliderX.setEventHandler( new UIAction() { public void change(UISlider slider) { if (selectedAgent != null) { selectedAgent.setX((int) (slider.getValue() * Environment.width)); } } }); winStats.addObject(sliderX); sliderY = new UISlider(this, 10, 60, 230, 15); sliderY.setEventHandler( new UIAction() { public void change(UISlider slider) { if (selectedAgent != null) { selectedAgent.setY((int) (slider.getValue() * Environment.height)); } } }); winStats.addObject(sliderY); // boost agent health back to 100% btnSelectHealth = new UIButton(this, 10, 115, 65, 20, "100%"); btnSelectHealth.setColor(84, 255, 159); btnSelectHealth.setEventHandler( new UIAction() { public void click(UIButton btn) { if (selectedAgent != null) { selectedAgent.updateHealth(1); } } }); winStats.addObject(btnSelectHealth); // thrust selected agent btnSelectThrust = new UIButton(this, 93, 115, 65, 20, "Thrust"); btnSelectThrust.setColor(251, 150, 20); btnSelectThrust.setEventHandler( new UIAction() { public void click(UIButton btn) { if (selectedAgent != null) { selectedAgent.thrust(5); } } }); winStats.addObject(btnSelectThrust); // kill poor agent btnSelectKill = new UIButton(this, 175, 115, 65, 20, "KILL"); btnSelectKill.setColor(210, 50, 50); btnSelectKill.setEventHandler( new UIAction() { public void click(UIButton btn) { if (selectedAgent != null) { // env.removeAgent(selectedAgent); env.scheduledRemove.add(selectedAgent); selectedAgent = null; } } }); winStats.addObject(btnSelectKill); // Toggle focused / tracking mode for selected agent btnToggleFocused = new UIButton(this, 120, 5, 65, 15, (agentFocused ? "Unfocus" : "Focus")); btnToggleFocused.setIsLeft(false); btnToggleFocused.setColor(50, 100, 255); btnToggleFocused.setEventHandler( new UIAction() { public void click(UIButton btn) { agentFocused = !agentFocused; btn.setText(agentFocused ? "Unfocus" : "Focus"); } }); winStats.addObject(btnToggleFocused); // 3D neural network visual UITab bottomWindow = new UITab(this, 0, 300, 250, 300); bottomWindow.setIsTop(false); sidePanel.addObject(bottomWindow); UIWindow tabNeural = bottomWindow.addTab("Network"); UIWindow tabTheme = bottomWindow.addTab("Theme"); tabTheme.setBackground(30); neuralVisual = new UIDrawable3D(this, 0, 0, 250, 250); neuralVisual.setBackground(30); neuralVisual.setFixedBackground(true); tabNeural.addObject(neuralVisual); neuralVisual.setEventHandler( new UIAction() { private float zoom = 0.5f; private int offX = 0; private int offY = 0; boolean arrows[] = new boolean[4]; private boolean rotating = true; public void draw(PApplet canvas) { if (selectedAgent == null) return; if (arrows[0] && !arrows[1]) offY -= moveSpeed / 3; // UP if (arrows[1] && !arrows[0]) offY += moveSpeed / 3; // DOWN MNetwork net = selectedAgent.getNetwork(); noStroke(); pushMatrix(); rotateY(neuralRotation); scale(zoom, zoom, zoom); translate(offX, offY); for (MNeuron n : net.getNeurons()) { // draw the neurons int isFired = (n.isFiring() ? 255 : 60); if (n.getID() >= 3 && n.getID() < 3 + Agent.configNumSegments) fill(theme.getColor(Types.FOOD), isFired); else if (n.getID() >= 3 + Agent.configNumSegments && n.getID() < 3 + Agent.configNumSegments * 2) fill(theme.getColor(Types.WALL), isFired); else if (n.getID() >= 3 + Agent.configNumSegments * 2 && n.getID() < 3 + Agent.configNumSegments * 3) fill(theme.getColor(Types.SHARK), isFired); else if (n.getID() < 3) fill(0, 255, 255, isFired); else fill(theme.getColor(Types.NEURON), isFired); MVec3f vec = n.getCoords(); // clip node if off the display if ((vec.y + offY) * zoom < -135) continue; translate(vec.x, vec.y, vec.z); sphere(3); translate(-vec.x, -vec.y, -vec.z); } for (MSynapse s : net.getSynapses()) { // draw the links between the neurons MNeuron pre = s.getPreNeuron(); MNeuron post = s.getPostNeuron(); MVec3f n1 = pre.getCoords(); MVec3f n2 = post.getCoords(); // clip edge if both nodes above clipping if ((n1.y + offY) * zoom < -135 && (n2.y + offY) * zoom < -135) continue; int isFired = (pre.isFiring() ? 100 : 10); if (pre.getID() >= 3 && pre.getID() < 3 + Agent.configNumSegments) stroke(theme.getColor(Types.FOOD), isFired); else if (pre.getID() >= 3 + Agent.configNumSegments && pre.getID() < 3 + Agent.configNumSegments * 2) stroke(theme.getColor(Types.WALL), isFired); else if (pre.getID() >= 3 + Agent.configNumSegments * 2 && pre.getID() < 3 + Agent.configNumSegments * 3) stroke(theme.getColor(Types.SHARK), isFired); else if (pre.getID() < 3) stroke(0, 255, 255, isFired); else stroke(255, isFired); // partial clipping when one node if above line if ((n1.y + offY) * zoom < -135) { double t = (((-135 / zoom) - offY) - n2.y) / (n1.y - n2.y); int x = (int) ((int) (n2.x + t * (n1.x - n2.x)) / zoom); line( (int) (x), (int) (-135 / zoom) - offY, 0, (int) (n2.x), (int) (n2.y), (int) n2.z); } else if ((n2.y + offY) * zoom < -135) { double t = (((-135.0 / zoom) - offY) - (n1.y)) / (double) ((n2.y - n1.y)); int x = (int) (n1.x + t * (n2.x - n1.x)); line( (int) (n1.x), (int) (n1.y), (int) n1.z, (int) (x), (int) (-135 / zoom) - offY, 0); } else { line((int) n1.x, (int) n1.y, (int) n1.z, (int) n2.x, (int) n2.y, (int) n2.z); } } popMatrix(); if (rotating) neuralRotation -= 0.02; } public boolean mouseWheel(MouseWheelEvent event) { if (!Utilities.isPointInBox( mouseX, mouseY, screen.width - 250, screen.height - 250, 250, 250)) return false; if (zoom > minZoom || event.getWheelRotation() > 0) { zoom = Math.max(minZoom, (zoom + 0.1f * event.getWheelRotation())); } return true; } public boolean mousePressed() { if (!Utilities.isPointInBox( mouseX, mouseY, screen.width - 250, screen.height - 250, 250, 250)) return false; rotating = !rotating; return true; } public boolean keyReleased() { // Hotkeys for buttons if (!Utilities.isPointInBox( mouseX, mouseY, screen.width - 250, screen.height - 250, 250, 250)) return false; switch (keyCode) { case (UP): arrows[0] = false; return true; case (DOWN): arrows[1] = false; return true; case (LEFT): arrows[2] = false; return true; case (RIGHT): arrows[3] = false; return true; } return false; } public boolean keyPressed() { // Hotkeys for buttons if (!Utilities.isPointInBox( mouseX, mouseY, screen.width - 250, screen.height - 250, 250, 250)) return false; switch (keyCode) { case (UP): arrows[0] = true; return true; case (DOWN): arrows[1] = true; return true; case (LEFT): arrows[2] = true; return true; case (RIGHT): arrows[3] = true; return true; } return false; } }); // printout of selected agents stats lblStatTitle = addStatLabel("Selected Agent", 5); lblX = addStatLabel("X", 155); lblY = addStatLabel("X", 170); lblHeading = addStatLabel("X", 185); lblHealth = addStatLabel("X", 200); lblAngle = addStatLabel("X", 215); lblSpeed = addStatLabel("X", 230); // Themes window themeColorWheel = new UIColorWheel(this, 45, 40); themeColorWheel.setEventHandler( new UIAction() { public void change(UIColorWheel wheel) { theme.setColor((Types) themeDrop.getSelected(), wheel.getColor()); } }); tabTheme.addObject(themeColorWheel); themeDrop = new UIDropdown<Types>(this, 25, 10, 200, theme.getKeys()); themeDrop.setEventHandler( new UIAction() { public void change(@SuppressWarnings("rawtypes") UIDropdown drop) { themeColorWheel.setColor(theme.getColor((Types) drop.getSelected())); } }); tabTheme.addObject(themeDrop); // adds mouse scrolling listener to the applet addMouseWheelListener( new MouseWheelListener() { public void mouseWheelMoved(MouseWheelEvent event) { mouseWheel(event); } }); }
private void drawSimulation(PApplet canvas) { pushMatrix(); translate(offsetX, offsetY); scale(zoomLevel); ArrayList<Agent> agents = env.getAllAgents(); // Returns an arraylist of agents ArrayList<Food> food = env.getAllFood(); // Returns an arraylist of all the food on the map ArrayList<Wall> walls = env.getAllWalls(); // Returns an arraylist of all walls ArrayList<Seaweed> seaweed = env.getAllSeaweed(); for (int i = 0; i < agents.size(); i++) { // Runs through arraylist of agents, will draw them on the canvas Agent ag = agents.get(i); // draw the field of view for the agent if (selectedAgent == null || !agentFocused || (agentFocused && ag == selectedAgent)) stroke(128); else stroke(128, 100); // , (float) ag.getHealth()*200+55 noFill(); double range = ag.getVisionRange() * 2; pushMatrix(); translate(ag.getX(), ag.getY()); rotate((float) Utilities.toRadians(ag.getViewHeading() - ag.getFOV())); line(0, 0, (int) (range / 2), 0); popMatrix(); pushMatrix(); translate(ag.getX(), ag.getY()); rotate((float) Utilities.toRadians(ag.getViewHeading() + ag.getFOV())); line(0, 0, (int) (range / 2), 0); popMatrix(); arc( (float) ag.getX(), (float) ag.getY(), (float) range, (float) range, (float) Utilities.toRadians(ag.getViewHeading() - ag.getFOV()), (float) Utilities.toRadians(ag.getViewHeading() + ag.getFOV())); // draw our circle representation for the agent noStroke(); // if(selectedAgent == null || !agentFocused || (agentFocused && ag == selectedAgent)) // fill(theme.getColor((ag instanceof Enemy ? Types.SHARK : Types.FISH))); // else fill(theme.getColor((ag instanceof Enemy ? Types.SHARK : Types.FISH)), 100); //, // (float) ag.getHealth()*200 +55); // Alpha was severly impacting performance of simulation if (ag instanceof Enemy) { fill( ((ag.getSpeciesId() + 1) * 25) % 256, ((ag.getSpeciesId() + 1) * 47) % 256, ((ag.getSpeciesId() + 1) * 69) % 256, (agentFocused && ag == selectedAgent ? 100 : 256)); pushMatrix(); translate(ag.getX(), ag.getY()); rotate((float) Utilities.toRadians(ag.getViewHeading())); rect(-10, -10, 20, 20); popMatrix(); } else { fill( ((ag.getSpeciesId() + 1) * 25) % 256, ((ag.getSpeciesId() + 1) * 47) % 256, ((ag.getSpeciesId() + 1) * 69) % 256, (agentFocused && ag == selectedAgent ? 100 : 256)); ellipse(ag.getX(), ag.getY(), 20, 20); } if (agentFocused && ag == selectedAgent) { // keep agent on screen if in focused / tracking mode int simAgX = (int) ((ag.getX() * zoomLevel) + offsetX); // screen coordinates of the selected agent int simAgY = (int) ((ag.getY() * zoomLevel) + offsetY); if (simAgX < trackingBounds) offsetX += trackingBounds - simAgX; else if (simAgX > draw_width - trackingBounds) offsetX -= simAgX - draw_width + trackingBounds; if (simAgY < trackingBounds) offsetY += trackingBounds - simAgY; else if (simAgY > draw_height - trackingBounds) offsetY -= simAgY - draw_height + trackingBounds; } } noStroke(); fill(theme.getColor(Types.FOOD)); for (int i = 0; i < food.size(); i++) { // Runs through arraylist of food, will draw them on the canvas Food fd = food.get(i); ellipse(fd.getX(), fd.getY(), 5, 5); } noStroke(); fill(201, 23, 134); for (int i = 0; i < seaweed.size(); i++) { // Runs through arraylist of food, will draw them on the canvas Seaweed fd = seaweed.get(i); ellipse(fd.getX(), fd.getY(), 5, 5); } stroke(theme.getColor(Types.WALL)); noFill(); for (Wall wl : walls) { // Runs through arraylist of walls, will draw them on the canvas switch (wl.getWallType()) { case Collision.TYPE_WALL_AGENT: stroke(theme.getColor(Types.FISH)); break; case Collision.TYPE_WALL_ENEMY: stroke(theme.getColor(Types.SHARK)); break; default: stroke(theme.getColor(Types.WALL)); } line( (float) wl.getStart().x, (float) wl.getStart().y, (float) wl.getEnd().x, (float) wl.getEnd().y); } popMatrix(); fill(0); // rect(draw_width - 50, 0, 250, draw_height); }