I'm trying to make a matrix rain app. I want different arrays to move at different speeds, but I can't solve the effect of freezing symbols (when a symbol from the array stays at its previous Y coordinate while the array continues to move down). When the speed of the array doesn't match the font size it starts to twitch while moving. My headache lines are these two
int charIndex = Math.abs((i - s.posY) % s.text.length);
g2d.drawString(s.text[charIndex], s.posX, s.posY - (i * FONT_SIZE));
I know I need to compensate for font-size and speed offset but I can't figure it out
public class TextDrops extends JPanel
{
private static final int SCREEN_WIDTH = 1400;
private static final int SCREEN_HEIGHT = 700;
private static final int FONT_SIZE = 14;
private static final int DELAY_MILLIS = 30;
private static final int SPEED_MIN = 5; // 5
private static final int SPEED_MAX = 20; // 20
private List<Streamer> listStreamers;
public TextDrops() {
listStreamers = new ArrayList<>();
populateList();
}
public void populateList() {
int maxStreamers = 200;
for (int i = 0; i < maxStreamers; i++) {
Streamer s = new Streamer();
listStreamers.add(prepareStreamer(s));
}
}
public Streamer prepareStreamer(Streamer s) {
// pick random x-coord for a rain drop
s.posX = new Random().nextInt(SCREEN_WIDTH / FONT_SIZE) * FONT_SIZE;
s.posY = 0;
s.speed = new Random().nextInt(SPEED_MAX) + SPEED_MIN;
s.text = new String[] {
"A", "B", "C", "D", "E", "F", "G", "H", "I",
"J", "K", "L", "M", "N", "O", "P", "Q", "R",
"S", "T", "U", "V", "W", "X", "Y", "Z"
};
return s;
}
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
for (Streamer s : listStreamers) {
s.posY += s.speed;
for (int i = 0; i < s.text.length; i++) {
// trying to emulate the freezing symbols effect here
int charIndex = Math.abs((i - s.posY) % s.text.length);
// draw frame
g2d.drawString(s.text[charIndex], s.posX, s.posY - (i * FONT_SIZE));
}
// reset text drop as soon as its tail reaches the end of the screen
if (s.posY - (s.text.length * FONT_SIZE) >= SCREEN_HEIGHT) {
prepareStreamer(s);
}
}
try {
Thread.sleep(DELAY_MILLIS);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
public static class Streamer
{
private int posX;
private int posY;
private int speed;
private String[] text;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TextDrops());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
