Sonntag, 14. Juli 2013

Ein letzter Abgabepost :-)

... ein bisschen Designentwicklung und Entscheidungen zusammengefasst:

Mehr Platz auf dem Spielfeld

Sowohl die zuerst eingefügte Spiralbindung wie auch die Titelanzeige haben wir schliesslich weggelassen, um den Raum besser auszunutzen (zumal das im höchstens ablenkend und nicht notwendig war (Links beispielsweise das erste Optionsmenü, links die neue version mit mehr Fläche)





Nehmen und Ablegen der Knoten

Irgendwie müssen jedoch auch die Knoten aufgenommen und abgelegt werden können. Ein Extrabutton verbraucht Platz und war deswegen ausgeschlossen. Alternativ kann die Bewegung des Smartphones (Aufwärts zur Aufnahme, Abwärts zur Ablage, oder auch Schütteln verwendet werden. Wir haben uns stattdessen entschlossen, die gesamte Anzeigefläche als Schalterfläche zu verwenden, und jeweils unten ein Hilfssymbol anzuzeigen, je nachdem welche Funktion aktuell durch eine Bildschirmberührung durchgeführt werden kann.

Kantenevolution

Kanten sollten unterscheidbar sein, um das Spiel vielfältiger zu gestalten: Kanten gleicher Art dürfen sich nicht schneiden, unterschiedliche hingegen schon. Dies kann entweder durch die Farbe oder durch die Form der Kanten geschehen. Um ein Umschalten zwischen Schwarz-Weiss und Farbe zu vermeiden (da beides seine Vor- und Nachteile hat), verwenden wir Bilder für die Kanten, die beides kombinieren.

Knotenrevolution

Eine weitere Überlegung war, einige Knoten nur aufhebbar durch einen bestimmten Spieler zu machen, beispielsweise angezeigt durch passendes Farbe von Spieler und Knoten. Damit kann aber leicht ein (nicht vorhandener) Zusammenhang zwischen Knoten-, Spieler- und Kantenfarbe vermutet werden. Ausserdem setzt dies vorraus, das nicht weitere Spieler während des Spiels hinzukommen können bzw. wenn ein Spieler das Spiel verlässt, kann es für die übrigen unlösbar werden.

Somit blieben wir zunächst bei schwarzen (nicht-farbigen :-) Knoten, welche sich nur in der Form unterscheiden: Rechteckig für unbewegbare, Rund für bewegbare Knoten, welches leicht verdeutlicht, welche davon sich durch die Spielerdarstellung mit rundem Innenring aufgenommen werden können.
Jedoch wurden diese später doch farbig ergänzt: Es erschien uns sinnvoll, denjenigen Knoten hervorzuheben, welcher durch den Spieler aufgehoben werden kann. Eine erste Überlegung, dies mit einer Art "Lichtkranz" zu machen, ergab das Problem, das damit die Beschränkung "Runder Knoten passt in Spielerkranz" nicht mehr funktioniert.

Nähert sich ein Spieler nun einem Knoten nahe genug, wird jetzt der Innenbereich des Knotens und der Spieleranzeige gelb gefärbt, und beide werden bei Aufnahme des Knotens grün. Ist kein Knoten in der Nähe (und keiner aufgenommen) wird die Spielerfigur rot.

Womit wir auch schon beim nächsten Punkt sind:

Die Spieleranzeige

Sowohl die Anzeige des eigenen wie auch anderer Mitspieler besteht aus einem (Innen-)Ring, um zu den aufnehmbaren Knoten zu passen. Um die Anzeige nicht zu überladen, ist dies auch das einzige, was man von anderen Spielern sieht (also kein Name, Farbe oder ähnliches). 


Die eigene Figur ist zusätzlich erweitert um eine Art Fadenkreuz, welches sich je nach Status (s.o.) verfärbt (Die kleine Männchen darauf, welche fernab von Knoten bloss herumliegen, sich nahe eines Knoten hinsetzten, und diesen schliesslich festhalten, wenn ein Knoten aufgenommen ist, sind auf dem Smartphonedisplay natürlich nicht besonders gut zu erkennen :-).

Schwierigkeitsgrad

Anstelle einen Schwierigkeitsgrad irgendwie zu berechen, haben wir uns dazu entschlossen, einfach die Anzahl Knoten, die maximal erlaubte Anzahl Kanten sowie die maximale Anzahl unterschiedlicher Kantentypen mittels Schieberegler festzulegen. Damit ist natürlich auch kein definierter Gefahrenbereich für zu schwere Graphen vorhanden, daher wurde das Hintergrundbilde des Schiebereglers entsprechend angepasst.

Achievements und Statistik

werden zusammen angezeigt. Dabei wird die zurückgelegte Gesamtstrecke und die Anzahl aller aufgehobenen Knoten sowie die Anzahl aller bisher gewonnenen Spiele angezeigt. Zusätzlich werden auch die Achievements angezeigt. Diese sind mit einem Fragezeichen verdeckt, wenn sie noch nicht erworben worden sind, ansonsten (wenn sie in einem Spiel erworben wurden) wird daraus ein Häkchen. In diesem Fall kann man sie durch Klicken auf die Karte enthüllen. 

Vorhanden sind bisher (obwohl sowohl das Senden an den und Empfangen der Spielerstatistiken von  dem Server bereits vorhanden ist, arbeitet die Bestimmung noch rein lokal (abgesehen von der zurückgelegten Strecke der übrigen Spieler, welche aber auch lokal aus den Spielerpositionen bestimmt wird - die Schwierigkeit ist nämlich sonst zu bestimmen, wann alle Spieler ihre jeweiligen Daten gesendet haben, da schliesslich auch Spieler das Spiel verlassen haben können):

Flash Checker: Aktuell bekommt das jeder Spieler, der ein Spiel bekommen hat. In Zukunft nur derjenige Spieler, der als erstes dem Server meldet, das das Spiel gewonnen ist (was natürlich automatisch geschieht, worauf der Spieler also gar keinen Einfluss hat :-)

Iron Mistress: Kein Knoten wurde durch den Spieler in einem Spiel aufgehoben. Das funktioniert schon perfekt, ist aber auch nicht so schwer gewesen.
Travelling Salesman: Jeder (aufnehmbare) Knoten wurde durch den Spieler in einem Spiel auch aufgehoben. Optimal wäre hier natürlich für die Zukunft noch, das er gleichzeitig auch die kürzeste Entfernung aller Spieler, die diese erste Bedingung erfüllt haben, zurückgelegt hat... aber das muss ja nicht sein.

Lethargic Labourer: Weniger Knoten als aufhebbar wurden aufgehoben - für die Zukunft derjenige Spieler, der die wenigsten Konten aufgehoben hat.

Graph Matress: Mehr Knoten als aufhebbar wurden aufgenommen - in Zukunft derjenige Spieler, der die meisten Knoten aufgenommen hat.
Nodeman: Mehr Knoten aufgenommen als aufhebbar (in Zukunft: die Meisten) und zusätzlich die längste Strecke aller Spieler zurückgelegt.
 
Relaxo: Die geringste Strecke aller Spieler zurückgelegt.

Forrest Gump: Die längste Strecke aller Spieler zurückgelegt.






Grapherzeugung

In einer ersten Fassung wurde versucht den Graph intelligent zu erzeugen, um z.B. auch eine bestimmte Anzahl von Kantenüberschneidungen zu erhalten um einen bestimmten Schwierigkeitsgrad zu erhalten.

Die aktuell verwendete einfache Variante arbeitet einfach Brute-Force: Er erzeugt zunächst einen Graphen mit der gewünschten Anzahl Knoten an zufälligen Positionen. Danach wird nach und nach jeweils eine der möglichen Kanten ausgewählt, geprüft, ob sich diese mit (schon vorhandenen) anderen Kanten schneidet. Falls dies nicht der Fall ist, wird sie dem Graphen hinzugefügt, ansonsten das gleich nochmal mit einer anderen Kantenform durchgeführt, bis die maximal erlaubte Anzahl Kantenformen getestet worden ist. Danach geht es weiter mit der nächsten Kante, bis entweder alle möglichen Kanten durchgetestet worden sind, oder die gewünschte Anzahl Kanten dem Graphen hinzugefügt worden ist. Anschliessend werden solange die Knotenpositionen vertauscht, bis der Graph nicht mehr gelöst ist, und das Spiel kann beginnen. 

Man kann natürlich es auch übertreiben, aber es  geht noch mehr :-)











Dialog-Boxen

...machen unsere schöne Spielatmosphäre kaputt. Deswegen würden sie eigentlich auch durch eigene Bilder ersetzt werden. Zumindest für eine haben wir das bereits gemacht: Wenn kein name eingegeben wird, kommt dieses schöne Pop-Up:
 
...wäre zwar grundsätzlich hübscher, aber hier kann der Benutzter nicht erkennen, was er falsch gemacht hat - also schlechtes Feedback und deswegen nicht verwendet.




Ein paar andere sind bereits vorbereitet, z.B. zur Erzeugung des Spiels und zum Verbindungsaufbau, die sind aber nicht verwendet worden (bzw. nur als normales Bild)




Gastgeber, Gäste und Zuschauer

Zunächst war angedacht, das man zunäachst zwischen Host zur Spielerstellung, Gästen die mitspielen, und Gästen, die nur zuschauen unterscheidet. Diese Unterscheidung haben wir allerdings wegfallen lassen. Es ist einfacher, wenn jeder einfach mitspielen kann, indem er sich in das Spiel einloggt (und wenn er nur zuschauen will, muss er ja nur einfach nichts tun, und kriegt dann sogar ein Achievement (s.o.)). Der einzige Fall, wofür die Unterscheidung zwischen Gastgeber und Gast noch sinnvoll wäre ist zur Spielerstellung, da momentan noch der Schwierigkeitsgrad bzw. die Parameter zur Grapherstellung noch nicht an alle Mitspieler übergeben wird. Damit sollte momentan nur derjenige der das Spiel erstellt, dieses auch starten können.

Weggelassene Funktionen

...da das Spiel so schon kompliziert und das Spielfeld voll genug ist:

- (Feste) Hindernisse, durch die keine  Kante verlaufen darf
- Abschatten des Graphen durch darüberliegende Objekte (Bäume)
- Knoten ändern ihre Position (könnten dann allerdings auch den Graphen aus versehen lösen, anstelle es schwieriger zu machen)
- Chatfunktion nicht notwendig, man ist ja in einem überschaubaren Bereich (man kann natürlich auch weltweit spielen, aber dann spielt man wahrscheinlich eh nicht pausenlos bis man den Graphen gelöst hat)
- Ton: Mit auf das Smartphone starrend durch den Westpark zu laufen ist schon schlimm genug, eine musikalische Untermalung, ob man einen Knoten aufnimmt oder ablegt muss dann nicht unbedingt auch noch sein.

Zukünftig vielleicht ergänzbar

- Wettstreit: Zwei Gruppen bekommen den gleichen Graphen und versuchen diesen schneller als die andere Gruppe zu lösen
- Der Graph vergrössert sich im Laufe der Zeit (Knoten bewegen sich nach aussen), damit man sich nicht zuviel Zeit lässt.

Englisch vs. Deutsch

Nunja, den Blog haben wir auf deutsch geschrieben, da wir ja nicht denken, das den ausser uns (+ zwei weiteren Personen) jemand liest. Dafür ist das Spiel (gut, ist nicht sonderlich viel Text) und Program mit Kommentaren natürlich in Englisch gehalten, wie es sich gehört.

Mittwoch, 10. Juli 2013

...

Etwas überarbeitet (Schwierigkeitsgrad, Statistik, Beenden, Pokal :-)
Hoffentlich es läuft weiterhin

Android APK
Eclipse Workspace



Das Ende naht...

 Daher noch die Links zum eigentlichen Programm (falls jemand damit rumspielen will)

Was allerdings noch nicht richtig läuft:

- Lobbys werden noch nicht angezeigt (Lobbynamen muss man eintippen)
- Schwierigkeit (Anzahl Knoten, Kanten, Kantenstyles werden noch nicht übergeben) -> hardcoded in Graph(-erzeugung)
- Beenden des Spiels (Finished wird angezeigt, aber es wird nicht verlassen)
- Statistiks & Achievement

Aber trotzdem hier die Links:

Android APK
Eclipse workspace

Freitag, 5. Juli 2013

Weitere Grafiken...

Da man ja aufgrund der Icon-grösse im Programm nicht erkennen kann, das unser erstes Icon kein Geist sondern ein Graph mit Knoten war, der nur Geistform hatte, hier eine abgewandelte Version mit einem Android(en) der nur zufällig die gleiche Position einnimmt, wie vorher der Geist... aä, ich meine: Graph.
Ansonsten noch ein paar fehlende Buttons, Deco-Elemente und schliesslich ein paar Decobilder:Zwei alternative Warnhinweise für eine fehlende Texteingabe, da die normalen Warnhinweise grafisch nicht so recht passen, Bilder für etwaige Wartezeiten beim verbindungsaufbau und Graphgenerierung und ein Willkommensbildchen.

Dienstag, 2. Juli 2013

Erste Version des Servers

Letzten Freitag Abend ist die erste Version des Servers online gegangen. Der Server unterstützt seitdem den Großteil der festgelegten API (es fehlt nur noch die Statistik, welche diese Woche folgt). Der Server ist in Ruby geschrieben und benutzt als Datenbank Redis. Er läuft auf der PAAS Heroku unter der Domain http://dncts.herokuapp.com

Der Code wurde testgetrieben entwickelt: Die Unit-Tests sind mit Hilfe des RSpec Frameworks geschrieben, die Acceptance Tests mit Cucumber und Faraday.

Hier nun der Stand der API – den aktuellen Stand gibt es immer hier.


# API

A request is always a JSON Object with the given types (`lobby_id`, `game_state` etc.) as the key and a value as described in the section **Data Types**. A section of an URL beginning with colons has to be replaced by a value in the form described in the section **Data Types**. The response section of the routes always describes the success and failure case, each with the according Status Code and the body (if there is any). A failure will always have a body as JSON object with a key `failure` and a String value with the description of the error.

## Data Types

We define a number of data types which are represented via JSON.

### Identifier

`id`, `lobby_id`, `player_id`, `vertex_a_id` and `vertex_b_id` are all represented as Strings. Only use IDs provided by the server.

### Geo Position

`lat` and `long` are both represented as Strings (and are the String representation of a Java `Double`).

### Name

`player_name` and `lobby_name` are represented as Strings and may only contain upper- and lowercase letters and numbers.

### Lobby Arrays

`lobbies` is an array, each element has the following attributes:

* `id`
* `lobby_name`

### Player

`player` is a JSON Object with the following attributes:

* `id` (as described above)
* `lat` (as described above)
* `lon` (as described above)

### Vertex

`vertex` is a JSON Object with the following attributes:

* `id` (as described above)
* `lat` (as described above)
* `lon` (as described above)
* `carrier`: Either "" (if carried by no one) or a `player\_id` (as described above)

### Game State

`game_state` is a JSON Object with the following attributes:

* `vertices` is an Array, each element is a `vertex` (as described above)
* `players` is an Array, each element is a `player` (as described above)
* `is_finished` is a Boolean

### Game Statistics

`game_statistics` is a JSON Object with the IDs of all players as keys, each has an object with the following keys as its value:

* `distance`: Number
* `different_vertices_touched`: Number
* `total_vertices_touched`: Number

### Game

`game` is a JSON Object with the following attributes:

* `vertices` is an Array, each element has the following attributes:
    * `id` (as described above)
    * `lat` (as described above)
    * `lon` (as described above)
    * `portable`: Either true or false
    * `carrier`: Either "" (if carried by no one) or a `player\_id` (as described above)
* `edges` is an Array, each element has the following attributes:
    * `vertex_a_id` (as described above)
    * `vertex_b_id` (as described above)
    * `color`: A String
* `players` is an Array, each element has the following attributes:
    * `id` (as described above)
    * `player_name` (as described above)
    * `lat` (as described above)
    * `lon` (as described above)
* `is_started` is a Boolean

### Player Statistics

`player_statistics` is a JSON Object with the following attributes:

* `distance`: Number
* `different_vertices_touched`: Number
* `total_vertices_touched`: Number

### Graph

`graph` is a JSON Object with the following attributes:

* `vertices` is an Array, each element has the following attributes:
    * `id` (as described above)
    * `lat` (as described above)
    * `lon` (as described above)
    * `portable`: Either true or false
* `edges` is an Array, each element has the following attributes:
    * `vertex_a_id` (as described above)
    * `vertex_b_id` (as described above)
    * `color`: A String

## Routes

We define a number of routes to post to and get information from the server.

### POST: `/update`

Updates the position of the player and the vertex he or she carries.

#### Request

* player
* vertex

#### Response

* Success: 204
* Failure: 500

### GET: `/currentGameState/:lobby_id`

Get the current game state for the given lobby.

Example:
```
curl -X GET -H "Content-Type: application/json" http://localhost:9292/currentGameState/1212ffa11
```

#### Response

* Success: 200, body: GameState
* Failure (e.g. game was not started yet): 500

### POST: `/finishGame`

Marks the game as finished.

#### Request

* lobby\_id

#### Response

* Success: 204
* Failure: 500

### GET: `/game/:lobby_id`

Get all information about a game (including players, edges).

#### Response

* Success: 200, body: Game
* Failure: 500

### POST: `/lobby`

Create a new lobby with a given name

#### Request

* lobby_name

#### Response

* Success: 201, body: lobby\_id
* Failure (e.g. Lobby with this name already exists): 500

### POST: `/player`

Create a new player with a given name.

#### Request

* player_name

#### Response

* Success: 201, body: player\_id
* Failure (e.g. A player with this name already exists): 500

### POST: `/joinLobby`

Let a player with a certain ID join a certain lobby.

#### Request

* lobby\_id
* player\_id

#### Response

* Success: 204
* Failure (e.g. Lobby does not exist): 500

### GET: `/lobbies`

Get all available lobbies.

#### Response

* Success: 200, body: lobbies
* Failure: 500

### POST: `/game`

Start a game for a certain lobby with a given graph.

#### Request

* lobby\_id
* graph

#### Response

* Success: 204
* Failure (e.g. the game was already started): 500

### POST: `/leaveLobby`

Remove a player from a certain lobby.

#### Request

* lobby\_id
* player\_id

#### Response

* Success: 204
* Failure: 500

Montag, 1. Juli 2013

Threadübersicht

Hab ich bloss kopiert, nicht das ich das verstehen würde :-)




Einige Screenshots...

...ein bisschen läuft schon:


 Hauptmenü

Einstellungen
Eine Option :-)
Hilfe - so sollte es mal laufen
Spiel erstellen
Spielfeld mit Beispielgraph
Statistiken und mögliche Achievements