# Korrekte Darstellung von Wasser in 2D Spiel



## Letavino (5. Jul 2012)

Hallo,
ich programmiere gerade aus Übungszwecken ein kleines 2D Spiel.
Nun war ich gerade dabei, Regen in das Spiel zu implementieren, welcher in Abhängigkeit der Schwerkraft und dem Wind zu Boden fällt.

Das funktioniert auch einwandfrei.
Für die Regentropfen habe ich eine eigene Klasse geschrieben, die das Bild erstellt und gezeichnet wird.
Nun habe ich aber schnell über 10000 Tropfen Objekte und es werden ja immer mehr.
Gibt es einen besseren Weg, Regen zu erstellen?

Das Wasser landet anschließend auf einem eingezeichneten Boden. Mit einer Kollisionserkennung wird ermittelt, welcher Teil des Hintergrundes Transparent ist und welcher nicht. Nicht-transparente Teile gelten als solide und lösen eine Kollision aus.
Will ich nun allerdings, dass sich das Wasser am Boden anstaut, müsste ich für jeden Tropfen mit jedem anderen Tropfen eine Kollisionserkennung machen, was bei dieser Anzahl der Objekte einfach nicht effektiv ist und das Spiel unspielbar macht.

Wie muss ich an das Problem rangehen, dass sich das Wasser wie Wasser verhalten kann und trotzdem den Ressourcenverbrauch nicht sprengt?
Bringt JOGL oder ähnliches Besserung?

Die Hilfsklasse zur jetzigen einfachen Kollisionserkennung, welche die Map übergeben bekommt:

```
// Koordinaten und Bild des Source Objects und des Referenz Objektes

public static boolean[] collision(float srcX, float srcY, BufferedImage srcImg, int refX, int refY, BufferedImage refImg)
	{
		int xs = 0;
		int ys = 0;
		
		int xr = 0;
		int yr = 0;
		
		boolean[] b = {false,false,false,false}; //Kollision oben, rechts, unten, links

// Kollision beim Rand der Karte
		if(srcX == 0)
			b[3] = true;
		else if(srcX+srcImg.getWidth() == Main.bg.getWidth())
			b[1] = true;
		
		if(srcY+srcImg.getHeight() == Main.bg.getHeight())
			b[2] = true;
		
		Rectangle srcRect = new Rectangle((int)srcX,(int)srcY,srcImg.getWidth(),srcImg.getHeight());
		Rectangle refRect = new Rectangle((int)refX,(int)refY,refImg.getWidth(),refImg.getHeight());
		
		Rectangle intRect = new Rectangle();
		// Überschneidungen feststellen
		if(!srcRect.intersects(refRect))
			return b; 
		
		intRect = srcRect.intersection(refRect);
		
		xs = (int) (Math.max(intRect.getX(), srcRect.getX()) - Math.min(intRect.getX(), srcRect.getX()));
		ys = (int) (Math.max(intRect.getY(), srcRect.getY()) - Math.min(intRect.getY(), srcRect.getY()));
		
		xr = (int) (Math.max(intRect.getX(), refRect.getX()) - Math.min(intRect.getX(), refRect.getX()));
		yr = (int) (Math.max(intRect.getY(), refRect.getY()) - Math.min(intRect.getY(), refRect.getY()));	
			
		BufferedImage srcSub = srcImg.getSubimage(xs, ys, (int)intRect.getWidth(), (int)intRect.getHeight());
		BufferedImage refSub = refImg.getSubimage(xr, yr, (int)intRect.getWidth(), (int)intRect.getHeight());
		
		
		
		for(int i=0;i<intRect.getWidth();i++)
			for(int j=0;j<intRect.getHeight();j++)
			{	
				if(i<intRect.getWidth()-1)
					if(!isTransparent(i,j,srcSub)&&!isTransparent(i+1,j,refSub))
						b[1] = true;
				if(j<intRect.getHeight()-1)
					if(!isTransparent(i,j,srcSub)&&!isTransparent(i,j+1,refSub))
						b[2] = true;
				if(i>0)
					if(!isTransparent(i,j,srcSub)&&!isTransparent(i-1,j,refSub))
						b[3] = true;
				if(j>0)
					if(!isTransparent(i,j,srcSub)&&!isTransparent(i,j-1,refSub))
						b[0] = true;
			}		
				
		return b;
	}
```

