Blobbers das Game: Ein Screencast

05 Feb

Es ist fertig. Nachdem Blobbers nun schwimmen kann, Haien ausweichen und sogar gefressen werden kann, sind wir nun am Ende angekommen. Das Spiel ist fertig.

blobbers_fertig

Hier könnt ihr euch das Spiel Blobbers als Processing-Datei herunterladen.

Zum Abschluss haben wir in einem Screencast nochmal die Dinge erklärt, die wir am kompliziertesten fanden.

Hier könnt hier euch diesen herunterladen.

Wir hoffen, ihr hattet Spaß beim Verfolgen des Blogs und spielt nun fleißig Blobbers – Das Spiel! =)

Die Probleme mit den Ebenen

02 Feb

Die zwei Ebenen, die wir einführten, waren zwar für die Kollisionsabfrage eine gute Lösung, es entstanden dadurch aber weitere Probleme. Wir müssen immer gleichzeitig zwei Haie zeichnen, die übereinander liegen. Einen in der unteren Ebene um die Kollision auszulösen und einen Hai, der angezeigt wird.

Wir hatten zunächst versucht eine Hai-Klasse zu erstellen, die für beide Ebenen benutzt werden kann. Deshalb haben wir diese Klasse in einem weiteren Tab erstellt und in den jeweiligen Ebenen darauf zugegriffen. Dadurch wurden aber beide Haie immer unterhalb der beiden Ebenen gezeichnet. Also mussten wir doch zwei Klassen erstellen: eine auf der Hintergrund- und eine auf der Vordergrundebene.

Wenn ihr euch erinnert, haben wir für die y-Position des Hais immer eine Random-Zahl genommen. Wenn jetzt also ein Hai mit dieser Zahl gezeichnet wird, ist es sogar sehr wahrscheinlich, dass der Hai im Hintergrund und der im Vordergrund nicht übereinander liegen. Das ist aber wichtig, weil der Spieler den entscheidenden Hai im Hintergrund nicht sieht und somit einfach Glück haben muss, damit Blobbers nicht gefressen wird. Diesen Gedanken fanden wir zunächst sehr amüsant! =D Danach entschlossen wir uns aber, dass Blobbers doch kein Glücksspiel werden sollte. Also mussten wir auch hier eine Variable einführen, die für die übereinander liegenden Haie die gleiche Zahl produziert und von ihnen aufgerufen werden kann.

So weit so gut. Das Spiel wäre ja aber sehr langweilig, wenn nur ein Hai kommen würde, weshalb wir ja vorher Klassen und ein Array für die Haie anlegten. Im nächsten Schritt mussten wir also auch ein Array für die Zufallszahl erstellen.

————————————-

float[] randomPosition;

void setup(){

randomPosition = new float[100];
for(int bla2 = 0; bla2 < 100; bla2++)
{
randomPosition[bla2] = random(50,500);
}

randomPosition = new float[100];

//muss mindestens so groß sein, wie das Hai-Array, damit immer für jeden Hai eine neue Zahl erzeugt werden kann

for(int bla2 = 0; bla2 < 100; bla2++) // diese Schleife erzeugt pro neuen Hai eine neue Zufallszahl, die unten verwendet wird

{

randomPosition[bla2] = random(50,500);

}

// hier wird jetzt also unser Hai-Array befüllt

haiArray = new hai[100];

for(int anzahl = 0; anzahl < 100; anzahl++)

// das Hai-Aarray wird durch den Zähler „anzahl“ durchlaufen, so wird immer ein Hai nach dem anderen erstellt

// im folgenden wird jetzt das Array befüllt

{

haiArray[anzahl] = new hai(1024,randomPosition[anzahl],“Hai.gif“);

}

}

draw(){

for(int bla=0; bla <= haiAnzahl; bla++)

// damit nicht pro Frame ein neuer Hai erstellt wird, haben wir wieder eine for-Schleife benutzt, die von haiAnzahl abhängig ist

{

haiArray[bla].schwimme();

haiArray[bla].showHai();

println (bla + „. Hai“); // damit man auch schön mitverfolgen kann, vor wie vielen Haien Blobbers schon beschützt werden konnte

}

}

————————————-

Wenn ihr aufgepasst habt, sollte euch auffallen, dass die Variable haiAnzahl noch neu ist. Hier also die Erklärung dazu und wie wir sie weiterhin nutzten beziehungsweise erstellten:

————————————-

// die Variable wird zunächst einmal festgelegt

