In diesem Tutorial erfahren Sie, wie Sie mit Physi.js einer mit Three.js erstellten 3D Szene Spielphysik hinzufügen können. Wir erstellen ein einfaches Spiel, in dem wir einen Wagen um das Sammeln von Gegenständen herum fahren, wobei wir grundlegende physikalische Formen und Einschränkungen verwenden.
Dieses Tutorial wird auf den Konzepten unseren vorherigen Three.js Tutorials aufbauen.
Aufgrund einer technischen Einschränkung beim Hosting von Webworker-basierten Lösungen auf JSFiddle können wir das interaktive Spiel nicht in diese Tutorial-Seite einbinden. Bitte verwenden Sie den mitgelieferten Quellcode, um das Funktionsbeispiel auf allen Cloudbasierten IDEs oder durch Self-Hosting zu überprüfen.
3D Physics im Web.
Es gibt derzeit mehrere Frameworks und Engines, mit denen 3D-Inhalte für das Web mit Physics erstellt werden können. Einige von ihnen sind Turbulenz, BabylonJS, PlayCanvas und Unity WebGL Build. Aber wenn es um Popularität und Benutzerfreundlichkeit geht, verwenden die meisten Leute gerne Three.js für ihre Experimente. Da Three.js eine Rendering-Engine ist und keine integrierte Physics hat, müssen wir zusätzliche Frameworks erforschen, um die Physikfähigkeit hinzuzufügen.
Eine sehr beliebte JavaScript-Physics-Lösung ist Ammo.js, eine direkte Portierung der Bullet-Physik. Während die direkte Nutzung von Ammo.js möglich ist, ist es nicht sehr anfängerfreundlich und hat eine Menge Boilerplate Code für jeden Aspekt. Da es nicht manuell geschrieben, sondern mit Emscripten portiert wird, ist der Code auch nicht leicht zu verstehen.
Eine alternative Lösung ist die Verwendung von Cannon.js oder Physijs. Das Interessante an Physijs ist, dass der Schwerpunkt immer darauf liegt, die Dinge zu erleichtern, was es zur idealen Wahl für Anfänger macht. Es basiert auf Ammo.js und hat sogar einen Cannon.js-Zweig. Dieses Tutorial verwendet Physijs und Three.js, um einen Prototypen eines Arbeitsspiels mit physikalischen Eigenschaften zu erstellen.
Eine weitere Möglichkeit, auch wenn Sie zu stark vereinfacht ist, wäre die Verwendung des Whitestorm-Frameworks, das ein komponentenbasiertes Framework auf Basis von Three.js und Physijs ist.
Einrichten von Physijs.
Wir benötigen die Dateien ammo.js, physi.js, physijs_worker.js und Three.js in unserer Ordnerstruktur oder Programmierumgebung, um Physijs verwenden zu können. Physijs verwendet einen Webworker, um verschiedene Threads für physikalische Berechnungen zu verwenden. Der erste Schritt im Integrationsprozess besteht also darin, den Webworker wie folgt einzurichten:
An dieser Stelle ist das Setup angeschlossen und wir können mit der Verwendung des physikalischen Frameworks beginnen. Physijs hat darauf geachtet, dass es dem Codierungsstil von Three.js folgt und die meisten Konzepte sind einfach Einsatz für das entsprechende Three.js-Konzept.
Grundlegende Schritte.
Anstelle von THREE.Scene müssen wir Physijs-Scene verwenden.
In Physijs stehen mehrere Meshes zur Verfügung, die anstelle von THREE.Mesh verwendet werden müssen. Die verfügbaren Optionen sind PlaneMesh, BoxMesh, SphereMesh, CylinderMesh, ConeMesh, CapsuleMesh, ConvexMesh, ConcaveMesh und HeighfieldMesh.
Wir müssen die Methode scene.simulate aufrufen, um die physikalischen Berechnungen entweder in der Rendermethode oder in häufigen Abständen durchzuführen. Wir möchten Sie daran erinnern, dass die physikalischen Berechnungen in einem anderen Thread stattfinden und nicht asynchron oder so schnell wie die Szenen-Render-Schleife sein werden.
Auch der nächste Call von scene.simulate kann erfolgen, während die vorherigen Berechnungen noch laufen. Um es richtig mit den physikalischen Berechnungen zu synchronisieren, können wir das Update Event der Physijs-Szene verwenden.
Um eine Kollision auf einem Physijs-Mesh-Objekt zu registrieren, das willkürlich als Würfel bezeichnet wird, können wir das Kollisionsereignis hören.
Innerhalb der obigen Methode bezieht sich dies auf den Würfel, während objCollidedWith ist, mit dem der Objektwürfel kollidiert ist.
Beispiel eines Spielprototyps.
Für dieses Tutorial werden wir ein ein sehr einfaches, physikalisch basiertes Spiel erstellen, bei dem wir physikalische Einschränkungen nutzen werden, um ein Fahrzeug zu erstellen. Der Spieler kann mit den Pfeiltasten das Fahrzeug steuern und einen springenden Ball einsammeln, der zufällig auf dem Spielfeld erscheint.
Interessanterweise hat Physijs bereits eine spezielle Fahrzeugfunktion, die direkt für die Erstellung von Fahrzeugen verwendet werden kann, aber wir werden sie nicht verwenden.
Die Spiel-Welt.
Unsere Spielwelt ist ein riesiger Boden mit Wänden auf allen Seiten.
Wir verwenden Physijs.BoxMesh für den Boden und die vier Wände, siehe dazu den folgenden Code:
Beachten Sie die Verwendung von Physijs.createMaterial, um die notwendigen physikalischen Materialien zu erstellen, indem Sie einen Reibungswert und einen Rückgabewert übergeben. Der Reibungswert bestimmt den Griff am Boden und der Rückgabewert bestimmt die Sprungkraft. Eine wichtige Sache zu beachten ist, dass, wenn wir einen Massenwert von 0 angeben, wir ein stationäres Meshobjekt erstellen.
Das Fahrzeugobjekt.
Wir werden ein spezielles Fahrzeug entwickeln, das aus zwei miteinander verbundenen Teilen besteht. Der vordere Teil, der drei Räder hat, dient als Engine und der hintere Teil, der zwei Räder hat, dient als Schlitten. Das Schlittenteil ist mit dem Engineteil über ein Scharniergelenk verbunden, das mit einem Physijs.HingeContraint realisiert ist.
Die Räder verwenden Physijs-DOFConstraint, was eine gewisse Freiheitsbeschränkung darstellt, die an der Karosserie des Fahrzeugs angebracht werden kann, während die Fähigkeit zur unabhängigen Drehung erhalten bleibt. Wir möchten Sie einladen, die offizielle Dokumentation über die verschiedenen in Physijs verfügbaren Einschränkungen zu lesen.
Engine Body und Carriage Body sind einfache BoxMesh-Objekte wie der oben gezeigte Boden, jedoch mit einem bestimmten Massenwert. Sie werden über ein Scharniergelenk miteinander verbundenen, wie im folgenden Code dargestellt. Ein Scharniergelenk schränkt die Bewegung des verbundenen Objekts wie bei einer normalen Tür ein.
Der zweite Teil des Codes wendet Grenzen für die Drehung des Scharniers an, die in diesem Fall zwischen -Math.PI/3 und Math.PI/3 liegt.
Die Räder verwenden einen Freiheitsgrad, mit dem sowohl die Linear- als auch die Winkelbewegung in allen drei Achsen begrenzt werden können. Es wird eine Methode addWheel zum Hinzufügen von Rädern erstellt, die mehrere Parameter berücksichtigt.
Die Parameter sind die Position des Rades, das Gewicht des Rades, ob das Rad groß oder klein ist und das Radbezugsobjekt. Die Methode gibt einen neu erstellten DOFConstraint zurück, der zum Fahren des Fahrzeugs verwendet wird.
Die großen Räder müssen am Schlitten befestigt werden und die kleinen Räder sind an der Engine befestigt. Die Räder erhalten einen Dämpfungswert, so dass ihre Winkelgeschwindigkeit reduziert wird, wenn keine äußere Kraft aufgebracht wird. Dadurch wird sichergestellt, dass das Fahrzeug beim Loslassen des Gaspedals langsamer wird.
Wir werden die Fahrlogik in einem späteren Abschnitt untersuchen. Jedem Rad-Mesh wird zusammen mit dem Fahrzeug-Meshes der Name des Wagens zur Indentifizierung während des Collision Callbacks zu geordnet. Jede Radbegrenzung hat unterschiedliche Winkelbegrenzungen, die nach ihrer Erstellung unabhängig voneinander eingestellt werden. Hier zum Beispiel der Code für das vordere mittlere Rad der Engine, car_wheel_fm und die entsprechende Einschränkung, car.wheel_fm_constraint.
Der Ball.
Der Ball ist ein Physijs.SphereMesh-Objekt mit einem niedrigeren Massenwert von 20. Wir verwenden die releaseBall-Methode, um den Ball zufällig auf unserem Spielfeld zu positionieren, wann immer er abgeholt wird.
Bemerkenswert ist die Tatsache, dass wir die in der physikalischen Simulation festgelegten Positionswerte überschreiben müssen, um unseren Ball neu zu positionieren. Dazu verwenden wir das _dirtyPosition-Flag, das sicherstellt, dass die neue Position für die weitere physikalische Simulation verwendet wird.
Der Ball wird gesammelt, wenn er mit einem beliebigen Teil des Fahrzeugs kollidiert, was bei der onCollision Listener Methode geschieht.
Mit dem Fahrzeug fahren.
Wir fügen Event-Listener für die onkeydown und onkeyup Events des Dokuments hinzu, wo wir den keyCode bestimmen, um die Werte der entsprechenden Radbeschränkungen einzustellen. Die Theorie ist, dass das einzelne Vorderrad der Engine die Drehung unseres Fahrzeugs steuert und die beiden Räder auf der Rückseite der Engine steuern die Beschleunigung und Verzögerung. Die Räder auf dem Schlitten spielen beim Fahren keine Rolle.
Die DOFConstraint verwendet das enableAngularEngine-Verfahren, um die Winkelgeschwindigkeit auf das Rad anzuwenden, das das Rad basierend auf dem als Parameter angegebenen Achswert dreht. Im Grunde drehen wir nur die Räder und die Bewegung des Fahrzeugs geschieht aufgrund der Reibungsreaktion des Bodens, wie in der realen Welt.
Wir können das Arbeitsspiel nicht in diese Seite einbetten, wie am Anfang des Tutorials erwähnt. Bitte geben Sie die komplette Quelle durch, um zu verstehen, wie alles miteinander verbunden ist.
Schlußfolgerungen.
Dies ist eine sehr einfache Einführung in die Implementierung der Physik in ihre Three.js-3D-Welt. Die Physijs-Dokumentation ist sehr mangelhaft, aber es gibt bereits viele Beispiele, die es wert sind, untersucht zu werden. Physijs ist ein sehr anfängerfreundliches Framework, wie Three.js, wenn man die Komplexität berücksichtigt, die durchaus vorhanden ist.
Wir hoffen, dass dieses Tutorial dabei geholfen hat, die interessante Welt der 3D Physics für Webspiele zu erkunden.