Dear @kll,
this is almost a MCVE since even if I haven’t got rid of the sound it doesn’t have any effect here just mouseX and mouseY are used as variables. Regarding the font, any font in .ttf format can be used as RFont()… We need this to use Geomerative library. And for the library, not sure you need to know so much, I just think I misplaced my attractor in the sketch and also where I change the letter size… It’s more a general programmation issue I think. Thank you very much for your help. Best wishes, L
Dear @kll,
I’m coming back to you about my problem regarding my deformed typography, remember?!
Well the solution was not linked to the Geomerative library. @Chrisir gave me the solution, so I shere it with you ! Thank you very much again for your help. I appreciate. see you around. best, L
Here is the comment by @Chrisir to explain the code below:
Blockquote The basic idea is simple: When we want the letters to keep their position after the mouse is gone, we need to store the mouse position and tell the
WordAttractor
to use the stored position.
But the storing only works when we don’t store the mouse position throughout but only when the mouse is close to the letter. Hence I check for the min distance and store the mouse position then when the distance is minimal (or when key is als pressed).
I am using these 2D arrays for this:
RPoint[][] pointsP;
WordAttractor[][] listWordAttractors;
float[][] listDistMap;
PVector[][] listPV;
The pointsP was there already
Blockquote
import geomerative.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
String soundNameFR = "FR_01";
Minim minim;
AudioPlayer soundsFR;
FFT fftFR;
float bandHeightFR;
int x, y;
String [] message={"music is like a mountain path"};
color textColor=0;
RFont f;
RShape [] gShape = new RShape[message.length];
float fontSize=110;
int splitGlyph = 120;
RPoint[][] pointsP;
WordAttractor[][] listWordAttractors;
float[][] listDistMap;
PVector[][] listPV;
float r = random(5, 20);
WordAttractor attractorW;
int tChildCount;
characterSpec characters;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
size(1920, 1080);
RG.init(this);
f = new RFont("BRITANIC.TTF", int( fontSize), LEFT);
minim=new Minim(this);
soundsFR=minim.loadFile("jingle.mp3", 512);
soundsFR.play();
fftFR= new FFT(soundsFR.bufferSize(), soundsFR.sampleRate());
for (int l =0; l<message.length; l++) {
characters = new characterSpec( gShape[l], message[l]);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void draw() {
background(0);
smooth();
soundFFTAnalyse();
//pushMatrix();
translate(200, height/2);
for (int l =0; l<message.length; l++) {
characters.update();
characters.display();
}
// popMatrix();
}
void soundFFTAnalyse() {
AudioPlayer fr = soundsFR;
fftFR.forward(fr.mix);
for (int i=0; i<fftFR.specSize(); i++) {
float bandDBFR = 10*log(fftFR.getBand(i)/fftFR.timeSize());
bandHeightFR = map(bandDBFR*4, 0, -220, 0, height);
constrain(bandHeightFR, 0, 1000);
noStroke();
fill(255, 0, 0);
ellipse(fr.position()/10, bandHeightFR/20, 5, 5);
}
}
// ======================================================================
class characterSpec {
RShape bShape;
String m;
RShape letterShapes;
float maxForce=2;
float radiousForce=100;
characterSpec(RShape _letterShapes, String _m) {
letterShapes=_letterShapes;
m = _m;
pointsP= new RPoint [m.length()][splitGlyph];
listWordAttractors = new WordAttractor [m.length()][splitGlyph]; //
listDistMap = new float [m.length()][splitGlyph]; //
for (int k = 0; k < m.length(); k++) {
for (int j=0; j<splitGlyph; j++) {
listDistMap[k][j]=1000000;
}
}
listPV = new PVector [m.length()][splitGlyph]; //
bShape = new RShape();
bShape = f.toShape(m);
RShape [] letterShapes = bShape.children;
letterShapes = bShape.children;
tChildCount = bShape.children.length;
}
void update() {
for (int k = 0; k < tChildCount; k++) {
//float posX=map(soundsFR.position(), 200, soundsFR.length(), 200, width-200);
//float posY=bandHeightFR/4;
float posX = mouseX;
float posY = mouseY;
float d = dist(posX, 0, bShape.children[k].getCenter().x, 0);
float sx = map(d, 0, 100, 1, 1.01);
//sx=abs(sx);
//float r= map(d, 0, 100, 0, -TWO_PI);
if (d<100) {
bShape.children[k].scale(sx, bShape.children[k].getCenter());
//bShape.children[k].rotate(r, bShape.children[k].getCenter());
}
for (int j=0; j<splitGlyph; j++) {
float frac=(1.0/splitGlyph);
pointsP[k][j]=bShape.children[k].getPoint(j*frac);
float dist1 = dist(posX-200, posY-500,
pointsP[k][j].x, pointsP[k][j].y);
// if (dist1 < listDistMap[k][j]) {
if (keyPressed&&dist1 < 200) {
listDistMap[k][j]=dist1;
listPV[k][j] = new PVector(posX-200, posY-500);
listWordAttractors[k][j] = new WordAttractor(listPV[k][j].x, listPV[k][j].y, pointsP[k][j]);
}
if (pointsP[k][j]!=null&&listWordAttractors[k][j]!=null) {
listWordAttractors[k][j].points = pointsP[k][j];
listWordAttractors[k][j].attract();
}
}
}
}
void display() {
for (int k = 0; k < tChildCount; k++) {
for (int j=0; j<splitGlyph; j++) {
pushMatrix();
translate(pointsP[k][j].x, pointsP[k][j].y);
stroke(255);
beginShape();
noFill();
strokeWeight(0.2);
float angle = TWO_PI/18;
rotate(angle*j/4+noise(pointsP[k][j].x)/20);
bezier(-5*(noise(5)), 5, -10*(noise(2)), 5, -5*noise(10), -5, 5, -5);
endShape();
popMatrix();
}
}
}
}
// ======================================================================
class WordAttractor {
float force_radious = 100;
float maxForce = 50;
RPoint position;
RPoint points;
float pX;
float pY;
WordAttractor(float x, float y, RPoint p) {
points = p;
position = new RPoint(x, y);
}
void attract() {
float d= points.dist(position);
if (d < force_radious) {
RPoint desired = new RPoint(points);
desired.sub(position);
desired.normalize();
desired.scale(map(d, 0, force_radious, maxForce, 0));
points.add(desired);
}
}
}
//