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.
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.
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!
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.
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!
Repository auf GitHub
Jetzt fangen wir an!
Zunächst benötigen wir eine React- Projektvorlage. Beginnen wir also mit der Installation.
npm create vite@latest
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.
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.
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.
In der App- Komponente fügen wir eine Sky- Komponente hinzu, die als Hintergrund in unserer Spielszene in Form eines Himmels angezeigt wird.
Erstellen wir eine Ground- Komponente und platzieren sie in der App- Komponente.
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.
Obwohl wir als Materialfarbe Grau angegeben haben, erscheint das Flugzeug komplett schwarz.
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.
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.
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.
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.
Nehmen wir eine kleine Änderung für die Ground- Komponente vor.
Aus Gründen der Übersichtlichkeit fügen wir der Szene einen einfachen Würfel hinzu.
<mesh position={[0, 3, -5]}> <boxGeometry /> </mesh>
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.
Danach werden wir sofort sehen, dass der Würfel jedes Mal, wenn die Seite neu geladen wird, unter dem Einfluss der Schwerkraft herunterfällt.
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.
Kehren wir zur Ground- Komponente zurück und fügen eine RigidBody- Komponente als Wrapper über der Bodenoberfläche hinzu.
Wenn der Würfel nun fällt, bleibt er wie ein echter physischer Gegenstand auf dem Boden.
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.
Platzieren Sie die Player- Komponente innerhalb der Physics-Komponente.
Nun ist unsere Figur auf der Bildfläche erschienen.
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.
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.
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.
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.
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.
Code-Erklärung:
- const world = rapier.world; Erhalten Sie Zugang zur Rapier- Physik-Engine-Szene. Es enthält alle physischen Objekte und verwaltet deren Interaktion.
- 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.
- 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.
Heben wir die Kamera etwas höher an, um die Szene besser sehen zu können.
Abschnittscode
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.
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.
Abschnittscode
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.
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.
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.
Jetzt importieren wir das erstellte Modell in die Szene. Fügen Sie in der App.jsx- Datei die WeaponModel- Komponente hinzu.
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.
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.
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.
Ä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.
Fügen Sie „castShadow“ und „receiveShadow“ für Cube hinzu.
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.
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.
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.
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.
Fügen wir einen useState hinzu, um die Animation zu speichern.
Lassen Sie uns eine Funktion erstellen, um die Animation zu initialisieren.
Code-Erklärung:
- const twSwayingAnimation = new TWEEN.Tween(currentPosition) ... Erstellen einer Animation eines Objekts, das von seiner aktuellen Position zu einer neuen Position „schwingt“.
- const twSwayingBackAnimation = new TWEEN.Tween(currentPosition) ... Erstellen einer Animation des Objekts, das nach Abschluss der ersten Animation zu seiner Startposition zurückkehrt.
- 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.
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.
Code-Erklärung:
- 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.
- 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.
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:
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.
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.
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.
Lassen Sie uns Funktionen erstellen, um einen zufälligen Vektor der Rückstoßanimation zu erhalten – „generateRecoilOffset “ und „generateNewPositionOfRecoil “.
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.
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.
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.
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.
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.