Bouncing Circle Scroller
This was my entry to the DBF scroll competition. Didn't win - but it was fun to code since this was my first real JavaApplet I have written.
In action
Technique
The effect itself is written as a standard java applet. The used soundsystem called Ana-Mp is by Torkjel Hongve. Furthermore the music you hear was composed by stargazer/cplx.
Sourcecode
package anakata.modplay.example.applet;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import anakata.modplay.Meta;
import anakata.modplay.ThreadedPlayer;
import anakata.modplay.loader.ModuleLoader;
import anakata.modplay.module.Module;
import anakata.sound.output.JavaSoundOutput;
import anakata.sound.output.SoundDataFormat;
public class CircleScrollAna extends Applet {
// Module Stuff
public static final String INFO = Meta.PROJECT_NAME + " " + Meta.VERSION;
public static final int BITS = 16;
public static final int RATE = 44100;
public static final int CHANNELS = 2;
public static final boolean INTERPOLATE = true;
public static final int BUFFERSIZE = 500;
private Module module;
private URL theUrl;
private ThreadedPlayer tp;
private String protocol;
private String host;
private int port;
private List fileList = new ArrayList();
private int nextModule = 0;
private int lengthOfModule = 0;
// Applet Stuff
public int appHeight;
public int appWidth;
public Font appFont;
// Circlescroll Stuff
public CircleLetter[] letters = new CircleLetter[18];
public float fallFactor = 0.5f;
public float circleCenter_X;
public float circleCenter_Y;
public int border_Y;
public int circleRadius = 100;
public int circleTextCount = 0;
public String circleText = "... put scrolltext here ...";
Image buffer;
Graphics2D gBuffer;
// CircleLetter InnerClass
public class CircleLetter {
private String letter = "";
private double radius;
private int x,y;
private boolean directionDown = true;
private boolean directionLeft = true;
public CircleLetter( double radius ) {
this.radius = radius;
}
private void rotate( Graphics2D gBuffer ) {
// Rotate and change chars
radius = radius - 2 % 360;
if ( (int)radius == 450 ) {
letter = "" + circleText.charAt( circleTextCount );
circleTextCount++;
if ( circleTextCount == circleText.length() ) circleTextCount = 0;
radius = 810;
}
// bounce up/down
if ( directionDown ){
fallFactor = fallFactor + 0.001f;
circleCenter_Y = circleCenter_Y + fallFactor;
if ( circleCenter_Y > border_Y ) {
directionDown = false;
}
} else {
fallFactor = fallFactor - 0.012f;
if ( fallFactor < 0 ) {
directionDown = true;
}
}
// bounce left/right
if ( directionLeft ){
circleCenter_X = circleCenter_X + 0.1f;
if ( circleCenter_X > 280 ) {
directionLeft = false;
}
} else {
circleCenter_X = circleCenter_X - 0.1f;
if ( circleCenter_X < 20 ) {
directionLeft = true;
}
}
// rotate
x = (int)(circleRadius * Math.cos( radius * ( 2 * Math.PI / 360)) + circleCenter_X);
y = (int)(circleRadius * Math.sin( radius * ( 2 * Math.PI / 360)) + circleCenter_Y);
if ( y > appHeight ) y = appHeight;
if ( x > 288 ) x = 288;
if ( x < 0 ) x = 0;
gBuffer.drawString( letter, x, y);
}
}
// Applet methods
public void init() {
// App Stuff
appHeight = this.getHeight();
appWidth = this.getWidth();
appFont = new Font( "Courier New", Font.BOLD, 20 );
// CircleScroll Stuff
circleCenter_X = this.getWidth() / 2;
circleCenter_Y = this.getHeight() / 2;
border_Y = (int)(this.getHeight() * 0.95);
circleText = circleText.toUpperCase();
int start = 452;
for ( int i = 0; i < letters.length; i++ ) {
letters[i] = new CircleLetter( start );
start = start + 20;
}
// Music Stuff
protocol = getParameter("protocol");
host = getParameter("host");
port = Integer.parseInt(getParameter("port"));
StringTokenizer st = new StringTokenizer(getParameter("files"), ",");
while (st.hasMoreTokens())
fileList.add(st.nextToken());
module = loadModule(nextModule++);
// start the thread
tp = createPlayer(module);
lengthOfModule = tp.getModule().getNumberOfPositions();
tp.start();
}
public void start() {
tp.pause(false);
}
public void stop() {
tp.pause(true);
}
public void destroy() {
tp.stop();
}
/**
* create a player thread for playing the
* @param module
* @return
*/
private ThreadedPlayer createPlayer(Module module) {
ThreadedPlayer player = new ThreadedPlayer();
try {
player.init(
new JavaSoundOutput(new SoundDataFormat(BITS, RATE, CHANNELS), BUFFERSIZE),
INTERPOLATE);
player.load(module);
} catch (Exception e) {
throw new RuntimeException(e);
}
player.pause(true);
return player;
}
/**
* load the nextModule'th file in the file list.
* @param nextModule
* @return
*/
private Module loadModule(int nextModule) {
int mc = fileList.size();
while (nextModule <= 0) nextModule += mc;
try {
theUrl = new URL(protocol, host, port, (String)fileList.get((nextModule + mc) % mc));
return ModuleLoader.getModuleLoader(theUrl).getModule();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void paint(Graphics g) {
// Double-Buffering
if (buffer==null) {
buffer=createImage(this.getSize().width, this.getSize().height);
gBuffer=(Graphics2D)buffer.getGraphics();
}
gBuffer.setBackground( new Color( 120, 120, 250 ));
gBuffer.setColor( Color.WHITE );
gBuffer.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
gBuffer.clearRect( 0,0,this.getSize().width, this.getSize().height);
// Antialiasing
gBuffer.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gBuffer.setFont( appFont );
for ( int i=0; i < letters.length; i++ ) {
letters[i].rotate( gBuffer );
}
g.drawImage (buffer, 0, 0, this);
// Delay
try {Thread.sleep(10);}
catch (InterruptedException e) {}
// Loop Module
if ( lengthOfModule == tp.getPosition() ) {
tp.setPosition( 0 );
tp.start();
}
repaint();
}
public void update(Graphics g) {
paint(g);
}
}


