init
This commit is contained in:
commit
b06bf13382
40
Boid.java
Normal file
40
Boid.java
Normal file
@ -0,0 +1,40 @@
|
||||
import java.awt.Graphics;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
public class Boid extends PhysicsObject implements Drawable {
|
||||
public Boid(int width, int height) {
|
||||
super(0, 0, 0, 0);
|
||||
Random r = new Random();
|
||||
this.x = r.nextInt(width);
|
||||
this.y = r.nextInt(height);
|
||||
this.apply_force(r.nextFloat() * 2 - 1, r.nextFloat() * 2 - 1, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics g) {
|
||||
g.fillOval((int) x, (int) y, 2, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulate() {
|
||||
super.simulate();
|
||||
ArrayList<PhysicsObject> others = ChunkManager.get_objects((int) x, (int) y);
|
||||
|
||||
if (others.size() == 0)
|
||||
return;
|
||||
|
||||
for (PhysicsObject o : others) {
|
||||
double dist = this.get_sqr_distance(o);
|
||||
if (dist < 500 && dist > 20) {
|
||||
// Rule 1: collect in groups
|
||||
this.apply_force(o.x - x, o.y - y, (float) Math.min(0.005 / dist, 1));
|
||||
this.apply_force(o.v_x, o.v_y, 0.005f);
|
||||
} else if (dist < 20) {
|
||||
// Rule 2: keep distance
|
||||
this.apply_force(x - o.x, y - o.y, (float) Math.min(0.005 / dist, 1));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
68
ChunkManager.java
Normal file
68
ChunkManager.java
Normal file
@ -0,0 +1,68 @@
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChunkManager {
|
||||
private static ArrayList<ArrayList<PhysicsObject>> chunks;
|
||||
private static int width;
|
||||
private static int height;
|
||||
private static int chunks_x;
|
||||
private static int chunks_y;
|
||||
|
||||
public static void init(int width, int height, int chunks_x, int chunks_y) {
|
||||
ChunkManager.width = width;
|
||||
ChunkManager.height = height;
|
||||
ChunkManager.chunks_x = chunks_x;
|
||||
ChunkManager.chunks_y = chunks_y;
|
||||
ChunkManager.chunks = new ArrayList<ArrayList<PhysicsObject>>(chunks_x * chunks_y);
|
||||
ChunkManager.clear();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
chunks.clear();
|
||||
for (int i = 0; i < chunks_x * chunks_y; i++) {
|
||||
chunks.add(new ArrayList<PhysicsObject>());
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] to_chunk_coordinates(int x, int y) {
|
||||
return new int[] { (x * chunks_x) / width, (y * chunks_y) / height };
|
||||
}
|
||||
|
||||
private static int get_chunk_index(int x, int y) {
|
||||
return x + (y * chunks_x);
|
||||
}
|
||||
|
||||
private static int wrap(int index, int max) {
|
||||
int normalized = index;
|
||||
while (normalized < 0) {
|
||||
normalized += max;
|
||||
}
|
||||
return normalized % max;
|
||||
}
|
||||
|
||||
public static void register(PhysicsObject obj) {
|
||||
int[] chunk = to_chunk_coordinates((int)obj.x, (int)obj.y);
|
||||
int index = get_chunk_index(chunk[0], chunk[1]);
|
||||
chunks.get(index).add(obj);
|
||||
}
|
||||
|
||||
public static ArrayList<PhysicsObject> get_objects(int x, int y) {
|
||||
int[] chunk = to_chunk_coordinates(x, y);
|
||||
int[][] chunks = new int[][] {
|
||||
chunk,
|
||||
new int[] {wrap(chunk[0] + 1,chunks_x), chunk[1]},
|
||||
new int[] {wrap(chunk[0] - 1,chunks_x), chunk[1]},
|
||||
new int[] {wrap(chunk[0] + 1,chunks_x), wrap(chunk[1] + 1, chunks_y)},
|
||||
new int[] {wrap(chunk[0] - 1,chunks_x), wrap(chunk[1] + 1, chunks_y)},
|
||||
new int[] {wrap(chunk[0] + 1,chunks_x), wrap(chunk[1] - 1, chunks_y)},
|
||||
new int[] {wrap(chunk[0] - 1,chunks_x), wrap(chunk[1] - 1, chunks_y)},
|
||||
new int[] {chunk[0], wrap(chunk[1] + 1, chunks_y)},
|
||||
new int[] {chunk[0], wrap(chunk[1] - 1, chunks_y)}
|
||||
};
|
||||
ArrayList<PhysicsObject> objects = new ArrayList<PhysicsObject>();
|
||||
for (int[] c : chunks) {
|
||||
int index = get_chunk_index(c[0], c[1]);
|
||||
objects.addAll(ChunkManager.chunks.get(index));
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
}
|
33
Display.java
Normal file
33
Display.java
Normal file
@ -0,0 +1,33 @@
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
public class Display extends JFrame {
|
||||
private static final long serialVersionUID = 8274011568777903027L;
|
||||
private int width;
|
||||
private int height;
|
||||
private DrawableCollection dc;
|
||||
|
||||
public Display(int width, int height, DrawableCollection dc) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.dc = dc;
|
||||
this.setSize(width, height);
|
||||
this.setVisible(true);
|
||||
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
BufferedImage b = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics bg = b.getGraphics();
|
||||
bg.setColor(Color.BLACK);
|
||||
bg.fillRect(0, 0, width, height);
|
||||
bg.setColor(Color.WHITE);
|
||||
for (Drawable d : dc.get_drawables()) {
|
||||
d.draw(bg);
|
||||
}
|
||||
g.drawImage(b,0, 0, width, height, Color.BLACK, this);
|
||||
}
|
||||
}
|
5
Drawable.java
Normal file
5
Drawable.java
Normal file
@ -0,0 +1,5 @@
|
||||
import java.awt.Graphics;
|
||||
|
||||
public interface Drawable {
|
||||
public void draw(Graphics g);
|
||||
}
|
3
DrawableCollection.java
Normal file
3
DrawableCollection.java
Normal file
@ -0,0 +1,3 @@
|
||||
public interface DrawableCollection {
|
||||
public Drawable[] get_drawables();
|
||||
}
|
53
Main.java
Normal file
53
Main.java
Normal file
@ -0,0 +1,53 @@
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class Main implements DrawableCollection {
|
||||
private static final int WIDTH = 800;
|
||||
private static final int HEIGHT = 600;
|
||||
private static final int BOID_COUNT = 10000;
|
||||
private static final int CHUNKS_X = 32;
|
||||
private static final int CHUNKS_Y = 32;
|
||||
private static final int FRAME_STEP = 16;
|
||||
private static final float MAX_SPEED = 1;
|
||||
|
||||
private Boid[] boids;
|
||||
private Display d;
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
ChunkManager.init(WIDTH, HEIGHT, CHUNKS_X, CHUNKS_Y);
|
||||
PhysicsObject.width = WIDTH;
|
||||
PhysicsObject.height = HEIGHT;
|
||||
PhysicsObject.max_speed = MAX_SPEED;
|
||||
new Main().run();
|
||||
}
|
||||
|
||||
public Main() {
|
||||
boids = new Boid[BOID_COUNT];
|
||||
for (int i = 0; i < BOID_COUNT; i++) {
|
||||
boids[i] = new Boid(WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
d = new Display(WIDTH, HEIGHT, this);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
new Timer().scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Boid b : boids) {
|
||||
b.simulate();
|
||||
}
|
||||
ChunkManager.clear();
|
||||
for (Boid b : boids) {
|
||||
ChunkManager.register(b);
|
||||
}
|
||||
d.repaint();
|
||||
}
|
||||
}, 100, FRAME_STEP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable[] get_drawables() {
|
||||
return boids;
|
||||
}
|
||||
}
|
49
PhysicsObject.java
Normal file
49
PhysicsObject.java
Normal file
@ -0,0 +1,49 @@
|
||||
public class PhysicsObject {
|
||||
public float x;
|
||||
public float y;
|
||||
public float v_x;
|
||||
public float v_y;
|
||||
|
||||
public static int width = 0;
|
||||
public static int height = 0;
|
||||
public static float max_speed = 0;
|
||||
|
||||
public void simulate() {
|
||||
v_x = clamp(v_x, -max_speed, max_speed) * 0.998f;
|
||||
v_y = clamp(v_y, -max_speed, max_speed) * 0.998f;
|
||||
|
||||
x += v_x;
|
||||
y += v_y;
|
||||
while (x < 0) {
|
||||
x += width;
|
||||
}
|
||||
while (y < 0) {
|
||||
y += height;
|
||||
}
|
||||
x %= width;
|
||||
y %= height;
|
||||
}
|
||||
|
||||
private float clamp(float f, float min, float max) {
|
||||
return Math.min(max, Math.max(f, min));
|
||||
}
|
||||
|
||||
public void apply_force(float x, float y, float factor) {
|
||||
if (x == 0 && y == 0)
|
||||
return;
|
||||
double len = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
||||
v_x += (x / len) * factor;
|
||||
v_y += (y / len) * factor;
|
||||
}
|
||||
|
||||
public PhysicsObject(int x, int y, float v_x, float v_y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.v_x = v_x;
|
||||
this.v_y = v_y;
|
||||
}
|
||||
|
||||
public double get_sqr_distance(PhysicsObject obj) {
|
||||
return Math.pow(obj.x - x, 2) + Math.pow(obj.y - y, 2);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user