Gruß, Letavino


----------



## Robokopp (5. Jul 2012)

Ich hab mal was ähnliches gemacht. Ich hatte eine feste Anzahl an tropfen und hab sie, nach dem sie den Boden berührt haben wieder über den Bildschirm gesetzt und die Sache wiederholt. Alternativ kannst du Objekte löschen und jedesmal neue erstellen.

Gesendet von meinem GT-I9100 mit Tapatalk 2


----------



## Letavino (5. Jul 2012)

Robokopp hat gesagt.:


> Ich hab mal was ähnliches gemacht. Ich hatte eine feste Anzahl an tropfen und hab sie, nach dem sie den Boden berührt haben wieder über den Bildschirm gesetzt und die Sache wiederholt. Alternativ kannst du Objekte löschen und jedesmal neue erstellen.
> 
> Gesendet von meinem GT-I9100 mit Tapatalk 2



Ähnliches hatte ich mir auch schon gedacht, allerdings wollte ich, dass sich das Wasser auf dem Boden sammelt und auch verläuft, etc.
Um es einigermaßen realistisch zu gestalten müssen die Tropfen als Objekte bestehen bleiben, oder gibt es eine andere Alternative?

Gruß!


----------



## Noisefever (6. Jul 2012)

Ich glaube nicht daß das so machbar ist (mag aber sein daß ich eine Möglichkeit überseh). Und ich würde auch sagen dem Spieler ist das nachher sowas von egal ob das realistisch ist.

Ich würde vermutlich einfach die Tropfenmenge pro Tile/Quadrant messen und dort den Wasserstand entsprechend anpassen wobei das Wasser aus Polygonen besteht, nicht aus einzelnen Tropfen. Ich würde auch schon bei den Regentropfen mit Wiederholung in Quadranten arbeiten, aber das geht in deinem Fall natürlich nicht wenn es Luftwirbel gibt (ich weiß nicht wie weit dein Wind geht).

Auch von pixelbasierender Kollision würde ich ansich abraten, lieber auf Geometrie testen (Rectangle, Polygon).


----------



## Letavino (6. Jul 2012)

Danke für deine Antwort!



Noisefever hat gesagt.:


> Ich glaube nicht daß das so machbar ist (mag aber sein daß ich eine Möglichkeit überseh). Und ich würde auch sagen dem Spieler ist das nachher sowas von egal ob das realistisch ist.



Ok, realistisch ist hier wohl eher relativ zu sehen.
Was ich damit ausdrücken wollte, sind eher folgende Punkte:

- Das Wasser soll sich am Boden sammeln
- Es soll bei einer schräge nach unten fließen können
- Es soll natürlich keine Türmchen bilden
- Es soll, wenn sich ein Loch unten auftut, optisch gesehen realitätsnah nach unten fallen

- Ist der Regen noch in der Luft, soll er auf aufgrund der Schwerkraft nach unten beschleunigen und bei Wind (nur seitlicher Wind) seine Richtung verändern.

Mehr ist erstmal nicht vorgesehen.



> Ich würde vermutlich einfach die Tropfenmenge pro Tile/Quadrant messen und dort den Wasserstand entsprechend anpassen wobei das Wasser aus Polygonen besteht, nicht aus einzelnen Tropfen. Ich würde auch schon bei den Regentropfen mit Wiederholung in Quadranten arbeiten, aber das geht in deinem Fall natürlich nicht wenn es Luftwirbel gibt (ich weiß nicht wie weit dein Wind geht).



Ich bin nun auf die Idee gekommen, eine Boolean Matrix über die Karte zu spannen und die Koordinaten der Regentropfen, die den Boden berühren dort auf True zu setzen.
Dann wird ein BufferedImage erzeugt, bei denen die Koordinaten, welche auf True stehen, blau gezeichnet werden. Dieses Image wird über das Originalbild gelegt.
Folglich müsste man beim weiteren Vorgehen nur ein paar Verschiebungen in der Matrix vornehmen, was um einiges schneller gehen sollte.

Ich hab erst angefangen, es zu implementieren, kann also noch nicht sagen, ob es geht, wie ich mir das vorgestellt habe.
Was haltet ihr von dieses Möglichkeit?
Oder sollte ich lieber deinen Ansatz aufgreifen?

Gruß


----------

