I’m very new to learning Processing on my own and would like to work with a sketch I found that mimics the old Solari train station timetable displays. I found the sketch here: https://github.com/lukecyca/Solari
The sketch requires Twitter API key information, which I have placed in a separate file named “twitter.conf” in the data folder. I’ve also put a copy of the Helvetica.ttf file in the same folder.
However I keep getting a Java runtime error, which I am thinking has something to do with the createFont() line, but I need some help figuring out how to fix it. Any help or suggestions would be greatly appreciated.
Here is my code, which I copied from the original sketch on GitHub:
final float scale = 1;
final int lowASCII = 32;
final int highASCII = 90;
final int flapHeight = 57;
final int flapWidth = 50;
final PFont flapFont = createFont("Helvetica", 46);
PGraphics[] flaps = new PGraphics[highASCII - lowASCII + 1];
PImage titleImg;
int digitsAnimating = 0;
final int maxDigitsAnimating = 17;
// PI/ms
final float flipVelocity = 9.0 / 1000.0;
final float misfireProbability = 0.2;
final int nColumns = 34;
final int nLines = 13;
SolariDigitLine[] lines = new SolariDigitLine[nLines];
int lastDraw;
import java.util.List;
import java.util.Collections;
import ddf.minim.*;
void createflaps() {
//Populates the flaps array
for (int i=0; i < highASCII - lowASCII + 1; i++) {
flaps[i] = createGraphics(flapWidth, flapHeight);
flaps[i].beginDraw();
flaps[i].background(40);
flaps[i].fill(225, 255, 50);
flaps[i].textAlign(CENTER, CENTER);
flaps[i].textFont(flapFont);
flaps[i].text((char)(i + lowASCII), flapWidth>>1, flapHeight>>1);
flaps[i].endDraw();
}
}
PGraphics getFlap(byte c) {
// Returns the correct file for a given ASCII code
return flaps[c - lowASCII];
}
class SolariDigit {
// ASCII code of the digit currently showing, or about to show (if a flip is in progress)
byte digit = lowASCII;
// ASCII code of the digit we're seeking
byte seekDigit = lowASCII;
// Angle of the current flip
float angle = 0;
// Buffers for the current (top) digit and the previous (bottom) digit
PGraphics topFlap, bottomFlap;
SolariDigit() {
topFlap = getFlap(digit);
bottomFlap = getFlap(digit);
}
void seekDigit(char d) {
seekDigit = (byte)d;
}
void advanceDigit() {
bottomFlap = getFlap(digit);
digit++;
if (digit > highASCII)
digit = lowASCII;
topFlap = getFlap(digit);
}
void flipStep(int ms) {
if (angle == 0) {
if (digitsAnimating > maxDigitsAnimating || random(1) < misfireProbability) {
image(topFlap, -flapWidth>>1, -flapHeight>>1);
return;
}
advanceDigit();
}
image(topFlap.get(0, 0, flapWidth, flapHeight>>1), -flapWidth>>1, -flapHeight>>1);
image(bottomFlap.get(0, flapHeight>>1, flapWidth, flapHeight>>1), -flapWidth>>1, 0);
pushMatrix();
if (angle < 0.5) {
rotateX(-angle * PI);
image(bottomFlap.get(0, 0, flapWidth, flapHeight>>1), -flapWidth>>1, -flapHeight>>1);
}
else {
rotateX(-(min(angle, 1) - 1.0) * PI);
image(topFlap.get(0, flapHeight>>1, flapWidth, flapHeight>>1), -flapWidth>>1, 0);
}
popMatrix();
angle += ms * flipVelocity;
if (angle > 1) {
angle = 0;
}
digitsAnimating++;
}
void display(int ms) {
if (angle > 0 || digit != seekDigit)
flipStep(ms);
else
image(topFlap, -flapWidth>>1, -flapHeight>>1);
}
}
class SolariDigitLine {
int length;
SolariDigit[] digits;
SolariDigitLine(int l) {
length = l;
digits = new SolariDigit[length];
for (int i=0; i<length; i++) {
digits[i] = new SolariDigit();
}
}
void setText(String str) {
// Blank them all
for (int i=0; i<length; i++) {
digits[i].seekDigit(' ');
}
// Copy characters in
char[] chars = str.toUpperCase().toCharArray();
for (int i=0; i<min(chars.length, length); i++) {
digits[i].seekDigit(chars[i]);
}
}
void display(int ms) {
for (int i=0; i<length; i++) {
pushMatrix();
translate(flapWidth * 1.1 * i, 0);
digits[i].display(ms);
popMatrix();
}
}
}
Twitter twitter;
Query query;
void initTwitterSearch() {
String conf[] = loadStrings("twitter.conf");
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setOAuthConsumerKey(conf[0]);
cb.setOAuthConsumerSecret(conf[1]);
cb.setOAuthAccessToken(conf[2]);
cb.setOAuthAccessTokenSecret(conf[3]);
twitter = new TwitterFactory(cb.build()).getInstance();
query = new Query("@sidneyyork");
query.setCount(10);
}
List<Status> getTweets(int n) {
try {
QueryResult result = twitter.search(query);
List<Status> tweets = result.getTweets();
Collections.shuffle(tweets);
return tweets.subList(0, n);
}
catch (TwitterException te) {
println("Couldn't connect: " + te);
return Collections.emptyList();
}
}
String getMultilinePartition(String str, int lineNum) {
return str.substring(min(lineNum * nColumns, str.length()), min((lineNum + 1) * nColumns, str.length()));
}
void showMerch() {
lines[0].setText( "Destination Flt# Remarks");
lines[1].setText( "");
lines[2].setText( "CD $ 10 On Time");
lines[3].setText( "Vinyl $ 20 On Time");
lines[4].setText( "T-Shirt $ 10 On Time");
lines[5].setText( "Luggage Tag $ 5 On Time");
lines[6].setText( "Stickers 3/$1 On Time");
lines[7].setText( "2 CD Pack $ 15 Special");
lines[8].setText( "CD+T-Shirt $ 15 Special");
lines[9].setText( "Vinyl+T-Shirt $ 25 Special");
lines[10].setText("Buttons FREE W/Email");
lines[11].setText("");
lines[12].setText(" www.sidneyyork.com ");
}
void showTweets(List<Status> tweets) {
lines[0].setText( "Tweet @sidneyyork 2 win free stuff");
lines[1].setText( "");
lines[2].setText(tweets.get(0).getUser().getName() + " says:");
lines[3].setText(getMultilinePartition(tweets.get(0).getText(), 0));
lines[4].setText(getMultilinePartition(tweets.get(0).getText(), 1));
lines[5].setText(getMultilinePartition(tweets.get(0).getText(), 2));
lines[6].setText(getMultilinePartition(tweets.get(0).getText(), 3));
lines[7].setText( "");
lines[8].setText(tweets.get(1).getUser().getName() + " says:");
lines[9].setText(getMultilinePartition(tweets.get(1).getText(), 0));
lines[10].setText(getMultilinePartition(tweets.get(1).getText(), 1));
lines[11].setText(getMultilinePartition(tweets.get(1).getText(), 2));
lines[12].setText(getMultilinePartition(tweets.get(1).getText(), 3));
System.out.println(tweets.get(0).getText());
System.out.println(tweets.get(1).getText());
}
void setup() {
frameRate(45);
noiseDetail(4, 0.25);
size(int(1920 * scale), int(1080 * scale), P3D);
createflaps();
titleImg = loadImage("title.png");
// Init the matrix
for (int i=0; i<nLines; i++) {
lines[i] = new SolariDigitLine(nColumns);
}
initTwitterSearch();
lastDraw = millis();
}
List<Status> tweets;
int nextFramerateDisplay = 5000;
int nextScreenChange = 0;
int nextScreen = 0;
void draw() {
directionalLight(255, 255, 255, .5, 1, -.5);
lightSpecular(255, 255, 255);
ambientLight(150, 150, 150);
ambient(150, 150, 150);
background(20);
scale(scale);
pushMatrix();
translate(258, 30);
image(titleImg, 0, 0);
popMatrix();
if (millis() > nextScreenChange) {
if (nextScreen == 0) {
showMerch();
}
if (nextScreen == 1) {
tweets = getTweets(4);
showTweets(tweets.subList(0, 2));
}
if (nextScreen == 2) {
showTweets(tweets.subList(2, 4));
}
nextScreen = (nextScreen+1) % 3;
nextScreenChange = millis() + 80000;
}
if (millis() > nextFramerateDisplay) {
println(frameRate);
nextFramerateDisplay = millis() + 5000;
}
// Animate the matrix
pushMatrix();
digitsAnimating = 0;
translate(51, 293);
for (int i=0; i<nLines; i++) {
pushMatrix();
translate(0, flapHeight * 1.1 * i);
lines[i].display(millis() - lastDraw);
popMatrix();
}
popMatrix();
lastDraw = millis();
}
And here are the errors I am getting:
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at processing.core.PApplet.runSketch(PApplet.java:10852)
at processing.core.PApplet.main(PApplet.java:10620)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at processing.core.PApplet.runSketch(PApplet.java:10846)
... 1 more
Caused by: java.lang.RuntimeException: createFont() can only be used inside setup() or after setup() has been called.
at processing.core.PApplet.createFont(PApplet.java:6422)
at processing.core.PApplet.createFont(PApplet.java:6363)
at Solari_partial.<init>(Solari_partial.java:43)
RuntimeException: java.lang.reflect.InvocationTargetException
... 6 more