# Space Invaders Problem



## Degelsegger (4. Jun 2011)

Hallo Freunde! Ich bin gerade am ausprogrammieren des Spiels Space Invaders und habe ein kleines Problem:
Beim erzeugen der Gegner verwende ich einen Parser der durch ein vom mir angegebenes Textfeld geht und dann je nach Buchstabe einen Gegner erzeugt. Gestern habe ich wieder beim Programm weiter gearbeitet und habe versehentlich einen Fehler eingebaut, den ich jetzt nicht mehr finden kann.
Fehler befindet sich vermutlich in MyGameField oder in einer der Enemie Klassen. 

Danke im Voraus




```
// My Game :
import javax.swing.*;
import java.awt.*;

public class MyGame {
	private JFrame f;
	private MyGameField field;
	
	public static void main(String[] args) {
		new MyGame().start();
	}
	
	public void start() {
		f = new JFrame("Space Invaders");
		
		Container c = f.getContentPane();
		c.setLayout(new BorderLayout());
		field = new MyGameField();
		c.add(field, BorderLayout.CENTER);
		
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(800, 800);
		f.setVisible(true);
		f.setResizable(false);
		
		field.start();
	}
	
}

//Figure:

import java.awt.*;
import java.util.*;

public abstract class Figure {
	protected Rectangle bounds;
	int speedX;
	int speedY;
	public Figure(int x, int y, int w, int h) {
		bounds = new Rectangle(x, y, w, h);
	}
	
	public abstract void draw(Graphics g);
	
	public void invertDirection(ArrayList<Figure> figures, boolean left, boolean right){
	}
	public void move() {
	}
	public void fire(){
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
	}
	
	public void collisionWall(boolean left, boolean right, boolean top, boolean bottom) {
		if(right) {
			speedX = -Math.abs(speedX);
			bounds.y += 44;
			
		}
	}
	
	public int getXPos() {
		return bounds.x;
	}
	public int getYPos() {
		return bounds.y;
	}
	public int getWidth() {
		return bounds.width;
	}
	public int getHeight() {
		return bounds.height;
	}
	public Rectangle getBounds() {
		return bounds;
	}
}

//Enemie A-D:
import java.awt.*;
import java.util.*;

public class EnemieA extends Figure {
	Image EnemieAimg;
	Image EnemieA2img;
	int speedX;
	int speedY;
	public EnemieA(int x, int y, int sx, int sy) {
		super(x, y, 44, 36);
		speedX = sx;
		speedY = sy;
		int cnt = 0;
		EnemieAimg = Toolkit.getDefaultToolkit().getImage("EnemieA.jpg");
		EnemieA2img = Toolkit.getDefaultToolkit().getImage("EnemieA2.jpg");
	}
	public void draw(Graphics g) {
		g.drawImage(EnemieAimg, bounds.x, bounds.y, null);
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof Fire){
			removeList.add(this);
		}
	}
	public void move() {
			bounds.x += speedX;
			bounds.y += speedY;
	}
	
	public void invertDirection(ArrayList<Figure> figures, boolean left, boolean right, int speedX){
		int size = figures.size();
		System.out.println("Aufgerufen");
		for(int i = 0; i < size; i++){
			Figure f = figures.get(i);
			f.bounds.y += 44;
			speedX = -Math.abs(speedX);
			}
	}
	public void collisionWall(boolean left, boolean right, boolean top, boolean bottom, ArrayList<Figure> figures) {
		if(left) {
			invertDirection(figures, left, right);
			System.out.println("Aufgerufen");
		}
		if(right) {
			invertDirection(figures, left, right);
			System.out.println("Aufgerufen");
		}
		if(top) {
		}
		if(bottom) {
		}
	}
}

import java.awt.*;
import java.util.*;

public class EnemieB extends Figure {
	int a = 0;
	int speedX;
	int speedY;
	Image EnemieBimg;
	public EnemieB(int x, int y, int sx, int sy) {
		super(x, y, 44, 36);
		speedX = sx;
		speedY = sy;
		
		EnemieBimg = Toolkit.getDefaultToolkit().getImage("EnemieB.jpg");
	}
	public void draw(Graphics g) {
		g.drawImage(EnemieBimg, bounds.x, bounds.y, null);
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof Fire){
			a ++;
			while(a == 2) {
				removeList.add(this);
				a = 0;
			}
		}
	}
	public void move() {
			bounds.x += speedX;
			bounds.y += speedY;
	}
	
	public void collisionWall(boolean left, boolean right, boolean top, boolean bottom) {
		if(left) {
			speedX = Math.abs(speedX);
			bounds.y += 44;
		}
		if(right) {
			speedX = -Math.abs(speedX);
			bounds.y += 44;
		}
		if(top) {
			speedY = Math.abs(speedX);
		}
		if(bottom) {
			speedY = -Math.abs(speedX);
		}
	}
}

import java.awt.*;
import java.util.*;

public class EnemieC extends Figure {
	Image EnemieCimg;
	MyGameField field;
	int speedX;
	int speedY;
	public EnemieC(int x, int y, int sx, int sy) {
		super(x, y, 44, 36);
		speedX = sx;
		speedY = sy;
		EnemieCimg = Toolkit.getDefaultToolkit().getImage("EnemieC.jpg");
	}
	public void draw(Graphics g) {
		g.drawImage(EnemieCimg, bounds.x, bounds.y, null);
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof Fire){
			removeList.add(this);
		}
	}
	
	public void move() {
			bounds.x += speedX;
			bounds.y += speedY;
			
	}
	
	public void collisionWall(boolean left, boolean right, boolean top, boolean bottom) {
		if(left) {
			speedX = Math.abs(speedX);
			bounds.y += 44;
		}
		if(right) {
			speedX = -Math.abs(speedX);
			bounds.y += 44;
		}
		if(top) {
			speedY = Math.abs(speedX);
		}
		if(bottom) {
			speedY = -Math.abs(speedX);
		}
	}
}

import java.awt.*;
import java.util.*;

public class EnemieD extends Figure {
	Image EnemieDimg;
	MyGameField field;
	int speedX;
	int speedY;
	public EnemieD(int x, int y, int sx, int sy) {
		super(x, y, 44, 36);
		speedX = sx;
		speedY = sy;
		EnemieDimg = Toolkit.getDefaultToolkit().getImage("EnemieD.jpg");
	}
	public void draw(Graphics g) {
		g.drawImage(EnemieDimg, bounds.x, bounds.y, null);
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof Fire){
			removeList.add(this);
		}
	}
	
	public void move() {
			bounds.x += speedX;
			bounds.y += speedY;
			
	}
	
	public void collisionWall(boolean left, boolean right, boolean top, boolean bottom) {
		if(left) {
			speedX = Math.abs(speedX);
			bounds.y += 44;
		}
		if(right) {
			speedX = -Math.abs(speedX);
			bounds.y += 44;
		}
		if(top) {
			speedY = Math.abs(speedX);
		}
		if(bottom) {
			speedY = -Math.abs(speedX);
		}
	}
}

//MyGameField:


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

public class MyGameField extends JComponent implements Runnable {
	private Thread aniTh;
	ArrayList<Figure> figures;
	public static final String[] feld1 =
		new String[] {
			"AC",
			"BAC",
			"CAB",
			"X",
		};
	

	public MyGameField() {
		figures = new ArrayList<Figure>();
		figures.add(new Bar(this));
		
		int y = 25;
		for (int i = 0; i < feld1.length; i ++) {
			String line = feld1[i];
			int x = 25;
			for (int j = 0; j < line.length(); j ++) {
				char fig = line.charAt(j);
				switch(fig) {
					case 'A': figures.add(new EnemieA(x, y, 2, 0));
					break;
					case 'B': figures.add(new EnemieB(x, y, 2, 0));
					break;
					case 'C': figures.add(new EnemieC(x, y, 2, 0));
					break;
					case 'X': figures.add(new Baricade(x, y, 0, 0));
					break;
					}
				}
				x += 50;
			}
			y += 50;
	}

	public void start() {
		aniTh = new Thread(this);
		aniTh.start();
	}

	public void paint(Graphics g) {
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, getWidth(), getHeight());
		for (int i = 0; i < figures.size(); i ++) {
			figures.get(i).draw(g);
		}
	}

	public void collisionDetection() {
		int size = figures.size();
		for (int i = 0; i < size; i ++) {
			Figure f = figures.get(i);
			boolean left = false, right = false;
			boolean top = false, bottom = false;
			if (f.getXPos() < 0) { // Koll. links
				left = true;
			}
			if (f.getYPos() < 0) { // Koll. oben
				top = true;
			}
			if (f.getXPos() + f.getWidth() > getWidth()) { // Koll. rechts
				right = true;
			}
			if (f.getYPos() + f.getHeight() > getHeight()) { // Koll. unten
				bottom = true;
			}
			f.collisionWall(left, right, top, bottom);
		}
		ArrayList<Figure> removeList = new ArrayList<Figure>();
		ArrayList<Figure> addList = new ArrayList<Figure>();
		for (int i = 0; i < size; i ++) {
			Figure f1 = figures.get(i);
			Rectangle b1 = f1.getBounds();
			for (int j = i + 1; j < size; j ++) {
				Figure f2 = figures.get(j);
				Rectangle b2 = f2.getBounds();
				if (b1.intersects(b2)) {
					f1.collidesWith(f2, removeList, addList);
					f2.collidesWith(f1, removeList, addList);
				}
			}
		}
		figures.removeAll(removeList);
		figures.addAll(addList);
	}

	public void run() {
		while (true) {
			for (int i = 0; i < figures.size(); i ++) {
				figures.get(i).move();
			}
			collisionDetection();
			repaint();
			try {
				Thread.sleep(20);
			}
			catch (InterruptedException ex) {
			}
		}
	}
	
	public void addFigure(Figure f){
		figures.add(f);
	}
}

//Bar:

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

public class Bar extends Figure implements MouseMotionListener, MouseListener{
	
	MyGameField field;
	Image shipImg;
	public Bar(MyGameField field){
		super(100, 600, 60, 50); // Werte Rammy bar.jpg
		shipImg = Toolkit.getDefaultToolkit().getImage("Ship.jpg");
		this.field = field;
		field.addMouseMotionListener(this);
		field.addMouseListener(this);
	}
	public void draw(Graphics g){
//		g.setColor(Color.BLUE);
//		g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
		g.drawImage(shipImg, bounds.x, bounds.y, null); //NULL für ImageObserver
	}
	
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof EnemieA || f instanceof EnemieB || f instanceof EnemieC) {
			boolean GameOver = false;
			if(GameOver == true) {
				System.out.print("Verloren!");
			}
		}
	}
	
	public void collisionWall(boolean left, boolean right, boolean top, boolean bottom) {
	}
	
	public void mouseDragged(MouseEvent e){
		mouseMoved(e);
	}
	
	public void mouseMoved(MouseEvent e){
		int x = e.getX();
		int y = e.getY();
		bounds.x = x - bounds.width / 2;
		//bounds.y = y - bounds.height / 2;
	}
	
	public void mouseClicked(MouseEvent e){
	}
	
	public void mouseEntered(MouseEvent e){
	}
	
	public void mouseExited(MouseEvent e){
	}
	public void mousePressed(MouseEvent e){
		Fire f = new Fire(bounds.x + bounds.width/2, bounds.y - 20);
		field.addFigure(f);
	}
		
	public void mouseReleased(MouseEvent e){
	}
}

//Fire:

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

public class Fire extends Figure{
	public Fire(int x, int y){
		super(x, y, 5, 25);
	}
	public void draw(Graphics g){
		g.setColor(Color.RED);
		g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
	}
	
	public void move(){
		bounds.y = bounds.y - 20;
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof EnemieA) {
			removeList.add(this);
		}
		if (f instanceof EnemieC) {
			removeList.add(this);
		}
		if (f instanceof EnemieB) {
			removeList.add(this);
		}
		if (f instanceof Baricade){
			removeList.add(this);
		}
	}
}

//Baricade:

import java.awt.*;
import java.util.*;

public class Baricade extends Figure {
	int cnt = 0;
	Image Baricadeimg1;
	Image Baricadeimg2;
	Image Baricadeimg3;
	Image Baricadeimg4;
	Image Baricadeimg5;
	
	public Baricade(int x, int y, int sx, int sy) {
		super(x, y, 80, 40);
		Baricadeimg1 = Toolkit.getDefaultToolkit().getImage("Baricade1.jpg");
		Baricadeimg2 = Toolkit.getDefaultToolkit().getImage("Baricade2.jpg");
		Baricadeimg3 = Toolkit.getDefaultToolkit().getImage("Baricade3.jpg");
		Baricadeimg4 = Toolkit.getDefaultToolkit().getImage("Baricade4.jpg");
		Baricadeimg5 = Toolkit.getDefaultToolkit().getImage("Baricade5.jpg");
	}
	public void draw(Graphics g) {
		if (cnt <= 2) {
			g.drawImage(Baricadeimg1, bounds.x, bounds.y, null);
		}
		if (cnt > 2 && cnt <= 5){
			g.drawImage(Baricadeimg2, bounds.x, bounds.y, null);
		}
		if (cnt > 5 && cnt <= 7){
			g.drawImage(Baricadeimg3, bounds.x, bounds.y, null);
		}
		if (cnt > 7 && cnt <= 9){
			g.drawImage(Baricadeimg4, bounds.x, bounds.y, null);
		}
		if (cnt > 8 && cnt <= 10){
			g.drawImage(Baricadeimg4, bounds.x, bounds.y, null);
		}
	}
	
	public void collidesWith(Figure f, ArrayList<Figure> removeList, ArrayList<Figure> addList) {
		if (f instanceof Fire){
			cnt ++;
			if(cnt == 10) {
				removeList.add(this);
			}
		}
	}
}
```


