paint-brush
Erstellen Sie Ihren eigenen 3D-Shooter mit dem React- und Three.js-Stack – Teil 1von@varlab
907 Lesungen
907 Lesungen

Erstellen Sie Ihren eigenen 3D-Shooter mit dem React- und Three.js-Stack – Teil 1

von Ivan Zhukov17m2023/10/21
Read on Terminal Reader

Zu lang; Lesen

Im Zeitalter der aktiven Entwicklung von Webtechnologien und interaktiven Anwendungen werden 3D-Grafiken immer relevanter und gefragter. Aber wie erstellt man eine 3D-Anwendung, ohne die Vorteile der Webentwicklung zu verlieren? In diesem Artikel schauen wir uns an, wie Sie die Leistungsfähigkeit von Three.js mit der Flexibilität von React kombinieren, um Ihr eigenes Spiel direkt im Browser zu erstellen. In diesem Artikel stellen wir Ihnen die React Three Fiber-Bibliothek vor und zeigen Ihnen, wie Sie interaktive 3D-Spiele erstellen.
featured image - Erstellen Sie Ihren eigenen 3D-Shooter mit dem React- und Three.js-Stack – Teil 1
Ivan Zhukov HackerNoon profile picture
0-item
1-item

In der modernen Webentwicklung verschwimmen die Grenzen zwischen klassischen und Webanwendungen täglich. Heute können wir nicht nur interaktive Websites, sondern auch vollwertige Spiele direkt im Browser erstellen. Eines der Tools, das dies ermöglicht, ist die React Three Fiber- Bibliothek – ein leistungsstarkes Tool zum Erstellen von 3D-Grafiken auf Basis von Three.js mithilfe der React- Technologie.

Über den React Three Fiber Stack

React Three Fiber ist ein Wrapper für Three.js , der die Struktur und Prinzipien von React nutzt, um 3D-Grafiken im Web zu erstellen. Mit diesem Stack können Entwickler die Leistungsfähigkeit von Three.js mit dem Komfort und der Flexibilität von React kombinieren und so den Prozess der Anwendungserstellung intuitiver und organisierter gestalten.


Das Herzstück von React Three Fiber ist die Idee, dass alles, was Sie in einer Szene erstellen, eine React- Komponente ist. Dadurch können Entwickler bekannte Muster und Methoden anwenden.

Einer der Hauptvorteile von React Three Fiber ist die einfache Integration in das React- Ökosystem. Alle anderen React- Tools können bei Verwendung dieser Bibliothek weiterhin problemlos integriert werden.

Relevanz von Web-GameDev

Web-GameDev hat in den letzten Jahren große Veränderungen erfahren und sich von einfachen 2D- Flash- Spielen zu komplexen 3D-Projekten entwickelt, die mit Desktop-Anwendungen vergleichbar sind. Diese wachsende Beliebtheit und Leistungsfähigkeit machen Web-GameDev zu einem Bereich, der nicht ignoriert werden darf.


Einer der Hauptvorteile von Web-Gaming ist seine Zugänglichkeit. Spieler müssen keine zusätzliche Software herunterladen und installieren – klicken Sie einfach auf den Link in ihrem Browser. Dies vereinfacht den Vertrieb und die Werbung für Spiele und macht sie einem breiten Publikum auf der ganzen Welt zugänglich.


Schließlich kann die Entwicklung von Webspielen eine großartige Möglichkeit für Entwickler sein, sich mit vertrauten Technologien im Gamedev zu versuchen. Dank der verfügbaren Tools und Bibliotheken ist es auch ohne Erfahrung in der 3D-Grafik möglich, interessante und qualitativ hochwertige Projekte zu erstellen!

Spieleleistung in modernen Browsern

Moderne Browser haben einen langen Weg zurückgelegt und sich von relativ einfachen Webbrowser-Tools zu leistungsstarken Plattformen für die Ausführung komplexer Anwendungen und Spiele entwickelt. Große Browser wie Chrome , Firefox , Edge und andere werden ständig optimiert und weiterentwickelt, um eine hohe Leistung zu gewährleisten, was sie zu einer idealen Plattform für die Entwicklung komplexer Anwendungen macht.


