Skip to content

Instantly share code, notes, and snippets.

Created Sep 28, 2017
Embed
What would you like to do?
/*
DRAW ME - FINAL CODE
Enna Kim, Mika Hirata, Vivian Wong
Professor Kate Hartman
DIGF 2004 - Atelier I
September 27, 2017
This sketch includes all of the technical code which controls
Arduino Firmata through Processing. It allows the user to interact
with a touch textile grid connected to two separate capacitive sensors,
one for X, and one for Y. The user can control where certain features appear
when interacting with different locations on the grid. In addition, a
pressure-sensor is used to control the shade of the colour on screen, mimicking
pen-pressure sensitivity used in drawing tablets.
This current sketch only includes technical code, as a result it can only
display ellipses as it's output to test the functionality. When combined with
"DRAW ME Visual Code," the user can control the on-screen position of a variety
of interesting and unique visual outputs.
Note: This sketch can only run after standardFirmata has been uploaded to the Arduino
through the Arduino IDE once. If run on a different computer from the original, please
use Processing File>Examples>ArduinoInput to identify which port the Arduino is connected
to. Then replace "[1]" with the correct value that corresponds to the port.
VISUAL REFERENCES:
/* Reference Codes
https://processing.org/reference/millis_.html
https://py.processing.org/tutorials/p3d/
https://www.openprocessing.org/sketch/153224
https://www.openprocessing.org/sketch/218641
http://p5aholic.hatenablog.com/entry/2015/06/15/194250\
http://p5aholic.hatenablog.com/entry/2015/12/11/000000
TECHNICAL REFERENCES:
https://stackoverflow.com/questions/2788159/turn-javascript-local-variable-into-global-variable
https://processing.org/reference/map_.html
https://processing.org/examples/map.html
http://playground.arduino.cc/Interfacing/Processing
https://processing.org/examples/mousepress.html
http://processingjs.org/reference/for_/
http://resistor.cherryjourney.pt/ used to identify the resistance of resistors
https://github.com/plusea/CODE/tree/master/EXAMPLE%20CODE/Resistive%20Sensors/LOCATION
https://www.youtube.com/watch?v=PAViBKCWrlg the guy talking about the matrix on the fabric
http://www.instructables.com/id/Analog-Fabric-Joypad/ analog fabric joypad (our first insipration)
https://www.youtube.com/watch?v=vuu3XORygbY grid made with conductive thread
https://www.youtube.com/watch?v=oecwY5hkXzw grid made with conductive tape(copper tape)
*/
// import all necessary libraries
import processing.serial.*;
import cc.arduino.*;
import org.firmata.*;
import processing.sound.*;
///////////////////////// ON-SCREEN STUFF ////////////////////////
SoundFile soundFile; // name for sound file
int sceneCounter = 0; // setting a counter to switch the scenes
Timer t1; // declaring the class method "Timer" in the main sketch
Timer t2; // declaring the class method for the orbs
Line lines; // declaring the class method "Lines" in the main sketch
Letter[] letters; // declaring the class method "Letter" in the main sketch
Sein sein; // create Sein objects
Orb[] orbs = new Orb[500]; //create array with size of 500 orbs
int totalOrbs = 0; // set variable for number of total orbs
float speed2 = 1.0; //speed for animation two
int numberX; // the number of characters in x axis direction for animation one
int numberY; // the number of characters in y axis direction for animation one
int size; // the size of the character
float x;
float y;
float y2;
float radius = 200; // set radius as 300 for the green sphere (second animation)
float ellipse_size = 0.0; // size of yellow ellipse at the end of the film credit (seventh animation)
int[] xpos = new int[50]; // create array for xPos
int[] ypos = new int[50]; // create array for yPos
float rot = 0; // float variable for rotation
float velocity = 0; // the value to add on t
float acceleration = 0.05; //the number to add velocity
color c; // declare variable c as color
color c2;
///////////////////////// ARDUINO STUFF ////////////////////////
Arduino a1; // initialize Arduino as a1
int[] pin = new int[12]; // create new pin array with 12 items
int drawPosX; // initialize integer variable for drawPosX
int drawPosY; // initialize integer variable for drawPosY
int sensor1 = 2; // set sensor1 as analog pin 2
Serial myPort; // Name serial port:
// set up size of sketch and background
void setup() {
size(800, 800, P3D); // set size of sketch to be 800 by 800 pixels
background(0); // set background colour to black
/////////////// ON-SCREEN SETUP ///////////////
soundFile = new SoundFile(this, "background.mp3"); //the name of the music file
soundFile.play(); //play the music
t1 = new Timer(8000); // setting up the timer with 8 sec interval
t2 = new Timer(20); // setting up the timer with 0.2 sec interval for animation four
lines = new Line(); // setting up line class (third animation)
sein = new Sein(); // setting up sein class (fourth animation)
t2.start(); // starting the timer for fourth animation(orbs)
textAlign(CENTER, CENTER); // centering the text for the title page
size = 20;
textSize(size); // size of the text
numberX = width/size; // the number of text that goes to x axis
numberY = height/size; // the number of text that goes to y axis
letters = new Letter[numberX * numberY]; // creating new letters for each x and y axis
//loop structure to create the letters costantly when the mouse is on the canvas
for (int x = 0; x < numberX; x++) {
for (int y = 0; y < numberY; y++) {
letters[x*numberY+y] = new Letter(x*size+size/2, y*size+size/2);
}
}
/////////////// ARDUINO SETUP //////////////
a1 = new Arduino (this, Arduino.list()[1], 57600); // create new item a1 for Arduino, set to port [1]
// for integer i equal to 2, i less than 12, increment i by one
for (int i = 2; i < 12; i++) {
pin[i] = i; // set pin[i] equal to the value of i
a1.pinMode(pin[i], Arduino.INPUT); // set pin[i] as input (Pins 2-12 set as input)
println(pin[i]); // print pin[i] to test if forloop worked
}
printArray(Serial.list()); // list all the available serial ports
}
void draw() {
///////////// ON-SCREEN DRAW ////////////
checkTime(); //time checker
if (sceneCounter == 0 || sceneCounter == 1 ) { //16 sec interval
checkPosition1(); //loading animation
} else if (sceneCounter == 2 || sceneCounter == 3 ) { //16 sec interval
background(128, 240, 190); //background color
noCursor(); //not to show the cursor on canvas
//drawing the characters for the title page
for (int i = 0; i < letters.length; i++) {
letters[i].display();
title();
}
} else if (sceneCounter == 4 || sceneCounter == 5 ) { //16sec interval
checkPosition2(); //first animation
} else if (sceneCounter == 6 || sceneCounter == 7 ) { //16sec interval
checkPosition3(); //second animation
} else if (sceneCounter == 8 || sceneCounter == 9 ) { //16sec interval
four(); //third animation
} else if (sceneCounter == 10 || sceneCounter == 11) { //16sec interval
five(); //fourth animation
} else if (sceneCounter >= 11 ) { // after all the animation
six(); //last animation
}
//////////// ARDUINO DRAW //////////////
checkPositionAll(); // call checkPositionAll function
colourChange(); // call colourChange function
}
void checkPosition1() {
checkPositionX(); // call checkPositionX function
checkPositionY(); // call checkPositionY function
one();
}
void checkPositionTitle() {
checkPositionX(); // call checkPositionX function
checkPositionY(); // call checkPositionY function
title();
}
void checkPosition2() {
checkPositionX(); // call checkPositionX function
checkPositionY(); // call checkPositionY function
//two();
colourChange2();
}
void checkPosition3() {
checkPositionX(); // call checkPositionX function
checkPositionY(); // call checkPositionY function
three();
}
// Function which combines checkPosition functions for X and Y axis and drawScreen
void checkPositionAll() {
checkPositionX(); // call checkPositionX function
checkPositionY(); // call checkPositionY function
//drawScreen(); // call drawScreen function
}
void colourChange2() {
two();
}
// Function which checks position of X-axis with capacitive sensor X
void checkPositionX() {
// for integer j equal to 2, j less than 7, increment j by 1
for (int j = 2; j < 7; j++) {
pin[j] = j; // set pin[j] equal to j
if (a1.digitalRead(pin[j]) == Arduino.LOW) { // check if value of checked pin is LOW
drawPosX = pin[j-2]; // set drawPosX equal to j-2
println("Pin " + pin[j-2] + " is ON" + " drawPosX x-axis: " + drawPosX); // print which pin is ON
} else {
println("Pin " + pin[j-2] + " is OFF"); // print which pin is off
}
}
}
////////// ON-SCREEN FUNCTIONS /////////////
void title() {
noStroke();
text("DRAW ME!", width/2, height/2);
text("By", width/2, height/2+40);
text("Enna Kim, Vivian Wong, Mika Hirata", width/2, height/2+80);
}
//Loading page at the beggining
void one() {
background(255); //background color
noCursor(); //not to show the cursor
fill (0); //fill with black
text("LOADING...", width/2, height/2);
translate(drawPosX*100+200, drawPosY*50, 0); //the circle moves with the location of cursor
rotateX(frameCount*0.01); //rotate in x direction
rotateY(frameCount*0.01); //rotate in y direction
//remember the previous corrdinate of x and y axis
float lastX = 0, lastY = 0, lastZ = 0;
float radius = 200;
float s = 0, t = 0;
while (s <= 180) {
float radianS = radians(s);
float radianT = radians(t);
// renew the present corrdinate of x and y axis
float x = radius * sin(radianS) * cos(radianT);
float y = radius * sin(radianS) * sin(radianT);
float z = radius * cos(radianS);
stroke(245, 195, 175); //color of the sphere
if (lastX != 0) {
strokeWeight(0.5);
//draw a line from the previous corrdinate to the present corrdinate
line(x/2, y/2, z/2, lastX, lastY, lastZ);
}
strokeWeight(7);
point(X+4, y+4, z+4);
point(x, y, z);
//renew the last corrdinate
lastX = x;
lastY = y;
lastZ = z;
//renew s and t at the same time
s++;
t += velocity;
}
//adding velocity to the acceleration
velocity += acceleration;
}
//first animation (circle)
void two() {
noCursor(); //not to show the cursor
background(71, 149, 242); // background color
//if(mousePressed == true) {
translate(drawPosX*100+120, drawPosY*190-850); //translate mousex and mousey into the center of the canvas
rotateX(frameCount*0.02); // rotate the sphere around x-axis
rotateZ(frameCount*0.03); // rotate the sphere around y-axis
for (int i = 0; i <= 180; i += 1) {
float radianS = radians(i);
float z = radius * cos(radianS); //declaring z value
for (int t = 0; t < 360; t += 3) {
float radianT = radians(t);
float x = radius * sin(radianS) * cos(radianT); // declaring x value
float y = radius * sin(radianS) * sin(radianT); // declaring y value
//stroke(0, 0, 0, random(255)); //stroke color: white
stroke(c);
strokeWeight(2); //thickness of the circles
point(x, y, z);
}
}
}
//animation two (lines)
void three() {
noCursor(); //not to show the cursor
//background(232, 148, 63); //background color
background(c2);
lines.display(); //class Line
fill(random(200, 255));
x+=speed2;
if (x== 410) {
speed2 = 0; //stop moving the font when it hits 410
}
}
//animation three (orbs)
void four() {
background(0);
anim1();
circle2(0); // unique duo colour achieved by overlaying circle2() on Sein()
sein();
}
//animation four
void five() {
//create an ellipse which is a transition
fill(87, 107, 201);
ellipse(width/2, height/2, ellipse_size, ellipse_size); //sizr and location of the ellipse)
ellipse_size = ellipse_size + 5.0; //the size of the ellpise increases by 5.0
}
//last scene
void six() {
fill(255);
text("Thank you for your time! ", width/2, height/2);
}
// main Sein object, that will be called at the beginning
// different Seins had to be called because they will move differently
void sein() {
noCursor(); // Hides cursor, replaced by Sein
sein.move(drawPosX*150+50, drawPosY*170-600);
sein.display();
xpos[xpos.length - 1] = drawPosX*150+50; // original, xPos corresponds to xPos of cursor
ypos[ypos.length - 1] = drawPosY*170-600; // original, yPos corresponds to yPos of cursor
}
// animation of orbs floating upwards
void anim1() {
if (t2.isFinished() == true) { // when timer reaches 30 milliseconds
orbs[totalOrbs] = new Orb(); // display new orb
totalOrbs++; // increment number of orbs
t2.start(); // reset time
if (totalOrbs >= orbs.length) {
totalOrbs = 0; // reset number of orbs to 0 if there are over 500 orbs
}
}
for (int i = 0; i < totalOrbs; i++) { // for loop calls each class function for each orb
orbs[i].move(); // move property of orbs
orbs[i].display(); // display property of orbs
orbs[i].lightOnTouch(sein); // give each orb the property to be lit up if touched by Sein
}
}
void circle2(int colour) {
for (int s = 0; s < xpos.length - 1; s++) {
xpos[s] = xpos[s+1];
ypos[s] = ypos[s+1];
}
for (int s = 0; s < xpos.length - 1; s++) {
xpos[s] = xpos[s+1];
ypos[s] = ypos[s+1];
}
xpos[xpos.length - 1] += 1; // set previous xPos to xPos + 1
ypos[ypos.length - 1] += 1; // set previous yPos to yPos + 1
for (int k = 0; k < xpos.length; k++) {
// choose between blue glow (calm mode)
if (colour == 0) {
fill(random(50, 70), random(50, 70), random(220, 255), 250);
}
// or purple glow when calling function (attacking mode)
if (colour == 1) {
fill(192, 135, random(220, 255), 250);
}
ellipse(xpos[k], ypos[k], k/2, k/2); // draw ellipse
}
}
void checkTime() {
if (t1.isFinished()) {
sceneCounter = sceneCounter+1; //when the timer hits 5.5 sec the sceneCounter will increase by 1
t1.start(); //start the timer again
}
}
void mousePressed() {
sceneCounter++; //when the mouse is pressed the sceneCounter will increase by 1
//if the mouse if pressed, sceneCounter will be increated by one and pass it to next scene
}
////////// ARDUINO FUNCTIONS /////////////
// Function which checks position of X-axis with capacitive sensor Y
void checkPositionY() {
// for integer j equal to 7, j less than 11, increment j by 11
for (int j = 7; j < 11; j++) {
pin[j] = j; // set pin[j] equal to j
if (a1.digitalRead(pin[j]) == Arduino.LOW) { // check if value of checked pin is LOW
drawPosY = pin[j-2]; // set drawPosX equal to j-2
println("Pin " + pin[j-2] + " is ON" + " drawPosX y-axis: " + drawPosY); // print which pin is ON
} else {
println("Pin " + pin[j-2] + " is OFF"); // print which pin is off
}
}
}
// Function for pressure sensor colour-changing mechanic
// Changes from light green to navy blue
void colourChange () {
float val = a1.analogRead(sensor1); // set float value equal to analog value of sensor1 (textile pressure sensor)
float valA = map(val, 500, 1000, 75, 255); // map value to value A
float valB = map(val, 500, 1000, 10, 25); // map value to value B
// if val is less than or equal to 800
if (val <= 800) {
c = color(valA*5, valA*10, valB*20, valB*10); // change fill colour to specified values relevant to ValA and ValB
c2 = color(valA*5, valA*5, valB*25, valB*10);
//rect(0, 0, height, width); // draw a 200 by 200 rectangle at 100 px right, 200 px down
}
//println(int(val), int(valA), int(valB)); // used to check values of valA and valB
// drawing function, currently with mouse, replace with pressure sensor
}
// Function for controlling the on-screen drawing process
//void drawScreen() {
// noStroke(); // remove stroke
// ellipse(drawPosX*100+200, drawPosY*80, 20, 20); // draw an ellipse depending on touch sensor location detected
//}
//Thank you for your time! Mika Hirata, Vivian Wong, Enna Kim
class Letter {
char c; // the characters to show
int x, y; // x-axis and y-axis
int gray = 255; //color
Letter(int x, int y) {
this.x = x;
this.y = y;
// setting what kind of fcharacter to show as the shadow
c = char(int(random(97, 0)));
}
void display() {
// calculating the distance of the mouse
float distance = dist(drawPosX*200, drawPosY*200-900, x, y);
// draw in black within 100px
if (distance <= 100) {
gray = 0;
}
// resetting the character in 10% probability
if (random(100) < 10) {
c = char(int(random(97, 200)));
}
// draw the characters
fill(gray);
text(c, x, y);
// fade the character into white color in the 4.0 pace
gray += 4;
}
}
//class for lines
class Line{
int step1 = 10;
int x1 = 100;
int x2 = 100;
int y1 = 50;
int y2 = 50;
int y3 = 10;
int move = 50;
void display(){
if(x1 > 100 || x2 < 10){
move = move*40;
}
if(x2> 250 || x2 < 10){
move = move*40;
}
x1+=move;
y1+=move;
y2-=move;
x1 -= move;
float xFactor = map(drawPosX*100/2, drawPosY*100/2, width, 1.5, 8.0);
float yFactor = map(drawPosY*100/2, drawPosY*100/2, height, 2.5, 2.0);
for(int i = 0; i < width; i+=step1){
//setting for the lines
stroke(255, 31, 83, random(0,100));
strokeWeight(1);
//how do the line move
line(i, i*xFactor, width + i*xFactor, height - i*xFactor*yFactor);
line(i, i*xFactor, width - i*xFactor, height + i*xFactor*yFactor);
line(i, i*xFactor, width + i*xFactor, height - i*xFactor*yFactor);
line(width, i*xFactor, width - i*xFactor, height + i*xFactor*yFactor);
line(width+ i, i*xFactor, i*xFactor, height + i*xFactor*yFactor);
line(width- i, i*xFactor, i*xFactor, height - i*xFactor*yFactor);
line(i, i*xFactor, i*xFactor, height + i*xFactor*yFactor);
line(i, i*xFactor, i*xFactor, height - i*xFactor*yFactor);
}
}
}
// glowing orbs are a signficant image in Ori and the Blind Forest
class Orb {
color c;
float size;
float x;
float y;
float speed;
Orb() {
x = random(width);
y = height;
size = random(30,60);
speed = 0.05 * size;
c = color (100, 237, random(150, 255), random(100));
}
void move() {
y -= speed;
}
void display() {
noStroke();
fill(c);
ellipse(x, y, size, size);
}
boolean checkIntersect(Sein s) {
float distance = dist(x, y, s.x, s.y);
float myRadius = size/2;
float otherRadius = s.size/2;
if (distance <= myRadius + otherRadius) {
return true;
} else {
return false;
}
}
// function allowing opacity to increase randomly if orb is touched by Sein object
void lightOnTouch(Sein s) {
if (checkIntersect(s) == true) {
c = color(100, 237, random(150, 255), random(200, 255));
}
}
}
// create Sein object, Sein is a creature of blue light
class Sein {
float size;
color c;
float x;
float y;
Sein() {
size = 10;
c = color (100, 230, 250, 10);
}
void move(float _x, float _y) {
x = _x;
y = _y;
// for loop to calculate the position depending on length of xpos - 1
for (int s = 0; s < xpos.length - 1; s++) {
xpos[s] = xpos[s+1];
ypos[s] = ypos[s+1];
}
for (int s = 0; s < xpos.length - 1; s++) {
xpos[s] = xpos[s+1];
ypos[s] = ypos[s+1];
}
}
void display() {
strokeWeight(4);
fill(c);
ellipse(x, y, size, size);
for (int k = 0; k < xpos.length; k++) {
noStroke();
fill(10, 235, random(220, 255), k);
ellipse(xpos[k], ypos[k], k/2, k/2);
}
}
}
// class for Timer
class Timer {
int timeStarted;
int interval;
Timer(int _totalTime) {
timeStarted = _totalTime;
}
void start() {
interval = millis();
}
boolean isFinished() {
int elapsedTime = millis()- timeStarted;
if (elapsedTime > interval) {
return true;
}else {
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment