Candy colored spiral visual effect

This has gone through many iterations of trial and error to get the coolest effect.

Im using spiraled ellipses as a main element for my mid term, so I have been experimenting with it.

Code for creating the spiral:

float angle;

float x;
float y;
void setup() {
  size(800, 800);
  noFill();
  shapeMode(CENTER);
}

void draw() {

  //fill(255);
   fill(255,200,200); //pale rose, change the color of the candy.
  ellipse(height/2, width/2, 600, 600);
  
  int hundred=100;
  //rotate(angle);

  for (int i=0; i<500; i+=100)

  { 
    strokeWeight(20);
    stroke(0); //change the color of the spiral
    noFill();
    ;
    arc(height/2, width/2, hundred+i, hundred+i, radians(180), radians(360) );
    arc(height/2-25, width/2, hundred*1.5+i, hundred*1.5+i, radians(0), radians(180));
  }
  //angle=angle+0.1;
  //save("mySpiral.jpg");
};

I exported the code above to a .jpg format to use as an image in the sketch below.

Code for the animation:

float angle;
PImage img;
void setup() {
  size(900, 900);
  img = loadImage("mySpiral.png");
};
void draw() {
    background(255);
  for (int i=0; i<width; i++) {
 
     translate(width/2+i, height/2+i);
  imageMode(CENTER);
  rotate(angle);
  image(img, 0, 0,300,300);
  
 
  }
 angle=angle+1*1;
}

 

Next step :

I would like each candy spiral to go through several colored versions of itself:

 

  for (int a= 0; a<1; a++) {
     save(random(20)+"spiral");
  }

This code allows different colored versions from random to be saved as a new version of itself , I plan on using the saved photos as part of a sprite sheet to add to the animation above.

Generative text assignment

In last week’s class, I was really interested in the circle of letters code, so I wanted to do something similar for my generative text assignment. I borrowed a lot of code from the circle code document, and in this week’s assignment, a lot of my time was put into studying the code in order to apply the additions that I wanted to.

Regarding my idea, the circle of letters reminded me of Iron man 1, when Pepper gave Tony the gift that said: “Proof that Tony Stark has a heart.” Our assignment was to create generative texts, so I couldn’t just create a stagnant version of the gift. Instead, I decided to make it blink, like how tony’s reactor would blink sometimes.

Code wise, some lines in the code was really helpful in helping me understand arrays and objects. For instance:

Circle letters[] = new Circle[s.length()];

I was still unfamiliar with calling multiple objects and putting them into arrays, so this line helped clear things up for me well. The use of trigonometry was also inspiring for my future approaches to OOP.

Here is my full code:

String s = "        PROOF THAT TONY STARK                    TRAEH A SAH            "; 
PImage img;
float speed = 2;

Circle letters[] = new Circle[s.length()];
PFont f;
float r = 250;
float dir = 1;
float font_size = 30;

void setup(){
  size(640, 640);
  img = loadImage("Tony.png");
}

void draw(){
  background(0);
  f = createFont("Arial", font_size);
  textFont(f);
  float radius = r;
  float startingAngle = PI;
  float circleCenterX = width/2;
  float circleCenterY = height/2;
  
  for (int i =0; i<s.length();i++){
     float angle = startingAngle + i*TWO_PI/s.length();
     float x = cos(angle)*radius + circleCenterX;
     float y = sin(angle)*radius + circleCenterY;
     letters[i] = new Circle(x, y, s.charAt(i));
  }

  for (int i =0; i<s.length();i++){
     letters[i].display(); 
  }  

  if (r >=  250){
    dir = -dir;
  }
  else if (r <= 20){
    dir = 1;
  }
  imageMode(CENTER);
  image(img, width/2+font_size/3, height/2-font_size/3,  r*2-font_size, r*2-font_size);
  
  if (dir == -1){
  font_size = font_size - speed/8;
  }
  else if (dir == 1){
  font_size = font_size + speed/8;
  }
  
  
  r = r + speed * dir;

}

Circle class:

class Circle {
  float x, y;
  char letter;

  Circle(float _x, float _y, char _c) {
    x = _x;
    y = _y;
    letter = _c;
  }

  void display() {
    fill(255);
    text(letter,x,y);
  }
}

Video:

Help Needed! – Spotify Top 20 Visualization