P.S.: Bilder müsst ihr euch selber welche unter jeweiligen Namen einfügen.


----------



## XHelp (4. Jun 2011)

Degelsegger hat gesagt.:


> Gestern habe ich wieder beim Programm weiter gearbeitet und habe versehentlich einen Fehler eingebaut, den ich jetzt nicht mehr finden kann.
> Fehler befindet sich vermutlich in MyGameField oder in einer der Enemie Klassen.



Und "Fehler" heißt bitte was?
Darüber hinaus steht auf der Seite in *DEZENTER ROTER SCHRIFT* was über die Verwendung von Java-Tags, was man eigentlich nicht so leicht übersehen kann.


----------



## Degelsegger (4. Jun 2011)

Sorry, ist das erste mal das ich was in einem Forum poste 

Der Fehler ist das die Gegner Objekte nicht mehr richtig erzeugt werden, bzw wird nur ein Gegner vom Typ B im linken oberen Eck erzeugt und der Rest nicht.


----------



## XHelp (4. Jun 2011)

Degelsegger hat gesagt.:


> Sorry, ist das erste mal das ich was in einem Forum poste



Macht nichts, dann kannst du es ja noch nachträglich ändern.


----------



## Degelsegger (4. Jun 2011)

Muss leider dringend weg. Versuche, heute am Abend den Quelltext zu senden. Danke mal vorläufig!


