My project is a generative drawing project where the user gets to draw with hands/joystick and then save the work they drew.
I started my work by exploring different shapes and types of brushes to choose one. After some time and looking around I decided it was best to give the user the option to use more than one brush in one piece.
I am still not done with the brush class but after testing the brushes separately, that is my unedited code for the brush class:
Main Class Function:
import java.util.*;
class Brush {
int brushN;
float stepSize;
float angle;
float x, y, tempX, tempY;
color col;
//
int counter;
PFont font;
float fontSize;
String letters;
float fontSizeMin;
//
float [] blurX={ -stepSize, -stepSize, 0, stepSize, stepSize, stepSize, 0, -stepSize};
float [] blurY={ 0, stepSize, stepSize, stepSize, 0, -stepSize, -stepSize, -stepSize};
//linemoduelw
PShape lineModule;
float linelength=100;
float [] numX={ -100, -70, 0, 70, 100, 70, 0, -70};
float [] numY={ 0, 70, 100, 70, 0, -70, -100, -70};
Brush(int defaultt, float step_size) {
// 1 blur
// 2 random cylinder
// 3 dynamic shapes
// 4 text lines
// 5 rotating lines
brushN = defaultt;
stepSize = step_size;
angle = 270;
x = mouseX;
y = mouseY;
col = color(255);
fontSizeMin=200;
fontSize=50;
letters = "It isn't true that my mattress is made of cotton candy. It was the first time he had ever seen someone cook dinner on an elephant. Homesickness became contagious in the young campers' cabin. Every manager should be able to recite at least ten nursery rhymes backward.";
// for(int i; i<8; i++){
// numX = (float)acos()
// }
}
void setbrush(int brushn) {
brushN=brushn;
}
void setSize(int size) {
stepSize=size;
}
void draw() {
switch (brushN) {
case 1:
blur();
break;
case 2:
randomprisms();
break;
case 3:
dynamicShapes();
break;
case 4:
textlines();
break;
default :
rotatingLines();
break;
}
}
...
}
class ColorWheel{
}
Blur:
void blur() {
float diam = 1;
if (mousePressed) {
float d = dist(x, y, mouseX, mouseY);
if (d > stepSize) {
// gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
angle = (float)Math.atan2(mouseY-y, mouseX-x);
tempX = x;
tempY = y;
pushMatrix();
//
translate(x, y);
rotate(angle);
noStroke();
fill(col, 40);
//
for (int i=0; i<200; i++) {
int dir = int(random(0, 7));
rotate(random(5));
tempX=blurX[dir]*random(1, 10);
tempY=blurY[dir]*random(1, 10);
circle(tempX, tempY, diam);
}
//
popMatrix();
x=x+(float)Math.cos((angle))*stepSize;
y=y+(float)Math.sin((angle))*stepSize;
}
}
col = color(noise(100+0.01*frameCount)*255, noise(200+0.01*frameCount)*255, noise(300+0.01*frameCount)*255, 255);
}
Random Size Prisms Brush:
void randomprisms() {
if (mousePressed) {
float d = dist(x, y, mouseX, mouseY);
if (d>stepSize) {
// gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
angle = (float)Math.atan2(mouseY-y, mouseX-x);
for ( int i=0; i<8; i++) {
numX[i]+=random(0-stepSize/2, stepSize/2);
numY[i]+=random(0-stepSize/2, stepSize/2);
}
pushMatrix();
//
translate(x, y);
rotate(angle+random(-0.1, 0.1));
stroke(col);
strokeWeight(stepSize/4);
// if (frameCount%2 == 0) stroke(100);
// line(0, 0, 0, linelength*random(0.95, 1)*d/100);
rectMode(CENTER);
noFill();
rect(0, 0, linelength*random(0.95, 1)*d/100, linelength*random(0.95, 1)*d/100);
// noFill();
// beginShape();
// curveVertex(numX[0], numY[0]);///////////////
// curveVertex(numX[0], numY[0]);///////////////
// curveVertex(numX[1], numY[1]);//mid
// curveVertex(numX[2], numY[2]);///////////////
// curveVertex(numX[3], numY[3]);// mid
// curveVertex(numX[4], numY[4]);///////////////
// curveVertex(numX[5], numY[5]);//mid
// curveVertex(numX[6], numY[6]);///////////////
// curveVertex(numX[7], numY[7]);//mid
// curveVertex(numX[0], numY[0]);///////////////
// curveVertex(numX[0], numY[0]);///////////////
// endShape();
popMatrix();
x=x+(float)Math.cos((angle))*stepSize;
y=y+(float)Math.sin((angle))*stepSize;
x=mouseX;
y=mouseY;
}
}
col = color(noise(100+0.01*frameCount)*255, noise(200+0.01*frameCount)*255, noise(300+0.01*frameCount)*255, 255);
}
void dynamicShapes() {
if (mousePressed) {
float d = dist(x, y, mouseX, mouseY);
if (d>stepSize) {
//
lineModule = createShape();
stroke(col);
strokeWeight(10);
noFill();
lineModule.beginShape();
lineModule.vertex(100, 0); // first point
lineModule.vertex(0, 100);// /
lineModule.vertex(-100, 0);// \
lineModule.vertex(0, -100);// /
lineModule.vertex(100, 0);// \
lineModule.endShape();
// lineModule = createShape();
// stroke(col);
// strokeWeight(10);
// fill(col);
// lineModule.beginShape();
// lineModule.vertex(50, 75); // first point
// lineModule.bezierVertex(100, 100, 500, 100, 400, 300);
// lineModule.endShape();
//
// gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
angle = (float)Math.atan2(mouseY-y, mouseX-x);
pushMatrix();
//
translate(mouseX, mouseY);
rotate((angle+PI));
shape(lineModule, 0, 0, d, noise(1+frameCount*0.0001)*10);
//
popMatrix();
x=x+(float)Math.cos((angle))*stepSize;
y=y+(float)Math.sin((angle))*stepSize;
}
}
col = color(noise(100+0.01*frameCount)*255, noise(200+0.01*frameCount)*255, noise(300+0.01*frameCount)*255, 255);
}
Text Brush:
void textlines() {
if (mousePressed) {
float d = dist(x, y, mouseX, mouseY);
d= constrain(d, 60, 7000);
if (d>stepSize) {
// gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
angle = (float)Math.atan2(mouseY-y, mouseX-x);
fontSize= fontSizeMin*60/d;
println("d: "+d);
font = createFont("Calibri", fontSize);
textFont(font, fontSize);
char newLetter = letters.charAt(counter);
stepSize = textWidth(newLetter);
fill(col);
//stroke(col);
pushMatrix();
//
translate(x, y);
rotate(angle);
text(newLetter, 0, 0);
//
popMatrix();
counter++;
if (counter>letters.length()-1) counter=0;
x = x + (float)Math.cos(angle)*stepSize;
y = y + (float)Math.sin(angle)*stepSize;
}
}
col = color(noise(100+0.01*frameCount)*255, noise(200+0.01*frameCount)*255, noise(300+0.01*frameCount)*255, 255);
}
My idea is to make a drawing machine on Processing and to use Arduino-controlled Joy Sticks to control the mouse position on the screen.
The user would get to control the colors and save the image if desired.
If the user decides to save their generative art drawing, the 5 last saved drawings will show on the screen in a polaroid-like look.
Processing Inspiration:
I chose to make a generative art piece on processing because I feel that a drawing using a joystick can only get you so far without much practice, so I decided that a generative art algorithm would work better for this case.
These are some sources that I feel inspire my goal for the processing part of my project.
First design this is a randomly generated piece, but it is really close to what I thought of when I first thought of generative.
Second design This is a drawing piece where the letters are drawn instead of ink at the position of the mouse and the size is decided by the speed of the movement of the mouse.
Third design In this one the cursor is followed by randomly changing shape instead of a normal brush.
Fourth design This, like the first, does not follow the mouse, it is just random instead-but follows a random path and is not completely random.
I think this might be nice to add behind any of the other designs with a lower opacity to give a smoky look behind the drawing.
Arduino:
My plan is to have 2 joysticks, one to control the mouse location and one to change the color of the drawing at a certain point.
I also plan to add push buttons to toggle values that will reset/save/show prev saved images.
This is the arrangement I have in mind at the moment
I decided, after a struggle of thought, to make a simple water refill reminder. Drinking water is crucial and many people tend to try to forget. So I made this simple water that detects the weight of the bottle and knows how much water is left in the bottle/cup using a force sensor.
using the force sensor on its own did not give a range of weight enough for the water weight detector. so I decided to place the force sensor on a sponge.
I also used an on/off button that turns the circuit on when pressed and off when pressed once more
I also used 4 red lights that are more likely to capture someone’s attention and remind them to refill their water bottle when it’s empty.
and I used 4 blue led lights, more of the blue lights light up the more water there is in the bottle.
this is how my circuit looks:
the last set of wires that are neither connected to the button or the less is connected to the force sensor.
video:
the video shows how the circuit works:
Code:
const int outs[] = {3, 5, 6, 9,
10, 11, 12, 13
};
const int ins[] = {A2, A3};
int var, var2, b, r, maxx = 0;
long timer;
bool turnon = 0, curr, prev;
void setup() {
Serial.begin(9600);
for (int i = 0; i < sizeof(outs); i++) {
pinMode(outs[i], OUTPUT);
}
Serial.begin(9600);
for (int i = 0; i < sizeof(ins); i++) {
pinMode(ins[i], INPUT);
}
}
void loop() {
if (curr != prev && curr == 1) {
turnon = !turnon;
}
curr = digitalRead(ins[1]);
timer = millis();
var = analogRead(ins[0]);//0-250
var = map(var, 0, 500, 0, 255);
var2 = constrain(var, 250, 255);
Serial.print(" on: ");
Serial.print(turnon);
Serial.print(" curr: ");
Serial.print(curr);
Serial.print(" prev: ");
Serial.println(prev);
if (turnon == 1) {
on();
}
else {
for (int i = 0; i < 8; i++) {
analogWrite(outs[i], 0);
}
}
//
prev = digitalRead(ins[1]);
}
void redled(int n) {
if (timer % (n * 4) < (n * 1)) {
analogWrite(outs[4], var2);
analogWrite(outs[5], 0);
analogWrite(outs[6], 0);
analogWrite(outs[7], 0);
}
else if (timer % (n * 4) < (n * 2)) {
analogWrite(outs[4], 0);
analogWrite(outs[5], var2);
analogWrite(outs[6], 0);
analogWrite(outs[7], 0);
}
else if (timer % (n * 4) < (n * 3)) {
analogWrite(outs[4], 0);
analogWrite(outs[5], 0);
analogWrite(outs[6], var2);
analogWrite(outs[7], 0);
}
else {
analogWrite(outs[4], 0);
analogWrite(outs[5], 0);
analogWrite(outs[6], 0);
analogWrite(outs[7], var2);
}
}
void on() {
if (var < 20) {
b = -1;
r = 4;
}
else if (var < 140) {
b = 0;
r = 0;
}
else if (var < 260) {
b = 1;
r = 0;
}
else if (var < 380) {
b = 2;
r = 0;
}
else {
b = 3;
r = 0;
}
// there is water
if (r == 0) {
for (int i = 0; i < b + 1; i++) {
analogWrite(outs[i], var2);
}
for (int i = 7; i > b; i--) {
analogWrite(outs[i], 0);
}
}
else {
for (int i = 0; i < 4; i++) {
analogWrite(outs[i], 0);
}
redled(1000);
}
}
I have always been the worst when it came to forgetting different things at different places. Forgetting my card at the most random places was getting me locked out of my room more than I would have liked. So I decided to make a switch that reminds you to put your card back in its place sometime out.
I started by placing a switch in the circuit and making it work using a normal push-button switch. once I finished the circuit I replaced one end of the switch with a wire connected to the card and the other end with a wire connected to a cardholder that is to be stuck to a phone.
I connected the wires to copper tape that I stuck on contacting sides of the card and the cardholder so that when the card is in place, the switch is closed.
I used a yellow led light for the normal time when the card is placed in its location. when you remove the card from the cardholder, a timer starts, when the time span in the code ends, the red light starts to blink to remind you to put the card back in.
IMAGES:
Breadboard Circuit:
Whole Circuit:
Card Connection
Video:
CODE:
long mytime=500, timer = 0;
const int outs[] = {2, 4};
const int ins = A2;
int curr = 0, prev=0;
bool flip=false;
long blinkk=0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
for (int i = 0; i < sizeof(outs); i++) {
pinMode(outs[i], OUTPUT);
}
pinMode(ins, INPUT);
}
void loop() {
curr = digitalRead(ins);// <500, <900, >900
if (curr == 0) {
Serial.print(timer);
Serial.print(" ");
Serial.println(mytime);
if (mytime == timer) {
if(blinkk<=millis()){
flip=!flip;
blinkk+=500;
}
digitalWrite(outs[0], flip);
digitalWrite(outs[1], LOW);
}
else{
timer+=1;
digitalWrite(outs[0], LOW);
digitalWrite(outs[1], LOW);
}
}
else {
{
timer=0;
digitalWrite(outs[1], HIGH);
digitalWrite(outs[0], LOW);
blinkk=millis();
}
}
prev = digitalRead(ins);
}
The purpose of this game is for the student, skeleton in the picture, to collect all the questions and then collect the final paper to get the full grade for their exam.
IDEA(details):
Background:
Originally, I intended to have clouds as the background with the stars, but even when I used images instead of pixels, the game’s frameRate dropped and the game was barely functioning so I settled for a clear starry night look.
I choose this because:
firstly, I have really sensitive eyes, and I find it easier on my eye to look at a dark screen.
Secondly, I am a night person, night always looks better ;).
For the stars, I used overlapping circles to give a faded look, which resembles actual stars more than normal circles would.
Code:
class Bg {
float[] x = new float[50];
float[] y = new float[50];
Bg() {
for (int i=0; i<50; i++) {
x[i] = random(0, widthh);
y[i] = random(0, heightt);
}
}
void drawBG() {
if (frameCount%50==0) {
for (int i=0; i<50; i++) {
x[i] = random(0, width);
y[i] = random(0, height);
}
}
background(50, 50, 80);
for (int i=0; i<50; i++) {
for (int j=0; j<10; j++) {
noStroke();
fill(255, 25);
ellipse(x[i], y[i], 1+j, 1+j);
}
}
}
}
Creature:
Instead of making repetitive classes, I used class inheritance, where I made the Superclass, Creatures, for all the live items in the game.
For the player, I choose the skeleton, because obviously, we are all dead during midterm and final seasons. That also gave me the idea of the name “dead student“.
Sprite:
With the player, I struggled a little with the jumps. I wanted to only allow double jumps, which I thought was the case until my roommate tried it and I realized it didn’t. I tried to fix it, but that only made it worse, so I left it as it was when my roommate tried it. (I mean what works, works right?)
Code:
class Player extends Creature {
boolean left;
boolean up;
boolean right;
SoundFile jump;
int count;
Player(float x, float y, float r, float g, PImage _img, float w, float h, int num_frames, PApplet sketch) {
super(x, y, r, g, _img, w, h, num_frames);
left = false;
up = false;
right = false;
jump = new SoundFile(sketch, "jump.wav");
count = frameCount;
}
void update() {
gravity();
//====================
if (left==true) {
speed.x=-3;
dir=false;
} else if (right==true) {
speed.x=3;
dir=true;
} else {
speed.x=0;
}
//====================
if (up==true && pos.y>=ground-size.y &&secondJump==false) {
jump.play();
speed.y = -6;
} else if (up==true && speed.y<0 && secondJump==true && pos.y<ground-size.y) {
jump.play();
speed.y = -8;
secondJump=false;
}
pos.x +=speed.x;
pos.y +=speed.y;
if (frameCount%5 == 0 && speed.x !=0 && speed.y ==0) {
frame= (frame+1)%numFrames;
} else if (speed.x==0) {
frame=8;
}
//====================
if (pos.x<=0) {
pos.x = 0;
}
//====================
if (pos.x+size.x>= widthh) {
pos.x = widthh- size.x;
} else if (pos.x<size.x) {
pos.x = size.x;
}
//====================
for (int i =0; i<game.myMonsters.length; i++) {
float numME = pow((pow(size.x, 2)+(pow(size.y, 2))), 0.5);
float numthem = pow((pow(game.myMonsters[i].size.x, 2)+(pow(game.myMonsters[i].size.y, 2))), 0.5);
if (game.myMonsters[i].distance(this)<=numME/2.5+numthem/2.5 && game.myMonsters[i].alive) {
if (speed.y>0) {
game.myMonsters[i].alive=false;
game.myMonsters[i].sound2.play();
} else {
game.myMonsters[i].sound1.play();
alive = false;
}
}
}
for (int i =0; i<game.myQuestions.length; i++) {
if (game.myQuestions[i].distance(this)<=size.x/2+game.myQuestions[i].size.x/2 && game.myQuestions[i].alive) {
game.score++;
game.myQuestions[i].sound.play();
game.myQuestions[i].alive = false;
}
}
if (game.myfinal.distance(this)<=size.x/2+game.myfinal.size.x/2 && game.myfinal.alive) {
game.score+=5;
game.myfinal.sound.play();
game.myfinal.alive = false;
game.won= true;
}
}
}
Monsters:
Finding Sprites for the monsters was not easy. I was trying to find monsters that represent the distractions we have while studying. So instead of finding different monsters, I made my own using emojis and clip art images.
I used the facial features from the emojis and the body of what I think represents distractions. I made them alternate between an Innocent look and an evil look because distractions usually don’t look so bad.
For this one, I thought it was better to have a bouncy still image, as it was the only one that was completely dead. I used the same class for both as they had the same charactaristics.
For the full game, I made a game class that allows me to create a game object whenever I want to start the game. This helps with restarting and waiting for the user to press a key to start; as I just create a game object if the player is dead and the user presses enter at the welcom screen.
My game class only had the creation of all the game objects and the display call for them.
Code:
class Game {
//
int ground = 100;
public int score = 0;
boolean won;
Player myplayer;
Platforms[] plats = new Platforms[5];
Platforms groundd;
int platLocH[] = new int[5];
int platLocW[] = new int[5];
Monster[] myMonsters = new Monster[6];
Question[] myQuestions = new Question[5];
Question myfinal;
Game(PApplet sketch, PImage playerImg, PImage[] monsters, PImage questionIMG, PImage finalIMG) {
// creating ground
groundd = new Platforms(0, heightt-ground, widthh, ground, 0);
// creating platforms
for (int i=0; i<plats.length; i++) {
platLocH[i] = (heightt-255)-i*155;
platLocW[i] = int(random(0, widthh-500));
plats[i]= new Platforms(platLocW[i], platLocH[i], 600, heightt/25, 15);
}
// creating Monsters(1@ground & 4 at plats 0-3)
int n;
float m;
for (int i=4; i>-1; i--) {
n = int(random(0, 3));
myMonsters[i]= new Monster(platLocW[i]+60, platLocH[i]-60*(monsters[n].width/monsters[n].height)-10, 60, ground, monsters[n], monsters[n].width, monsters[n].height, 2, platLocW[i]+random(40, 50), platLocW[i]+random(160, 220), sketch);
}
n = int(random(0, 3));
m = random(widthh/2, widthh-450);
myMonsters[5] = new Monster(m+60, heightt-ground, 60, ground, monsters[n], monsters[n].width, monsters[n].height, 2, m+random(40, 50), m+random(160, 220), sketch);
// creating Questions
for (int i=3; i>-1; i--) {
myQuestions[i]=new Question(platLocW[i]+400, platLocH[i]-60*(questionIMG.width/questionIMG.height)-50, 60, ground, questionIMG, questionIMG.width, questionIMG.height, 1, sketch);
}
myQuestions[4]=new Question(m+400, heightt-ground, 60, ground, questionIMG, questionIMG.width, questionIMG.height, 1, sketch);
// creating final
myfinal = new Question(platLocW[4]+400, platLocH[4]-80*(finalIMG.width/finalIMG.height)-50, 80, ground, finalIMG, finalIMG.width, finalIMG.height, 1, sketch);
myfinal.alive=false;
// creating Player
myplayer = new Player(20, height-ground-180, 70, ground, playerImg, playerImg.width, playerImg.height, 9, sketch);
won = false;
}
void main() {
for (int i = 0; i<5; i++) {
plats[i].display();
if (myQuestions[i].alive) {
myQuestions[i].display();
}
}
groundd.display();
myplayer.display();
for (int i=0; i<6; i++) {
if (myMonsters[i].alive) {
myMonsters[i].display();
}
}
if (score == myQuestions.length) {
myfinal.alive = true;
myfinal.display();
}
}
}
Start and end screens and Key presses:
I made functions to display text at the start and end of each game. This allowed me to easily call either whenever needed.
I reset my game variables in the end screen functions, but that is just to avoid unexpected errors.
void startSc() {
textFont(f, 80);
fill(255);
textAlign(CENTER);
text("Dead Student", widthh/2, heightt/2-100);
textFont(f, 40);
text("press enter to start", widthh/2, heightt/2-10);
textFont(f, 20);
text("Collect the questions to get to final paper", widthh/2, heightt/2+100);
text("You can kill monsters by jumping on them", widthh/2, heightt/2+130);
text("Please use left, right, and up arrows to play", widthh/2, heightt/2+190);
}
void endSc() {
if (game.won) {
textFont(f, 40);
fill(255);
textAlign(CENTER);
text("YOU WON!!", widthh/2, heightt/2);
text("YOUR GRADE IS:", widthh/2, heightt/2+50);
text(String.valueOf(game.score)+" /10", widthh/2, heightt/2+100);
text("CONGRATS!!", widthh/2, heightt/2+150);
textFont(f, 20);
text("press r to reset", widthh/2, heightt/2+200);
} else {
for (int i=0; i<game.myMonsters.length; i++) {
game.myMonsters[i].alive=true;
}
for (int i=0; i<game.myQuestions.length; i++) {
game.myQuestions[i].alive=true;
}
textFont(f, 40);
fill(255);
textAlign(CENTER);
text("YOU DIED", widthh/2, heightt/2);
text("YOUR GRADE IS:", widthh/2, heightt/2+50);
text(String.valueOf(game.score)+" /10", widthh/2, heightt/2+100);
textFont(f, 20);
text("press r to reset", widthh/2, heightt/2+150);
}
}
Key Pressed/Released Code:
I created the game when the user presses enter;
void keyPressed() {
if (keyCode == 10 && started==false) {//enter
started = true;
game = new Game(this, playerimg, monsters, question, finall);
} else if (keyCode==82 && started==true) {//r-> reset
started=false;
startSc();
} else if (started==true && game.won==false) {
if (keyCode == LEFT) {
game.myplayer.left = true;
}
if (keyCode==RIGHT) {
game.myplayer.right = true;
}
if (keyCode==UP) {
game.myplayer.up = true;
}
}
}
void keyReleased() {
if (started==true) {
if (keyCode == LEFT) {
game.myplayer.left = false;
}
if (keyCode==RIGHT) {
game.myplayer.right = false;
}
if (keyCode==UP) {
game.myplayer.up = false;
game.myplayer.secondJump=true;
}
}
}
There is a game played a while back that I really liked, and as recreating that game will take much longer than the time I have now, I got an idea that is similar in a way, but simpler.
The game I got inspired by is called HUE.
In this game, hue needs to save his mom by collecting pieces of the color ring in the picture above.
My Idea:
My idea, similarly, the student needs to collect a few questions and the exam to pass.
Game Parts:
– The player/student needs to collect all the questions on the screen and get to the final before the timer ends.
– If the student collects all the questions, they can collect the final exam paper and get the full grade on the exam. Otherwise, they get points for the questions they collected.
-each question is guarded by a monster(monsters are inspired by the monsters that face students like anxiety, procrastination, and distractions).
This is a rough draft of what the game is supposed to look like:
Progress:
I started with the background. Instead of using a still image, I used loadPixels() to make the background look something like a night sky.
Code:
class Bg {
float[] x = new float[50];
float[] y = new float[50];
Bg() {
for (int i=0; i<50; i++) {
x[i] = random(0, widthh);
y[i] = random(0, heightt);
}
}
void drawBG() {
loadPixels();
for (int y=0; y<heightt; y++) {
for (int x=0; x<widthh; x++) {
float n = noise(x*.002, y*.005);
//n = frameCount%width+n;
//n= map(n,0,width,0,255);
pixels[x+y*width]=color(n*150);
}
}
updatePixels();
if (frameCount%5==0) {
for (int i=0; i<50; i++) {
x[i] = random(0, width);
y[i] = random(0, height);
}
}
for (int i=0; i<50; i++) {
for (int j=0; j<10; j++) {
noStroke();
fill(255, 25);
ellipse(x[i], y[i], 1+j, 1+j);
}
}
}
}
I added platforms, which the questions and monsters will be on at random, saved, x-locations:
I wrote a code that reads from the billboard top 100 songs (not the most recent). I edit the .csv file I found online to remove redundant data that I did not need and I used the left data to draw circles at random locations for each of the top 100.
I added a small alpha value to show the layering of circles as they are random.
I had to deal with longer song names and make them wrap around.
Instead of trying to find a library that works, I decided to try to make the wrap work myself to explore and know what I can do to manipulate a string.
key:
Code:
I started with a circle class to draw each circle at a random location and depending on circle details. I added an array to save the circles.
String names[];
int ranks[];
int weeks[];
boolean arrDone[] = new boolean[100];
boolean flag = false;
int counterDone = 0;
PFont myFont;
class Circles {
//attributes
PVector pos ;
int col;
int diam;
String text;
// number of weeks on board gives color shade, and rank determines radius
Circles(int weeks, int ranks, String _text) {
pos = new PVector(random(0, width), random(0, height));
//calculate fraction from 255
col = int((255*weeks/87));
text = _text;
//max diam = 70
diam =int((width)/ranks);
diam = constrain(diam, 50, 500);
}
void draw_circle() {
fill(0, 0, col, 200);
//fill(255,100);
noStroke();
ellipse(pos.x, pos.y, diam, diam);
// split text into lines
String[] words = split(text, ' ' );
writetext(words);
}
The next function is part of the circle class, I put it here separately because it includes the code for the wrap of the text.
Here, I declared the circle’s object array and then loaded and processed the data from the .csv file.
void readData() {
String stuff[] = loadStrings("charts.csv");
String data[]= new String[3];
// Convert String into an array of integers using ',' as a delimiter
// string array is returned, which we cast to an int array
names = new String[stuff.length];
ranks = new int[stuff.length];
weeks = new int[stuff.length];
for (int i=1; i<stuff.length; i++) {
data = split(stuff[i], ',' );
//fill arrays with data
ranks[i] = int(data[0]);
names[i] = data[1];
weeks[i] = int(data[2]);
}
}
in the creat function here I added a boolean array to check if the song has been output on the screen or not to avoid repitition.
void create() {
int num = int(random(1, 99));
boolean flag = false;
if (arrDone[num]) {
flag= true;
} else {
arrDone[num] = true;
}
if (!flag && count<=100) {
// int weeks, int ranks, String _text){
circle[count] = new Circles(weeks[num], ranks[num], names[num]);
circle[count].draw_circle();
count++;
}
}
I only used the draw function for the text to appear at the beginning of the code running time. I generated the circles with mouse clicks instead to give time for the user to analyze each new circle.
void setup() {
size(1000, 1000);
background(200);
readData();
}
void draw() {
myFont = createFont("SourceCodePro-Light.ttf", 60);
textFont(myFont);
if (frameCount<25) {
String textt = "Press at a random location";
textSize(60);
text(textt, width/2-(textWidth(textt)/2), height/2-32/2);
}else if(frameCount<30){
background(200);
}
}
void mouseClicked() {
if (frameCount>30){
create();
}
}
This was inspired by one of the things we saw in class. For some reason, I cannot seem to find it, but it was a piece where lines go from a circumference of a circle inwards to fill the circle.
I had a plan in mind to have lines growing out of the center into a circle, but I did not like how it looked, as the lines were too sharp for my preference.
So instead I used the noise function to make random dots, on a 360-degree variation.
I wanted to make it look more natural, however, so I decided to also add some cloudy form around it.
When I saw this, I felt like it reminded me of a laptop screen saver, as the circles grow out and it progresses into what it is. Screen savers though, unlike this design above, have different circles it would usually be more than one, so using a random function, I generated the circles starting from a different center point every 100 frameCounts.
That, if I would let go on I would have gotten into a huge mesh after some time, so I called the background function after every 5 circular things are created.
Later I also edited the colors and added an alpha value to make the circles a little easier on the eye.
and to make it a little user-controlled, I called the background function and reset the center with each click on the screen.
I also decided to make it a full screen like a real screen saver.
video:
code:
main file:
Circles _circles;
int centerX = 0;
int centerY = 0;
void setup() {
fullScreen();
background(0);
frameRate(10);
_circles = new Circles(width/2, height/2);
}
void draw() {
_circles.generate();
if (frameCount%20==0){
_circles.cloudy();
}
if (frameCount%100==0){
_circles.setCenter(random(0, width),random(0, height));
}
if (frameCount%500==0){
background(0);
}
}
void mouseClicked(){
background(0);
_circles.setCenter(mouseX, mouseY);
}
Circle file:
class Circles {
public float xcenter;
public float ycenter;
public float x_pt;
public float y_pt;
public int rad;
public float[][] ptarr = new float[90][2];
Circles(float _xcenter, float _ycenter) {
xcenter = _xcenter;
ycenter = _ycenter;
rad = 4;
setupp(30, xcenter, ycenter);
}
public void setupp(int num, float x, float y) {
for (int i=0; i<90; i++) {
x_pt = x + num*cos((float)radians(i*4));
y_pt = y + num*sin((float)radians(i*4));
fill(255, 50);
noStroke();
}
}
//getters and setters
public void setCenter(float _xcenter, float _ycenter) {
xcenter = _xcenter;
ycenter = _ycenter;
setupp(30, xcenter, ycenter);
}
public void generate() {
int offset = 30+(frameCount%100)*5;
float newoffset;
float newoffset2x;
float newoffset2y;
fill(random(100, 200), random(100, 200), random(100, 200), 100);
noStroke();
for (int i=0; i<90; i++) {
newoffset = noise(frameCount + i*0.01)*offset;
newoffset2x= noise(frameCount + i*0.02)*cos((float)radians(i*4));
x_pt = xcenter + newoffset*newoffset2x;
newoffset2y= noise(frameCount + i*0.02)*sin((float)radians(i*4));
y_pt = ycenter + newoffset*newoffset2y;
circle(x_pt, y_pt, rad);
}
}
public void cloudy() {
fill(100, 30);
float new_x = random(xcenter-(frameCount*20)%width/3, xcenter+(frameCount*20)%width/3);
float new_y = random(ycenter-(frameCount*20)%height/3, ycenter+(frameCount*20)%height/3);
for (int i=0; i<99; i++) {
circle(random(new_x-width/10, new_x+width/10), random(new_y-height/10, new_y+height/10), random(40, 80));
}
}
}
I did this design using both circles and “center” mode rects.
In the beginning, I tried using the normal formula for a circle to decide the midpoints of each layer of rect/circles, but for some reason, it did not work as required. So, after a long bugging session, I changed my equations, and I used sin and cos instead.
I started the code with the center circle starting at the top left corner, as it has (0,0) coordinates, making it easier to figure out what I was trying to do.
After getting this part to work, I made the center point based on the center of the canvas.
I started with the centric shape being all circles with random-fill colors.
But I then thought, why not make a random alternation between both squares and rectangles? It would make it more interesting.
I also wanted to make it a little interactive, so I made the center point follow the mouse press as shown in the video.
And that is the end of my project’s story. 🙂
Code:
import java.lang.Math;
int dimWidth = 1000;
int dimHeight = 800;
int centerX = 500;
int centerY = 400;
void pattern(){
////x=0, y=0;
//double x = Math.toRadians(50);
//println(x);
int rad;
if(mousePressed){
centerX = mouseX;
centerY = mouseY;
}
for(int j=1; j<50 ; j++){
fill((int)random(0,255),(int)random(0,255),(int)random(0,255), 20);
int num = (int)random(0,2);
strokeWeight(0.3);
for(int i=0;i<32;i++){
rad = j*30+j*15;
float x_coordinate = centerX + rad*cos((float)Math.toRadians(i*90/8));
float y_coordinate = centerY + rad*sin((float)Math.toRadians(i*90/8));
if (num==1){
circle(x_coordinate,y_coordinate,j*10+30);
}
else{
rectMode(CENTER);
rect(x_coordinate,y_coordinate, j*10+30, j*10+30);
}
}
}
}
void setup(){
size(1000,800);
background(255);
}
void draw(){
if (frameCount%10==0){
background(255);
pattern();
}
}