Skip to content
Open
Binary file added .DS_Store
Binary file not shown.
Binary file added Coder.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions Invader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
class Helper {
static setCharsAt(str,index,chr) {
if(index > str.length-1) return str;
return str.substr(0,index) + chr + str.substr(index+chr.length);
}
}

class Invader {
constructor(appearance, id) {
this.appearance = appearance;
this.id = id;
}

shootLaser() {
console.log("Invader " +this.id+" Laser shot")
}

explode() {
console.log("Invader "+this.id+" exploded")
}

isHitByBullet(bulletX, bulletY) {
//prüfen ob der Bullet den Invader trifft
}
}

class InvaderRow {
constructor(posX, posY, width, height, invaders, id) {
this.id = id;
this.posX = posX;
this.posY = posY;
this.width = width;
this.height = height;
this.invaders = invaders;
}

static generateInvader(width, height) {
let currentInvader = [];
for (let y = 0; y < height; y++) {
currentInvader[y] = " ".repeat(width*2+1);
for (let x = 0; x < width; x++) {
let randomNumber = Math.random();
if (randomNumber >= 0.5) {
currentInvader[y] = (Helper.setCharsAt(currentInvader[y], x,'▧'));
currentInvader[y] = (Helper.setCharsAt(currentInvader[y], 2 * width - x,'▨'));
}
}
}
return currentInvader;
}

static generateInvaderRow(invaderWidth, invaderHeight) {
let currentInvaders = [];
let rowWidth = Math.floor(cols*0.8);
let wholeInvader = invaderWidth * 2;
let spacerWidth = invaderWidth/2;
let numInvaders = Math.floor((rowWidth / ((wholeInvader+spacerWidth))));
let invaderAppearance = InvaderRow.generateInvader(invaderWidth, invaderHeight);
//let numInvaders = Math.floor(spacing);
for(let i = 0; i < numInvaders ; i++) { // gerundet(x = ((breite - breite*0,2) / invaderbreite) + (x - 1) * invaderbreite/2 ))
let newInv = new Invader(invaderAppearance, i);
currentInvaders.push(newInv);
}
return currentInvaders;
}
}
242 changes: 241 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,242 @@
# 01_03_spacebase
Base for Space Invaders

