Bees & Bombs
Rebuilding a gif from Bees & Bombs
Here are eight Processing examples coded in C4.
Creating shapes in C4 is very similar to Processing. Here you’ll see that C4 has an Arc
shape that corresponds to Processing’s arc()
function.
From: Pie Chart
Uses the arc() function to generate a pie chart from the data stored in an array.
int[] angles = { 30, 10, 45, 35, 60, 38, 75, 67 };
void setup() {
size(640, 360);
noStroke();
noLoop(); // Run once and stop
}
void draw() {
background(100);
pieChart(300, angles);
}
void pieChart(float diameter, int[] data) {
float lastAngle = 0;
for (int i = 0; i < data.length; i++) {
float gray = map(i, 0, data.length, 0, 255);
fill(gray);
arc(width/2, height/2, diameter, diameter, lastAngle, lastAngle+radians(angles[i]));
lastAngle += radians(angles[i]);
}
}
There are many math functions that are common between both projects. This example also shows that using C4’s map
function is almost identical.
override func setup() {
let angles: [Double] = [30.0, 10, 45, 35, 60, 38, 75, 67]
var pΘ = 0.0
for i in 0..<angles.count {
let c = map(Double(i), min: 0, max: Double(angles.count), toMin: 0, toMax: 1)
let Θ = degToRad(angles[i])
let a = Wedge(center: canvas.center, radius: 150, start: pΘ, end: pΘ+Θ)
a.fillColor = Color(red: c, green: c, blue: c, alpha: 1.0)
a.lineWidth = 0.0
pΘ += Θ
canvas.add(a)
}
}
The effect of the Array 2D example shows how to create a fading grid of points. This example shows you how to create the same effect, even though the C4 version doesn’t actually use arrays.
From: Array 2D
Demonstrates the syntax for creating a two-dimensional (2D) array. Values in a 2D array are accessed through two index values. 2D arrays are useful for storing images. In this example, each dot is colored in relation to its distance from the center of the image.
float[][] distances;
float maxDistance;
int spacer;
void setup() {
size(640, 360);
maxDistance = dist(width/2, height/2, width, height);
distances = new float[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float distance = dist(width/2, height/2, x, y);
distances[x][y] = distance/maxDistance * 255;
}
}
spacer = 10;
noLoop(); // Run once and stop
}
void draw() {
background(0);
for (int y = 0; y < height; y += spacer) {
for (int x = 0; x < width; x += spacer) {
stroke(distances[x][y]);
point(x + spacer/2, y + spacer/2);
}
}
}
Instead of points, we create Circle
shapes that are 1pt
in diameter.
override func setup() {
let maxDistance = distance(Point(), rhs: canvas.center)
canvas.backgroundColor = black
var pt = Point(8, 8)
repeat {
repeat {
let c = Circle(center: pt, radius: 0.5)
let d = distance(pt, rhs: canvas.center) / maxDistance
c.lineWidth = 0.0
c.fillColor = Color(red: d, green: d, blue: d, alpha: 1.0)
canvas.add(c)
pt.x += 10.0
} while pt.x < canvas.width
pt.y += 10.0
pt.x = 8.0
} while pt.y < canvas.height
}
There is no mouse in C4, but there are gesture recognizers. This example shows how you can add a long press gesture recognizer to an object to achieve a similar effect to mousePressed
, mouseDragged
and mouseReleased
.
From: Mouse Functions
Click on the box and drag it across the screen.
float bx;
float by;
int boxSize = 75;
boolean overBox = false;
boolean locked = false;
float xOffset = 0.0;
float yOffset = 0.0;
void setup() {
size(640, 360);
bx = width/2.0;
by = height/2.0;
rectMode(RADIUS);
}
void draw() {
background(0);
if (mouseX > bx-boxSize && mouseX < bx+boxSize &&
mouseY > by-boxSize && mouseY < by+boxSize) {
overBox = true;
if(!locked) {
stroke(255);
fill(153);
}
} else {
stroke(153);
fill(153);
overBox = false;
}
rect(bx, by, boxSize, boxSize);
}
void mousePressed() {
if(overBox) {
locked = true;
fill(255, 255, 255);
} else {
locked = false;
}
xOffset = mouseX-bx;
yOffset = mouseY-by;
}
void mouseDragged() {
if(locked) {
bx = mouseX-xOffset;
by = mouseY-yOffset;
}
}
void mouseReleased() {
locked = false;
}
To achieve a similar effect in C4 requires a lot less code because iOS handles the gesture for you. Simply let the system track touch positions for you.
override func setup() {
let rect = Rectangle(frame: Rect(0,0,100,100))
rect.center = canvas.center
rect.strokeColor = clear
canvas.add(rect)
var position = Point()
let press = rect.addLongPressGestureRecognizer { (locations, center, state) -> () in
switch state {
case .Began:
ShapeLayer.disableActions = true
rect.strokeColor = C4Pink
rect.fillColor = white
position = center
case .Changed:
let dxdy = Vector(center) - Vector(position)
rect.center += dxdy
case .Ended:
rect.strokeColor = clear
rect.fillColor = C4Blue
default:
_ = ""
}
}
press.minimumPressDuration = 0.0
}
I really like the aesthetic of how the circles fade away as you move your mouse around the screen. In C4, there are no draw loops and we cannot rely on frame-based updating. However, we can create animations that give us the same effect!
From: Storing Input
Move the mouse across the screen to change the position of the circles. The positions of the mouse are recorded into an array and played back every frame. Between each frame, the newest value are added to the end of each array and the oldest value is deleted.
int num = 60;
float mx[] = new float[num];
float my[] = new float[num];
void setup() {
size(640, 360);
noStroke();
fill(255, 153);
}
void draw() {
background(51);
// Cycle through the array, using a different entry on each frame.
// Using modulo (%) like this is faster than moving all the values over.
int which = frameCount % num;
mx[which] = mouseX;
my[which] = mouseY;
for (int i = 0; i < num; i++) {
// which+1 is the smallest (the oldest in the array)
int index = (which+1 + i) % num;
ellipse(mx[index], my[index], i, i);
}
}
Here you’ll see how we create an animation for every circle which, upon completion, removes that circle from the canvas.
override func setup() {
canvas.addPanGestureRecognizer { locations, center, translation, velocity, state in
ShapeLayer.disableActions = true
let circle = Circle(center: center, radius: 30)
self.canvas.add(circle)
ShapeLayer.disableActions = false
let a = ViewAnimation(duration: 1.0) {
circle.opacity = 0.0
circle.transform.scale(0.01, 0.01)
}
a.addCompletionObserver {
circle.removeFromSuperview()
}
a.curve = .Linear
a.animate()
}
}
Drawing a line in Processing is dead-easy. In C4, there’s a bit more complexity because a line is actually a Shape
object. The major difference is that in C4 you end up with an object whose properties can be animated, copied, manipulated and styled rather than a bitmap.
From: Continuous Lines
Click and drag the mouse to draw a line.
void setup() {
size(640, 360);
background(102);
}
void draw() {
stroke(255);
if (mousePressed == true) {
line(mouseX, mouseY, pmouseX, pmouseY);
}
}
Here you’ll see things are slightly more cumbersome because you have to create a shape object. But, it’s not that much more code and you can do a lot with the shape object.
override func setup() {
let p = Path()
let poly = Polygon()
canvas.add(poly)
canvas.addPanGestureRecognizer { locations, center, translation, velocity, state in
if state == .Began {
p.moveToPoint(center)
} else {
p.addLineToPoint(center)
}
poly.path = p
}
}
Tracking the speed of mouse movement requires you to store the previous position and do a little displacement calculation. In C4, the gesture recognizer handles that kind of thing for you.
From: Patterns
Move the cursor over the image to draw with a software tool which responds to the speed of the mouse.
void setup() {
size(640, 360);
background(102);
}
void draw() {
variableEllipse(mouseX, mouseY, pmouseX, pmouseY);
}
void variableEllipse(int x, int y, int px, int py) {
float speed = abs(x-px) + abs(y-py);
stroke(speed);
ellipse(x, y, speed, speed);
}
Here we grab the velocity
of the pan gesture and use its values x
and y
to manipulate the size of a new circle as well as its lineWidth
.
override func setup() {
var circles = [Circle]()
canvas.addPanGestureRecognizer { locations, center, translation, velocity, state in
let c = Circle(center: center, radius: abs(velocity.x/50.0))
c.lineWidth = abs(velocity.y/100.0)
self.canvas.add(c)
circles.append(c)
if circles.count > 100 {
circles[0].removeFromSuperview()
circles.removeAtIndex(0)
}
}
}
Vector math is a powerful component of Processing, and C4 too.
From: Vector Math
Demonstrating some basic vector math: subtraction, normalization, scaling. Normalizing a vector sets its length to 1.
void setup() {
size(640,360);
}
void draw() {
background(0);
PVector mouse = new PVector(mouseX,mouseY);
PVector center = new PVector(width/2,height/2);
mouse.sub(center);
mouse.normalize();
mouse.mult(150);
translate(width/2,height/2);
stroke(255);
strokeWeight(4);
line(0,0,mouse.x,mouse.y);
}
Setting the anchorPoint
to {0, 0}
allows for rotating the shape around the beginning of the line, rather than its center
.
override func setup() {
let line = Line((Point(),Point(100,0)))
line.opacity = 0.25
line.anchorPoint = Point(0,0)
line.lineWidth = 20
line.center = canvas.center
canvas.add(line)
let vc = Vector(canvas.center)
canvas.addPanGestureRecognizer { locations, center, translation, velocity, state in
let vl = Vector(center)
let Θ = (vl-vc).heading
ShapeLayer.disableActions = true
line.rotation = Θ
}
}
This builds on the VectorMath
example by showing how you can embed objects in one another.
From: Follow 1
A line segment is pushed and pulled by the cursor.
float x = 100;
float y = 100;
float angle1 = 0.0;
float segLength = 50;
void setup() {
size(640, 360);
strokeWeight(20.0);
stroke(255, 100);
}
void draw() {
background(0);
float dx = mouseX - x;
float dy = mouseY - y;
angle1 = atan2(dy, dx);
x = mouseX - (cos(angle1) * segLength);
y = mouseY - (sin(angle1) * segLength);
segment(x, y, angle1);
ellipse(x, y, 20, 20);
}
void segment(float x, float y, float a) {
pushMatrix();
translate(x, y);
rotate(a);
line(0, 0, segLength, 0);
popMatrix();
}
You’ll see here that the Vector
class has many functions that are identical to Processing. The difference between these two examples is that we don’t have calls to pushMatrix()
and popMatrix()
. Instead, we position the circle (which has the line embedded as a subview).
override func setup() {
let circle = Circle(center: Point(0,0), radius: 10)
circle.strokeColor = C4Purple.colorWithAlpha(0.25)
circle.lineWidth = 20.0
let line = Line((Point(),Point(50,0)))
line.opacity = 0.25
line.anchorPoint = Point(0,0)
line.lineWidth = 20
line.center = circle.bounds.center
circle.add(line)
canvas.add(circle)
var v = Vector()
canvas.addPanGestureRecognizer { locations, center, translation, velocity, state in
let vl = Vector(center)
let dxdy = vl-v
let Θ = dxdy.heading
v = vl - Vector(x: cos(Θ) * 50, y: sin(Θ) * 50)
ShapeLayer.disableActions = true
circle.center = Point(v.x, v.y)
line.rotation = Θ
}
}
###Want to Contribute? We’d love to have a bigger list of comparisons to other open-source projects. If you’ve created some comparison examples let us know and we can publish them here with you as the author.