¿Cómo agrego un efecto de lluvia a un juego de layout de arriba hacia abajo en Java, sin usar bibliotecas externas?

Estoy creando un juego de arriba hacia abajo para mi proyecto informático de nivel A / nivel universitario, y estoy tratando de implementar la lluvia. El juego debe poder usarse en cualquier plataforma, por lo que el uso de bibliotecas externas está fuera de cuestión. Actualmente tengo la GUI ejecutándose en el package de Gráficos de Java, y el juego se representa píxel por píxel a partir de una matriz de píxeles. El objective sería tener un efecto de lluvia que se parece a esto http://d2436y6oj07al2.cloudfront.net/spff/previews/vbme0577.jpg . Si esto es posible, esto sería realmente bueno. Actualmente también tengo una class de partículas y desovadores de partículas, que agregan el efecto de sangre y el efecto de los proyectiles "explotando" cuando golpean una panetworking.

¿Hay alguna manera de implementar algo de lluvia de lo que ya tengo? Intenté implementar una class Rain, que genera partículas en un lugar aleatorio dentro de los límites de un área de la pantalla, para que parezca que venía desde la perspectiva de los bloques.

Aquí está la lluvia que intenté agregar (partículas azules): enter image description here

El problema es que se mueve y no se parece en nada a la image vinculada anteriormente. Además, aquí está mi class Rain, que el jugador agrega actualmente solo para probar, pero el juego final será tener una class "WeatherManager" que maneje todos los cambios climáticos y el desove del clima (lluvia, nieve, etc.).

package com.ritcat14.GotYourSix.entity.particle; import java.util.Random; import com.ritcat14.GotYourSix.Game; import com.ritcat14.GotYourSix.entity.Entity; import com.ritcat14.GotYourSix.graphics.Sprite; import com.ritcat14.GotYourSix.level.Level; public class Rain extends Entity { private int time = 0; //time it is raining for private int currTime = 0; private boolean timeOfDay = false; //if it is night or day (false - night, true - day) private Level level = null; private Sprite drop = null; private int amount = 0; public Rain(int time, boolean timeOfDay, Level level) { init(level); this.time = time; this.timeOfDay = timeOfDay; this.level = level; if (timeOfDay) { drop = new Sprite(1, 0x87F7FF); } else { drop = new Sprite(1, 0xEFFBFF); } } public void update() { currTime++; if (currTime > time) { remove(); } else { Random ran = new Random(); if (time % (ran.nextInt(120) + 1) == 0) { int x = ran.nextInt(Game.getWindowWidth()); int y = ran.nextInt(Game.getWindowHeight() / 4) + 100; level.add(new Particle(x, y, 1000, drop)); amount++; } } } public void setDay(boolean dayTime) { this.timeOfDay = dayTime; } } 

Aquí está mi class de partículas:

 package com.ritcat14.GotYourSix.entity.particle; import java.util.Random; import com.ritcat14.GotYourSix.entity.Entity; import com.ritcat14.GotYourSix.entity.mob.Player; import com.ritcat14.GotYourSix.entity.projectile.Projectile; import com.ritcat14.GotYourSix.graphics.Screen; import com.ritcat14.GotYourSix.graphics.Sprite; public class Particle extends Entity { private Sprite sprite = null; private int life = 0; private int time = 0; protected double xx = 0, yy = 0, zz = 0; protected double xa = 0, ya = 0, za = 0; private Random ran = new Random(); public Particle(int x, int y, int life, Sprite sprite) { this.x = x; this.y = y; this.xx = x; this.yy = y; this.life = life + (random.nextInt(50) - 25); this.sprite = sprite; this.xa = random.nextGaussian(); this.ya = random.nextGaussian(); this.zz = random.nextFloat() + 2.0; int col = ran.nextInt(4); if (sprite != Sprite.particle_blood) { if (Projectile.weapon == Projectile.Weapon.FIREDCANNON || Projectile.weapon == Projectile.Weapon.FIREDARROW) { if (col == 0) this.sprite = new Sprite(2, 0xff000000); if (col == 1) this.sprite = new Sprite(2, 0xffF8A800); if (col == 2) this.sprite = new Sprite(2, 0xffF8F8C8); if (col == 3) this.sprite = new Sprite(2, 0xffF8A800); } else if (Projectile.weapon == Projectile.Weapon.FIREBALL || Projectile.weapon == Projectile.Weapon.FIREWALL) { if (col == 0) this.sprite = new Sprite(2, 0xffF86800); if (col == 1) this.sprite = new Sprite(2, 0xffF8A800); if (col == 2) this.sprite = new Sprite(2, 0xffF8F8C8); if (col == 3) this.sprite = new Sprite(2, 0xffF8D840); } else if (Projectile.weapon == Projectile.Weapon.ICEDCANNON || Projectile.weapon == Projectile.Weapon.ICEDARROW) { if (col == 0) this.sprite = new Sprite(2, 0xff427AFF); if (col == 1) this.sprite = new Sprite(2, 0xff607BFF); if (col == 2) this.sprite = new Sprite(2, 0xff7C9BFF); if (col == 3) this.sprite = new Sprite(2, 0xff000000); } else if (Projectile.weapon == Projectile.Weapon.ICEBALL || Projectile.weapon == Projectile.Weapon.ICEWALL) { if (col == 0) this.sprite = new Sprite(2, 0xff427AFF); if (col == 1) this.sprite = new Sprite(2, 0xff607BFF); if (col == 2) this.sprite = new Sprite(2, 0xff7C9BFF); if (col == 3) this.sprite = new Sprite(2, 0xffD3DEFF); } } } public void update() { time++; if (time >= Integer.MAX_VALUE - 100) time = 0; //Safety check if (time > life) remove(); za -= 0.1; if (zz < 0) { zz = 0; za *= -0.55; xa *= 0.4; ya *= 0.4; } move(xx + xa, (yy + ya) + (zz + za)); } private void move(double x, double y) { if (collision(x, y)) { this.xa *= -0.5; this.ya *= -0.5; this.za *= -0.5; } this.xx += xa; this.yy += ya; this.zz += za; } public boolean collision(double x, double y) { boolean solid = false; for (int c = 0; c < 4; c++) { double xt = (x - c % 2 * 16) / 16; double yt = (y - c / 2 * 16) / 16; int ix = (int)Math.ceil(xt); int iy = (int)Math.ceil(yt); if (c % 2 == 0) ix = (int)Math.floor(xt); if (c / 2 == 0) iy = (int)Math.floor(yt); if (level.getTile(ix, iy).solid()) solid = true; } return solid; } public void render(Screen screen) { screen.renderSprite((int)xx - 1, (int)yy - (int)zz - 1, sprite, true); } } 

¿Alguna idea sobre cómo mejorar y / o hacer que parezca "caer" al suelo? Logré esto con partículas estándar, pero no entiendo cómo "Rain" parece "caer" en un mundo en 2D. ¿Algunas ideas? Gracias