Eines der wichtigsten Tools, das die Entwicklung browserbasierter Spiele vorangetrieben hat, ist WebGL . Dieser Standard ermöglichte Entwicklern die Nutzung der Hardware-Grafikbeschleunigung, was die Leistung von 3D-Spielen deutlich verbesserte. Zusammen mit anderen webAPIs eröffnet WebGL neue Möglichkeiten, beeindruckende Webanwendungen direkt im Browser zu erstellen.


Dennoch ist es bei der Entwicklung von Spielen für den Browser wichtig, verschiedene Leistungsaspekte zu berücksichtigen: Ressourcenoptimierung, Speicherverwaltung und Anpassung an verschiedene Geräte sind allesamt wichtige Punkte, die den Erfolg eines Projekts beeinflussen können.

Auf dein Zeichen!

Allerdings sind Worte und Theorie eine Sache, praktische Erfahrung jedoch eine ganz andere. Um das volle Potenzial der Entwicklung von Webspielen wirklich zu verstehen und zu schätzen, ist es am besten, in den Entwicklungsprozess einzutauchen. Als Beispiel für eine erfolgreiche Entwicklung von Webspielen werden wir daher unser eigenes Spiel erstellen. Dieser Prozess wird es uns ermöglichen, wichtige Aspekte der Entwicklung kennenzulernen, uns echten Problemen zu stellen und Lösungen dafür zu finden und zu sehen, wie leistungsstark und flexibel eine Webspiel-Entwicklungsplattform sein kann.


In einer Reihe von Artikeln schauen wir uns an, wie man mithilfe der Funktionen dieser Bibliothek einen Ego-Shooter erstellt, und tauchen in die aufregende Welt von Web-Gamedev ein!


Letzte Demo


Repository auf GitHub


Jetzt fangen wir an!

Einrichten des Projekts und Installieren von Paketen

Zunächst benötigen wir eine React- Projektvorlage. Beginnen wir also mit der Installation.


 npm create vite@latest


  • Wählen Sie die React- Bibliothek aus.
  • Wählen Sie JavaScript aus.


Installieren Sie zusätzliche npm-Pakete.


 npm install three @react-three/fiber @react-three/drei @react three/rapier zustand @tweenjs/tween.js


Dann löschen Sie alles Unnötige aus unserem Projekt.


Abschnittscode

Anpassen der Canvas-Anzeige

Fügen Sie in der Datei main.jsx ein div-Element hinzu, das auf der Seite als Bereich angezeigt wird. Fügen Sie eine Canvas- Komponente ein und legen Sie das Sichtfeld der Kamera fest. Platzieren Sie innerhalb der Canvas- Komponente die App- Komponente.


main.jsx


Fügen wir index.css Stile hinzu, um die UI-Elemente auf die volle Höhe des Bildschirms auszudehnen und den Bereich als Kreis in der Mitte des Bildschirms anzuzeigen.


index.css


In der App- Komponente fügen wir eine Sky- Komponente hinzu, die als Hintergrund in unserer Spielszene in Form eines Himmels angezeigt wird.


App.jsx


Den Himmel in der Szene anzeigen


Abschnittscode

Bodenfläche

Erstellen wir eine Ground- Komponente und platzieren sie in der App- Komponente.


App.jsx


Erstellen Sie in Ground ein flaches Oberflächenelement. Bewegen Sie es auf der Y-Achse nach unten, sodass diese Ebene im Sichtfeld der Kamera liegt. Und drehen Sie die Ebene auch um die X-Achse, um sie horizontal zu machen.


Ground.jsx


Obwohl wir als Materialfarbe Grau angegeben haben, erscheint das Flugzeug komplett schwarz.


Flach am Tatort


Abschnittscode

Grundbeleuchtung