----------



## Degelsegger (4. Jun 2011)

Also, was soll ich dir jetzt schicken?


----------



## XHelp (4. Jun 2011)

Gar nichts. Du sollst nachträglich die JAVA-Tags in deinem 1. Post setzen.


----------



## Degelsegger (5. Jun 2011)

Passts jetzt?


----------



## Volvagia (5. Jun 2011)

Du hast einen Fehler eingebaut. Das ist normal, Fehler gehören zum Programmieren, sonst wärs ja langweilig. Was passiert, wenn du was machst, und was sollte passieren?


----------



## Degelsegger (5. Jun 2011)

Volvagia hat gesagt.:


> Du hast einen Fehler eingebaut. Das ist normal, Fehler gehören zum Programmieren, sonst wärs ja langweilig. Was passiert, wenn du was machst, und was sollte passieren?



Okey wie du von Zeile 296 bis 299 lesen kannst habe ich da ein Paar Buchstaben reingeschrieben, die jeweils für eine Art von Figur stehen. 
Z.b.: Wenn ein A da steht dann soll an dieser Stelle ein Gegner vom Typ A erzeugt werden. Dann werden x- und y-Koordinaten verändert und es wird der nächste Buchstabe eingelesen und an den jeweiligen Koordinaten wird dann wieder die Figur ausgegeben.