int haiAnzahl;

// im Setup wird sie auf 0 gesetzt, damit wir einen Startwert haben

setup()

{

haiAnzahl = 0;

}

// nun also zum Hauptteil

draw()

{

if(frameCount % (80-z) == 0)
//wenn die Frame-Anzahl durch 80 teilbar ist, dann
{
haiAnzahl++;
if(haiAnzahl>99)
//sind 100 Haie erschienen, …
{
//… dann setzte den Haizähler auf 0 zurück und der Spaß geht wieder von vorne los =)
haiAnzahl = 0;
}
}

if (frameCount % 80 == 0)

//wenn die Frame-Anzahl durch 80 teilbar ist, also alle 80 Frames:

{

haiAnzahl++;

// erhöhe haiAnzahl um 1

if(haiAnzahl>99)

//sind 100 Haie erschienen, …

{

//… dann setzte den Haizähler auf 0 zurück und der Spaß geht wieder von vorne los =)

haiAnzahl = 0;

}

}

}

————————————-

Ebenen in Processing

17 Jan

Da die Kollisionsabfrage nach einem bestimmten Farbwert sucht, welcher durch einen Hintergrundhai und die Überschneidung eines blauen Kreises um Blobbers erzeugt wird. muss die Kollisionsabfrage auf einer anderen Ebene, wie das eigentliche Spiel dargestellt werden.

Auf der Suche nach einer Möglichkeit das zu lösen, sind wir im Internet fündig geworden: Processing Layers – eine library von nootropic design

Anhand der Anleitung, die auf der Seite der Entwickler angegeben war, haben wir die Ebenenlibrary eingebunden und somit zwei Ebenen erzeugt: die Vordergrundebene mit Fisch Hai und Hintergrundbild und die Hintergrundebene mit dem Kreis um Blobbers, dem roten Hai und der Kollisionsabfrage.

Über das ein- und ausblenden der Funktion

//setVisible(false);

kann man die untere Ebene anschauen, wobei die obere Ebene ausgeblendet ist. Zum Verständnis dieser Ebenenlösung haben wir euch zwei Screenshots gemacht. Einmal mit sichbarer oberen Ebene, einmal mit ausgeblendeter oberer Ebene:

ebenen

Achtung Hindernis! – Die Kollisionsabfrage

13 Jan

Blobbers und die Haie schwimmen nun. Um zu prüfen, ob der Spieler mit seiner Stimme Blobbers vor den Gefahren des Meeres retten kann, benötigen wir eine Kolisionsabfrage. Die Hindernisse werden sich im Spiel auf den Fisch zubewegen, sodass abgefragt werden muss, wann der Fisch und das jeweilige Hindernis die gleiche Position haben.

Das Problem hierbei ist, dass der Spieler die Position des Fisches bestimmt. Und Blobbers kann an mehreren Positionen mit einem Hinderniss kollidieren. Oben, unten und vorne können die Gefahren des Meeres lauern. Deshalb haben wir uns dazu entschieden, die Kollisionsabfrage über eine kreativeren Ansatz zu lösen: Pixels. Hierfür haben wir uns einen kleinen Sketch gebastelt, um einfach einmal auszuprobieren, wie diese Funktion reagiert und wie wir sie für unsere Kollisionsabfrage verwenden können.

kollisionsabfrage

Hier könnt ihr euch den Sketch herunterladen.

Pixels ist eine Funktion in Processing, die den Farbwert eines Pixels oder mehrerer Pixel anzeigen kann. Genau das wird hier gemacht. Wir haben einen festen Pixel gewählt und fragen nun ab, wann dieser Pixel einen bestimmten Farbwert annimmt. Wird dieser bestimmte Farbwert angenommen, soll ein Event ausgelöst werden. Zum Test haben wir in diesem Sketch zwei Kreise genommen. Beim Überschneiden entsteht eine Farbe und es wird beispielhaft das Event ausgelöst, dass die Kreise rot werden sollen.

In unserem Spiel soll das natürlich ähnlich ablaufen. Jedoch wird die Kollisionsabfrage so gelöst, dass das Array Pixels den gesamten Screen durchläuft. Hier seht ihr also den Code, der im fertigen Spiel für die Kollisionsabfrage über Pixels verwendet wird:

—————————————————

//Farbe, die die Kollision darstellt
color  k = color (205,19,38);
loadPixels();