Standardmäßig gibt es in der Szene keine Beleuchtung, also fügen wir eine Lichtquelle ambientLight hinzu, die das Objekt von allen Seiten beleuchtet und keinen gerichteten Strahl hat. Stellen Sie als Parameter die Intensität des Glühens ein.


App.jsx


Beleuchtetes Flugzeug


Abschnittscode

Textur für die Bodenoberfläche

Damit die Bodenoberfläche nicht homogen aussieht, fügen wir eine Textur hinzu. Erstellen Sie ein Muster auf der Bodenoberfläche in Form von Zellen, die sich entlang der gesamten Oberfläche wiederholen.

Fügen Sie im Assets- Ordner ein PNG-Bild mit einer Textur hinzu.


Textur hinzugefügt


Um eine Textur in die Szene zu laden, verwenden wir den useTexture- Hook aus dem @react-drei/drei- Paket. Und als Parameter für den Hook übergeben wir das in die Datei importierte Texturbild. Stellen Sie die Wiederholung des Bildes in den horizontalen Achsen ein.


Ground.jsx


Textur auf einer Ebene


Abschnittscode

Kamerabewegung

Fixieren Sie mithilfe der PointerLockControls- Komponente aus dem @react-drei/drei- Paket den Cursor auf dem Bildschirm, sodass er sich nicht bewegt, wenn Sie die Maus bewegen, sondern die Position der Kamera in der Szene ändert.


App.jsx


Demonstration der Kamerabewegung


Nehmen wir eine kleine Änderung für die Ground- Komponente vor.


Ground.jsx


Abschnittscode

Physik hinzufügen

Aus Gründen der Übersichtlichkeit fügen wir der Szene einen einfachen Würfel hinzu.


 <mesh position={[0, 3, -5]}> <boxGeometry /> </mesh> 


Der Würfel am Tatort


Im Moment hängt er nur im Weltraum.


Verwenden Sie die Physics- Komponente aus dem Paket @react- three/rapier, um der Szene „Physik“ hinzuzufügen. Als Parameter konfigurieren wir das Schwerkraftfeld, wobei wir die Gravitationskräfte entlang der Achsen einstellen.


 <Physics gravity={[0, -20, 0]}> <Ground /> <mesh position={[0, 3, -5]}> <boxGeometry /> </mesh> </Physics>


Allerdings befindet sich unser Würfel innerhalb der Physikkomponente, es passiert ihm aber nichts. Damit sich der Würfel wie ein echtes physisches Objekt verhält, müssen wir ihn in die RigidBody- Komponente aus dem @react-drei/rapier- Paket einbinden.


App.jsx


Danach werden wir sofort sehen, dass der Würfel jedes Mal, wenn die Seite neu geladen wird, unter dem Einfluss der Schwerkraft herunterfällt.


Würfel fallen


Aber jetzt gibt es eine andere Aufgabe – es ist notwendig, den Boden zu einem Objekt zu machen, mit dem der Würfel interagieren kann und über das er nicht hinausfällt.


Abschnittscode

Der Boden als physisches Objekt

Kehren wir zur Ground- Komponente zurück und fügen eine RigidBody- Komponente als Wrapper über der Bodenoberfläche hinzu.


Ground.jsx


Wenn der Würfel nun fällt, bleibt er wie ein echter physischer Gegenstand auf dem Boden.


Fallender Würfel im Flugzeug


Abschnittscode

Einen Charakter den Gesetzen der Physik unterwerfen

Erstellen wir eine Player- Komponente, die den Charakter in der Szene steuert.


Der Charakter ist das gleiche physische Objekt wie der hinzugefügte Würfel, daher muss er sowohl mit der Bodenoberfläche als auch mit dem Würfel in der Szene interagieren. Deshalb fügen wir die RigidBody- Komponente hinzu. Und lassen Sie uns den Charakter in Form einer Kapsel erstellen.


Player.jsx


Platzieren Sie die Player- Komponente innerhalb der Physics-Komponente.


App.jsx


Nun ist unsere Figur auf der Bildfläche erschienen.


