Skip to content

Instantly share code, notes, and snippets.

@yogthos
Created April 30, 2011 04:44
Show Gist options
  • Save yogthos/949426 to your computer and use it in GitHub Desktop.
Save yogthos/949426 to your computer and use it in GitHub Desktop.
package main
import java.awt.Graphics
import java.awt.Dimension
import javax.swing.JFrame
import java.awt.Color
import java.awt.Canvas
object Metaball extends Canvas {
val WIDTH = 600
val HEIGHT = 600
val MIN_THRESHOLD = 1
val MAX_THRESHOLD = 50
setBounds(0, 0, WIDTH, HEIGHT)
setBackground(Color.BLACK)
val frame = new JFrame("Metaballs")
frame.setSize(new Dimension(WIDTH, HEIGHT))
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
frame.getContentPane.add(this)
frame.setResizable(false)
frame.setVisible(true)
createBufferStrategy(2)
val buffer = getBufferStrategy
val graphics = buffer.getDrawGraphics
class Ball(var x: Double, var y: Double, var vx: Double, var vy: Double, val radius: Double, val color: Color)
def random(min: Double, max: Double) = min + Math.random * (max - min + 1.0)
def getInfluence(ball: Ball, px: Int, py: Int): Double = {
val dx = ball.x - px
val dy = ball.y - py
return ball.radius / Math.sqrt(dx * dx + dy * dy)
}
def move(ball: Ball) {
ball.vx = if (ball.x > WIDTH || ball.x < 0) -ball.vx else ball.vx
ball.vy = if (ball.y > HEIGHT || ball.y < 0) -ball.vy else ball.vy
ball.x += ball.vx
ball.y += ball.vy
}
def colorFalloff(color: Double, sum: Double): Int = {
val distance = if (sum > MAX_THRESHOLD) MAX_THRESHOLD - sum else MIN_THRESHOLD + sum
val newColor = (color / distance * 2).toInt
if (newColor < 0) return 0
else if (newColor > 255) return 255
return newColor
}
def drawPixel(g: Graphics, c: Color, x: Int, y: Int, size: Int) {
g.setColor(c)
g.fillRect(x, y, size, size)
}
def render(balls: IndexedSeq[Ball]) {
val sampleSize = 4
val xrange = Range(0, WIDTH / sampleSize) map ((n) => n * sampleSize)
val yrange = Range(0, HEIGHT / sampleSize) map ((n) => n * sampleSize)
for (x <- xrange) {
for (y <- yrange) {
var red = 0.0
var green = 0.0
var blue = 0.0
var sum = 0.0
for (ball <- balls) {
val influence = getInfluence(ball, x, y)
red += ball.color.getRed * influence
green += ball.color.getGreen * influence
blue += ball.color.getBlue * influence
sum += influence
}
if (sum <= MAX_THRESHOLD) drawPixel(graphics, Color.white, x, y, sampleSize)
if (sum >= MIN_THRESHOLD) {
val color = new Color(
if (red > 255) 255 else red.toInt,
if (blue > 255) 255 else blue.toInt,
if (green > 255) 255 else green.toInt)
drawPixel(graphics, color, x, y, sampleSize)
} else {
val color = new Color(colorFalloff(red, sum), colorFalloff(blue, sum), colorFalloff(green, sum))
drawPixel(graphics, color, x, y, sampleSize)
}
}
}
if (!buffer.contentsLost) buffer.show
for (ball <- balls) move(ball)
Thread.sleep(10)
render(balls)
}
def main(args: Array[String]) {
val balls = Range(0, 6) map
((_) =>
new Ball(random(10, WIDTH - 10),
random(10, HEIGHT - 10),
random(1, 10),
random(1, 10),
random(50, 70),
new Color(random(1, 255).toInt, random(1, 255).toInt, random(1, 255).toInt)))
render(balls)
}
}
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends Canvas {
private static final long serialVersionUID = 1L;
private static double MIN_THRESHOLD = 1;
private static double MAX_THRESHOLD = 1.1;
final static int WIDTH = 500;
final static int HEIGHT = 500;
public BufferStrategy strategy;
static class Metaball {
public double x, y;
public double radius;
public double xspeed, yspeed;
public Color color;
Metaball(double x, double y, double xspeed, double yspeed, double radius, Color color) {
this.x = x;
this.y = y;
this.xspeed = xspeed;
this.yspeed = yspeed;
this.radius = radius;
this.color = color;
}
}
List<Metaball> balls = new ArrayList<Metaball>();
static double random(double min, double max) {
return min + Math.random() * (max - min + 1);
}
static double getInfluence(Metaball ball, int px, int py) {
double dx = (ball.x - px);
double dy = (ball.y - py);
return ball.radius / Math.sqrt(dx * dx + dy * dy);
}
static void move(Metaball ball) {
ball.xspeed = (ball.x > WIDTH || ball.x < 0) ? -ball.xspeed : ball.xspeed;
ball.yspeed = (ball.y > HEIGHT || ball.y < 0) ? -ball.yspeed : ball.yspeed;
ball.x += ball.xspeed;
ball.y += ball.yspeed;
}
static int colorInRange(double c) {
return c < 0 ? 0 : c > 255 ? 255 : (int) c;
}
static int colorFalloff(int color, double sum) {
double distance;
if (sum > MAX_THRESHOLD)
distance = MAX_THRESHOLD - sum;
else
distance = MIN_THRESHOLD + sum;
return colorInRange((int) (color / distance * 2));
}
static void drawPixel(Graphics g, Color c, int x, int y, int size) {
g.setColor(c);
g.fillRect(x, y, size, size);
}
public void render(Graphics g) {
double sum;
int red, green, blue;
int sampleSize = 4;
while (true) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for (int x = 0; x < WIDTH; x += sampleSize) {
for (int y = 0; y < HEIGHT; y += sampleSize) {
red = 0;
green = 0;
blue = 0;
sum = 0;
for (Metaball ball : balls) {
double influence = getInfluence(ball, x, y);
red += ball.color.getRed() * influence;
green += ball.color.getGreen() * influence;
blue += ball.color.getBlue() * influence;
sum += influence;
}
if (sum <= MAX_THRESHOLD) {
drawPixel(g, Color.white, x, y, sampleSize);
}
if (sum >= MIN_THRESHOLD) {
drawPixel(g, new Color(colorInRange(red), colorInRange(green), colorInRange(blue)), x, y, sampleSize);
} else {
drawPixel(g,
new Color(colorInRange(colorFalloff(red, sum)),
colorInRange(colorFalloff(green, sum)),
colorInRange(colorFalloff(blue, sum))),
x, y, sampleSize);
}
}
}
if (!strategy.contentsLost())
strategy.show();
for (Metaball ball : balls) {
move(ball);
}
try {
Thread.sleep(10);
} catch (InterruptedException ignored) {
}
}
}
public Main() {
for (int i = 0; i < 10; i++) {
balls.add(new Metaball(random(10, WIDTH - 10),
random(10, HEIGHT - 10),
random(1, 3),
random(1, 3),
random(20, 25),
new Color((int) random(1, 255), (int) random(1, 255), (int) random(1, 255))));
}
render(init());
}
private Graphics init() {
setBounds(0, 0, WIDTH, HEIGHT);
setBackground(Color.BLACK);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
panel.add(this);
JFrame frame = new JFrame("Invaders");
frame.add(panel);
frame.setBounds(0, 0, WIDTH, HEIGHT);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createBufferStrategy(2);
strategy = getBufferStrategy();
return strategy.getDrawGraphics();
}
public static void main(String[] args) {
new Main();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment