# Blutspritzer mit Pixeln



## LoN_Nemesis (19. Dez 2006)

Hallo,

ich würde gerne etwas Blut spritzen lassen wenn die Protagonisten in meinem Spiel getroffen werden, um die Kämpfe etwas aufzuwerten. Dabei könnte ich entweder eine Animation z.b. als animiertes GIF einspielen oder das Blut quasi selbst direkt in Java malen. Die zweite Variante erscheint mir besser, da ich erstens nicht gut malen kann und zweitens kann ich dann Varianz realisieren, z.B. in Abhängigkeit des Schadens die Menge des Blutes erhöhen oder je nachdem welche Kreatur getroffen wurde die Blutfarbe ändern.

Nach einigen kümmerlichen Versuchen, die allesamt absolut nicht wie Blut aussahen, wollte ich wissen ob jemand von euch eine Idee dazu hat? Vielleicht irgendeinen Tipp für eine mathematische Funktion mit der spritzendes Blut mit Pixeln simulieren kann.

P.S.: Das Ganze sollte sich maximal in einem Areal von 40x40 Pixeln abspielen.


----------



## Revenant (20. Dez 2006)

puh also das is echt ne schwierige Sache.. klar zeichnen ohne animierte .gifs wäre flexibler und wohl auch schneller... hm..

Also das einzige das ich mir vorstellen könnte ist, dass die Flugbahn der Blutspritzer (zunächst Pixel) eine Parabel ist. Bzw. eine halbe Parabel auf je einer Seite des Sprites. Man könnte die Steigung der Parabel noch verändern (stauchen/strecken) so dass man verschieden "winkel" bekommt in der das Blut spritz. Ausserdem müsste man sowas wie ein Alter implementieren das die Größe der Pixel festlegt. Vllt kann das Alter sogar einfach der X-Wert der Parabel sein. Und mit zunehmendem Alter zeichnet man den Pixel größer (Plastikeffekt?!). Für die Farbe könnte man ein Rot wählen, das mit zunehmendem alter dunkler oder heller wird (ausprobieren). Also es is schon sau schwer würd ich mal sagen das realistisch aussehn zu lassen. Nichts desto trotz wag ich mich da mal dran, ich sag dir dann nochmal Bescheid


----------



## Revenant (20. Dez 2006)

check this:


```
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;


public class Test
{
	public static void main(String args[])
	{
		new Frame("Test-Projekt");
	}
}

class Frame extends JFrame
{
	Frame(String title)
	{
		super(title);
		pack();
		setSize(800,600);
		setResizable(false);
		setLayout(new FlowLayout());
		add(new Panel(this));
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setVisible(true);
	}
}

class Panel extends JPanel implements Runnable
{
	Image sprite;
	Blood[] blut = new Blood[7];
	
	Panel(Frame frame)
	{
		setBackground(Color.BLACK);
		
		try
		{
			sprite = new ImageIcon(new URL("http://www.videogamesprites.net/SecretofMana/Enemies/Robin%20Foot.gif")).getImage();
		} 
		catch (MalformedURLException e)
		{
			e.printStackTrace();
			System.out.println("Fehler, Sprite nicht gefunden!");
		}
		
		for (int i=0 ; i < 7 ; i++)
		{
			boolean side = true;
			if (Math.random()-0.5 < 0) side = false; 	
			blut[i]=new Blood(this,420,320,side); // for simple testing, otherwhise all blood objects over each other
		}
		
		new Thread(this).start();
	}

	public void run()
	{
		while (true)
		{
			repaint();
			
			try
			{
				Thread.sleep(30);
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
		}
	}

	public Dimension getMinimumSize()
	{
		return new Dimension(800, 600);
	}

	public Dimension getPreferredSize()
	{
		return getMinimumSize();
	}

	public void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		g.drawImage(sprite, 400, 300, this);
		g.setColor(Color.GREEN);
		g.drawRect(400, 300, 42, 52);
		g.setColor(new Color(200,0,0));
		for (int i=0 ; i < 7 ; i++)
		{
			if (blut[i]!= null)
			{
				blut[i].draw(g);
				if (!blut[i].getAlive()) blut[i] = null;
			}
			else
			{
				if (Math.random()<0.02) //well think you need a better way to make blood appear randomly, however works
				{
					boolean side = true;
					if (Math.random()-0.5 < 0)
						{
							side = false; 
						}
					blut[i] = new Blood(this,420,320,side);
				}
			}
		}
	}
}

class Blood
{
	Panel panel;
	int xpos = 0;
	int ypos = 0;
	// y = -ax²+b but we have to remove the "-" in front of the a because coordinate system is rotated ~~
	double y=0;
	double x=0;
	double a=0.075;
	double b=-20;
	boolean side;
	
	Blood(Panel panel, int x, int y, boolean side)
	{
		this.panel = panel;
		this.xpos = x;
		this.ypos = y;
		this.side = side;
		this.a = Math.random()*0.075 + 0.025;
	}
	
	public void draw(Graphics g)
	{
		y = a*(x*x)+b;
		if (side == true)
		{
			x++;
		}
		else
		{
			x--;
		}
		
		g.fillOval(xpos+(int)x, ypos+(int)y, (int)(Math.abs((int)x)/10*3), (int)(Math.abs((int)x)/10*3));
	}
	
	public boolean getAlive()
	{
		if (x >20 && side) return false;
		if (x <-20 && !side) return false;
		return true;
	}
}
```