Ein Charakter in Kapselform


Abschnittscode

Einen Charakter bewegen – einen Hook erstellen

Der Charakter wird mit den WASD- Tasten gesteuert und mit der Leertaste springt er.

Mit unserem eigenen React-Hook implementieren wir die Logik zum Bewegen des Charakters.


Erstellen wir eine Datei „hooks.js“ und fügen dort eine neue Funktion „usePersonControls“ hinzu.


Definieren wir ein Objekt im Format {"Schlüsselcode": "auszuführende Aktion"}. Fügen Sie als Nächstes Ereignishandler zum Drücken und Loslassen von Tastaturtasten hinzu. Wenn die Handler ausgelöst werden, ermitteln wir die aktuell ausgeführten Aktionen und aktualisieren ihren aktiven Status. Als Endergebnis gibt der Hook ein Objekt im Format {"action in progress": "status"} zurück.


Hooks.js


Abschnittscode

Einen Charakter bewegen – einen Hook implementieren

Nach der Implementierung des usePersonControls- Hooks sollte dieser zur Steuerung des Charakters verwendet werden. In der Player- Komponente fügen wir die Verfolgung des Bewegungszustands hinzu und aktualisieren den Vektor der Bewegungsrichtung des Charakters.


Wir werden auch Variablen definieren, die die Zustände der Bewegungsrichtungen speichern.


Player.jsx


Um die Position des Charakters zu aktualisieren, verwenden wirFrame, der vom @react-two/fiber- Paket bereitgestellt wird. Dieser Hook funktioniert ähnlich wie requestAnimationFrame und führt den Hauptteil der Funktion etwa 60 Mal pro Sekunde aus.


Player.jsx


Code-Erklärung:

1. const playerRef = useRef(); Erstellen Sie einen Link für das Player-Objekt. Dieser Link ermöglicht eine direkte Interaktion mit dem Spielerobjekt in der Szene.

2. const { vorwärts, rückwärts, links, rechts, springen } = usePersonControls(); Wenn ein Hook verwendet wird, wird ein Objekt mit booleschen Werten zurückgegeben, das angibt, welche Steuertasten gerade vom Spieler gedrückt werden.

3. useFrame((state) => { ... }); Der Hook wird in jedem Frame der Animation aufgerufen. Innerhalb dieses Hakens werden die Position und die lineare Geschwindigkeit des Spielers aktualisiert.

4. if (!playerRef.current) return; Prüft, ob ein Spielerobjekt vorhanden ist. Wenn kein Spielerobjekt vorhanden ist, stoppt die Funktion die Ausführung, um Fehler zu vermeiden.

5. const Velocity = playerRef.current.linvel(); Ermitteln Sie die aktuelle lineare Geschwindigkeit des Spielers.

6. frontVector.set(0, 0, rückwärts – vorwärts); Stellen Sie den Vorwärts-/Rückwärtsbewegungsvektor basierend auf den gedrückten Tasten ein.

7. sideVector.set(links - rechts, 0, 0); Legen Sie den Links-/Rechts-Bewegungsvektor fest.

8. Direction.subVectors(frontVector, sideVector).normalize().multiplyScalar(MOVE_SPEED); Berechnen Sie den endgültigen Vektor der Spielerbewegung, indem Sie die Bewegungsvektoren subtrahieren, das Ergebnis normalisieren (so dass die Vektorlänge 1 ist) und mit der Bewegungsgeschwindigkeitskonstante multiplizieren.

9. playerRef.current.wakeUp(); „Weckt“ das Spielerobjekt auf, um sicherzustellen, dass es auf Änderungen reagiert. Wenn Sie diese Methode nicht verwenden, wird das Objekt nach einiger Zeit „schlafen“ und nicht auf Positionsänderungen reagieren.

10. playerRef.current.setLinvel({ x: Direction.x, y: Velocity.y, z: Direction.z }); Stellen Sie die neue lineare Geschwindigkeit des Spielers basierend auf der berechneten Bewegungsrichtung ein und behalten Sie die aktuelle vertikale Geschwindigkeit bei (um Sprünge oder Stürze nicht zu beeinträchtigen).


