# 2D Shooter (von oben) Kugelberechnung und drehen der Figur



## florian1995 (18. Aug 2010)

hallo!
ich will einen 2d shooter in einem Jframe programmieren.
dabei soll sich die figur an der maus ausrichten. habs schon gegooglet aber nichts gefunden.
die kugeln sollen bei einem mausklick in richtung maus fliegen.

kann mir jmd ein codebeispiel nennen oder ein tutorial? die figur ist ein image.


----------



## Quaxli (18. Aug 2010)

Mit anderen Worten: Du hast noch nie ein Spiel programmiert. :question::question::question:


----------



## florian1995 (18. Aug 2010)

DOCH!
ich weiß nur nicht wie man die kugeln berechnet und ein image an der maus ausrichtet!! hab mir zwar eine berechnungsmethode ausgedacht diese ist jedoch sehr ungenau


----------



## Tomate_Salat (18. Aug 2010)

naja, das sollte mit einfacher Steigunsberechung funktioneren:

[c]m = (y2-y1)/(x2-x1)[/c]

wobei dann die eine Koordinate deine Figur ist und die andere die Maus. Dann musste dir halt noch [c]b[/c] ausrechnen. Die Formel ist ja bekannt:
[c]f(x) = mx+b[/c] => [c]b = y/mx[/c]

MFG

Tomate_Salat


----------



## florian1995 (18. Aug 2010)

frage: was ist m?
also fasse ich das richtig auf?
m= mausx+mausy/playerx+playery?
kapier das nicht so richtig

ich wollte es so machen das es ein xspeed und ein yspeed gibt


----------



## Gast2 (18. Aug 2010)

m ist die Steigung deiner Geraden.



> m= mausx+mausy/playerx+playery?


So ist das falsch.

```
m = mausy - playery / mausx - playerx
```
 passt schon eher. Du musst allerdings mal schauen wie das passt wenn die maus rechts/links/unten/oben vom player ist.

dein xSpeed und ySpeed ansatz sollte übrigens auch auf nen ähnlichen Ansatz kommen.


----------



## florian1995 (18. Aug 2010)

kann man theoretisch sagen

```
yspeed=m 
xspeed=mousex-playerx[code=Java]
```


----------



## florian1995 (18. Aug 2010)

ok ich brauch jz mal hilfe!

```
public Shot(int playerx,int playery,int mousex,int mousey){
 //hier xspeed und yspeed berechnen
}

public void moveShot(){
 x+=xspeed;
 y+=yspeed;
}
```
hoffe jemand kann mir sagen wie ich das jetzt berechne


----------



## Steev (18. Aug 2010)

*Dreieck ? Wikipedia*

Im Grunde genommen kannst du das doch über die gängigen Dreieckssätze lösen.
Du hast die Position des Spielers (Mittelpunkt) = P1 und du hast die Position des Cursors = P2. Alle anderen Punkte und Größen kannst du daraus ableiten.
Dann kannst du mithilfe der Winkelsätze den Winkel berechnen und anhand des Winkels das Bild ausrichten. Per AffineTransform z.B. (Achtung: Bogenmaß)

Foundation Flash: - Rotation in AS3

Gruß
Steev


----------



## florian1995 (18. Aug 2010)