Wenn ich dann das Programm ausführe sollten eigentlich dann die Gegner alle an ihren Positionen stehen.
Jetzt habe ich aber gestern weiterprogrammiert und wollte noch einen Typ von Gegnern hinzufügen und da ist mir irgendwo ein Fehler unterlaufen (voraussichtlich in der Klasse MyGameField). Und ich kann ihn wirklich nicht mehr finden. 
Es kompiliert doch wenn ich es ausführe steht nur ein Typ von Gegnern im Eck links oben auch wenn ich mehrere gezeichnet habe.


----------



## Volvagia (5. Jun 2011)

Was mir bis jetzt aufgefallen ist, dass x += 50; und y += 50; an der falschen Position sind.


----------



## Degelsegger (5. Jun 2011)

Nein, wieso? Zuerst wird geprüft ob die Zeile aus ist, wenn nicht geht es in die innere Schleife und der jedes Objekt geprüft wird -->  nach jeder Überprüfung werden die x Koordinaten geändert. 
Und wenn eine Zeile aus ist werden die y Koordinaten geändert.


----------



## Volvagia (5. Jun 2011)

Ne. x wird erst nach der Char-Schleife geändert und sofort danach wieder ungültig, y wird am Ende des Konstruktors verändert. Kontrolliere die Klammern.