//im kompletten Sketch überprüfen, ob die Farbe k vorkommt
for( int i=0; i < (width*height); i++) {
if(pixels[i] == k) {
//wenn k vorhanden ist, dann soll die Variable kollision gleich 1 gesetzt werden, damit sie auf der anderen Ebene benutzt werden kann
kollision = 1;
}
}

—————————————————

Da diese Kollisionsabfrage nach einem bestimmten Farbwert sucht, die sich durch die Überschneidung eines blauen Kreises und eines roten Haibildes ergibt, muss die Kollisionsabfrage selbst auf einer anderen Ebene gelöst werden. Wir begaben uns also auf die Suche, nach einer Möglichkeit diese verschiedenen Ebenen zu realisieren

Haie und Haiklassen

03 Jan

Der Fisch schwimmt und kann ausweichen. Aber die Hindernisse fehlen noch.

Wir zeichneten also einen schrecklichen, fürchterlichen und blobbersverzehrenden Hai:

Hai

Nun galt es, diesen Hai so zu programmieren, dass er sich in einem bestimmten zeitlichen Abstand auf einer zufälligen Höhe wiederholt und damit Blobbers in Gefahr bringt. Hierzu verwendeten wir eine Klasse. Zu Anfang des Sketches wird ein Hai-Array befüllt, das aus Haien verschiedenster Zufalls-Höhen besteht. Durch die Funktionen „showhai“ und „schwimme“ haben wir nun den Hai anzeigen lassen und durch den Screen bewegen lassen. Durch die Variable „haiAnzahl“  legen wir fest, wann ein neuer Hai erstellt werden soll.

Hier also unsere Hai-Klasse:

————————————-

//Klasse hai zum Anzeigen
class hai {
public float a;
float r;
PImage haibild;

//Konstruktor: wird ausgeführt, wenn Hai erzeugt wird
hai (float tmpA, float tmpR, String bildname) {
a = tmpA;
this.r = tmpR;
haibild = loadImage(bildname);
}

//Funktion den Hai anzuzeigen
void showHai() {
image(haibild,a,this.r);
}
void schwimme() {
a-=15;
}
}

//Legt haie für einen neuen Hai fest. Dieser wird unten mit „new hai“ gezeichnet.
hai[] haiArray;

————————————-

Blobbers lernt schwimmen

27 Nov

In diesem Schritt wollen wir Blobbers beibringen sich nach Soundeingabe nach oben oder unten zu bewegen. Für das Spiel genügt es, wenn sich Blobbers nur nach oben oder unten bewegt. Das Vorwärtsschwimmen wird durch einen sich bewegenden Hintergrund simuliert.

Um die Motivation zu steigern, haben wir Blobbers gleich als Bild eingefügt und eine Unterwasserwelt als Hintergrund eingerichtet.

screenshot2

Hier könnt ihr euch die Processing-Datei herunterladen.

Damit Blobbers nicht in einem weißen Kasten eingesperrt ist, sondern sich frei bewegen kann, haben wir diesen transparent gemacht und als .gif gespeichert. Dieses Bild kann dann einfach in Processing eingebunden werden und die Transparenz wird erkannt.

Das Hintergrundbild haben wir vorher schon auf die Größe unseres Ausgabefensters skaliert, damit es in Processing genügt, es ebenfalls nur einzubinden. Das kann man machen, wenn die endgültige Größe des Ausgabefensters schon festgelegt ist. Ansonsten empfiehlt es sich, die Größe in Processing über

image(img, x, y, width ,height);

anzupassen. Darin werden der Bildname, die x-Position, y-Position, Breite und Höhe angegeben.

Damit sich unser Held nach hohen oder tiefen Tönen verhält, müssen wir Variablen einsetzen. Zunächst muss Blobbers‘ Position flexibel sein, also nutzen wir die image() Funktion und setzen für die x- und y-Position ein x bzw ein y ein, statt einer konkreten Zahl. Danach werden die Variablen aus dem vorangegangenen Schritt in einer if-Anweisung verwendet.

if(y<0 || y>768) {
if(y<=0) {
y=0;
}
else {
y=768;
}
}
else {
if (tief > hoch && tief > 30) {
y += 4.55;
}
if (hoch > tief && hoch > 11) {
y -=4.55;
}
}
image(blobbers,x,y);

Void draw wird um folgendes ergänzt:

image (blobbers, x, y);

if (y<0 || y>768)  // wenn Blobbers am oberen oder unteren Rand ankommt, dann:

