Skip to content

Instantly share code, notes, and snippets.

@bakman329
Created October 16, 2015 03:30
Show Gist options
  • Save bakman329/740536f151930d20d8b5 to your computer and use it in GitHub Desktop.
Save bakman329/740536f151930d20d8b5 to your computer and use it in GitHub Desktop.
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);
}
}
}
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);
}
}
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);
}
}
}
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();
}
}
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() {}
}
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