Grass Veins
This was my entry to the Horticulture Challenge by DBF. So the task was to make a plant life themed effect. After googling the web a bit I found several vein effects mostly written in actionscript/flash.
This effects reminded me on growing grass so I thought this might fit into the compo's theme. All code was coded 100% from scratch since I did not have access to the .fla files.
There are still some bugs in it - but I ran out of time.
You can press in the applet window to reset the grass root.
In action
Technique & Credits
Code benny!weltenkonstrukteur.de
Music unknown (does anyone know the author?)
Soundsystem JavaMod Daniel "quippy" Becker
Sourcecode
GrassVein.java
import java.applet.Applet;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
public class GrassVeins extends Applet {
//
// Generic
//
private Graphics2D g2;
private Graphics2D g2Back;
private BufferedImage biBack;
private int appWidth, appHeight;
//
// Specific
//
public static final int IMG_X = 800;
public static final int IMG_Y = 800;
private Branch branch;
private Twig twig[] = new Twig[8];
private Color colBranch;
private Color colTwig;
private Stroke strokeBranch;
private Stroke strokeTwig;
private EasyModPlay modPlayer;
//private String modFile = "http://labs.weltenkonstrukteur.de/jar/data/ldrunner.mod";
private String modFile = "data/ldrunner.mod";
private URL modFileURL;
public void init() {
//
// Init
//
appWidth = this.getWidth();
appHeight = this.getHeight();
reinit();
try {
modFileURL = new URL( getCodeBase(), modFile );
} catch (Exception ex) {
ex.printStackTrace();
}
modPlayer = new EasyModPlay( modFileURL );
modPlayer.doStartPlaying();
}
private void reinit() {
//
// create backbuffer
//
if ( biBack==null ) {
//bImg = (BufferedImage)createImage( appWidth, appHeight );
biBack = new BufferedImage(IMG_X,
IMG_Y,
BufferedImage.TYPE_INT_RGB);
/*
try {
biBack = ImageIO.read(new File("wall.jpg"));
} catch (IOException e) {
}
*/
try {
URL url = new URL(getCodeBase(), "data/wall.jpg");
biBack = ImageIO.read(url);
} catch (IOException e) {
}
g2Back = (Graphics2D)biBack.getGraphics();
g2Back.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
strokeBranch = new BasicStroke(2.0f);
strokeTwig = new BasicStroke(1.0f);
}
//
// Specific
//
branch = new Branch (IMG_X/2, IMG_Y/2);
for (int i = 0; i < twig.length; i++) {
twig[i] = new Twig();
}
colBranch = new Color( 0, 255, 0, 80 );
colTwig = new Color( 0, 255, 0, 60 );
}
public void update(Graphics g) {
//
// Delay ... don't consume too much cpu power
//
try {Thread.sleep(25);}
catch (InterruptedException e) {}
//
// Specific
//
if ( branch.grow() == -1 ) reinit();
//g2Img.setColor( Color.black );
g2Back.setColor( colBranch );
g2Back.setStroke( strokeBranch );
g2Back.drawLine((int)branch.x,
(int)branch.y,
(int)branch.x + (int)branch.dx,
(int)branch.y + (int)branch.dy);
if ( WKMath.rand_minmax( 0, 30 ) < 5 ) {
for ( int i=0; i < twig.length; i++ ) {
if ( twig[i].isActive == false ) {
twig[i].init( branch.x, branch.y, branch.deg );
break;
}
}
}
g2Back.setColor( colTwig );
g2Back.setStroke( strokeTwig );
for ( int i=0; i < twig.length; i++ ) {
if ( twig[i].isActive ) {
twig[i].grow();
g2Back.drawLine((int)twig[i].x,
(int)twig[i].y,
(int)twig[i].x + (int)twig[i].dx,
(int)twig[i].y + (int)twig[i].dy);
}
}
paint(g);
}
public void paint (Graphics g){
int move_x = ((int)branch.x-(IMG_X/2)) / 2;
if ( move_x > 200 ) move_x = 200;
if ( move_x < -200 )move_x = -200;
int move_y = ((int)branch.y-(IMG_Y/2)) / 2;
if ( move_y > 200 ) move_y = 200;
if (move_y < -200 ) move_y = -200;
g2 = (Graphics2D)g;
g2.drawImage( biBack,
0,
0,
appWidth,
appHeight,
200+move_x, // 200 = (IMG_X/2) - (appWidth/2)
200+move_y, // 200 = (IMG_Y/2) - (appHeight/2)
600+move_x, // 600 = appWidth + ((IMG_X/2) - (appWidth/2))
600+move_y, // 600 = appHeight+ ((IMG_Y/2) - (appHeight/2))
this );
repaint();
}
public boolean mouseDown(Event ev, int xDown, int yDown) {
reinit();
return true;
}
public void destroy() {
modPlayer.doStopPlaying();
}
}
Branch.java
/*
* GrassVein
* by benny!weltenkonstrukteur.de
* (c) 2oo8
*
* Class: Branch.java
*
* This program is provided 'as is', without warranty of any kind,
* express or implied. The author shall not be liable for any damages
* caused by the use of or inability to use this program. This means
* that the user must assume the entire risk of using this program.
*
* Use of this program commercially without prior consent of the
* author is prohibited.
*
* This program may be freely distributed, but may not be sold.
*
* Use of this program indicates you understand and agree to the
* conditions of this license agreement.
*/
public class Branch {
public int deg;
public float x, y, dx, dy;
private static final float PI2 = 6.28f;
private static final float DEG_RAD = 360 / PI2;
private static final int STEP = 5;
private boolean isOutOfBounce;
public Branch( int x, int y) {
this.x = x;
this.y = y;
this.dx = 0;
this.dy = 0;
this.deg = 90;
this.isOutOfBounce = false;
}
public int grow() {
this.x = this.x + this.dx;
this.y = this.y + this.dy;
this.dx = (float)Math.cos( (this.deg/DEG_RAD ) ) * STEP;
this.dy = (float)-Math.sin( (this.deg/DEG_RAD) ) * STEP;
if ( ( (this.x < 50) || (this.y < 50 )
|| (this.x > (GrassVeins.IMG_X-50) )
|| (this.y > (GrassVeins.IMG_Y-50) ) )
&& isOutOfBounce == false ) {
isOutOfBounce = true;
this.deg = this.deg + WKMath.rand_minmax(145, 160);
}
if ( ( (this.x > 50) && (this.y > 50 )
&& (this.x < (GrassVeins.IMG_X-50) )
&& (this.y < (GrassVeins.IMG_Y-50) ) )
&& isOutOfBounce == true ) {
isOutOfBounce = false;
}
if ( isOutOfBounce == false ) {
this.deg = this.deg + WKMath.rand_minmax( -25, +25 );
}
if ( (this.x < 0) || ( this.y < 0 )
|| (this.x > GrassVeins.IMG_X)
|| (this.y > GrassVeins.IMG_Y) ) {
return -1;
} else {
return 0;
}
}
}
Twig.java
/*
* GrassVein
* by benny!weltenkonstrukteur.de
* (c) 2oo8
*
* Class: Twig.java
*
* This program is provided 'as is', without warranty of any kind,
* express or implied. The author shall not be liable for any damages
* caused by the use of or inability to use this program. This means
* that the user must assume the entire risk of using this program.
*
* Use of this program commercially without prior consent of the
* author is prohibited.
*
* This program may be freely distributed, but may not be sold.
*
* Use of this program indicates you understand and agree to the
* conditions of this license agreement.
*/
public class Twig {
public int deg;
public float x, y, dx, dy;
public boolean isActive;
private static final float PI2 = 6.28f;
private static final float DEG_RAD = 360 / PI2;
private static final int STEP = 3;
private int lifetime;
public Twig() {
isActive = false;
}
public void init( float x, float y, int deg) {
lifetime = WKMath.rand_minmax(0, 20) + 20;
this.x = x;
this.y = y;
this.deg = deg;
this.isActive = true;
}
public void grow() {
this.x = this.x + this.dx;
this.y = this.y + this.dy;
this.dx = (float)Math.cos( (this.deg/DEG_RAD ) ) * STEP;
this.dy = (float)-Math.sin( (this.deg/DEG_RAD) ) * STEP;
if ( (this.x < 50) || (this.y < 50 )
|| (this.x > (GrassVeins.IMG_X-50) )
|| (this.y > (GrassVeins.IMG_Y-50) ) ) {
this.deg = this.deg + WKMath.rand_minmax( 5, 25 );
} else {
this.deg = this.deg + WKMath.rand_minmax( -25, +25 );
}
lifetime--;
if ( lifetime == 0 ) isActive = false;
}
}
EasyModPlay.java
/*
* GrassVein
* by benny!weltenkonstrukteur.de
* (c) 2oo8
*
* Class: EasyModPlay.java
*
* This program is provided 'as is', without warranty of any kind,
* express or implied. The author shall not be liable for any damages
* caused by the use of or inability to use this program. This means
* that the user must assume the entire risk of using this program.
*
* Use of this program commercially without prior consent of the
* author is prohibited.
*
* This program may be freely distributed, but may not be sold.
*
* Use of this program indicates you understand and agree to the
* conditions of this license agreement.
*/
import java.awt.HeadlessException;
import java.net.URL;
import javax.sound.sampled.UnsupportedAudioFileException;
import de.quippy.javamod.loader.Module;
import de.quippy.javamod.loader.ModuleFactory;
import de.quippy.javamod.main.gui.PlayThread;
import de.quippy.javamod.main.gui.PlayThreadEventListener;
import de.quippy.javamod.mixer.Mixer;
import de.quippy.javamod.multimedia.mod.ModMixer;
import de.quippy.javamod.system.Helpers;
import de.quippy.javamod.system.Log;
public class EasyModPlay implements PlayThreadEventListener {
private URL modFileName;
private int sampleSizeInBits;
private int channel;
private int sampleRate;
private int doISP;
private boolean doWideStereoMix;
private boolean doNoiseReduction;
private boolean doMegaBass;
private PlayThread playerThread = null;
/*
static // THIS IS FROM JAVAMODMAINBASE FROM WICH THIS CLASS DOES NOT EXTEND
{
// Now load and initialize all classes, that should not be
// initialized during play!
try
{
Helpers.registerAllClasses();
}
catch (ClassNotFoundException ex)
{
Log.error("JavaModMainBase: a class moved?!", ex);
}
}
*/
public EasyModPlay( URL modFile ) throws HeadlessException
{
super();
sampleSizeInBits=16;
channel=2;
sampleRate=44100;
doISP=2;
doWideStereoMix=false;
doNoiseReduction=true;
doMegaBass=false;
modFileName = modFile;
/*
try {
modFileName = new URL( modFile );
} catch (Exception ex) {
ex.printStackTrace();
}*/
}
/**
* @param thread
* @see de.quippy.javamod.main.gui.PlayThreadEventListener
* #playThreadEventOccured(de.quippy.javamod.main.gui.PlayThread)
*/
public void playThreadEventOccured(PlayThread thread)
{
if (thread.isRunning())
{
//
}
else
{
//
}
Mixer mixer = thread.getCurrentMixer();
if (mixer!=null)
{
/*
if (mixer.isPaused())
//
else
//
*/
}
}
/**
* start playback of a mod
* @since 01.07.2006
*/
public void doStartPlaying()
{
if (modFileName!=null)
{
doStopPlaying();
Module mod = null;
try
{
mod = ModuleFactory.getInstance(modFileName);
}
catch (UnsupportedAudioFileException ex)
{
/*NOOP*/
}
if (mod!=null)
{
ModMixer mixer = new ModMixer(mod,
sampleSizeInBits,
channel,
sampleRate,
doISP,
doWideStereoMix,
doNoiseReduction,
doMegaBass);
playerThread = new PlayThread(mixer, null, null, this);
playerThread.start();
}
}
}
/**
* stop playback of a mod
* @since 01.07.2006
*/
public void doStopPlaying()
{
if (playerThread!=null)
{
playerThread.stopMod();
playerThread = null;
}
}
/**
* pause the playing of a mod
* @since 01.07.2006
*/
public void doPausePlaying()
{
if (playerThread!=null)
{
playerThread.pausePlay();
}
}
}
WKMath.java
/*
* GrassVein
* by benny!weltenkonstrukteur.de
* (c) 2oo8
*
* Class: WKMath.java
*
* This program is provided 'as is', without warranty of any kind,
* express or implied. The author shall not be liable for any damages
* caused by the use of or inability to use this program. This means
* that the user must assume the entire risk of using this program.
*
* Use of this program commercially without prior consent of the
* author is prohibited.
*
* This program may be freely distributed, but may not be sold.
*
* Use of this program indicates you understand and agree to the
* conditions of this license agreement.
*/
public class WKMath {
public static int rand_minmax( int min, int max ) {
long range = (long)max - (long)min + 1;
int value = (int)(min + (long)( Math.random() * range ) );
if ( value > max ) {
return max;
} else {
return value;
}
}
}