----------



## Degelsegger (5. Jun 2011)

Danke, das wars!


----------



## Degelsegger (5. Jun 2011)

Noch ein zweites Problem würde ich hier gerne posten (hat eh auch mit diesem Prog zu tun).
Vielleicht kennt ihr das Spiel Space Invaders und die Bewegung der Gegner, wäre sicherlich zur Lösung dieses Problems von Vorteil.
Folgendes:
Die Bewegung die die Gegner machen, sollte so aussehen dass wenn ein Gegner die Wand berührt alle Gegner eine Zeile nach unten gehen und ihre Richtung ändern.
Das habe ich auch schon ausprogrammiert und beim Typ A von Gegnern eingefügt, doch dieser ruft die Methode jedoch nicht auf und fährt einfach schräg nach unten aus dem Feld raus. Die Klasse heißt InvertDirection und ist von Zeile 112 bis 119. Der Aufruf findet den Zeilen 121 bis 129 statt.
Wieso ruft er die nicht auf?

Vielleicht könnt ihr mir nochmal so schnell und erfolgreich helfen wie bei dem ersten Problem.

Danke im Voraus!


----------



## Fu3L (5. Jun 2011)

```
public void invertDirection(ArrayList<Figure> figures, boolean left, boolean right, int speedX){
        int size = figures.size();
        System.out.println("Aufgerufen");
        for(int i = 0; i < size; i++){
            Figure f = figures.get(i);
            f.bounds.y += 44;
            speedX = -Math.abs(speedX);
            }
    }
```

Das Erste Problem: 
	
	
	
	





```
invertDirection(figures, left, right);
```
 Das ruft nur die Methode ohne Implementierung aus abstract class Figure auf. Wenn du einen Parameter wie int speedX hinzufügst, ist das eine andere Methode! Also als Tipp: Solch eine Methode, die überschrieben werden *muss* auch als abstract deklarieren, dann meckert der Compiler gleich und am besten beim Implementieren/Überschreiben ein @Override über die Methodendeklaration, dann meckert der Compiler, dass du gar nicht überschreibst, wenn du die falschen Parameter wählst.
Außerdem änderst du mit  
	
	
	
	