Well, I’ve been trying to get different versions of this program to work for a while, but it’s not perfect yet. It’s far from it actually. I’m going to walk you through my thought process and show you my code, any suggestions would be much appreciated!

 

So, for this week, I noticed that Spotify allows users to access their own data as well as the charts from every day in CSV format (which is very cool). Unfortunately, personal data takes a long time to be prepared and sent to you, so even after asking for it on Thursday, I didn’t receive it so I couldn’t use it. Honestly, that was kind of a relief, I’m not ready to share my Spotify stats with you guys yet…a lot of embarrassing guilty pleasures on there.

Anyways, I decided to use the top 20 songs from the first week in September, and then create a data visualization of how well these songs were doing throughout the month. I downloaded all four CSV files that contain the Top 200 and recorded the values relevant to me (streams for week 1 top 20) in my own CSV file.

Process

Using a multi-row/column CSV file meant I needed different functions than the ones we used in class (loadStrings). I looked up loadTable() and watched a bunch of tutorials on it.

For my visualization, I wanted to achieve to main things. One, present the data using musical symbolism.  Two, use user text input to “search” one of the top 20 songs.

For one, I came up with a system where each note value represents a range of streams, and hence if the data in the CSV file corresponds to a certain range a certain note will be displayed on the staff I drew on screen.

So, through looking at a display of 4 notes on the screen one can evaluate how a certain song did throughout the month. which week had the most streams etc.

 

 

Example of a Visualization for a Song

 

 

 

 

 

 

 

 

Then, for 2, I looked in the processing reference for an input function and didn’t find anything relevant to what I needed. I ended up finding a very helpful code on learningprocessing.com, which allowed me to save the user input in a variable. However, my main struggle and the reason my code isn’t complete is that I am unable to compare the string in this variable with the song titles. I tried doing it through a for loop in the keypressed function and a for loop in the draw function, but it did not work. However, when I access a specific song and a specific week, it displays the corresponding note.

Song Class

For this program, I created a song class that takes the song title and the 4-week streaming values as arguments. The functions of this class consist mainly of display functions for different weeks and different kinds of notes.

Alternatives

I considered alternative options, such as simply clicking on the song title to display its data or pressing a number on the keyboard that corresponds to the song number on the chart, but I felt like I’ve already used these methods in previous assignments and was very stubborn about wanting user input to work.

Demonstration