Als Ergebnis begann sich die Figur beim Drücken der WASD- Tasten in der Szene zu bewegen. Er kann auch mit dem Würfel interagieren, da es sich bei beiden um physische Objekte handelt.


Charakterbewegung


Abschnittscode

Einen Charakter bewegen – springen

Um den Sprung zu implementieren, verwenden wir die Funktionalität der Pakete @dimforge/rapier3d-compat und @react-drei/rapier . In diesem Beispiel überprüfen wir, ob sich die Figur auf dem Boden befindet und die Sprungtaste gedrückt wurde. In diesem Fall legen wir die Richtung und Beschleunigungskraft des Charakters auf der Y-Achse fest.


Für den Spieler werden wir Masse hinzufügen und die Rotation auf allen Achsen blockieren, damit er nicht in verschiedene Richtungen umfällt, wenn er mit anderen Objekten in der Szene kollidiert.


Player.jsx


Code-Erklärung:

  1. const world = rapier.world; Erhalten Sie Zugang zur Rapier- Physik-Engine-Szene. Es enthält alle physischen Objekte und verwaltet deren Interaktion.
  1. const ray = world.castRay(new RAPIER.Ray(playerRef.current.translation(), { x: 0, y: -1, z: 0 })); Hier findet „Raycasting“ (Raycasting) statt. Es wird ein Strahl erstellt, der an der aktuellen Position des Spielers beginnt und entlang der y-Achse nach unten zeigt. Dieser Strahl wird in die Szene „geworfen“, um festzustellen, ob er ein Objekt in der Szene schneidet.
  1. constgrounded = ray && ray.collider && Math.abs(ray.toi) <= 1.5; Die Bedingung wird überprüft, wenn der Spieler am Boden liegt:
  • Strahl – ob der Strahl erstellt wurde;
  • ray.collider – ob der Strahl mit einem beliebigen Objekt in der Szene kollidiert ist;
  • Math.abs(ray.toi) – die „Belichtungszeit“ des Strahls. Wenn dieser Wert kleiner oder gleich dem angegebenen Wert ist, kann dies darauf hindeuten, dass sich der Spieler nahe genug an der Oberfläche befindet, um als „am Boden“ zu gelten.


Sie müssen auch die Bodenkomponente ändern, damit der Raytrace-Algorithmus zur Bestimmung des „Lande“-Status korrekt funktioniert, indem Sie ein physisches Objekt hinzufügen, das mit anderen Objekten in der Szene interagiert.


Ground.jsx


Heben wir die Kamera etwas höher an, um die Szene besser sehen zu können.


main.jsx


Charakter springt


Abschnittscode

Bewegen Sie die Kamera hinter die Figur

Um die Kamera zu bewegen, ermitteln wir die aktuelle Position des Players und ändern die Position der Kamera jedes Mal, wenn das Bild aktualisiert wird. Und damit sich der Charakter genau entlang der Flugbahn bewegt, auf die die Kamera gerichtet ist, müssen wir applyEuler hinzufügen.


Player.jsx


Code-Erklärung:

Die Methode applyEuler wendet eine Drehung auf einen Vektor basierend auf angegebenen Euler-Winkeln an. In diesem Fall wird die Kameradrehung auf den Richtungsvektor angewendet. Dies wird verwendet, um die Bewegung relativ zur Kameraausrichtung anzupassen, sodass sich der Spieler in die Richtung bewegt, in die die Kamera gedreht wird.


Passen wir die Größe von Player leicht an und machen ihn im Verhältnis zum Würfel höher, wodurch wir CapsuleCollider vergrößern und die „Sprung“-Logik korrigieren.


Player.jsx


Bewegen der Kamera


Abschnittscode

Erzeugung von Würfeln