```
speedX = -Math.abs(speedX);
```
 lediglich die lokale Variable, die nach verlassen der Methode nicht mehr sichtbar ist... Du musst schon die Geschwindigkeit der einzelnen Figuren ändern  Außerdem müsste es doch eher 
	
	
	
	





```
speedX = -speedX;
```
 sein, so änderst du egal von welcher Seite immer die Bewegungsrichtung und kannst eine Überprüfung sparen^^


----------



## Degelsegger (5. Jun 2011)

Jetzt ist sie als abstract deklariert, aber was mach ich jetzt mit den Variablen im Parameter über die der Kompiler meckert?
Bzw. wie funktioniert das mit @Override - hab ich noch nie gemacht. Sorry für meine Unwissenheit


----------



## Fu3L (5. Jun 2011)

```
@Override
public void invertDirection(ArrayList<Figure> figures, boolean left, boolean right){
        int size = figures.size();
        System.out.println("Aufgerufen");
        for(int i = 0; i < size; i++){
            Figure f = figures.get(i);
            f.bounds.y += 44;
            f.speedX = -f.speedX;
            }
    }
```

So müsste es tun  Du brauchst die Geschwindigeit ja nicht übergeben, oder? Es ist ja die Geschwindigkeit der Figuren entscheident

Der Compiler meckert halt, weil du nicht einfach einen Parameter zu einer Methode hinzufügen kannst, wenn du sie überschreiben willst 
@Override ist einfach nur dazu da, dass der Compiler weiß: Hier soll eine Methode überschrieben werden. Passiert das hier auch? und wenn nein, meckert er auch^^


----------



## Degelsegger (5. Jun 2011)

Gut, danke. Kompiliert soweit, ausgeführt wird sie aber trotzdem noch nicht.


----------



## Degelsegger (5. Jun 2011)

Problem liegt irgendwo bei Zeile 121, also bei der Klasse CollisionWall. Programm geht nämlich nicht in die Methode(CollisionWall). Das passiert aber nur wenn ich die ArrayList im Parameter habe. Wenn ich sie rausmache geht er ganz normal in die Methode hinein und führt die Kommandos darin aus. 

Ich brauche die ArrayList aber in dieser Methode und wenn ich sie im Parameter nicht habe funktionierts nicht.

Wie könnte man das lösen?


----------



## Fu3L (5. Jun 2011)

Gleiches Problem wie vorher. Eine überschreibende Methode muss die gleichen parameter verlangen, wie die ursprüungliche Methode.. Also einfach in Figure den Parameter zur Ursprungsmethode hinzufügen^^

Edit: Du machst die allerdings viel Arbeit, wenn du sowas bei jeder Klasse neu hinzufügst.. das dürfte sich doch relativ ähneln oder nicht? Wenn sich nur Werte unterscheiden, dann verschiebe um einen Wert in einer Variablen, die in jeder Klasse anders ist dann^^


----------



## Degelsegger (5. Jun 2011)

Okey danke, jetzt wird sie aufgerufen!


----------



## Degelsegger (6. Jun 2011)

Die Klasse InvertDirection soll dafür sorgen, dass wenn ein Gegner die Wand berührt alle Gegner die Richtung ändern und 44 Pixel nach unten gehen. Jetzt hab ich darin aber einen kleinen Semantikfehler, den ich nicht wirklich sehe.

Die Gegner bewegen sich alle einfach gerade nach unten und machen nicht diese Bewegung.

Danke im Voraus!


----------



## Fu3L (6. Jun 2011)

Sollen die auch einen "Ruck" zur Seite durchführen oder wie meinst du das? Dann einfach: 
	
	
	
	





```
f.bounds.x -= Math.signum(f.speedX) * 44;
```
 oder so ähnlich^^ (verschiebt halt in die entgegengesetzte Richtung. Muss natürlich dann vor 
	
	
	
	





```
f.speedX = -f.speedX;
```
 eingefügt werden^^ Wenn dus danach machen wolltest, einfach das -= in += umändern..)

Ich hab selbst wohl mal ein SpaceInvaders gebastelt, aber hab mich bei der Bewegung nicht an das Original gehalten^^


----------