{

if (y<=0) { // teste, ob er den oberen Rand erreicht hat, dann

y=0; // lass ihn nicht weiter hoch

}

else { //ansonsten, also, wenn Blobbers am unteren Rand anstößt, dann

y=768;  // lass ihn nicht weiter runter.

}

}

else { /*sollte sich Blobbers nicht am oberen und unteren Rand befinden, also dazwischen, da darüber oder darunter nicht geht, dann*/

if (tief > hoch && tief > 30) { /*teste, ob die Summe der tieferen Töne größer ist als die der höheren und, ob die Summe     der tieferen Töne größer ist als 30 (um Töne auszuschließen, die leiser sind) */

y += 4.55; // sollte das der Fall sein, erhöhe y mit jedem Frame um 4,55

}  else // ansonsten

if (hoch > tief && hoch > 11) { /* teste, ob die Summe der höheren Töne größer ist als die der tieferen und, ob die Summe der höheren Töne größer ist als 11 (um Töne auszuschließen, die leiser sind)*/

y -=4.55; // sollte das der Fall sein, erniedrige y mit jedem Frame um 4,55

}

}

Sound erfassen

27 Nov

Um Sound zu erfassen, haben wir uns zunächst das Beispiel ForwardFFT von Processing aus der Library Minim(Sound) angeschaut. Hier werden verschiedene Bänder angezeigt, die verschiedene Tonhöhen anzeigen.

Um die Library nutzen zu können, muss sie erst eingebunden werden und die Variabeln, die wir brauchen müssen, aufgerufen werden. Das funktioniert so:

import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
AudioInput linein;
FFT fftLog;

import ddf.minim.analysis.*;

import ddf.minim.*;

Minim minim;

AudioInput linein;

FFT fftLog;

Unser void setup sieht folgendermaßen aus:

void setup() {

size(1024, 768, P2D);

minim = new Minim(this);

linein = minim.getLineIn(Minim.STEREO, 2048);

fftLog = new FFT(linein.bufferSize(), linein.sampleRate());

fftLog.logAverages(10, 1);

}

Mit

fftLog.logAverages(10, 1);

haben wir die Anzahl der zu verarbeitenden Bänder auf 10 reduziert.

Da es für uns nur entscheidend ist, ob ein Ton hoch oder tief ist, haben jeweils die fünf unteren bzw die fünf oberen Bänder addiert und daraus eine Variable erstellt. Das sah dann so aus:

float tief = fftLog.getAvg(1) + fftLog.getAvg(2) + fftLog.getAvg(3) +fftLog.getAvg(4) +fftLog.getAvg(5);

float hoch = fftLog.getAvg(6) + fftLog.getAvg(7) + fftLog.getAvg(8) +fftLog.getAvg(9) +fftLog.getAvg(10);

Ich bin mir noch nicht sicher, wofür wir die folgende Zeile brauchen, aber ohne funktionierts nicht =P

fftLog.forward(linein.mix);

Void draw sieht jetzt so aus:

void draw() {

fftLog.forward(linein.mix);

float tief = fftLog.getAvg(1) + fftLog.getAvg(2) + fftLog.getAvg(3) +fftLog.getAvg(4) +fftLog.getAvg(5);

float hoch = fftLog.getAvg(6) + fftLog.getAvg(7) + fftLog.getAvg(8) +fftLog.getAvg(9) +fftLog.getAvg(10);

}

Jetzt haben wir die Grundlage für unser Spiel geschaffen. Der Sound wird erkannt und so vorbereitet, dass wir ihn für unsere nächsten Schritte benutzen können.

Blobbers – Unser Fisch

05 Nov

Im Studienfach „Processing“ wollen wir, Angelika Johnke und Janis Goldschmitt, dieses Semester Sound visualisieren. Wir haben uns überlegt, ein kleines Spielchen daraus zu machen.

Sinn dieses Spiels: Rette Blobbers vor den Gefahren des Meeres!

blobbers

Hierfür musst du ihn gekonnt mit deiner Stimme an den Hindernissen vorbeimanövrieren! Die Tonhöhe der Stimme ist dabei entscheidend.

Doch wie wird das umgesetzt?

Unsere Schritte:

  • Soundsignale erfassen
  • Form, die sich nach Soundsignalen auf y-Achse bewegt
  • Hindernisse, die sich auf die Form zubewegen
  • Kollision herausfinden
  • Bilder zeichnen und einfügen

Blobbersblog

Über Fische, Töne und Gefahren