Damit sich die Szene nicht völlig leer anfühlt, fügen wir die Würfelgenerierung hinzu. Listen Sie in der JSON-Datei die Koordinaten der einzelnen Würfel auf und zeigen Sie sie dann in der Szene an. Erstellen Sie dazu eine Datei „cubes.json“ , in der wir ein Array von Koordinaten auflisten.


 [ [0, 0, -7], [2, 0, -7], [4, 0, -7], [6, 0, -7], [8, 0, -7], [10, 0, -7] ]


Erstellen Sie in der Datei Cube.jsx eine Cubes- Komponente, die Cubes in einer Schleife generiert. Und die Cube- Komponente wird direkt zum generierten Objekt.


 import {RigidBody} from "@react-three/rapier"; import cubes from "./cubes.json"; export const Cubes = () => { return cubes.map((coords, index) => <Cube key={index} position={coords} />); } const Cube = (props) => { return ( <RigidBody {...props}> <mesh castShadow receiveShadow> <meshStandardMaterial color="white" /> <boxGeometry /> </mesh> </RigidBody> ); }


Fügen wir die erstellte Cubes- Komponente zur App- Komponente hinzu, indem wir den vorherigen einzelnen Cube löschen.


App.jsx


Erzeugung von Würfeln


Abschnittscode

Importieren des Modells in das Projekt

Nun fügen wir der Szene ein 3D-Modell hinzu. Fügen wir ein Waffenmodell für den Charakter hinzu. Beginnen wir mit der Suche nach einem 3D-Modell. Nehmen wir zum Beispiel dieses .


Laden Sie das Modell im GLTF-Format herunter und entpacken Sie das Archiv im Stammverzeichnis des Projekts.

Um das Format zu erhalten, das wir zum Importieren des Modells in die Szene benötigen, müssen wir das Zusatzpaket gltf-pipeline installieren.


npm i -D gltf-pipeline


Konvertieren Sie das Modell mithilfe des gltf-pipeline- Pakets erneut vom GLTF-Format in das GLB-Format , da in diesem Format alle Modelldaten in einer Datei abgelegt werden. Als Ausgabeverzeichnis für die generierte Datei geben wir den öffentlichen Ordner an.


gltf-pipeline -i weapon/scene.gltf -o public/weapon.glb


Dann müssen wir eine Reaktionskomponente generieren, die das Markup dieses Modells enthält, um es der Szene hinzuzufügen. Nutzen wir die offizielle Ressource der @react-two/fiber- Entwickler.


Wenn Sie zum Konverter gehen, müssen Sie die konvertierte Datei Weapon.glb laden.


Suchen Sie diese Datei per Drag & Drop oder per Explorer-Suche und laden Sie sie herunter.


Umgebautes Modell


Im Konverter sehen wir die generierte Reaktionskomponente, deren Code wir in einer neuen Datei WeaponModel.jsx in unser Projekt übertragen und dabei den Namen der Komponente in denselben Namen wie die Datei ändern.


Abschnittscode

Anzeigen des Waffenmodells vor Ort

Jetzt importieren wir das erstellte Modell in die Szene. Fügen Sie in der App.jsx- Datei die WeaponModel- Komponente hinzu.


App.jsx


Demonstration des importierten Modells


Abschnittscode

Schatten hinzufügen

Zu diesem Zeitpunkt in unserer Szene wirft keines der Objekte Schatten.

Um Schatten in der Szene zu aktivieren, müssen Sie der Canvas- Komponente das Schattenattribut hinzufügen.


main.jsx


Als nächstes müssen wir eine neue Lichtquelle hinzufügen. Trotz der Tatsache, dass ambientLight bereits vor Ort ist, kann es keine Schatten für Objekte erzeugen, da es keinen gerichteten Lichtstrahl hat. Fügen wir also eine neue Lichtquelle namens DirectionalLight hinzu und konfigurieren sie. Das Attribut zum Aktivieren des „ cast “-Schattenmodus ist castShadow . Das Hinzufügen dieses Parameters gibt an, dass dieses Objekt einen Schatten auf andere Objekte werfen kann.