viel besser wirds wohl nich gehn, aber das hast wohl selber schon so geschaft naja is halt schwierig. Theoretisch bräuchte man nen gescheiten Grafiker für sowas...


----------



## Illuvatar (21. Dez 2006)

Dz dz. Wer programmiert den hier Killerspiele? :noe:

*SCNR*


----------



## DP (21. Dez 2006)

ob der stoiber das gutfindet?!


----------



## LoN_Nemesis (21. Dez 2006)

Vielen Dank Revenant, da hast du dir ja richtig viel Arbeit gemacht.

Ich finde es sieht sehr gut aus, aber ist leider nicht ganz das was ich suche. Hab mich da leider etwas ungenau ausgedrückt. Das was du programmiert hast wäre toll für eine Art "Wunde", die eine zeitlang blutet. Ich suche aber eher etwas, wo durch den Treffer einer (Nahkampf-) Waffe einmal kurz Blut spritzt. Also nicht so einzelne Tropfen, sondern mehr eine "Fontäne" oder so.

Aber das was du gemacht hast gefällt mir so gut, dass ich mir überlege es für stark verwundete Gegner zu übernehmen.


----------



## Revenant (21. Dez 2006)

Schön wenns dir gefällt. 

Hm.. also wenn das so ist, wirds ja nochmal schwieriger... mir fällt jetzt aber gerade auch kein Beispiel ein wo man sowas sieht. Gut ich hab auch nie Tekken oder sowas gezockt. Kannst ja mal ein Beispiel aufführen (Screenshot oder sowas) wie das aussehn soll. Vllt finden wir ja dann noch ne Lösung.


----------



## Illuvatar (21. Dez 2006)

Ich glaube, er meint einen Effekt in der Art (nur eben in 2D)

http://home.arcor.de/sidiousx/blood.jpg

Und sagt nicht, dass Blut bei Skeletten unrealistisch ist


----------



## LoN_Nemesis (21. Dez 2006)

Atomic Butcher Screenshots

Sowas in der Art. Nicht so extrem, immerhin gibt es in meinem Spiel keine Granatenwerfer oder Shotguns, sondern nur Schwerter und Äxte. Die Gegner sollen auch nicht in irgendwelche Brocken zerfallen, aber vom Prinzip her in etwa so.

Ich glaube die machen das so, dass es quasi beim Aufprall der Kugel eine Art "Explosion" von Pixeln gibt, die sich dann aber nicht wie normale Explosionspartikel in alle Richtungen zerstreuen, sondern von der Schwerkraft nach unten gezogen werden.

Edit: Ich glaube aber das kann man nur bei Schusswaffen so machen


----------



## Revenant (21. Dez 2006)

Also ich glaub deine Splatter Effekte Illuvatar sind mit 2D Sprites gelöst, kann mir nicht vorstellen wie man sowas programmieren soll.  Aber nur weil ichs mir nicht vorstellen kann, heißt das nat nicht, dass es nicht geht.

Die Screenshots von dem Atomic Butcher Spiel sind schon nice. Ganz ehrlich: ich würd schon fliegende Körperteile reinbringen.. sieht doch "fetzig" aus und steigert irgendwie die Action find ich. Ja hört sich brutal an... aber ich glaub nich dass es jemand zum Amoklaufen bringt oder sich die Leute daran stören die sowas spielen. ~~

Ich hab eigentlich schon ne Idee wie man das realisieren könnte. Es handelt sich im Prinzip doch um nen waagrechten Wurf aus der Physik oder? Da gabs mal so ne Formel mit der man die Flugbahn von nem Körper (hier Pixel) realistisch berechnen kann (Erdbeschleunigung usw). Sollte eigentlich nicht so schwierig sein sowas zu implementieren. Dann erzeugt man halt zufällig einige dieser Pixel-Würfe und verschiebt das Gleichgewicht dabei gegen die Schussrichtung. Hm.. die Pixel haben anscheinend keinen zufälligen Rot-Wert sondern verblassen mit der Zeit.

Ich schau mal was ich machen kann

EDIT: lass doch mal was von deinem Gamechen sehn, bin neugierig  :wink:


----------



## LoN_Nemesis (21. Dez 2006)

Ich glaube du stellst dir das Spiel falsch vor  Ich glaube du hast es sogar schonmal gesehen, hatte vor einiger Zeit mal nach einem guten Regeneffekt gefragt, da hast du mir auch geholfen.

http://mitglied.lycos.de/destinyjava/new/

Wie du siehst sind die Kämpfe rundenbasierend und wirklich nicht sehr actionreich. Deswegen glaube ich auch, dass fliegende Körperteile zu überdimensioniert sind.

Ist natürlich noch mitten in der Entwicklung, vieles geht noch nicht.


----------



## Revenant (21. Dez 2006)

Stimmt jetzt kann ich mich wieder dran erinnern. Das Spiel Destiny. Da hast du dir aber was vorgenommen. Sieht echt alles sehr komplex aus und wird wirklich lange dauern das fertigzustellen. Da steckt sicher schon ne Menge Arbeit drin.

Klar, in dem Fall sind zu großartige Splatter-Effekte natürlich unangebracht


----------



## LoN_Nemesis (22. Dez 2006)

Habe nun eine einfache Partikelengine implementiert und stelle das Blut nun mit Partikeln dar. Momentan bluten noch alle Kreaturen und alle in der gleichen Farbe, das werde ich noch ändern.


----------



## Revenant (22. Dez 2006)

gut, dann kann ich mir das mit dem waagrechten wurf also sparen? 

würde den code aber trotzdem gerne sehen *ganzliebguck*


----------



## LoN_Nemesis (22. Dez 2006)

Sollst du haben!

Meine Partikel Klasse, sollte ziemlich selbsterklärend sein. Wird von ParticleEffect benutzt. Hab bei so einer kleinen Klasse auf Getter und Setter verzichtet.

```
package destiny.particles;

import java.awt.Color;
import java.awt.Graphics2D;

public class Particle {
	public final static int RECTANGLE = 1,
							ELLIPSE = 2;
	
	public boolean active;
	public int shape, size;
	public float posX, posY, horSpeed, verSpeed;
	public Color color;
	public int alphaDecay;
	
	public void draw(Graphics2D g) {
		if (!active) return;
		g.setColor(color);
		if (shape==Particle.ELLIPSE)
			g.fillOval((int)posX, (int)posY, size, size);
		else if (shape==Particle.RECTANGLE)
			g.fillRect((int)posX, (int)posY, size, size);
	}
	
}
```


