10

I am making a game in java and I want to create a simulation of a cloud that is pouring rain. The cloud is supposed to move to the right while raining. Moving the cloud is no problem. It's the rain that I am struggling with.

What I was thinking of doing was with a timer to draw a rectangle, thats supposed to look like falling rain at a random x value inside of the cloud. And then add 1 to the y value of the drop each 100 millisecond. But I don't want to create 100 different rectangles, x variables and y variables for each rain drop.

Any idea how I can accomplish this? Suggestions appreciated!


It is a 2d game.. Sorry.

  • Here's a link that may help: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=3704&lngWId=2. It was written in Java 1.2 so I'm not sure if it's the best solution, but it still may provide you insight. – Josh Jul 02 '12 at 14:49
  • looks interresting, thanks! will take a look – Thobias Nordgaard Jul 02 '12 at 14:50
  • Making sure: Is this a 2D game? Horizontal is horizon, vertical is height, and no depth? – Nick Jul 02 '12 at 14:51
  • I looked at the code, it seems straight forward. Essentially it's randomizing x,y, and velocity then drawing lines. – Josh Jul 02 '12 at 14:51
  • 2
    Your computer can do billions of operations per second. Why don't you try the simple approach first and see if it will work. – BillRobertson42 Jul 02 '12 at 14:56

5 Answers5

3

One approach would be to consider a marquee on a theater. You take a series of bulbs and, by lighting and extinguishing them in sequence, you can simulate linear motion.

In the same way, rather than creating raindrops and animating their movement, why not creating multiple raindrops that are invisible and show and hide them in sequence to simulate downward motion. Then, you would have a series of arrays representing a raindrop track and you simply need to cycle through then, hiding the current one, incrementing the array pointer and displaying that one.

Dancrumb
  • 26,597
  • 10
  • 74
  • 130
3

Is it a requirement that the rain drops be programmed? Traditionally, this would be done with a few rain sprites that you place under the cloud and animate so that it looks like the rain is falling.

dcow
  • 7,765
  • 3
  • 45
  • 65
2

I would recommend just storing the values as an ArrayList of objects.

class Raindrop {
    private int x;
    private int y;

    public void fall() {
        y--;
    }
}

Then make an ArrayList with a generic type.

ArrayList<Raindrop> drops = new ArrayList<Raindrop>();

To make each drop fall,

for (int i=0; i<drops.length(); i++) {
    drops.get(i).fall();
}
danmcardle
  • 2,079
  • 2
  • 17
  • 25
2

Here is my java (swing) implementation of 2d rain with drops, splash, wind and gravity

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

 public static void main( String [] args ) {
     JFrame frame = new JFrame();
     frame.setSize(800, 300);
     final RPanel rPanel=new RPanel();
     frame.add(rPanel);
     frame.setVisible( true );
     frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            super.windowClosing(e);
            rPanel.stop();
            System.exit(0);
        }
    });
}
}

class RPanel extends JPanel {
//*********SETTINGS****************************
private float mWind = 2.05f;
private float mGravity = 9.8f;
private double mRainChance = 0.99; // from 0 to 1

private int mRepaintTimeMS = 16;
private float mRainWidth=1;
private double mDdropInitialVelocity = 20;
private double mDropDiam = 2;
private Color mColor=new Color(0, 0, 255);
//*********************************************

private ArrayList<Rain> rainV;
private ArrayList<Drop> dropV;
private UpdateThread mUpdateThread;

public RPanel() {
    rainV = new ArrayList<>();
    dropV = new ArrayList<>();

    mUpdateThread=new UpdateThread();
    mUpdateThread.start();
}

public void stop() {
    mUpdateThread.stopped=true;
}

public int getHeight() {
    return this.getSize().height;
}

public int getWidth() {
    return this.getSize().width;
}

private class UpdateThread extends Thread {
    public volatile boolean stopped=false;
    @Override
    public void run() {
        while (!stopped) {
            RPanel.this.repaint();
            try {
                Thread.sleep(mRepaintTimeMS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    g2.setStroke(new BasicStroke(mRainWidth));
    g2.setColor(mColor);

    //DRAW DROPS
    Iterator<Drop> iterator2 = dropV.iterator();
    while (iterator2.hasNext()) {
        Drop drop = iterator2.next();
        drop.update();
        drop.draw(g2);

        if (drop.y >= getHeight()) {
            iterator2.remove();
        }
    }

    //DRAW RAIN
    Iterator<Rain> iterator = rainV.iterator();
    while (iterator.hasNext()) {
        Rain rain = iterator.next();
        rain.update();
        rain.draw(g2);

        if (rain.y >= getHeight()) {
            //create new drops (2-8)
            long dropCount = 1 + Math.round(Math.random() * 4);
            for (int i = 0; i < dropCount; i++) {
                dropV.add(new Drop(rain.x, getHeight()));
            }
            iterator.remove();

        }
    }

    //CREATE NEW RAIN
    if (Math.random() < mRainChance) {
        rainV.add(new Rain());
    } 
}

//*****************************************
class Rain {
    float x;
    float y;
    float prevX;
    float prevY;

    public Rain() {
        Random r = new Random();
        x = r.nextInt(getWidth());
        y = 0;
    }

    public void update() {
        prevX = x;
        prevY = y;

        x += mWind;
        y += mGravity;
    }

    public void draw(Graphics2D g2) {
        Line2D line = new Line2D.Double(x, y, prevX, prevY);
        g2.draw(line);
    }
}

//*****************************************
private class Drop {

    double x0;  
    double y0;  
    double v0; //initial velocity
    double t;  //time
    double angle;
    double x;
    double y;

    public Drop(double x0, double y0) {
        super();
        this.x0 = x0;
        this.y0 = y0;

        v0 = mDdropInitialVelocity;
        angle = Math.toRadians(Math.round(Math.random() * 180)); //from 0 - 180 degrees
    }

    private void update() {
        // double g=10;
        t += mRepaintTimeMS / 100f;
        x = x0 + v0 * t * Math.cos(angle);
        y = y0 - (v0 * t * Math.sin(angle) - mGravity * t * t / 2);
    }

    public void draw(Graphics2D g2) {
        Ellipse2D.Double circle = new Ellipse2D.Double(x, y, mDropDiam, mDropDiam);
        g2.fill(circle);
    }
}
}
ashakirov
  • 12,112
  • 6
  • 40
  • 40
0

You can use a particle system or use a vector of raindrops and animate them every X milliseconds. A link to a particle system library: http://code.google.com/p/jops/

example code for vector:

import java.util.Vector;
// In your class
Vector raindrops;
void animate()
{
    ListIterator iter = raindrops.listIterator;
    while (iter.hasNext()) {
        ((Raindrop)iter.next()).moveDown();
    }
}
Bob
  • 409
  • 5
  • 9