App.jsx


Danach fügen wir der Bodenkomponente ein weiteres Attribut „receiveShadow“ hinzu, was bedeutet, dass die Komponente in der Szene Schatten auf sich selbst empfangen und anzeigen kann.


Ground.jsx


Das Modell wirft einen Schatten


Ähnliche Attribute sollten anderen Objekten in der Szene hinzugefügt werden: Würfeln und Spieler. Für die Würfel werden wir „castShadow “ und „receiveShadow“ hinzufügen, da sie sowohl Schatten werfen als auch empfangen können, und für den Spieler werden wir nur „castShadow“ hinzufügen.


Fügen wir castShadow für Player hinzu.


Player.jsx


Fügen Sie „castShadow“ und „receiveShadow“ für Cube hinzu.


Cube.jsx


Alle Objekte auf der Bühne werfen einen Schatten


Abschnittscode

Schatten hinzufügen – Schattenbeschneidung korrigieren

Wenn Sie nun genau hinsehen, werden Sie feststellen, dass die Oberfläche, auf die der Schatten geworfen wird, recht klein ist. Und wenn man über diesen Bereich hinausgeht, wird der Schatten einfach abgeschnitten.


Schattenzuschnitt


Der Grund dafür ist, dass die Kamera standardmäßig nur einen kleinen Bereich der angezeigten Schatten von DirectionalLight erfasst. Wir können für die DirectionalLight- Komponente durch Hinzufügen zusätzlicher Attribute „shadow-camera-“ (oben, unten, links, rechts) diesen Sichtbarkeitsbereich erweitern. Nach dem Hinzufügen dieser Attribute wird der Schatten leicht unscharf. Um die Qualität zu verbessern, werden wir das Attribut „shadow-mapSize“ hinzufügen.


App.jsx


Abschnittscode

Waffen an einen Charakter binden

Fügen wir nun die Ego-Waffenanzeige hinzu. Erstellen Sie eine neue Waffenkomponente , die die Verhaltenslogik der Waffe und das 3D-Modell selbst enthält.


 import {WeaponModel} from "./WeaponModel.jsx"; export const Weapon = (props) => { return ( <group {...props}> <WeaponModel /> </group> ); }


Platzieren wir diese Komponente auf derselben Ebene wie den RigidBody des Charakters und legen wir im useFrame- Hook die Position und den Drehwinkel basierend auf der Position der Werte von der Kamera fest.


Player.jsx


Darstellung von Waffenmodellen aus der Ego-Perspektive


Abschnittscode

Animation des Waffenschwingens beim Gehen

Um den Gang des Charakters natürlicher zu gestalten, fügen wir ein leichtes Wackeln der Waffe während der Bewegung hinzu. Zum Erstellen der Animation verwenden wir die installierte Bibliothek tween.js .


Die Weapon- Komponente wird in ein Gruppen-Tag eingeschlossen, sodass Sie über den useRef- Hook einen Verweis darauf hinzufügen können.


Player.jsx


Fügen wir einen useState hinzu, um die Animation zu speichern.


Player.jsx


Lassen Sie uns eine Funktion erstellen, um die Animation zu initialisieren.


Player.jsx


Code-Erklärung:

  1. const twSwayingAnimation = new TWEEN.Tween(currentPosition) ... Erstellen einer Animation eines Objekts, das von seiner aktuellen Position zu einer neuen Position „schwingt“.
  1. const twSwayingBackAnimation = new TWEEN.Tween(currentPosition) ... Erstellen einer Animation des Objekts, das nach Abschluss der ersten Animation zu seiner Startposition zurückkehrt.
  1. twSwayingAnimation.chain(twSwayingBackAnimation); Verbinden Sie zwei Animationen, sodass die zweite Animation automatisch startet, wenn die erste Animation abgeschlossen ist.


In useEffect rufen wir die Animationsinitialisierungsfunktion auf.


Player.jsx


