21.06.2013
Die nächste Android-App, die ich vorstellen möchte ist eine, die sich mit Techniken mobiler Geräte beschäftigt.
Dabei handelt es sich um ein Spiel, das man sich als Mischung von einer Schnitzeljagd, einem Topfschlagen und einem Versteckspiel der modernen Technik vorstellen kann.
Die App kann in „Google play“ unter folgendem Link herunter geladen werden:
Alternativ ist der Link zusammen mit einem QR-Code im Download-Center verfügbar:
http://hadizadeh.de/downloadcenter/downloaddetails/?id=8
Eine Ausführliche Hilfe zu der App ist als PDF auf Deutsch und Englisch verfügbar.
Bei Fragen oder Problemen kann die Kommentarfunktion genutzt oder eine E-Mail gesendet werden.
Das Spiel „Radiation Runner“
1 Voraussetzungen
Um die Anwendung „Radiation Runner“ im vollen Umfang nutzen zu können, muss das verwendete Smartphone über WLAN, NFC und Bluetooth verfügen.
2 Menüpunkte und Funktionen
2.1 Spielen
Zum Spielen von Radiation Runner ist es notwendig mindestens selbst einen Kurs zu erstellen oder diese per „Teilen“ zu importieren. Existieren noch keine Kurse wird man darauf hingewiesen.
2.2 Spielelemente
2.2.1 Titel
Der Titel ist der Name des aktuellen Kurses.
2.2.2 Lebensbalken
Der dargestellte Lebensbalken wird von der WLAN Stärke der eingetragenen Schutzschilde beeinfluss. Sobald der stärkste Schutzschild unter 60% sinkt, sinkt der Lebensbalken. Dieser sinkt umso schneller, desto schwächer das stärkste Schutzschild ist. Sollte eines der Schutzschilde wieder über 60% steigen, steigt der Lebensbalken langsam an.
2.2.3 NFC-Tags
Es werden alle NFC-Tags angezeigt, die beim Erstellen der Kurse angelegt wurden. Wird während des Spiels ein NFC-Tag eingelesen, wird dieser abgehakt.
2.2.4 Schutzschilde
Es werden alle Schutzschilde (WLAN Netzwerke) angezeigt, die beim Erstellen des Kurses angelegt wurden.
2.2.5 Timer
Der Timer zeigt die vergangene Spielzeit und ist ein wichtiger Bestandteil der Punkteberechnung. Je weniger Zeit man benötigt desto höher ist die später ausfallende Punktzahl für die Bestenliste.
2.3 Spielablauf
Sobald das Spiel gestartet wird, hat der Spieler die Aufgabe alle in der Liste angezeigten NFC-Tags so schnell wie möglich zu finden und einzulesen. Hierzu sollte er sich in der Reichweite von mindestens einem Schutzschild (WLAN) befinden. Dessen Stärke sollte nicht unter 60% fallen, da dies die Lebenspunkte reduziert.
2.4 Spielende
2.4.1 Sieg
Wenn alle NFC-Tags eingelesen und die Lebenspunkte nicht unter null gefallen sind, hat der Spieler gewonnen. Anschließend wird die Punktzahl für die Bestenliste aus der vergangenen Zeit und dem verbliebenen Leben berechnet.
2.4.2 Niederlage
Sobald die Lebenspunkte unter null fallen und nicht alle NFC-Tags eingelesen sind, ist das Spiel verloren.
2.5 Kursgenerator
Mit dem Kursgenerator können eigene Kurse erstellt werden.
2.6 Kursgenerator Elemente
2.6.1 Kursname
Für die Erstellung des Kurses ist der Name des Kurses zwingend notwendig.
2.6.2 NFC-Tags
Über die Schaltfläche „NFC-Tag hinzufügen“ muss mindestens ein NFC-Tag beschrieben werden.
2.6.3 WLANs
Es muss mindestens ein WLAN ausgewählt werden, damit der Kurs erstellt werden kann. Dies geschieht über die Schaltfläche „WLAN hinzufügen“. In der darauf folgenden Ansicht erscheint eine Liste aller aktuell erreichbaren WLANs und deren Signalstärken.
2.6.4 Einträge Löschen
Sollte ein NFC-Tag oder WLAN falsch ausgewählt worden sein, kann dieses durch einen langen Druck („Long Press“) auf das Element in der jeweiligen Liste entfernt werden.
2.7 Teilen
Über die Teilen Funktion kann der Benutzer erstellte Kurse per Bluetooth exportieren oder importieren. Zusätzlich gibt es die Möglichkeit Kurse zu löschen.
2.7.1 Importieren
Um einen Kurs zu importieren, muss Bluetooth aktiviert sein. Ist dies nicht der Fall wird man darauf hingewiesen und hat die Möglichkeit Bluetooth zu aktivieren. Anschließend erscheint eine Liste aller Geräte mit aktivem Bluetooth. Aus dieser wählt man den Sender aus. Geschieht das zum ersten Mal, muss man dem „Pairing-Dialog“ zustimmen. Abschließend wird der Kurs empfangen und abgespeichert.
2.7.2 Exportieren
Um einen Kurs zu importieren, muss Bluetooth aktiviert sein. Ist dies nicht der Fall wird man darauf hingewiesen und hat die Möglichkeit Bluetooth zu aktivieren. Anschließend wartet das Gerät 300 Sekunden auf einen Verbindungsaufbau. Erfolgt dieser rechtzeitig, wird der Kurs automatisch versendet.
2.7.3 Löschen
Durch einen langen Druck „Long Press“ auf einen Kurs (in der Liste der zu exportierenden Kurse) kann dieser gelöscht werden.
2.8 Bestenliste
Die Bestenliste zeigt alle Siege und die jeweilige Punktzahl in absteigender Reihenfolge an. Durch die Auswahl eines Ergebnisses erscheinen weitere Details.
Anwendungs-Videos
Zum Abschluss der Spielbeschreibung möchte ich drei Videos vorstellen, die sowohl das Track-Generieren, als auch das Teilen sowie das Ablaufen eines Tracks veranschaulichen:
Technische Aspekte
Ich möchte damit beginnen, die verwendeten Techniken und deren Nutzen vorzustellen:
WLAN-Feldstärkenmessung
In „Radiation Runner“ ist die WLAN-Technologie ein entscheidendes Spielelement. Die Feldstärke ausgewählter WLAN-Router/Accesspoints dient als Indikator für Schildstärken, die den Spieler vor schädlicher Strahlung schützen. Verlässt der Spieler ein festgelegtes WLAN bzw. fällt die Feldstärke unter einen bestimmten Wert, ist er dieser Strahlung ausgesetzt und verliert kontinuierlich je nach Stärke des WLANs Leben. Fällt der Wert unter null, stirbt der Spieler und das Spiel gilt als verloren.
NFC (Near Field Communication)
NFC-Tags sind in „Radiation Runner“ als Checkpoints zu verstehen. Der Spieler hat die Aufgabe die angegeben NFC-Tags zu finden und „einzuchecken“. Hat der Spieler alle NFC-Tags gefunden und gescannt, hat er das Spiel gewonnen, wenn sein Leben bis dahin nicht unter null gefallen ist.
OpenGL ES (OpenGL for Embedded Systems)
Als zusätzliche mobile Technik wird OpenGL ES zur Echtzeitdarstellung des Lebensbalkens verwendet. Der Lebensbalken wird als eigenständiges Element in die bestehende Ansicht integriert und nimmt nicht wie bei vielen Anwendungen den kompletten Bildschirm ein.
Bluetooth
Bluetooth wird verwendet, um aufgezeichnete Tracks zu teilen. Dabei gibt es die Möglichkeit Tracks zu im- oder exportieren.
Code-Ausschnitte
An dieser Stelle möchte ich nun die für die Techniken selbst relevanten Code-Ausschnitte vorstellen:
WLAN-Messung
Für die WLAN-Messung habe ich einen Android-Service implementiert, der folgenden AsyncTask besitzt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | protected class WlanUpdater extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... arg0) { boolean scanFinished = true; while (isServiceStarted()) { if (scanFinished) { ArrayList wlanElements = getWlans(); Intent intent = new Intent(ACTION_WLAN_LEVEL_CHANGED); intent.putExtra(EXTRA_WLAN_LEVEL, getBestWlanLevel()); intent.putParcelableArrayListExtra(EXTRA_WLAN_DATA, wlanElements); sendBroadcast(intent); scanFinished = wifiManager.startScan(); } try { Thread.sleep(Settings.WLAN_METER_CYCLE); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } } |
Es wäre auch eine Möglichkeit, die Abfrage erst im Listener der WLAN-Ergebnisse zu wiederholen, dort ist aber die Dauer der Abfrage nicht definiert, daher habe ich es mit dieser Schleife gelöst. Die WLAN Daten werden als Broadcast gesendet, sodass auch mehrere Activities darauf zugreifen können (in dem Fall die Life-Activity und auch die WLAN-Hinzufügen-Activity). Um die ArrayList per Intent senden zu können ist sie als Parcelable implementiert.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class WlanElement implements Parcelable, Serializable { ... public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public WlanElement createFromParcel(Parcel in) { return new WlanElement(in); } public WlanElement[] newArray(int size) { return new WlanElement[size]; } }; @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(ssid); dest.writeString(bssid); dest.writeInt(level); dest.writeDouble(percent); } ... } |
NFC-Handler
Der NFC-Handler ist als Singleton implementiert:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class NfcHandler { ... private static NfcHandler instance = null; private NfcHandler() { super(); } public static synchronized NfcHandler getInstance() { if (instance == null) { instance = new NfcHandler(); } return instance; } ... } |
Um einen NFC-Tag lesen oder schreiben zu können, muss nach NFC-Tags gescannt werden. Diese Methode sieht wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | public void startScanning(Context context) { adapter = NfcAdapter.getDefaultAdapter(context); pendingIntent = PendingIntent.getActivity(context, 0, new Intent(context, context.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0); IntentFilter tag = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED); tag.addCategory(Intent.CATEGORY_DEFAULT); try { tag.addDataType("*/*"); } catch (MalformedMimeTypeException e) { ... } IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); ndef.addCategory(Intent.CATEGORY_DEFAULT); try { ndef.addDataType("*/*"); } catch (MalformedMimeTypeException e) { ... } IntentFilter tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED); tech.addCategory(Intent.CATEGORY_DEFAULT); try { tech.addDataType("*/*"); } catch (MalformedMimeTypeException e) { ... } intentFiltersArray = new IntentFilter[] { tag, ndef, tech }; techList = new String[][] { new String[] { NfcA.class.getName(), MifareUltralight.class.getName(), Ndef.class.getName() }, new String[] { NfcA.class.getName(), }, new String[] { Ndef.class.getName() }, new String[] { MifareUltralight.class.getName() } }; } public void resume() { adapter.enableForegroundDispatch((Activity) context, pendingIntent, intentFiltersArray, techList); } |
Hierbei werden neben dem scannen selbst auch die unterstützten NFC-Techniken und deren Kombinationen festgelegt.
Der Lesevorgang eines erkannten Tags ist in folgendem Codeausschnitt zu sehen:
1 2 3 4 5 6 7 8 9 10 11 12 | public String read(Intent intent) { Parcelable[] rawMsgs = intent .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (rawMsgs != null) { NdefMessage msg = (NdefMessage) rawMsgs[0]; String text = new String(msg.getRecords()[0].getPayload()); return text; } else { return ""; } } |
Schreiben eines Strings auf einen Tag:
1 2 3 4 5 6 7 8 9 | public void write(String text, Tag tag) throws IOException, FormatException { NdefMessage message = new NdefMessage( new NdefRecord[] { new NdefRecord(NdefRecord.TNF_ABSOLUTE_URI, NdefRecord.RTD_URI, new byte[0], text.getBytes("UTF-8")) }); Ndef ndef = Ndef.get(tag); ndef.connect(); ndef.writeNdefMessage(message); ndef.close(); } |
Bluetooth-Controller
Um einen Bluetooth-Controller zu implementieren, kann ich nur das Bluetooth-Chat Example empfehlen, welches man im Android-SDK findet. Als Erweiterung dazu habe ich zu den „InputStream“ und „OutputStream“ jeweils einen „ObjectInputStream“ sowie „ObjectOutputStream“ erzeugt, um meine Objekte versenden und empfangen zu können.
Mit dieser Information sollte nun auch klar sein, aus welchem Grund die Klasse WlanElement, neben dem Interface Parcelable auch das Interface Serializable implementiert. Dies ist für das Senden über ObjectStreams notwendig.
Kategorie: News |
Schlagwörter: android, app, bluetooth, nfc, spiel, strahlung, wlan