Uno AR

Konzept Bild

Moin,

heute möchte ich euch zeigen, wie man mit AR.js eine kleine Anwendung bauen kann, die ein klassisches Kartenspiel erweitert. Das Projekt habe ich während meiner Uni-Zeit entwickelt und möchte es nun mit euch teilen.

Um das Projekt zum Laufen zu bringen, benötigt ihr AR.js und ein Image Target, das ihr auf die Karte kleben könnt. Das Image Target habe ich in der Datei "targets-UNO.mind" gespeichert und im Code eingebunden. Achso, habe ich schon erwähnt, dass es um Uno geht?

In der Anwendung könnt ihr verschiedene Karten scannen, die dann auf dem Image Target erscheinen. Jede Karte zeigt euch an, welche Aktion ihr ausführen könnt. So könnt ihr beispielsweise eine Karte ziehen oder einen Spieler aussetzen.

Um das Spiel noch interaktiver zu gestalten, habe ich auch eine Audiofunktion hinzugefügt. Wenn ihr auf den Audio-Button klickt, wird euch der Assistent die Spielregeln erklären. In Zukunft könnte man so etwas auch einsetzen, um Binden vorlesen zu lassen, welche Karte sie gerade in der Hand halten. Für Uno müsste hier aber eine Möglichkeit entwickelt werden, welche die Farbe der Karte erkennt, da die Marker Funktion von ar.js nur Graustufen erkennt.

Ich hoffe, euch gefällt diese kleine Anwendung und vielleicht könnt ihr sie ja sogar als Inspiration für eigene AR-Projekte nutzen.

So genug der Beschreibung lasst uns mal einen Blick in den Code werfen (und keine Angst es ist recht simpel gehalten)

Code

Code auf Github

Im HTML-Code (index.html) werden zuerst die notwendigen JavaScript-Dateien eingebunden:

<script src="js/mindAR_components/mindar-image.prod.js"></script>
<script src="js/mindAR_components/aframe.min.js"></script>
<script src="js/mindAR_components/mindar-image-aframe.prod.js"></script>

Diese JavaScript-Dateien enthalten die notwendigen Funktionen und Elemente für die Nutzung von MindAR. A-Frame ist eine Web-Technologie, die es ermöglicht, 3D-Objekte mit HTML-Code zu erstellen. In diesem Projekt wird sie verwendet, um die 3D-Karten auf den UNO-Karten darzustellen.

Im HTML-Code sind auch die Links zu Bootstrap- und jQuery-Dateien zu sehen, welche für das Design und die Funktionen der Webseite benötigt werden.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>

Anschließend folgt die Struktur des Body-Tags mit dem div-Tag für die Bodyoverlay und dem Modal-Tag für die Spielanleitung. Außerdem gibt es ein Audio-Button und ein Info-Button.

<div class="bodyoverlay">
...
</div>
<a href="Assets/UNO-AR_Spielanleitung.pdf" target=”_blank” rel="noopener"><div id="info">&#9432</div></a>
<div id="toggleAudio">
...
</div>

So, fangen wir mal mit dem wahren Shit an:

Zuerst braucht ihr eure Marker. Dafür macht ihr am besten einen Scan eurer Spielkarten und ladet sie dann hier hoch: https://jeromeetienne.github.io/AR.js/three.js/examples/marker-training/examples/generator.html
Alternativ könnt ihr zum Testen schon einen vorgefertigten Marker benutzen. Oder nutzt einfach meine Marker, die findet ihr im Github Repo.

Aufbau des Tracker erstellens

Im A-Frame Code (innerhalb des a-scene-Tags) werden die 3D-Objekte definiert, die auf den UNO-Karten dargestellt werden sollen. Jede UNO-Karte bekommt dabei eine eindeutige ID zugewiesen.

 <a-scene mindar-image="imageTargetSrc: targets-UNO.mind;" color-space="sRGB" renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">

            <a-assets>
                <img id="retoure" src="Assets/images/retoure.png" />
                <img id="draw_4_color" src="Assets/images/draw_4_color.png" />
                <img id="draw_2" src="Assets/images/draw_2.png" />
                <img id="numbers" src="Assets/images/numbers.png" />
                <img id="skip" src="Assets/images/skip.png" />
            </a-assets>

            <a-camera position="0 0 0" look-controls="enabled: false"></a-camera>

Das Attribut "mindar-image-target" gibt hierbei an, dass die ID der zugehörigen UNO-Karte auf dem Bildschirm angezeigt werden soll, sobald die Kamera diese erfasst hat. Die "src"-Eigenschaft gibt den Pfad zum Bild an, das auf der UNO-Karte dargestellt werden soll. In diesem Fall ist es die Karte "Draw 2".

Im JavaScript-Code wird das MindAR-Objekt initialisiert und der Event-Listener für das Scannen der Karten hinzugefügt.

<a-entity id='card_draw_2' mindar-image-target="targetIndex: 0 ">
  <a-plane src="#draw_2" position="0 0 0" height="1.6" width="1" rotation="0 0 0"></a-plane>
</a-entity>

Das Attribut "mindar-image-target" gibt hierbei an, dass die ID der zugehörigen UNO-Karte auf dem Bildschirm angezeigt werden soll, sobald die Kamera diese erfasst hat. Die "src"-Eigenschaft gibt den Pfad zum Bild an, das auf der UNO-Karte dargestellt werden soll. In diesem Fall ist es die Karte "Draw 2".

Kleiner AR.js Exkurs

Innerhalb des <a-scene> Tags befinden sich alle 3D-Objekte, die in der AR-Szene gerendert werden sollen. Hier wird also die gesamte AR-Umgebung aufgebaut.

Zunächst einmal wird eine Liste mit allen benötigten Assets, also Bilddateien, die als Texturen auf den 3D-Objekten verwendet werden sollen, angelegt. Diese Assets werden dann später in den einzelnen <a-entity> Tags, also den Objekten, verwendet.

Der <a-camera> Tag definiert die Kamera, durch die der Benutzer die Szene betrachtet. In diesem Fall wird eine Kamera ohne Look-Controls verwendet, da die Rotation der Kamera durch die Bewegungen des Smartphones gesteuert wird.

Jedes <a-entity> Tag definiert ein 3D-Objekt in der Szene. Die Attribute id und mindar-image-target definieren das Objekt als AR-Objekt, das auf einem bestimmten Marker erkannt werden soll. Der targetIndex gibt dabei an, welcher der in a-assets definierten Marker erkannt werden soll.

Innerhalb jedes <a-entity> Tags wird ein <a-plane> Tag verwendet, um ein flaches Rechteck als sichtbare Fläche des Objekts zu erzeugen. Das Attribut src definiert hierbei die Textur, die auf der Fläche angezeigt wird.

Insgesamt wird die Szene also aus einer Liste von <a-entity> Tags aufgebaut, die jeweils ein 3D-Objekt mit einer Texturebene enthalten. Diese Objekte werden dann durch die MindAR-Bibliothek auf den erkannten Markern platziert.




Im JavaScript-Code wird das MindAR-Objekt initialisiert und der Event-Listener für das Scannen der Karten hinzugefügt.

mindAR.init({
  authkey: '...',
  appkey: '...'
}).then(() => {
  // Event listener for scanning images
  document.addEventListener('mindar-imagefound', function (event) {
    ...
  });
});

Innerhalb des Event-Listeners wird dann das Verhalten definiert, das ausgeführt werden soll, wenn eine Karte erkannt wurde.

Viel Spaß beim Ausprobieren!