Created
October 16, 2015 03:30
-
-
Save bakman329/740536f151930d20d8b5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
import java.util.ArrayList; | |
import java.util.Random; | |
/* | |
* Cell.java | |
* Defines a cell entity which can move around the canvas, eat food and multiply. | |
*/ | |
public class Cell extends Entity { | |
private final int default_delay; | |
private int current_delay; | |
private int angle; | |
private int velocity; | |
Random random; | |
public Cell(double x, double y) { | |
this(x, y, CellWorld.DEFAULT_CELL_COLOR); | |
} | |
public Cell(double x, double y, Color color) { | |
this(x, y, CellWorld.DEFAULT_CELL_RADIUS, color); | |
} | |
public Cell(double x, double y, double radius, Color color) { | |
super(x, y, radius, color); | |
this.default_delay = CellWorld.DEFAULT_CELL_MOVEMENT_DELAY; | |
this.current_delay = default_delay; | |
random = new Random(); | |
} | |
@Override | |
public void step() { | |
this.current_delay--; | |
if (this.current_delay == 0) { | |
this.current_delay = this.default_delay; | |
this.velocity = CellWorld.CELL_INITIAL_VELOCITY; | |
this.angle = random.nextInt(360); | |
} | |
if (velocity != 0) { | |
// Each iteration, the cell is moved 1 unit, plus the velocity times 0.15, in each dimension. | |
// Then basic trigonometry is applied in order to apply the angle. | |
final int x_offset = (int) ((1 + (0.15 * velocity)) * Math.sin(angle)); | |
final int y_offset = (int) ((1 + (0.15 * velocity)) * Math.cos(angle)); | |
if ((new Rectangle(0, 0, CellWorld.WIDTH, CellWorld.HEIGHT)) | |
.contains((int) x + x_offset, (int) y + y_offset, (int) radius, (int) radius)) { | |
x += x_offset; | |
y += y_offset; | |
} | |
this.velocity--; | |
} | |
ArrayList<Food> removeQueue = new ArrayList<>(); | |
for (Entity entity : CellWorld.entities) { | |
if (this.collision(entity) && entity instanceof Food) { | |
removeQueue.add((Food) entity); | |
this.radius += entity.radius; | |
if (this.radius >= (CellWorld.DEFAULT_CELL_RADIUS * 2)) { | |
this.radius = CellWorld.DEFAULT_CELL_RADIUS; | |
int old_colors[] = {this.color.getRed(), this.color.getGreen(), this.color.getBlue()}; | |
int[] new_colors = new int[3]; | |
for (int i = 0; i < 3; i++) { | |
new_colors[i] = old_colors[i] | |
+ (this.random.nextInt(CellWorld.MAX_COLOR_MUTATION + 1) | |
- CellWorld.MAX_COLOR_MUTATION / 2); | |
new_colors[i] = (new_colors[i] > 255) ? 255 : new_colors[i]; | |
new_colors[i] = (new_colors[i] < 0) ? 0 : new_colors[i]; | |
} | |
Color new_color = new Color(new_colors[0], new_colors[1], new_colors[2]); | |
CellWorld.entities.add(new Cell(x, y, new_color)); | |
} | |
} | |
} | |
removeQueue.forEach(CellWorld.entities::remove); | |
radius -= CellWorld.CELL_DECAY_RATE; | |
if (radius <= CellWorld.CELL_DEATH_RADIUS) { | |
CellWorld.entities.remove(this); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
/* | |
* CellCanvas.java | |
* Defines the drawing canvas for the game and the painting of entities. | |
*/ | |
public class CellCanvas extends Canvas { | |
@Override | |
public void paint(Graphics g) { | |
for (Entity entity : CellWorld.entities) entity.paint(g); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.event.MouseAdapter; | |
import java.awt.event.MouseEvent; | |
import java.util.concurrent.CopyOnWriteArrayList; | |
import java.util.Timer; | |
/* | |
* CellWorld.java | |
* Defines several constants for the program, the basic functionality and the window frame. | |
*/ | |
public class CellWorld { | |
public static final int WIDTH = 640; | |
public static final int HEIGHT = 480; | |
public static final int FOOD_INTERVAL = 100; | |
public static final double DEFAULT_CELL_RADIUS = 50; | |
public static final Color DEFAULT_CELL_COLOR = Color.BLACK; | |
public static final int MAX_COLOR_MUTATION = 70; | |
public static final int DEFAULT_CELL_MOVEMENT_DELAY = 100; | |
public static final int CELL_INITIAL_VELOCITY = 25; | |
public static final double CELL_DECAY_RATE = 0.04; | |
public static final int CELL_DEATH_RADIUS = 10; | |
static CopyOnWriteArrayList<Entity> entities = new CopyOnWriteArrayList<>(); | |
static FoodGenerator foodGenerator = new FoodGenerator(); | |
static Timer timer = new Timer(); | |
public static void main(String[] args) throws InterruptedException { | |
JFrame frame = new JFrame("Cell World"); | |
CellCanvas canvas = new CellCanvas(); | |
timer.schedule(foodGenerator, 0, CellWorld.FOOD_INTERVAL); | |
canvas.addMouseListener(new MouseAdapter() { | |
@Override | |
public void mouseClicked(MouseEvent e) { | |
if (e.getButton() == MouseEvent.BUTTON1) { | |
CellWorld.entities.add(new Cell(e.getX() - DEFAULT_CELL_RADIUS / 2, | |
e.getY() - DEFAULT_CELL_RADIUS / 2)); | |
} | |
} | |
}); | |
frame.getContentPane().add(canvas); | |
frame.setSize(WIDTH, HEIGHT); | |
frame.setVisible(true); | |
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); | |
while (true) { | |
canvas.repaint(); | |
Thread.sleep(10); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
/* | |
* Entity.java | |
* Defines an entity with a position, a radius, a color, and the capacities to collide with other entities and be drawn. | |
*/ | |
public abstract class Entity { | |
protected double x, y; | |
protected double radius; | |
protected Color color; | |
public Entity(double x, double y, double radius, Color color) { | |
this(x, y, radius); | |
this.color = color; | |
} | |
public Entity(double x, double y, double radius) { | |
this.x = x; | |
this.y = y; | |
this.radius = radius; | |
} | |
public double getX() { | |
return this.x; | |
} | |
public double getY() { | |
return this.y - (this.radius / 2); | |
} | |
public double getRadius() { | |
return this.radius; | |
} | |
public boolean collision(Entity other) { | |
double distanceSquared = Math.pow(this.x - other.getX(), 2) + Math.pow(this.y - other.getY(), 2); | |
double radiusSumSquared = Math.pow(this.radius + other.getRadius(), 2); | |
return (distanceSquared < radiusSumSquared); | |
} | |
public abstract void step(); | |
public void paint(Graphics g) { | |
g.setColor(color); | |
g.fillOval((int) x, | |
(int) y, | |
(int) radius, | |
(int) radius); | |
step(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
/* | |
* Food.java | |
* Defines a food particle. | |
*/ | |
public class Food extends Entity { | |
public Food(double x, double y) { | |
super(x, y, 10); | |
this.color = Color.BLUE; | |
} | |
@Override | |
public void step() {} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Random; | |
import java.util.TimerTask; | |
/* | |
* FoodGenerator.java | |
* Defines the timer task of generating new food on the canvas. | |
*/ | |
public class FoodGenerator extends TimerTask { | |
private static Food newFood() { | |
Random random = new Random(); | |
return new Food(random.nextInt(CellWorld.WIDTH), random.nextInt(CellWorld.HEIGHT)); | |
} | |
@Override | |
public void run() { | |
CellWorld.entities.add(newFood()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment