# Schüsse zeichnen



## lohr (31. Mrz 2008)

Servus,

Also mein kleines RTS Game wächst und gedeiht, meine Einheiten sind mehr schlecht als recht modelliert(in paint gezeichnet *g*) und die wegfindung ist katastrophal aber es geht  man kann sogar einheiten produzieren, also ich bin eigentlich schon mal zufrieden.

Nun zum problem...
Momentan sieht ein kampf bei mir so aus, das sich die einheit gegenüber stehen in ca 20 pixel entfernung dort warten und sie verlieren immer mehr health points^^das dies nicht sonderbar attraktiv ist ist auch mir klar, daher eine kleine Frage von mir wie man einen Schuss zeichnet/simuliert.

Habe am Anfang gedacht ich zeichne einfach einen kleinen Kreis laße den dann zum Gegner "gehen" und erhalte dadurch einen bewegebenden Schuss, jedoch ist in meinem Hinterkopf noch etwas wo ich sage das kann ja nicht die beste Lösung sein...

Habt ihr noch andere Vorschläge?
Vielen Dank im Voraus!

Gruß lohr


----------



## 0x7F800000 (31. Mrz 2008)

warum sollen es denn unbedingt kreise sein?
Erstelle dir ein paar bildchen mit raketen verschiedenster art, laserstrahlen, blitzen usw usw. und füge diese texturen entsprechend vervielfältigt und gedreht an den einheiten, die grad einen schuss abfeuern, an...
Wichtig ist, dass die textur eben zum größten teil transparent ist.

Aber so lässt sich nur schwer etwas vorschlagen, welche techniken setzst du denn bei deinem spiel ein?


----------



## lohr (31. Mrz 2008)

Sorry bin grad noch in der Arbeit daher fällt es mir schwer dazu jetzt mehr zu sagen...
Also momentan arbeite ich mit gar keiner besonderen Zeichentechnik, es wird alles von Java2d gezeichnet und ich lade eigentlich nur Bilder...
Ja ich weiß das ist nicht schön aber ich bin einfach nur grausam im Zeichnen/Malen, also hab ich mir gedacht dann brauch ich auch momentan keine effekte 

Also wegen den kreisen, nunja ich dachte wenn ich sie kleingenug wähle sehen sie fast aus wie kugeln und dadurch würde es schon wie ein schuss aussehen ^^
jo meine frage wäre halt dann, nehmen wir an ich zeichen mir eine kleine blaue rakete (o.ä.^^) ich lasse die dann von der kanone meiner einheit starten und dann einfach immer x und y werte erhöhen/erniedrigen bis sie am ziel ist...
würdet ihr für diesen partikel/schuss/rakete eine eigene Klasse entwerfen oder einfach nur in das Einheiten Objekt so einfügen? ich tendiere zu eine Schussklasse in der ich dann auch nach belieben eigene Schussimages reinladen kann und jedes einheitenobjekt enthält dann ein schussobjekt...
Passt das so?

Gruß Alex


----------



## 0x7F800000 (31. Mrz 2008)

mit java 2D kannst du bilder bestens drehen und zeichnen dort wo du sie haben willst. (wie machst du es denn mit den einheiten??) => mach es genauso mit schüssen auch, das sollte eigentlich einfach nur eine große abstrakte klasse etwa "Visible" sein, die eine referenz auf die textur, position, ausrichtung etc speichert, und dann einheitlich gezeichnet wird, dann musst du es nur einmal implementieren, und hast es für alle möglichen einheiten, bäume, gebäuden, schüsse, explosionen etc etc fertig.

Dann kannst du für jede einheitenart eine gif/png textur erstellen, das die draufsicht darstellt, und dann zeichnest du das alles eben... Ich übe z.B momentan mit GIMP, die erfolge sind bis dahin nicht gerade berauschend, weil das programm überanzählbar viele features aufweist, mit den ich oft wenig anfangen kann, aber zumindest kannst du damit bilder mit transparenten hintergrund erstellen, sodass deine einheiten eben nicht rechteckig sind^^ (mit paint geht das afaik nicht oder??  ???:L  )


----------



## Janus (1. Apr 2008)

grundsätzlich würd ich mir wahrscheinlich erstmal eine klasse schrauben, die beliebige bilder, beliebig gedreht an beliebigen positionen zeichnen kann. einheiten, schüsse, etc. werden dann mithilfe dieser klassen gezeichnet.

einer klasse, die sich um schüsse kümmert, würd ich dann wahrscheinlich als eigenständige klasse implementieren. für jede art von schuss eine eigene. und die bekommt eine methode, die die teilnehmer am schuss beinhaltet. was die schuss klasse dann macht ist, das projektil korrekt zu zeichnen und die entsprechenden methoden für abschuss und einschlag an den beteiligten klassen aufzurufen.


```
class Projectile
{
   public void fire( Unit source, Unit[] targets )
   {
       source.fire( this )
       for( Unit target : targets )
       {
           this.moveTo( target.location() );
           target.impact( this );
       }
   }
}
```

vielleicht ungefähr so als pseudo code.


----------



## lohr (1. Apr 2008)

hm gimp muss ich mir mal anguggn...
in paint ist es definitv nicht machbar und daher sind die einheiten  teilweise klötze^^aber ich finde das auch dies nicht mein problem ist da ich programmiertechnisch was lernen will und nicht zeichnerisch.daher werde ich mir gimp wohl doch eher nur bei genügend Zeit anguggn 

Der Pseudocode ist gut, werde das heute abend mal umsetzen.
Naja ich werde die jeglichen Klassen (verschiedene Projektile) wohl auch von meiner Spriteklasse ableiten damit hätte ich schon das gröbste.
Nun hätte ich aber noch eine Frage, die gegnerische Einheit bewegt sich ja meistens auch weiter, würdet ihr sobald ein Schuss abfeuert ist dann auch immer wieder die x und y koordinate der gegnerischen einheit aktualisieren, dass praktisch ein "verfolgungsschuss" entsteht, oder macht ihr das anders?

Vielen Dank für eure Hilfestellungen bisher!


----------



## 0x7F800000 (1. Apr 2008)

du willst dass die einheiten quasi vorausschauen können, wohin sich der gegner bewegt, und dorthin feuern, um nicht bloß die heiße spur zu treffen? Sowas wie auto-aiming?
Also, wenn die granaten den gegner "verfolgen" sieht das äußerst blöd aus^^


----------



## lohr (1. Apr 2008)

Das stimmt natürlich das des scheiße aussehen würde ^^
Jedoch würde ich sagen das wenn ich zb in wirklichkeit schieße dann ist die Kugel so schnell unterwegs das wenn ich sauber ziele das ziel auch trifft, hier ist es doch aber so das ich ja den schuß auch animieren will und zwar so das man ihn sieht.
das heißt das ganze sieht natürlich nicht nur langsamer aus sondern ist es doch auch oder? (oder verhau ich mich hier grad übel*g*)

Folgender Hergang:
- Genger an x,y
- ich schieße in richtung x,y
- gegner fährt auf x2,y2
- schuss geht vorbei

Oder meint ihr das ich vielleicht die animation deutlich und trotzdem schnell ausführen kann?
das praktisch der schuss sofort ankommt?


----------



## 0x7F800000 (1. Apr 2008)

nö. Also ich würde dir wirklich vorschlagen, sich für ne halbe stunde hinzusetzen, und sich die sache mit autoaiming nachzurechnen. Dann sehen die einheiten praktisch voraus, wo der gegner sein wird, wenn er sich gerade aus bewegt. Das sieht zum einen realistisch aus, zum anderen wertet es das spiel auf, wenn man sieht, dass die einheiten nicht übertrieben blöde klötze sind, die nur in den boden ballern 

also, ich glaub ich versuche heute noch eine auto-aiming demo herzustellen, kann aber nicht garantieren, dass es mir unterwegs nicht langweilig wird


----------



## lohr (1. Apr 2008)

also wenn du dir freiwillig die arbeit machst, danke 
aber musst du du nicht, das kann(hoffe ich zumindest *g*) ich auch selber ^^ nur man muss finde ich schon seine ideen präsentieren und halt fragen wie das andere machen ich finde dadurch lernt man am meisten...
noch dazu kommt, dass wenn ich mein problem aufschreiben muss, merke ich schon selber denkfehler und man überdenkt auch nochmal alles 

die denkanstöße hier im forum sind nämlich mehr als super ^^ aber vor was mir graut ist das ich jetzt dann bald ne wegfindung machen muss (ne richtige^^) und davor hab ich richtig schiss


----------



## 0x7F800000 (1. Apr 2008)

Aaaalso... hab hier jetzt ein ausführlicheres beispiel gebastelt.
Wenn du mit deinen Berechnungen fertig wirst, dürfte es in etwa so funktionieren:


```
import java.applet.*;
import java.awt.*;
import java.awt.event.*;

import java.awt.event.MouseEvent;
import java.awt.image.*;

public class AutoAiming extends Applet implements MouseMotionListener{

	public Vector3D mouse; //position of the mouse
	public BufferedImage backBuffer;
	
	private static class Ball{
		private Vector3D x,v; //position, velocity
		private double r; //radius
		private double m; //mass
		private double e; //elasticity
		private double f; //friction
		private Color color;
		
		public Ball(Vector3D _x, Vector3D _v, double _r, double _m, double _e, double _f, Color _color){
			x=_x; v=_v; r=_r; m=_m; f=_f; e=_e; color=_color;
		}
		
		public void move(double dt, Rectangle rect, Vector3D center){
			
			/*COLLISION
			//check collision with bound-rectangle
			if(x.x<r){
				x.x=r; v.x=-v.x;
			}else if(x.x>rect.width-r){
				x.x=rect.width-r; v.x=-v.x;
			}else if(x.y<r){
				x.y=r; v.y=-v.y;
			}else if(x.y>rect.height-r){
				x.y=rect.height-r; v.y=-v.y;
			}//*/
			
			//*Teleport
			
			//AUTOAIMING: only big balls "respawn"
			if(m>1){
			if(x.x<-r){
				x.x=rect.width+r;
			}else if(x.x>rect.width+r){
				x.x=-r;
			}else if(x.y<-r){
				x.y=rect.height+r;
			}else if(x.y>rect.height+r){
				x.y=-r;
			}
			}//*/
			
			//move
			Vector3D a=new Vector3D(v.mul(-f));
			v=v.add(a.mul(dt));
			x=x.add(v.mul(dt));
			
		}
		
		public void collision(Ball b){
			//check if the balls collide
			Vector3D connection=x.sub(b.x);
			double distSq=connection.getSqLength();
			double radiusSumSq=(r+b.r); radiusSumSq*=radiusSumSq;
			
			if(distSq<radiusSumSq){
				//TOUCH
				//normalize the vector connecting the middle points of the two balls
				connection=connection.normalize();
				
				//now calculate all the components parallel to the connection
				
				double this_parallel=v.dot(connection);
				double b_parallel=b.v.dot(connection);
				
				//check if the balls are moving towards each other
				if(this_parallel-b_parallel<0){
					//COLLISION
					//ortho-components of the velocities do not change
					Vector3D this_ortho=v.sub(connection.mul(this_parallel));
					Vector3D b_ortho=b.v.sub(connection.mul(b_parallel));
					
					//now some physics are required to calculate new parallel components
					//it is the velocity of the b-ball after the collision:
					double temp=(2*m*this_parallel+(b.m-m)*b_parallel)/(m+b.m)*b.e;
					//and this is the new velocity of "this":
					this_parallel=(2*b.m*b_parallel+(m-b.m)*this_parallel)/(m+b.m)*e;
					//copying temp into b_parallel: not necessary but better for the reader
					b_parallel=temp;
					
					//combine all components to new velocities again
					v=connection.mul(this_parallel).add(this_ortho);
					b.v=connection.mul(b_parallel).add(b_ortho);
				}
				
			}
		}
		
		public void draw(Graphics g){
			g.setColor(color);
			g.fillOval((int)(x.x-r),(int)(x.y-r), (int)(2*r), (int)(2*r));
		}
	}
	
	private static class BallMotionThread extends Thread{
		private AutoAiming component;
		private Graphics imageGraphics;
		private Rectangle bounds;
		private long timer;
		private Ball[] balls;
		
		private final static int SHOTS=80;
		
		public BallMotionThread(AutoAiming c, Rectangle rect){
			component=c;
			bounds=rect;
			imageGraphics=c.backBuffer.getGraphics();
			
			//the "shots"
			balls=new Ball[SHOTS+2];
			for(int i=0; i<balls.length; i++){
				balls[i]=new Ball(new Vector3D(20+i*7,900,0),
									new Vector3D(0,0,0),
									3, 0.0001, 1, 0, Color.BLACK);
			}
			//the "victim"
			balls[0]=new Ball(new Vector3D(20,20,0),
								new Vector3D(0.1,0.07,0),
								15, 100,1,0,Color.RED);
			//the "canon"
			balls[1]=new Ball(new Vector3D(50,550,0),
					new Vector3D(0,0,0),
					15, 500,1,0,Color.GREEN);
		}
		
		public void run(){
			
			long elapsedTime;
			timer=System.currentTimeMillis();
			
			long timeSinceLastShot=0;
			int lastShotIndex=2;
			
			while(true){
				elapsedTime=-timer+(timer=System.currentTimeMillis());
				timeSinceLastShot+=elapsedTime;
				//cls
				imageGraphics.setColor(Color.WHITE);
				imageGraphics.fillRect(bounds.x,bounds.y,bounds.width,bounds.height);
				
				for(int i=0; i<balls.length; i++){
					for(int j=i+1; j<balls.length; j++){
						balls[i].collision(balls[j]);
					}
					balls[i].move(elapsedTime, bounds, component.mouse);
					balls[i].draw(imageGraphics);
				}
				
				//AUTOAIMING
				
				double shotVelocity=0.17;
				Ball victim=balls[0];
				Ball cannon=balls[1];
				
				if(timeSinceLastShot>60){
					//bureaucracy
					timeSinceLastShot=0;
					lastShotIndex++;
					lastShotIndex=(lastShotIndex>=2+SHOTS)?(2):(lastShotIndex);
					//shoot
					Vector3D connection=victim.x.sub(cannon.x); //connection vector cannon-victim
					Vector3D ortho=Vector3D.eZ.cross(connection); //orthogonal to the connection Vector
					ortho.z=0; //just to make sure that everything is still on the 2D-plane...
					double connectionLength=connection.getLength();
					double f_ortho=victim.v.dot(ortho)/(shotVelocity*connectionLength);
					double f_parallel=Math.sqrt(1-f_ortho*f_ortho);	//normalized direction-vector component-factors
					Vector3D shotVelocityVector=ortho.mul(shotVelocity*f_ortho/connectionLength).
						add(connection.mul(shotVelocity*f_parallel/connectionLength));
					
					balls[lastShotIndex].x=cannon.x.add(shotVelocityVector.normalize().mul(victim.r*0.9));
					balls[lastShotIndex].v=shotVelocityVector;
				}
				
				// AUTOAIMING-END
				
				component.getGraphics().drawImage(
						component.backBuffer,0,0,component.getWidth(),component.getHeight(),component);
				
				try{
					sleep(1);
				}catch(InterruptedException e){}
				
			}
		}
	}
	
	//member vars
	BallMotionThread thread;
	
	public void init(){
		
		backBuffer=new BufferedImage(this.getWidth(),this.getHeight(),BufferedImage.TYPE_INT_RGB);
		mouse=new Vector3D(0,0,0);
		addMouseMotionListener(this);
		thread=new BallMotionThread(this, this.getBounds());
		thread.start();
		
	}
	
	public void mouseMoved(MouseEvent e){
		mouse.x=e.getX();
		mouse.y=e.getY();
	}
	
	public void mouseDragged(MouseEvent e){}
	
	public void destroyed(){}
}
```

dieses programm ist nicht komplett neugeschrieben, dieses ganze framework und ball-kollisionen waren schon da wegen dieser frage

in demselben thread (ende 1 seite) ist auch der code für Vector3D zu finden, den brauchst du auch zum compilieren.

Damit du in etwa weißt, was denn da überhaupt zu sehen ist: da sind zwei bälle "opfer" und "kanone". Kanone beschießt das Opfer mit schwarzen kreisen, und zwar nicht irgendwie, sondern mit auto-aiming  .

Vieles am code ist recht überflüssig (da sind noch irgendwelche listener u.ä. ) achte nicht darauf, das sind nur artefakte. Wichtig ist was im //AUTOAIMING block (zeilen 161-186) steht, den rest darfst du ruhig unbeachtet lassen.
balls[] ist ein array mit Bällen, x ist position, v ist die geschwindigkeit, der restliche kram wird nicht benötigt.

Tipp zur herleitung: Führe ein komfortables koordinatensystem ein: eine achse parallel zur verbindungsstrecke, und die zweite achse orthogonal dazu (im code: connection und ortho) In diesem Koordinatensystem muss gelten: Y-Komponente der schuss-geschwindigkeit= Y-komponente der Ziel-geschwindigkeit. Danch lässt sich das in 5 zeilen auflösen. :toll: 

Hoffentlich hilfts dir weiter.


----------



## lohr (2. Apr 2008)

Guten Morgen 

Jetzt bin ich erstmal baff ^^
Wirklich gut...also im grunde genommen versteh ich den code nur noch 2 Fragen dazu.

- Wieso benötigt man für eine 2D Berechnung (spielt doch alles im 2D bereich wenn ich das richtig sehe,oder ^^) einen 3D Pfeil?
- Wieso Kann ich net einfach das normale Koordinatensystem (normal = Java Koordinatensystem), da müsste doch die Berechnung wo das Ziel sich gerade befinden auch machbar sein?

Naja muss mir das heute Abend anschauen in der Arbeit wären sie da glaub ich net so begeistert wenn an meinem Bildschirm erstmal 2 Bälle rumspringen und sich gegenseitig abschießen 
Vielen Dank für deine Hilfe


----------



## 0x7F800000 (2. Apr 2008)

1) 3D brauchst du auch nicht, es wäre natürlich besser, alles für 2D zu optimieren, aber ich bin einfach zu faul um für solche demonstrationszwecke extra eine 2D klasse zu schreiben, hab deswegen meine alte gute 3D-Vektorpfeil-klasse genommen. 

2)um die ganzen positionen abzuspeichern kannst du selbstverständlich irgendein beliebiges koordinatensystem nehmen, das dir gerade sinnvoll erscheint, eines, das mit bildschirmkoordinaten übereinstimmt ist in den fällen optimal, wenn man nicht vorhat, die ganze karte drehbar zu machen (hab sowas ehrlich gesagt noch nie bei 2D gesehen, normalerweise dreht sich der charakter, bei Strategiespielen ist die Karte sowieso meist nicht drehbar, damit man sich leichter orientieren kann)

Was ich mit dem koordinatensystem gemeint habe ist: für die *herleitung* von auto-aiming sollte man von anfang an ein geeignetes koordinatensystem wählen. Wenn man sich das mit bleistift und papier alles hergeleitet hat, dann hat man das ergebnis, dann kan man das koordinatensystem getrost wieder vergessen.

ps: hoffentlich sind die arbeitsgeber wenigstens davon begeistert, wenn die mitarbeiter in irgendwelchen foren rumhocken und jede freie minute nutzen um sich weiterzubilden


----------



## lohr (2. Apr 2008)

So hab ich mir auch die beiden antworten vorgestellt ^^
Ich denke das der Arbeitgeber da weniger dagegen hat, Foren sind wirklich wirklich wirklich usefull  Als ich LabView angefangen hab zu lernen, bin ich glaub ich an einem normalen 8h Tag 6h im Forum unterwegs gewesen ^^

Naja back on topic, also ich werd das wie gesagt heute abend testen und wenn ich noch lustig bin schreib ich es auf 2D um  falls ich das tue schreib ich meine Lösung hier noch mitrein


----------