Nun gilt es, den Zeitpunkt zu bestimmen, in dem die Bewegung stattfindet. Dies kann durch die Bestimmung des aktuellen Vektors der Richtung des Zeichens erfolgen.


Wenn es zu einer Charakterbewegung kommt, aktualisieren wir die Animation und führen sie nach Abschluss erneut aus.


Player.jsx


Code-Erklärung:

  1. const isMoving = Direction.length() > 0; Hier wird der Bewegungszustand des Objekts überprüft. Wenn der Richtungsvektor eine Länge größer als 0 hat, bedeutet dies, dass das Objekt eine Bewegungsrichtung hat.
  1. if (isMoving && isSwayingAnimationFinished) { ... } Dieser Zustand wird ausgeführt, wenn sich das Objekt bewegt und die „schwingende“ Animation beendet ist.


Fügen wir in der App- Komponente einen useFrame hinzu, in dem wir die Tween-Animation aktualisieren.


App.jsx


TWEEN.update() aktualisiert alle aktiven Animationen in der TWEEN.js- Bibliothek. Diese Methode wird bei jedem Animationsframe aufgerufen, um sicherzustellen, dass alle Animationen reibungslos ablaufen.


Abschnittscode:

Rückstoßanimation

Wir müssen den Moment definieren, in dem ein Schuss abgefeuert wird, also wenn die Maustaste gedrückt wird. Fügen wir useState hinzu, um diesen Zustand zu speichern, useRef , um einen Verweis auf das Waffenobjekt zu speichern, und zwei Ereignishandler zum Drücken und Loslassen der Maustaste.


Weapon.jsx


Weapon.jsx


Weapon.jsx


Lassen Sie uns eine Rückstoßanimation beim Klicken mit der Maustaste implementieren. Zu diesem Zweck verwenden wir die Bibliothek tween.js .


Definieren wir Konstanten für die Rückstoßkraft und die Animationsdauer.


Weapon.jsx


Wie bei der Animation zum Wackeln der Waffe fügen wir zwei useState-Zustände für den Rückstoß und die Animation zur Rückkehr in die Ausgangsposition sowie einen Zustand mit dem Endstatus der Animation hinzu.


Weapon.jsx


Lassen Sie uns Funktionen erstellen, um einen zufälligen Vektor der Rückstoßanimation zu erhalten – „generateRecoilOffset “ und „generateNewPositionOfRecoil “.


Weapon.jsx


Erstellen Sie eine Funktion, um die Rückstoßanimation zu initialisieren. Wir werden auch useEffect hinzufügen, in dem wir den „Shot“-Status als Abhängigkeit angeben, sodass bei jedem Shot die Animation erneut initialisiert und neue Endkoordinaten generiert werden.


Weapon.jsx


Weapon.jsx


Und in useFrame fügen wir eine Prüfung zum „Gedrückthalten“ der Maustaste zum Abfeuern hinzu, damit die Abfeueranimation nicht stoppt, bis die Taste losgelassen wird.


Weapon.jsx


Rückstoßanimation


Abschnittscode

Animation bei Inaktivität

Realisieren Sie die Animation der „Inaktivität“ für den Charakter, sodass nicht das Gefühl entsteht, dass das Spiel „hängt“.


Dazu fügen wir über useState einige neue Zustände hinzu.


Player.jsx


Lassen Sie uns die Initialisierung der „Wackel“-Animation korrigieren, um Werte aus dem Zustand zu verwenden. Die Idee ist, dass verschiedene Zustände (Gehen oder Anhalten) unterschiedliche Werte für die Animation verwenden und jedes Mal die Animation zuerst initialisiert wird.


Player.jsx


Leerlaufanimation


Abschluss

In diesem Teil haben wir Szenengenerierung und Charakterbewegung implementiert. Wir haben außerdem ein Waffenmodell und eine Rückstoßanimation beim Schießen und im Leerlauf hinzugefügt. Im nächsten Teil werden wir unser Spiel weiter verfeinern und neue Funktionen hinzufügen.


Auch hier veröffentlicht.