Here’s a clip of my code failing :-(( :

Here’s an example of my program displaying the streams for a song after I specifically called the display function in draw() (not user input):

 

 

 

 

 

Take a look at my main code:

// text input code from http://learningprocessing.com/examples/chp18/example-18-01-userinput
//Treble Clef png by Vasily Gedzun from the Noun Project

//loading image for treble clef
PImage treble;

PFont f;
// Variable to store text currently being typed
String typing = "";

// Variable to store saved text when enter is hit
String searchInput = ""; 
Table top20; //creating table
Song[] allSongs; //object list

void setup() {
  size(1024,768);
  f = createFont("Kayak Sans Bold (Italic).otf",20);
  textFont(f);
  top20 = loadTable("TOP 20.csv", "header"); //loading table excluding the first row, which are the headers
  treble = loadImage("Treble Clef.png");
  allSongs = new Song[20]; //creating the list
  for (int i=0; i<19; i++){
   allSongs[i] = new Song(top20.getString(i,0), top20.getFloat(i,1),top20.getFloat(i,2),top20.getFloat(i,3),top20.getFloat(i,4)); //creating the object list, the arguments get their vals from acessing CSV file data
  }
  
}
int indent = 25; // indentation for text

void draw() {
  background(255);
  
  
  
  fill(0);
  
  // Display initial text
  textSize(20);
  text("Type a Top 10 Song Title to View September Streams \n Hit enter ", indent, 40);
  text("Typing: " + typing,indent,190);
  text("Searching: " + searchInput,indent,230);
  displayMusicStaff(); // calling the function that draws the staff
  textSize(15);
  //displaying the search options
  text("WAP (feat. Megan Thee Stallion) \n Hawaii \n Mood (feat. Iann Dior) \n Dynamite \n Ice Cream (with Selena Gomez) \n Savage Love (Laxed - Siren Beat) \n Watermelon Sugar \n Blinding Lights \n ROCKSTAR (feat. Roddy Ricch) \n Laugh Now Cry Later (feat. Lil Durk)", width/2, 550);
  text("Roses - Imanbek Remix \n Mood Swings (feat. Lil Tjay) \n Breaking Me \n Ay, DiOs Mío! \n For The Night (feat. Lil Baby & DaBaby) \n UN DIA (One Day) (Feat. Tainy) \n Head & Heart (feat. MNEK) \n Heather \n La Curiosidad", width/2 + 250, 550); 
     // loop that compares user input to song list
   for (int i = 0; i<19; i++){
   if (searchInput == allSongs[i].songTitle){
     allSongs[i].week1Display(); 
     allSongs[i].week2Display();
     allSongs[i].week3Display();
     allSongs[i].week4Display();
   }
  }

  
  
     
   
   
 
 
}


void keyPressed() {
  //Code for user input
  // If the enter key is pressed, the user input is saved in a variable called searchInput
  if (key == '\n' ) {
    searchInput = typing;
    
    //the user is no longer typing, so we clear the typing variable
    typing = ""; 
  } else {
    // if enter isn't pressed keep adding characters to the typing variable
    typing = typing + key;
    
  }
  
}

void displayMusicStaff(){
  //drawing the staff
  strokeWeight(2);
  line(250,250,840,250);
  line(250,300,840,300);
  line(250,350,840,350);
  line(250,400,840,400);
  line(250,450,840,450);
  image(treble,250,250);
  
}

My Song Class:

class Song{
 //declaring variables
String songTitle;
float streams;
int locX, locY;
int ellipseW, ellipseH;
float wk1Streams, wk2Streams, wk3Streams, wk4Streams;



Song(String tempTitle, float tempwk1Streams, float tempwk2Streams, float tempwk3Streams, float tempwk4Streams){
 locX = 380;
 locY = 450;
 ellipseW = 35;
 ellipseH = 25;
 songTitle = tempTitle;
 wk1Streams = tempwk1Streams;
 wk2Streams = tempwk2Streams;
 wk3Streams = tempwk3Streams;
 wk4Streams = tempwk4Streams;
 
  
}

//function checks the value of week 1 streams and displays the note shape accordingly by calling that note shape's function
void week1Display(){
    if (wk1Streams > 10000000 && wk1Streams < 20000000){
     thrityTwoNote(locX,locY);
  }
  else if ((wk1Streams > 20000000 && wk1Streams < 25000000)){
    sixteenNote(locX,locY);
  }
  else if (wk1Streams> 25000000 && wk1Streams < 30000000){
    eightNote(locX,locY); 
  }
 else if (wk1Streams > 30000000 && wk1Streams < 35000000){
  quarterNote(locX,locY);
   
 }
 
 else if (wk1Streams > 35000000 && wk1Streams < 40000000){
   halfNote(locX,locY);
 }
 else if (wk1Streams > 40000000 && wk1Streams < 46000000){
   wholeNote(locX,locY);
   
 }
}
 //week2
 
 void week2Display(){
   //x and y values here are dependent on the week 1 x and y, to keep the code dynamic
 if (wk2Streams > 10000000 && wk2Streams < 20000000){
     thrityTwoNote(locX+100,locY-50);
  }
  else if ((wk2Streams > 20000000 && wk2Streams < 25000000)){
    sixteenNote(locX+100,locY-50);
  }
  else if (wk2Streams> 25000000 && wk2Streams < 30000000){
    eightNote(locX+100,locY-50); 
  }
 else if (wk2Streams > 30000000 && wk2Streams < 35000000){
  quarterNote(locX+100,locY-50);
   
 }
 
 else if (wk2Streams > 35000000 && wk2Streams < 40000000){
   halfNote(locX+100,locY-50);
 }
 else if (wk2Streams > 40000000 && wk2Streams < 46000000){
   wholeNote(locX+100,locY-50);
   
 }
 }
 
 //week3
 void week3Display(){
  if (wk3Streams > 10000000 && wk3Streams < 20000000){
     thrityTwoNote(locX+200,locY-100);
  }
  else if ((wk3Streams > 20000000 && wk3Streams < 25000000)){
    sixteenNote(locX+200,locY-100);
  }
  else if (wk3Streams> 25000000 && wk3Streams < 30000000){
    eightNote(locX+100,locY-100); 
  }
 else if (wk3Streams > 30000000 && wk3Streams < 35000000){
  quarterNote(locX+200,locY-100);
   
 }
 
 else if (wk3Streams > 35000000 && wk3Streams < 40000000){
   halfNote(locX+200,locY-100);
 }
 else if (wk3Streams > 40000000 && wk3Streams < 46000000){
   wholeNote(locX+200,locY-100);
   
 }
 }
 void week4Display(){
 //week4
 if (wk4Streams > 10000000 && wk4Streams < 20000000){
     thrityTwoNote(locX+300,locY-150);
  }
  else if ((wk4Streams > 20000000 && wk4Streams < 25000000)){
    sixteenNote(locX+300,locY-150);
  }
  else if (wk4Streams> 25000000 && wk4Streams < 30000000){
    eightNote(locX+300,locY-150); 
  }
 else if (wk4Streams > 30000000 && wk4Streams < 35000000){
  quarterNote(locX+300,locY-150);
   
 }
 
 else if (wk4Streams > 35000000 && wk4Streams < 40000000){
   halfNote(locX+300,locY-150);
 }
 else if (wk4Streams > 40000000 && wk4Streams < 46000000){
   wholeNote(locX+300,locY-150);
   
 }
 
}



//smallest stream range note shape
void thrityTwoNote(int x, int y){
  fill(0);
  ellipse(x,y,ellipseW,ellipseH);
  line(x+17.5, y, x+17.5, y -70);
  line(x+17.5, y-70, x+35, y-60);
  line(x+17.5, y-60, x+35, y-50);
  line(x+17.5, y-50, x+35, y-40);
}
  
void sixteenNote(int x, int y){
  fill(0);
  ellipse(x,y,ellipseW,ellipseH);
  line(x+17.5, y, x+17.5, y -70);
  line(x+17.5, y-70, x+35, y-60);
  line(x+17.5, y-60, x+35, y-50);
  
  
}

void eightNote(int x, int y){
 fill(0);
  ellipse(x,y,ellipseW,ellipseH);
  line(x+17.5, y, x+17.5, y -70);
  line(x+17.5, y-70, x+35, y-60);
}

void quarterNote(int x, int y){
 fill(0);
  ellipse(x,y,ellipseW,ellipseH);
  line(x+17.5, y, x+17.5, y -70);
}

void halfNote (int x, int y){
 noFill();
  ellipse(x,y,ellipseW,ellipseH);
  line(x+17.5, y, x+17.5, y -70);
  line(x+17.5, y-70, x+35, y-60);
  
  }
  
  void wholeNote(int x, int y){
   noFill();
  ellipse(380,450,35,25);
  
  }
  
  
  
  
}

 

Week 5 Class – Pixels

Images to download

Sketches used:

class SimpleMover {
  float x, y, homeX, homeY;
  float xSpeed, ySpeed;
  float diam;
  boolean seek;
  char letter;

  SimpleMover(float _x, float _y, float _diam ) {
    homeX = x = _x;
    homeY = y = _y;
    xSpeed = ySpeed = 0;
    diam = _diam;
    seek = true;
  }

  void update() {
    x += xSpeed;
    y += ySpeed;
    xSpeed *= .95;
    ySpeed *= .95;
  }

  void display() {
    ellipse(x, y, diam, diam);
  }

  void seekHome() {
    if (seek) {
      float dirX = homeX-x;
      float dirY = homeY-y;
      dirX*=.005;
      dirY*=.005;
      xSpeed+=dirX;
      ySpeed+=dirY;
    }
  }

  void checkEdges() {
    if (y>height) {
      y=0;
    }
    if (y<0) {
      y=height;
    }
    if (x>width) {
      x=0;
    }
    if (x<0) {
      x=width;
    }
  }
}

 

Text alteration

For this weeks assignment I decided to further upgrade my scrolling text program. During class time I managed to get it to display a single line of text continuously, with a restriction that the line had to be shorter than the width of the screen. I have upgraded my code, so that now it displays texts of various lengths without any issue. I have also added a new functionality. The input for the news bar is taken directly from a text file, so you can simply type all the great news and they will be displayed automatically.

During coding, the hardest part was to get the moment of switching right. When one string has already left the screen and the other one needs to overwrite the main movement variable OffsetX. This happens when the last letters of the first string leave the screen. I had to add some padding in form of a constant, so that it would appear even smoother.

PFont f;
PImage img;
String myString;
int offsetX;
int textHeight = 370;
int spaceConst = 40;

void setup(){
  size(400, 400);
  f = createFont("Monaco", 40);
  textFont(f);
  myString = "";
  textAlign(LEFT);
  offsetX = width;
  noStroke();
  
  img = loadImage("news.jpg");
  
  String[] lines = loadStrings("text.txt");
  for (int i=0 ; i < lines.length; i++) {
    myString += "| " + lines[i] + " ";
  }
  
  image(img, 0, 0, width, 320);
}

void draw(){
  fill(255,255,0);
  rect(0, 320, width, 80);
  fill(0);
  for (int i=0; i< myString.length(); i++){
    if (offsetX+textWidth(myString) < (width)){
      text(myString.charAt(i), offsetX+textWidth(myString)+spaceConst+textWidth(myString.charAt(i))*i, textHeight);
    }
    text(myString.charAt(i), offsetX+textWidth(myString.charAt(i))*(i+1), textHeight);
    
    if (offsetX+textWidth(myString) < -spaceConst) {
      offsetX = offsetX+int(textWidth(myString))+int(textWidth(myString.charAt(i))*(i+1));
    }
  }
  offsetX -= 2;
}

 

Assignment #4: Generative Text

For this week’s assignment, I attempted to make an interactive art utilizing text. My art piece for this week is pretty straightforward. A text is displayed initially and the user can maneuver their cursor onto the test. Then, once the cursor is within the range of the text, the text starts to move away like it is trying to avoid you. I also created a sort of shivering effect to really make it seem like the text is hating the cursor.

The text keeps moving as it tries to avoid the cursor, and if the text moves away from the width and the height of the screen, then the text is called back into the screen.

I am eager to improve this piece and I am working on creating numerous more identical texts within the screen so that it creates a more mass-movement kind of effect when a cursor is placed anywhere on the screen.

Below is the video of my creation in action:

String message = "Go Away~"; // to calculate the string's length
float x,y,hr,vr;

void setup(){
  size(320,320);
  textFont(createFont("Monaco",36));
  textAlign(CENTER, CENTER);
  hr = textWidth(message);
  vr = (textAscent() + textDescent())/2;
  noStroke();
  x = random(hr, width - hr);
  y = random(vr, height - vr);
}

void draw() {
  fill(255, 120);
  rect(0, 0, width, height);

  // Once the mouse is on the text
  if (abs(mouseX-x) < hr && abs(mouseY - y) < vr){
    x += random(-10,10);
    y += random(-10,10);
    if (x+hr/2 > width || x-hr/2 < 0 || y+vr > height || y-vr < 0){
      x = random(hr, width-hr);
      y = random(vr, height-vr);
    }
  }
  fill(0);
  text("Go Away~",x,y);
}

 

BEE_TO text manipulation

I know it is a bad pun but I couldn’t help noticing it (bee in beeto).

I really liked the examples we dealt with in class, and for my assignment I decided to try to mix some of the different functions in these examples in addition to others to have a unique product.

So I made use of the geomerative with circle class file, the bounce logic, the drawing of a hexagonal polygon, and the logic of drawing a grid.

I decided that my theme would be that of bees and that the idea of having things vibrating in place fits it well. I looked up the color palette of a beehive, and I made the text particles bounce off the borders if they hit them. This was how it looked at first.

Then I decided to increase the speed so it fits the theme more, increased the size proportionally, added the hexagon grid classes, and adjusted the friction, initial speed, and the numericals involved with bringing the hexagons back home.

This is how the final things looks like where the background randomly changes color just as it would be in real life.

https://youtu.be/17Bj16mcsKQ

The main code drawing on everything:

import geomerative.*;
RFont font;
RPoint[] pnts;
Hexagon[] hexas;
int amountPerPoint;
int index;
HexGrid g;
color[] mainpallet = {  #985b10, #6b4701};
int rad, nwide, nhigh, shade;

void setup() {
  size(1000, 640);
  
  RG.init(this);

  font = new RFont("Raleway-Regular.ttf", 280, RFont.CENTER);
  pnts = getPoints("Bee_to");
  amountPerPoint = 4;
  
  rad=20;
  nhigh = (height/((rad*3)/2));
  nwide = int(width/(sqrt(3)*rad))+1;
  
  g = new HexGrid(nwide, nhigh, rad);
  g.display();
  
  hexas = new Hexagon[pnts.length*amountPerPoint];
  
  index = 0;
  
  for (int i = 0; i < pnts.length*amountPerPoint; i += amountPerPoint) {
    for (int j = 0; j < amountPerPoint; j++) {
      int k = i + j;
      hexas[k] = new Hexagon(width/2 + pnts[index].x + random(-2, 2), height/1.65 + pnts[index].y + random(-2, 2), random(8, 18));
    }
    index++;
  }
  
  
   
}

void draw() {
   background(107,71,1);
   
   shade = int(random(0,1));
   g.display();
   
   for (int i =0; i < hexas.length; i++) {
     hexas[i].seekHome();
     hexas[i].update();
     hexas[i].display(6);
     hexas[i].checkEdges();
   }
   
   for(int i=0; i < 5 ; i++)
  {
    Hbackground selected = g.getHex(int(random(nwide)), int(random(nhigh)));
    selected.setFillColour(mainpallet[int(random(2))]);
  }
}

void mousePressed() {
  for (int i = 0; i < hexas.length; i++){
    hexas[i].xSpeed = random(-30, 30);
    hexas[i].ySpeed = random(-30, 30);
    hexas[i].seek = false;
  }
  //delay(200);
}

void mouseReleased(){
  for (int i = 0; i < hexas.length; i++) {
    hexas[i].seek = true;
  }
  //delay(200);
}

RPoint[] getPoints(String str) {
  RCommand.setSegmentLength (20);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  RGroup grp;

  grp = font.toGroup(str);
  grp = grp.toPolygonGroup();
  return grp.getPoints();
}

Individual hexagons in background:

//this code was inspired from this website http://louisc.co.uk/?p=2554

class Hbackground {
 float centx;
 float centy;
 float radius;
 float angle = TWO_PI / 6;
 boolean fill = false;
 color c;
 
 Hbackground( float x, float y, float r ){
 centx = x;
 centy = y;
 radius = r;
 }
 
//The draw function will define the fill values and calculate the coordinates
 void display() {
   if(fill)
     fill(c);
   else
    noFill();
   
  
   beginShape();
     for (float a = PI/6; a < TWO_PI; a += angle) {
       float sx = centx + cos(a) * radius;
       float sy = centy + sin(a) * radius;
       vertex(sx, sy);
     }
     
     stroke(137,104,0);
     strokeWeight(4);
   endShape(CLOSE);
 }
 
 void setFillColour(color col)
 {
 fill = true;
 c = col;
 }
}

Grid of hexagons in background:

//this code was inspired from this website http://louisc.co.uk/?p=2554

class HexGrid {
  Hbackground[][] grid; //Our 2D storage array of Hexagon Objects
  int cols, rows;
  float radius;
 
  //Class Constructor required the grid size and cell radius
  HexGrid(int nocol, int norow, int rad)
  {
    //Define our grid parameters
    cols = nocol;
    rows = norow;
    radius=float(rad);
 
    //2D Matrix of Hexagon Objects
    grid=new Hbackground[cols][rows];
 
    //Lets assign the inital x,y coordinates outside the loop
    int x = int(sqrt(3)*radius);
    int y = int(radius);
 
    //These two nested for loops will cycle all the columns in each row
    //and calculate the coordinates for the hexagon cells, generating the
    //class object and storing it in the 2D array.
    for( int i=0; i < rows ; i++ ){
      for( int j=0; j < cols; j++)
      {
        grid[j][i] = new Hbackground(x, y, radius);
        x+=radius*sqrt(3); //Calculate the x offset for the next column
      }
      y+=(radius*3)/2; //Calculate the y offset for the next row
      if((i+1)%2==0)
        x=int(sqrt(3)*radius);
      else
        x=int(radius*sqrt(3)/2);
    }
  }
 
  //This function will redraw the entire table by calling the draw on each
  //hexagonal cell object
  void display()
  {
    for( int i=0; i < rows ; i++ ){
      for( int j=0; j < cols; j++)
      {
        grid[j][i].display();
      }
    }
  }
 
  //This function will return the hexagonal cell object given its column and row
  Hbackground getHex(int col, int row)
  {
    return grid[col][row];
  }
 
}

Individual hexagons making the text:

class Hexagon {
  float x, y, homeX, homeY;
  float xSpeed, ySpeed;
  float hWidth;
  boolean seek;
  char letter;
  float dirX, dirY;

  Hexagon(float _x, float _y, float _width ) {
    homeX = x = _x;
    homeY = y = _y;
    xSpeed = ySpeed = 0;
    hWidth = _width;
    seek = true;
  }

  void update() {
    x += xSpeed;
    y += ySpeed;
    xSpeed *= .95;
    ySpeed *= .95;
  }

  void display(int npoints) {
    float angle = TWO_PI / npoints;
    beginShape();
      fill(246,224,0);
      stroke(249,201,1);
      for (float a = PI/6; a < TWO_PI; a += angle) {
        float sx = x + cos(a) * hWidth;
        float sy = y + sin(a) * hWidth;
        vertex(sx, sy);
      }
      strokeWeight(2);
    endShape(CLOSE);
  }

  void seekHome() {
    if (seek) {
      dirX = homeX-x;
      dirY = homeY-y;
      dirX*=.009;
      dirY*=.009;
      xSpeed+=dirX;
      ySpeed+=dirY;
    }
  }

  void checkEdges() {
    if (y>height - hWidth) {
      ySpeed *= -1;
    }
    if (y< hWidth) {
      ySpeed *= -1;
    }
    if (x>width - hWidth) {
      xSpeed *= -1;
    }
    if (x< hWidth) {
      xSpeed *= -1;
    }
  }
}

 

Week 4 Assignment: Generative Text Output

For this week’s assignment, I was not able to really come up with my very own original creative idea, so I had to search online for some  examples online that had to do with some Generative Text Output. Firstly, when I was fumbling through countless Youtube videos with examples, I stumbled on this video where it showed how by repeating a bunch of short sentences and making them appear at different places on the screen really quick could create this kind of blurry image on the screen, just like how when our TV screen would act weird and these white and black bars would flicker on and off.

After I created this blurry image on the screen, I wanted to make a Typewriter effect for my text where my text would appear one by one, but I wasn’t sure how to incorporate that effect to the entire text (maybe because I had to create an array to make this effect for each character of my text?). So, after this wasn’t working, I wanted to make another effect and I thought I could use the mousePressed function to make it freeze or stop creating this blurry image when the mouse is pressed and at the same time create another text, but that did not work as well. So, I settled for making it change color each time the mouse was pressed.

String text1="Hello, my name is Ryan.";
String text2="Hi, I've stopped.";
PFont font;
int counter;
float i, x, y;

void setup() {
  size(800, 600, P2D);
  frameRate(5);
  smooth();
  font=createFont("Georgia", 30);
  textFont(font, 20);
  fill(0);
  counter=0;
}

void draw() {    
  background(255);
  translate(mouseX, mouseY);
  //typewriteText()
  for (i=0; i < 1000; i++) {
    float x = random(width);
    float y = random(height);
    text(text1, x, y);

    if ( mousePressed) {
      noLoop();
      fill(random(255), random(255), random(255));
      for (int i = 0; i < random(1000); i++) {
        textFont(font, random(50));
        x = random(width);
        y = random(height);
        text(text2, x, y);
      }
    } else {
      loop();
      background(255);
      for (i=0; i < 1000; i++) {
        x = random(width);
        y = random(height);
        text(text1, x, y);
      }
    }
  }
}

 

Displaying Text

For this assignment, I chose to display the text in the Processing window.

My initial idea was to create a string of letters that would appear in the window and move in some interesting way. After watching some YouTube tutorials and browsing the Processing forum, my first attempt to create the letter-objects that would appear in a typewriter effect, move around some arbitrary curve and then “find home” miserably failed (I am still not too sure why, but my best-educated guess is because I had a hard time with passing polar coordinates and translating them to regular coordinates).

From the second try, my goal was to create a string of letters that would be placed around the circle and would move around it if the mouse is pressed. To add some fun to it, I decided to place another string inside the circle, and make it change the size in a noise-like pattern, also when the mouse is pressed. This appeared to be more realistic and feasible with my skills, so I just went for implementing this with my code.

The most challenging part appeared to be the math: finding the arclength, placing each letter and making sure the spacing is right, and doing the whole polar coordinates thing.

Here’s the code:

String myText = "hello, I am...";
String anotherText = "Movement!";
PFont font;
float radius = 100;
float x, arclength, angle, move, t;

void setup(){
  size (340, 680);
  font = createFont("Calm", 64);
  textFont(font);
  textAlign(CENTER);
  smooth();
}

void draw(){
  
  background(0);
  
  x = 10;
  arclength = 0;
  
  circles();
  
  // Place the bigger circle
  translate(width/2, height/2);
  noStroke();
  ellipse(0, 0, radius*2, radius*2);
  
  push();
    fill(0);
    textSize(50+t);
    text(anotherText, 0, x);
  pop();
  
  for(int i=0; i<myText.length(); i++){
    
     // Place the next letter
    arclength += textWidth(myText.charAt(i))/2;
    angle = 5*PI/4 + arclength/radius + move;
    
    push();
      translate(radius*cos(angle), radius*sin(angle));
      rotate(angle+PI/2);
      text(myText.charAt(i), 0, 0);
    pop();
    
    // Place the next letter
    arclength += textWidth(myText.charAt(i))/2;
  
  // Move the string if the mouse is pressed
    if (mousePressed){
      move += 0.0082;
      t += random(-0.5,0.5);
    }
  }

}

// Make a background of color-changing circles
void circles(){
  for (int i = 0; i < 50; i++) {
    push();
      fill(random(200,250), random(200,250), random(200,250));
      ellipse(random(width), random(height), radius/10, radius/10);
    pop();  
  }
}

And the demo:

Week 4: Generative Text

 

This was a disaster to figure out, but it was worth it at the end. (I had a very long victory dance).

My initial idea is that i wanted something on an animated text, with a ball moving around. I drew a sketch on procreate to illustrate:

 

My first of many hurdles was getting a font of mine to work. I kept getting errors, (and sometimes processing would display the text different than i expected).  Next, I created two of the text, and placed them away from each other to mirror the illustration I had in mind. After trying and trying to figure out how to get the ball to slide like I did in my illustration, I decided to try something else. I used the example shown (The Bubble One) in class to create circles in each point,  and wanted to print them out one by one so that the text could be drawn. After spending a full day on this (no really, a full day), I found my mistake -I had accidentally called noLoop();.

After that, it was pretty smooth. I figured out my speed, how I wanted it to look, as well as how to toggle the colour to make it fade from black to red back and forth.

import geomerative.*;
import java.util.concurrent.TimeUnit;
RFont font; 
RPoint[] pnts;
float xValue = 0;
float yValue = 0;
int a = 175;
int i = 0;
int previousTime = 0;
float timePassed = 0.1;
int r = 255;
boolean b = true;

void setup(){
  frameRate(120);
  background(255);
  size (500, 500);
  RG.init(this);
  // set the font, the size, and left, center, or right adjusted
  font = new RFont("LeckerliOne-Regular.ttf", 150, RFont.CENTER);
  
  // get the points along a String
  pnts = getPoints("Media");
  System.out.println(pnts);
    
  noFill();
  //noLoop();
  stroke(0,100);
  
}
void update () {
  //stroke( 0, 0, 0, a);
  noStroke();
  fill( r, 0, 0);
  circle(xValue, yValue, 6);
}

void draw() {
  int time = -1;
  pushMatrix();
  translate(width/2, height/1.5);
  if ( millis() > previousTime + timePassed){
     previousTime= millis();
     //println("it works");
    if ( i <pnts.length ){
        update();
        if ( r >= 0 && b == true){
          r -= 1; 
          b = true; 
        }
        else if (r == 225 && b == false){
          r -= 1; 
          b = true; 
        }
        else {
          r +=1;
          b = false; 
        }
        //float diam = random(5,15);
        xValue =  pnts[i].x;
        yValue = pnts[i].y;
        i++;
        //System.out.println("This is Xvalue:" + xValue);
        //System.out.println("This is yvalue:" + yValue);
      }
     }
  popMatrix();
}



// function that returns an array of RPoints based on a string
RPoint[] getPoints(String str) {
  // change this number to change the resolution of points outlining the circle
  RCommand.setSegmentLength(1);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  RGroup grp;
  grp = font.toGroup(str);
  grp = grp.toPolygonGroup();
  return grp.getPoints();
}

void mousePressed(){
  xValue-=1;
  update();
  
}