Meine abstrakte Klasse ParticleEffect. Alle Effekte erben von ihr. Momentan gibt es nur das Blut als Effekt, aber ich hab einige Tests gemacht und man kann damit auch sehr schöne Zaubereffekte machen.

```
package destiny.particles;

import java.awt.Graphics2D;

public abstract class ParticleEffect {
	int centerX, centerY;
	Particle[] p;
	boolean loop, finished;
	
	public abstract void updateParticles();
	public abstract void resetParticle(Particle p1);
	
	public boolean isFinished() {return finished;}
	public void create(int count) {
		p = new Particle[count];
		for (int i=0; i<count; i++) {
			p[i] = new Particle();
			resetParticle(p[i]);
		}
	}
	public void draw(Graphics2D g) {
		for (int i=0; i<p.length; i++) {
			p[i].draw(g);
		}
		updateParticles();
	}
	
	public ParticleEffect(int centerX, int centerY) {
		loop = true;
		this.centerX = centerX;
		this.centerY = centerY;
	}

}
```


Und hier dann die eigentliche Implementierung des Blutes. Wie ich auf die Zahlen komme? Trial & Error 

```
package destiny.particles;

import java.awt.Color;

public class BloodEffect extends ParticleEffect {

	@Override
	public void resetParticle(Particle p) {
		p.active = true;
		finished = false;
		//p.posX = (float) (centerX -20 + Math.random()*40);
		//p.posY = (float) (centerY -20 + Math.random()*40);
		p.posX = (float) (centerX-5+Math.random()*10);
		p.posY = (float) (centerY-5+Math.random()*10);
		p.horSpeed = (float) (Math.random()*0.5);
		p.verSpeed = (float) (Math.random()*1.5);
		if (Math.random()<0.5)
			p.horSpeed *= -1;
		if (Math.random()<0.01)
			p.verSpeed *= -1;
		int wr = (int) (Math.random()*50);
		p.color = new Color((int) (150+Math.random()*85), wr, wr, (int) (Math.random()*255));
		p.alphaDecay = 10;
		p.shape = Particle.ELLIPSE;
		p.size = (int) Math.round(Math.random()*5);
}

	@Override
	public void updateParticles() {
		int nop = 0;
		for (int i=0; i<p.length; i++) {
			p[i].posX = p[i].posX + p[i].horSpeed;
			p[i].posY = p[i].posY + p[i].verSpeed;
			if (p[i].color.getAlpha()-p[i].alphaDecay>0)
				p[i].color = new Color(p[i].color.getRed(), p[i].color.getGreen(), p[i].color.getBlue(), p[i].color.getAlpha()-p[i].alphaDecay);
			else {
				p[i].active = false;
				nop++;
			}
			if (loop && !p[i].active)
				resetParticle(p[i]);
		}
		if (nop >=p.length-1)
			finished = true;
	}
	
	public BloodEffect(int centerX, int centerY, int numOfParticles) {
		super(centerX, centerY);
		create(numOfParticles);
	}

}
```


----------



## Revenant (22. Dez 2006)

Also es sieht jedenfalls nice aus! Kann man ziemlich vielseitig einsetzen denk ich.. Hm nur ein richtiger "Blutzspritzer" is es ja eigentlich auch nicht. Wie gut der Code jetzt is kann ich halt nich direkt beurteilen.. ich hab noch Probleme mit "richtiger OOP".. tendiere irgendwie zur prozeduralen Programmierung keine Ahnung..


----------



## LoN_Nemesis (23. Dez 2006)

Der Code ist nicht sehr toll wahrscheinlich, bin auch kein Programmierguru. Und es stimmt, hat physikalisch nicht viel mit einem Blutspritzer zu tun.. aber ich finde es sieht ok aus, und darauf kommt es an


----------