ok danke für die antwort 
nur das problem ist das ich erst 15 bin und dadurch noch nicht so viel höhere mathematik behersche.
ich kenne zwar die winkelsätze hab sie aber noch nie in einem game angewendet ;(

ich weiß wie affinetransform funktioniert nur weiß ich nicht wie ich die grad-zahl bekomme


----------



## florian1995 (18. Aug 2010)

edit:
jetzt verstehe ich was du meinst 
ich sehe mal ob es funktioniert


----------



## Steev (18. Aug 2010)

Müsste in etwa so funktionieren: (nicht getestet)

[Java]double ang = Math.atan2(pos1X - pos2X, pos1Y - pos2Y) / (Math.PI / 180);[/Java]

Gruß
Steev


----------



## Quaxli (18. Aug 2010)

florian1995 hat gesagt.:


> ok danke für die antwort
> nur das problem ist das ich erst 15 bin und dadurch noch nicht so viel höhere mathematik behersche.
> ich kenne zwar die winkelsätze hab sie aber noch nie in einem game angewendet ;(
> 
> ich weiß wie affinetransform funktioniert nur weiß ich nicht wie ich die grad-zahl bekomme



Das ist keine höhere Mathemathik. Sinus, Cosinus, Tangens. Die Begriffe hast Du bestimmt schon mal gehört? 

Das was Du vorhast besteht aus 2 Schritten:

1. Den aktuellen Winkel vom Spieler zum Mauszeiger berechnen und
2. das Ganze wieder rückwärts: Mit Hilfe der gewünschten Geschwindigkeit des Schusses und dem Winkel die x-/y-Geschwindigkeit errechnen.


----------



## Quaxli (18. Aug 2010)

Wollen wir mal nicht so sein....
Unten ein kleines, einfaches Beispiel, das die Geschichte demonstriert. In dem Fall wird immer aus der linken unteren Ecke geschossen und jeder neue Schuß "resettet" diesen. In einem Spiel mit beweglicher Figur ist das dann natürlich aufwändiger, aber es soll ja nur ein Beispiel sein und Du sollst ja auch noch was zu tun haben.


```
import java.awt.event.*;
import java.awt.geom.Rectangle2D;

import javax.swing.*;
import java.awt.*;

public class ShotExample extends JPanel implements Runnable, MouseMotionListener, MouseListener {

	private static final long	serialVersionUID	= 1L;
	JFrame frame;
	Point target;
	double angle;
	Shot shot;
	boolean fire = false;
	
	public static void main(String[] args) {
		new ShotExample(400,400);
	}
	
	public ShotExample(int i, int j) {
		 frame = new JFrame("ShotExample");
		 frame.setLocationRelativeTo(null);
		 setPreferredSize(new Dimension(i,j));
		 addMouseMotionListener(this);
		 addMouseListener(this);
		 frame.add(this);
		 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		 frame.pack();
		 frame.setVisible(true);
		 
		 target = new Point(0,0);
		 fire = false;
		 
		 Thread th = new Thread(this);
		 th.start();
		 
	}

	public void run() {

		long last = 0;
		long delta = 0;
		last = System.nanoTime();
		
     while(frame.isVisible()){
    	 
    	 delta = System.nanoTime() - last;
    	 last = System.nanoTime();
    	 
    	 computeAngle();
    	 checkShot();
    	 
    	 if(shot!=null){
      	 shot.move(delta);
    	 }
    	 
    	 try {
				Thread.sleep(10);
			} catch (InterruptedException e) {}
    	
			repaint();
    	 
     }
		
	}
	
	
	private void computeAngle(){
		
		double dx = target.getX();
		double dy = getHeight()-target.getY();
		
		//Java rechnet mit Radians, daher Tangens nach Grad umrechnen
		angle = Math.toDegrees(Math.atan2(dx, dy));

	}
	
	private void checkShot(){
		
		if(!fire){
			return;
		}
		fire = false;
		shot = new Shot(0,getHeight(),angle);
		
	}
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		g.setColor(Color.RED);
		
		if(shot!=null){
			g.drawRect((int)shot.x,(int)shot.y,(int)shot.width,(int)shot.height);
		}
	}
	
	public void mouseDragged(MouseEvent e) {
		
	}

	public void mouseMoved(MouseEvent e) {
		target = e.getPoint();
	}

	public void mouseClicked(MouseEvent e) {
		
		
	}

	public void mouseEntered(MouseEvent e) {
		
		
	}

	public void mouseExited(MouseEvent e) {
		
		
	}

	public void mousePressed(MouseEvent e) {
		
		
	}

	public void mouseReleased(MouseEvent e) {
		fire = true;
	}
	

}

class Shot extends Rectangle2D.Double{
	
	private static final long	serialVersionUID	= 1L;
	final static int SIZE = 10;
	final static int SPEED = 200;
	
	double dx;
	double dy;

	public Shot(int sx, int sy, double dir){
		super(sx-SIZE/2,sy-SIZE/2,SIZE,SIZE);
		computeDeltas(dir);
	}
	
	private void computeDeltas( double d){
		//Sinus u. Cosinus ausrechnen. Hypothenuse ist die Geschwindigkeit
		//evtl. einfach mal ausmalen
		dx = Math.sin(Math.toRadians(d)) * SPEED;
		dy = Math.cos(Math.toRadians(d)) * SPEED;
		dy *= -1; //Bewegung nach oben - daher y invertieren
	}
	
  public void move(long delta) {
    if (dy != 0) {
        y += dy * (delta / 1e9);
    }
    
    if (dx != 0) {
        x += dx * (delta / 1e9);
    }
}
	
}
```


----------



## florian1995 (19. Aug 2010)

ok danke!
werde ich bei gelegenheit mal ausprobieren


----------



## florian1995 (19. Aug 2010)

so habs jetzt getestest.

```
public Shot(int x, int y,int mouse_x,int mouse_y,GamePanel p){
        this.x=x;
        this.y=y;
        this.p=p;
        double dx = mouse_x;
        double dy = mouse_y;
        if(mouse_x<x){
            dx*=-1;
        }else{
            //startposition des balles vor oder nach der figur
            this.x+=p.radius;
        }
        if(mouse_y<y){
            dy*=-1;
        }else{
            this.y+=p.radius;
        }

        alpha = Math.toDegrees(Math.atan2(dx, dy));
        xspeed = Math.sin(Math.toRadians(alpha)) * maxspeed;
        yspeed = Math.cos(Math.toRadians(alpha)) * maxspeed;
        
        
        
    }
```

jetzt habe ich das problem dass es einen toten winkel hinter dem spieler gibt.
was ist mein fehler?


----------



## Quaxli (20. Aug 2010)

Erklär das mal näher aus dem Stück Code werde zumindest ich nicht schlau.
Aus dem Code überigens auch nicht:


```
public Shot(int x, int y,int mouse_x,int mouse_y,GamePanel p){
        this.x=x;
        this.y=y;
        this.p=p; //Sinn und Zweck dieser 3 Anweisungen?
        double dx = mouse_x;
        double dy = mouse_y; 
        //Was ist dx und dy? Scheint sich um einen Bewegungswert zu handeln, aber Du
       //übergibst wohl irgendwie die Mausposition
        if(mouse_x<x){
            dx*=-1;
        }else{
            //startposition des balles vor oder nach der figur
            this.x+=p.radius;
        }
        if(mouse_y<y){
            dy*=-1;
        }else{
            this.y+=p.radius;
        }
 
        alpha = Math.toDegrees(Math.atan2(dx, dy));  //warum hier Math.toDegrees?
        xspeed = Math.sin(Math.toRadians(alpha)) * maxspeed; //hier wird das gerad wieder rückgängig gemacht
        yspeed = Math.cos(Math.toRadians(alpha)) * maxspeed;
        
        
        
    }
```


----------



## Samuel72 (22. Aug 2010)

Hallo Florian,

ich würde das ganze ohne Winkel machen,
sondern einfach mit dem Steigungsdreieck:


```
public Shot(double playerx, double playery, double mousex, double mousey){
 xspeed = (mousex-playerx)/Math.sqrt((playerx-mousex)*(playerx-mousex)+(playery-mousey)*(playery-mousey));
 yspeed = (mousey-playery)/Math.sqrt((playerx-mousex)*(playerx-mousex)+(playery-mousey)*(playery-mousey));

}

public void moveShot(){
 x+=xspeed;
 y+=yspeed;
}
```
Für die Variablen würde ich grundsätzlich double verwenden, da bei Integern der Wert leicht einmal 0 wird, und dann gibt es gar keine Bewegung.


----------

