Als Webentwickler achte ich genau auf das Design von Videospielen. Vom HUD in Overwatch über den Fangbildschirm in Pokemon Go bis hin zur Jagd in Oregon Trail – Spiele haben oft interessante Mechaniken und befriedigende Interaktionen, von denen viele meine eigenen Coding-Spiele bei Codepip inspirieren.
Darüber hinaus ist die Implementierung kleiner Ausschnitte dieser Spieldesigns auf einem Webstack eine unterhaltsame und effektive Möglichkeit, deine Fähigkeiten zu erweitern. Indem du dich auf ein bestimmtes Element konzentrierst, verbringst du deine Zeit damit, an einem interessanten Teil zu arbeiten, ohne ein ganzes Spiel mit allem, was dazu gehört, erstellen zu müssen. Und selbst in diesem begrenzten Umfang wirst du oft neuen Technologien und Techniken ausgesetzt, die die Grenzen deines Entwicklerwissens erweitern.
Als Fallstudie für diese Idee führe ich dich durch meine Neuerstellung des Kartenswipes aus Among Us. Für alle, die es nicht kennen: Among Us ist ein beliebtes Multiplayer-Spiel. An Bord eines Raumschiffs müssen die Crewmitglieder herausfinden, wer von ihnen ein Betrüger ist. Dabei erledigen sie alltägliche Wartungsaufgaben und vermeiden es, vom Betrüger ausgeschaltet zu werden.
Der Kartenswipe ist die berüchtigtste der Wartungsaufgaben. Obwohl sie einfach ist, hatten viele Spieler damit so große Schwierigkeiten, dass sie zum Stoff von Streams und Memes geworden ist.
Hier ist meine Demo
Dies ist meine Interpretation der Kartenwisch-Aufgabe
Als Nächstes führe ich dich durch einige der Techniken, die ich verwendet habe, um diese Demo zu erstellen.
Ziehen mit Maus- und Touch-Events
Nachdem ich die Hauptkomponenten schnell im Code skizziert hatte, musste ich die Karte ziehbar machen. Im Spiel folgt die Karte beim Start des Ziehens horizontal der Position deines Zeigers, bleibt aber vertikal am Kartenleser ausgerichtet. Die Karte hat eine Grenze, wie weit sie über den Leser hinaus nach links oder rechts gezogen werden kann. Schließlich kehrt die Karte zu ihrer ursprünglichen Position zurück, wenn du deine Maus oder deinen Finger loslässt.
All dies wird durch die Zuweisung von Funktionen zu Maus- und Touch-Events erreicht. Drei Funktionen genügen, um Maus Down, Maus Move und Maus Up (oder Touch Start, Touch Move und Touch End, wenn du auf einem Touchscreen-Gerät bist) zu verwalten. Hier ist das Grundgerüst dieses JavaScript-Codes
const card = document.getElementById('card');
const reader = document.getElementById('reader');
let active = false;
let initialX;
// set event handlers
document.addEventListener('mousedown', dragStart);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', dragEnd);
document.addEventListener('touchstart', dragStart);
document.addEventListener('touchmove', drag);
document.addEventListener('touchend', dragEnd);
function dragStart(e) {
// continue only if drag started on card
if (e.target !== card) return;
// get initial pointer position
if (e.type === 'touchstart') {
initialX = e.touches[0].clientX;
} else {
initialX = e.clientX;
}
active = true;
}
function drag(e) {
// continue only if drag started on card
if (!active) return;
e.preventDefault();
let x;
// get current pointer position
if (e.type === 'touchmove') {
x = e.touches[0].clientX - initialX;
} else {
x = e.clientX - initialX;
}
// update card position
setTranslate(x);
}
function dragEnd(e) {
// continue only if drag started on card
if (!active) return;
e.preventDefault();
let x;
// get final pointer position
if (e.type === 'touchend') {
x = e.touches[0].clientX - initialX;
} else {
x = e.clientX - initialX;
}
active = false;
// reset card position
setTranslate(0);
}
function setTranslate(x) {
// don't let card move too far left or right
if (x < 0) {
x = 0;
} else if (x > reader.offsetWidth) {
x = reader.offsetWidth;
}
// set card position on center instead of left edge
x -= (card.offsetWidth / 2);
card.style.transform = 'translateX(' + x + 'px)';
}
Status setzen mit performance.now()
Als Nächstes musste ich feststellen, ob der Kartenswipe gültig oder ungültig war. Damit er gültig ist, muss die Karte mit der richtigen Geschwindigkeit über den Leser gezogen werden. Nicht weit genug gezogen? Ungültig. Zu schnell? Ungültig. Zu langsam? Ungültig.
Um zu überprüfen, ob die Karte weit genug gezogen wurde, habe ich in der Funktion dragEnd die Position der Karte relativ zum rechten Rand des Kartenlesers überprüft
let status;
// check if card wasn't swiped all the way
if (x < reader.offsetWidth) {
status = 'invalid';
}
setStatus(status);
Um die Dauer des Kartenswipes zu messen, habe ich in dragStart und dragEnd Start- und Endzeitstempel mithilfe von performance.now() gesetzt.
function setStatus(status) {
// status is only set for incomplete swipes so far
if (typeof status === 'undefined') {
// timestamps taken at drag start and end using performance.now()
let duration = timeEnd - timeStart;
if (duration > 700) {
status = 'slow';
} else if (duration < 400) {
status = 'fast';
} else {
status = 'valid';
}
}
// set [data-status] attribute on reader
reader.dataset.status = status;
}
Basierend auf jeder Bedingung wird ein anderer Wert auf das data-status-Attribut des Lesegeräts gesetzt. CSS wird verwendet, um die entsprechende Nachricht anzuzeigen und entweder ein rotes oder grünes Licht zu beleuchten.
#message:after {
content: "Please swipe card";
}
[data-status="invalid"] #message:after {
content: "Bad read. Try again.";
}
[data-status="slow"] #message:after {
content: "Too slow. Try again.";
}
[data-status="fast"] #message:after {
content: "Too fast. Try again.";
}
[data-status="valid"] #message:after {
content: "Accepted. Thank you.";
}
.red {
background-color: #f52818;
filter: saturate(0.6) brightness(0.7);
}
.green {
background-color: #3dd022;
filter: saturate(0.6) brightness(0.7);
}
[data-status="invalid"] .red,
[data-status="slow"] .red,
[data-status="fast"] .red,
[data-status="valid"] .green {
filter: none;
}
Letzte Details mit Schriftarten, Animationen und Audio
Mit der abgeschlossenen Kernfunktionalität habe ich noch ein paar weitere Details hinzugefügt, um das Projekt noch mehr wie Among Us aussehen zu lassen.
Zuerst habe ich eine kostenlose benutzerdefinierte Schriftart namens DSEG verwendet, um die segmentierte Schriftart von alten LCDs nachzuahmen. Alles, was dazu nötig war, war das Hosten der Dateien und das Deklarieren der Schriftart in CSS.
@font-face {
font-family: 'DSEG14Classic';
src: url('../fonts/DSEG14-Classic/DSEG14Classic-Regular.woff2') format('woff2'),
url('../fonts/DSEG14-Classic/DSEG14Classic-Regular.woff') format('woff'),
url('../fonts/DSEG14-Classic/DSEG14Classic-Regular.ttf') format('truetype');
}
Als Nächstes habe ich die Jitter-Animation des Textes im Original kopiert. Spieleentwickler fügen oft subtile Animationen hinzu, um einem Element Leben einzuhauchen, wie z. B. einen sich bewegenden Hintergrund oder eine atmende Figur. Um den Jitter zu erreichen, habe ich eine CSS-Animation definiert
@keyframes jitter {
from {
transform: translateX(0);
}
to {
transform: translateX(5px);
}
}
Zu diesem Zeitpunkt gleitet der Text sanft hin und her. Stattdessen möchte ich, dass er fünf Pixel auf einmal hin und her springt. Hier kommt die steps() Funktion ins Spiel
#message {
animation: jitter 3s infinite steps(2);
}
Schließlich habe ich dasselbe Audio-Feedback hinzugefügt, das auch in Among Us verwendet wird.
let soundAccepted = new Audio('./audio/CardAccepted.mp3');
let soundDenied = new Audio('./audio/CardDenied.mp3');
if (status === 'valid') {
soundAccepted.play();
} else {
soundDenied.play();
}
Soundeffekte werden in der Welt der Webentwicklung oft kritisch gesehen. Ein Projekt wie dieses ist eine Gelegenheit, sich mit Audio auszutoben.
Und damit sind wir fertig! Hier ist die Demo noch einmal
Probiere es selbst aus
Angesichts der Standardisierung von Look and Feel im Web ist dieser Ansatz, ein Element aus einem Spiel zu nehmen und es für das Web zu implementieren, eine gute Möglichkeit, aus deiner Komfortzone auszubrechen und etwas Neues auszuprobieren.
Nimm diesen Among Us Karten-Swipe. In einer kleinen, einfachen Demo habe ich mit Web-Schriftarten und Animationen in CSS experimentiert. Ich habe mit Eingabeereignissen und Audio in JavaScript herumgespielt. Ich habe mich mit einem unkonventionellen visuellen Stil beschäftigt.
Jetzt ist es an der Zeit, dass du interessante Mechaniken aus deinen Lieblingsspielen untersuchst und versuchst, sie zu replizieren. Du wirst überrascht sein, was du lernst.