# <u>Dokumentation Space Invader</u>
##### Maximilian Becht und Tara Monheim
>Maximilian Becht auf [Github](https://github.com/maxicozy).

>Tara Monheim auf [Github](https://github.com/taramonheim).

Unser Space Invader Projekt wurde im Laufe des ersten Semesters im Fach Programmiersprachen 1 gecoded. Das Space Invader
Projekt soll es dem Spieler ermöglichen mit dem Spaceship die Invaders zu treffen und sie zum explodieren zu bringen.
Die Invader Reihe kommt langsam immer weiter runter. Also ran an die Tasten und probier es aus!

Den Code haben wir mithilfe unseres Dozenten[ Florian Geiselhart](https://github.com/fg-uulm) (das bist du)
geschrieben. Er basiert auf dem Basis Code von unserem Dozenten und wurde von uns erweitert. Den Basis Code findet man
[hier](https://github.com/hfgcoding/01_03_spacebase).
Auch das Internet hilft in der Regel, aber da es sehr viele Space Invader Games gibt, die programmiert wurden,verliert
man schnell den Überblick.
Also ransetzen, denken und coden! Was immer hilft:
Die Klassen und Eigenschaften einfach mal aufzuschreiben. Mit Papier und Stift. Ganz Old School.

Eigenschaften des Spiels, an denen wir gearbeitet haben:

1. Die Invader werden radom gerendert.

2. Die Invader werden in einer Reihe generiert.
3. Es werden so viele Invader generiert, wie in das Feld passen.
4. Wenn die Invader Reihe an den Rand des Felds kommt bewegt sie sich eine Zeile runter und in die andere Richtung.
5. Das Spaceship schießt auf die Invader, trifft ein Bullet den Invader, explodiert dieser.
6. Ein Score am Rand zählt hoch, wenn man einen Invader trifft.
7. Unser Code baut auf Klassen auf, die wir in der Javascript Datei definiert haben.

<img src="coder2.JPG" />
<img src="Coder.JPG" />


# Usage / Benutzung

Um das Spiel selbst zu erleben, kann man den Code entweder einfach von Github downloaden und in einen Code Editor
öffnen, um ihn zu individualisieren oder man öffnet ihn mit einem Browser.
Im Code Editor braucht man
die [classes.js](classes.js) und die [index.html](index.html), die auf Github zu finden sind.
Um das ganze in einem belibiegen Browser öffnen zu können, muss man das Repository auf Github forken und clonen und dann
die Html Datei mit einem Browser öffnen.
Sobald die Seite geladen ist startet auch das Spiel. Die Invader bewegen sich in ihrer Reihe von links nach rechts,
treffen sie an den Rand, rücken sie eine Zeile nach unten und ändern ihre BEwegungsrichtung nun nach links.Das Spaceship
kann man mit den <kbd>key left</kbd> und <kbd>key right</kbd> Tasten bewegen. Durch die
<kbd>Leertaste</kbd> schießt das Spaceship auf die Invader. Diese explodieren, sobald sie getroffen werden. Durch die
Barriere, die das Spaceship schützen soll, kann man nicht durchschießen.
Die Invaders selber können zur Zeit noch nicht auf das Spaceship schießen.
Würde das funktionieren, müsste auch die Barriere, bei Abschuss derer, Stück für Stück verschwinden.
Durch den Reload Button des Fensters kann man das Spiel neu starten.

# Structure / Aufbau

Wir haben das Spiel anhand von Klassen aufgebaut,
deren Eigenschaften wir in der Javascript Datei angegeben haben. In der Html Datei greifen wir auf diese Klassen zu.

### **class Invader**:

<pre>
class Invader {
constructor(appearance, ischBinKaputt, explodeTime, id) {
this.appearance = appearance;
this.id = id;
this.ischBinKaputt = ischBinKaputt;
this.explodeTime = explodeTime;
}
shootLaser() {
console.log("Invader " + this.id + " Laser shot")
}
explode() {
this.appearance = [" ",
" \\ | / ",
" - p u f f - ",
" / | \\ ",
" "
];
}
}
</pre>

* hier haben wir der Klasse Invader die Eigenschaften `appearance`, `ischBinKaputt`, `explodeTime` und `id` zugeorndet.
Außerdem haben wir ihm die Methode `explode()` gegeben,um sein Aussehen nach dem Explodieren zu bestimmen.

### **class InvaderRow**
<pre>
class InvaderRow {
constructor(posX, posY, width, height, invaders, id) {
this.id = id;
this.posX = posX;
this.posY = posY;
this.width = width;
this.height = height;
this.invaders = invaders;
}
</pre>

* Die Klasse `InvaderRow` beinhaltet ihre eigene Position und invader.

### **static generateInvader:**

>Das <kbd>static</kbd> Schüsselwort definiert statische Methoden für eine Klasse.

<pre> static generateInvader(width, height) {
let currentInvader = [];
for (let y = 0; y < height; y++) {
currentInvader[y] = " ".repeat(width * 2 + 1);
for (let x = 0; x < width; x++) {
let randomNumber = Math.random();
if (randomNumber >= 0.5) {
currentInvader[y] = (Helper.setCharsAt(currentInvader[y], x, '#'));
currentInvader[y] = (Helper.setCharsAt(currentInvader[y], 2 * width - x, '#'));
}
}
}
return currentInvader;
}
</pre>

* `width, height`: Invadergröße (Property)
* `currentInvader`: ist ein Array, in das so viele Strings generiert werden, wie der Invader hoch ist
* eine zufällige Zahl wird generiert ist diese größer oder gleich `0.5`, so wird ein `"#"` an diese Stelle des
currentInvaders Arrays geschrieben. Somit hat man die Hälfte dieses Invaders. Diese wird anschließend gespiegelt.

### **static generateInvaderRow:**

<pre> static generateInvaderRow(invaderWidth, invaderHeight) {
let currentInvaders = [];
let rowWidth = Math.floor(cols * 0.8);
let wholeInvader = invaderWidth * 2;
let spacerWidth = invaderWidth / 2;
let numInvaders = Math.floor((rowWidth / ((wholeInvader + spacerWidth))));
let invaderAppearance = InvaderRow.generateInvader(invaderWidth, invaderHeight);
for (let i = 0; i < numInvaders; i++) {
let newInv = new Invader(invaderAppearance, false, 0, i);
currentInvaders.push(newInv);
}
return currentInvaders;
}
}</pre>

* hier wird ausgerechnet wie viele Invader in 80 % der Spielfeldbreite passen. Anschließend werden so viele Invader in ein Array gepusht.

### function renderInvaderrow

<pre>
function renderInvaderRow(invaders) {
let currentInvXPos = invaders[rowId].posX;
for (let j = 0; j < invaders[rowId].invaders.length; j++) {
for (let i = 0; i < invaders[rowId].invaders[j].appearance.length; i++) {
renderStr = Helper.setCharsAt(renderStr,xyToStringPos(invaders[rowId].invaders[j].id + currentInvXPos, invaders[rowId].posY+i), invaders[rowId].invaders[j].appearance[i]);
}
currentInvXPos = currentInvXPos + invaderWidth* 2 + invaderWidth/2;
}
}</pre>

* Diese Funktion läuft durch die aktuelle Invaderrow und deren Invader und schreibt diese anschließend in den Renderstring.

### function renderBullets

<pre>
function renderBullets() {
currentSpaceshipBullets = currentSpaceshipBullets.filter(bullet => bullet.y > 1);
currentSpaceshipBullets.forEach((bullet) => {
bullet.y -= 1;
if (renderStr[xyToStringPos(bullet.x, bullet.y - 1)] == '#') {
     let currentId = 0;
for (let invaderPos = invaders[rowId].posX; invaderPos <= invaders[rowId].posX + (invaderWidth * 2 + invaderWidth / 2); invaderPos = invaderPos + invaderWidth * 2 + invaderWidth / 2) {
if (bullet.x > invaderPos && bullet.x < invaderPos + invaderWidth * 2) {
invaders[rowId].invaders[currentId].ischBinKaputt = true;
invaders[rowId].invaders[currentId].explode();
invaderPoints++;
break;
}
currentId++;
}
currentSpaceshipBullets = currentSpaceshipBullets.filter(currentBullet => currentBullet != bullet);
}
if (renderStr[xyToStringPos(bullet.x, bullet.y - 1)] == '=') {
currentSpaceshipBullets = currentSpaceshipBullets.filter(currentBullet => currentBullet != bullet};
}
renderStr = Helper.setCharsAt(renderStr, xyToStringPos(bullet.x, bullet.y), "|");
})
}
</pre>

* Ein Großteil dieser Funktion wurde von unserem Dozenten gecoded. Wir haben hier die Funktion hinzugefügt, die prüft, ob die Bullet den Invader trifft. Das funktioniert über einen abgleich ob sich im Feld über der Bullet ein Hashtag befindet, also der Character aus dem ein Invader besteht.
Wenn dies der Fall ist wird nun abhängig von der aktuellen Anfangsposition der Invaderreihe ausgerechnet an welchem Invader sich die Bullet befindet, dann führt der getroffene Invader die Methode
`explode()` aus, ausserdem wird eine Variable mit jedem Treffer um eins hochgezählt.
Ausserdem wird die aktuell gerenderte Bullet aus dem currentSpaceshipBullets Array herausgefiltert, falls diese einen Invader getroffen hat.

* Das gleiche Prinzip haben wir für die Obstacles übernommen, dass die aktuell gerenderte Bullet auch checkt ob sich über ihr ein `=` befindet, auch in diesem Fall wird die Bullet gelöscht.





### Zusammenfassung
Abläufe:
* die Invaderreihe wird generiert und bewegt sich dann:

* ein Invader wird abgeschossen:








## ToDos

1. Man muss die Invaders selber schießen lassen. Dies muss random passieren.

2. Es sollen mehrere Reihen von Invaders aufeinander folgen.
3. Das Hindernis muss bei Abschuss der Invader kaputt gehen.
4. Wenn die Invader eine gewissen Punkt auf der y-Achse erreichen, sollte der Spieler verloren haben.
5. Man kann noch eine Game Over/ Win Schrift einbauen.
6. Wenn die Invader getroffen werden, erhöhen sie auch die Geschwindigkeit, damit es schwieriger wird sie Abzuschießen.
7. Einen New Game Button, um das Spiel mit dem Button neu zu starten.
8. Das Spaceship hat mehrere Leben und eine Lebensanzeige, die bei Treffer durch Invader weniger werden.
9. Ein Invader Boss, der auftaucht und mehr Punkte bringt.
10. Hintergrundmusik und Soundeffekte
13. Verschiedene Level mit unterschiedlichen Schwierigkeitsstufen.


















Loading