-:|:- www.pastorpixel.de -:|:- Experiment Michael Albers -:|:-
PlayCanvas ist eine Online Game Engine. Programmiersprache Javascript. https://playcanvas.com
Veröffentlichung auf verschiedenen Plattformen möglich.
Tutorials bei Youtube / schon etwas älter, aber durchaus hilfreich.
Desweiteren gibt es viele Tutorials und Dokumentationen direkt bei playcanvas
Scrollrad Ansicht vergrößern
Linke Maus Ansicht drehen
Shift Ansicht verschieben
rechte Maus Look around
Pfeiltasten ändern die Ansicht
Alle Entities sind in der Hierachie. Dort kann man sie auswählen.
Augenwerkzeug, setzt das Entity in den Focus
siehe User Manual
Alle Objekte sind Entities, also Instanzen. Diese kann man mit add Entity zuweisen.
Ein Entity kann vieles sein, ein Würfel, eine Figur oder einfach ein Punkt im Raum.
Entities erben einen Großteil ihrer Eigenschaften von pc.GraphNode. Alle Manipulationen kann man auch über pc.GraphNode programmieren. Über die lokale Transform Matrix kann man die Position, Orientierung und Größe des Entity und all seiner Child Entities bestimmen. Um das zu beherrschen muss man verstehen, dass es ein globales und lokales Koordinatensystem gibt.
Das World Coordinate System wird von allen Entities geteilt. Sein fester Nullpunkt liegt bei (0,0,0) und es hat eine feste Orientierung, dabei ist (0,1,0) oben. Das Local Coordinate System bezieht sich auf das Entity selbst. Hier liegt der Nullpunkt im Zentrum des Entities selber und die Orientierung folgt der Orientierung des Entities.
Entities sind eine Art pc.GraphNode. Sie werden zusammengefasst in parents und children. Jedes Entity kann ein parent haben und mehrere children. Die child- Entities erben ihre Transformation Information von ihren parents.
Die Word Transformation Matrix eines Entities mulitpliziert die lokale Transformation mit der World Tranformation des parents.
Zum Beispiel wenn ein child die translation (1, 0, 0) besitzt und dessen parent die translation (0, 1, 0) besitzt, so ist die world position des child (1, 1, 0).
Über die Schlüsselwort parent kann man auf das Elternelement zugreifen
Über das Schlüsselwort parent, kann man auf das Elternelement zugreifen.
this.entity.parent.setPosition(0,0,0);
Auch die Kindelemente lassen sich ansprechen. Dazu gibt es einige Methoden.
find, findByName, findByPath, findByTag
Wenn man jedem Entitie einen einmaligen Namen vergibt, kann man ihn über die Methode findByName(String) leicht finden. Die Methode liefert das erste Kindelement diesen Namens. Im folgenden Beispiel wird das Kindelement namens "wheel_front_left" auf der x Achse um 90 Grad gedreht.
this.entity.findByName("wheel_front_left").rotateLocal(90, 0, 0);
Nehmen wir an, in einem entity auto befindet sich ein Entity namens "Achse1" und darin befinden sich die beiden Kindelemente "rad1" und "rad2". Über findByPath, kann ich folgendermaßen auf rad1 zugreifen.
this.entity.findByPath("Achse1/rad1").rotateLocal(30,0,0);
//Liefert die Position eines Entity relativ zum Koordinatensystem des parent var lp = this.entity.getLocalPosition(); //Liefert die Position im World Space var wp = this.entity.getPosition();
Es wird eine Methode pc.Vec3([x,y,z]) geliefert. Ein Vektormenge in Form eines Arrays.
Im obigen Beispiel liefert wp.x die X-Position
Das Setzen der Position ist geschieht auf ähnlich, einfache Weise.
// Die Position relativ zum Koordinatensystem des parent Entity this.entity.setLocalPosition(x, y, z); //Die Entity Position im World Space this.entity.setPosition(x, y, z);
Anstatt einen vorhandenen Positionswert zu erhöhen oder zu verringern, kann man auch folgende Hilfsfunktionen nutzen.
// Versetze das Entity eine Einheit herab auf der position X-Achse des World Space. this.entity.translate(1, 0, 0); // Versetze das Entity eine Eiheit herauf auf der lokalen z-Achse. this.entity.translateLocal(0, 0, 1);
Die Orientierung oder Drehung auf den 3 Achsen kann man auf 2 Arten definieren, Euler Angles oder Quaternions.
Euler Angles ist die Drehung auf den 3 Achsen x,y,z. Wenn man von oben auf die Achse schaut, ist ein Anstieg des Wertes eine Drehung gegen den Uhrzeigersinn. Einfach zu verstehen und zu nutzen.
// Eine Drehung um 30 Grad gegen den Uhrzeigersinn um die x Achse des parent Elements. entity.setLocalEulerAngles(30, 0, 0); // Eine Drehung um die x-Achse gegen den Uhrzeiger im World Space entity.setEulerAngles(30, 45, 60);
Quaternions bestimmt die Orientierung aller Achsen im Raum über eine Matrix mit 4 Werten.
// Create an identity rotation var q = new pc.Quat(); // Die gleiche Rotation wie das parent Element, äquivalent zu // entity.setLocalEulerAngles(0, 0, 0) entity.setLocalRotation(q); // Keine Rotation in Bezug auf den World- Space, äquivalent zu //entity.setEulerAngles(0, 0, 0) entity.setRotation(q);
local
this.entity.rotateLocal(90, 0, 0);
world space
this.entity.rotate(0, 180, 0);
In einer update Funktion
WheelScript.prototype.update = function(dt) { this.entity.rotateLocal(0, 0, 40* dt); }
Mit folgender Funktion wird die Höhe des Entity verdoppelt, oder anders ausgedrückt mit 2 multipliziert.
Man kann die Größe nicht über den World Space definieren.
this.entity.setLocalScale(1, 2, 1);
In diesem geht es darum mit verschachtelten Entities und deren Koordinatensystem zu arbeiten. Es gibt einen Cube und darin einen Cylinder. Der Cylinder ist ein Kind vom Cube und dreht sich ständig um sich selbt. Außerdem bewegt er sich rauf und runter.
Der Cube kann mit den Pfeiltasten rauf und runter bewegt werden. Mit der A- Taste dreht er sich um sich selbst.
Erzeuge ein Primitive Cube durch klicken auf Pluszeichen "Add Entity". Wähle den Cube aus und erzeuge darin auf gleiche Weise ein Primitive Cylinder. Die Position des Cubes sowie des Cylinders im Cube befinden sich auf allen Koordinaten im Nullpunkt. Erzeuge ein Script für den Cube, um diesen mit Tastaurereignis zu bewegen. Pfeiltasten rauf und runter. A- Taste für die Drehung.
// initialize code called once per entity BoxMover.prototype.initialize = function() { }; // update code called every frame BoxMover.prototype.update = function(dt) { if(this.app.keyboard.wasPressed(pc.KEY_UP)){ this.entity.translate(0, this.upMove, 0); } /* wasPressed reagiert auf jeden neuen Tastendruck isPressed wird ausgeführt, wenn die die Taste gedrückt ist */ if(this.app.keyboard.isPressed(pc.KEY_DOWN)){ this.entity.translate(0,-0.04,0); } // is pressed wird ständig ausgeführt, solange die Taste gedrückt ist if(this.app.keyboard.isPressed(pc.KEY_A)){ this.entity.rotateLocal(0,0, 10); } };
Erzeuge ein Script für den Cylinder, um diesen im lokalen Koordinatensytem zu bewegen.
var WheelScript = pc.createScript('wheelScript'); // initialize code called once per entity WheelScript.prototype.initialize = function() { }; // update code called every frame WheelScript.prototype.update = function(dt) { this.entity.rotateLocal(0,10, 0); lp = this.entity.getLocalPosition(); if(lp.y > 1){ this.entity.setLocalPosition(0,0,0); }else{ this.entity.translateLocal(0, 0.01,0); } };
Diesen Entities kann man Components zuweisen.
sind Dateien und Elemente die man einem oder mehreren Entities zuweisen kann.
Erstelle ein neues Material Asset und weise diesem Eigenschaften zu. Das können verschiedene UV Maps sein und / oder Farben.
Hierbei geht es darum, dass Objekte physikalische Eigenschaften bekommen. Nehmen wir als Beispiel ein Objekt "Box" und ein Objekt "Ground". Diese erstelle ich mit mittels add Entity box
Beide Objekte bekommen die Komponenten Collision und Rigid Body
Die Collision Komponente dient dazu eine Form zu definieren, die ein Ereignis auslöst, wenn eine Berührung stattfindet. Dabei wird unterschieden zwischen Ein - und Austritt der Berührung oder Überschneidung. Im Zusammenhang mit der Rigidbody Komponente lassen sich so physikalische Simulationen erstellen.
Static bedeutet, es bewegt sich nicht, diese Eigenschaft kann man dem Ground zuweisen, denn dieser sollte nicht fallen.
Beide Objekte benötigen eine Collision Komponente. Dort wird unter type ein ein Vekorobjekt ausgewählt welches die Kollisionsgrenzen definiert. Cube, Sphere, Capsule, Mesh. Man weist diesem die halbe Größe des Originalobjekts zu, wenn es genauso groß sein soll.
Wenn ein Objekt physikalische Eigenschaften bekommt, sollte man nicht einfach die Positionswert und Drehwinkel bestimmen um es zu bewegen.
Beispiel für Forces und Impulses
In diesem Beispiel wird das Objekt im Worldspace in eine Richtung bewegt.
Wenn man jedoch das Objekt in seine eigene Drehrichtung bewegen will, kann man folgendermaßen vorgehen. this.speed ist ein Geschwindigkeitswert, der zuvor definiert wurde. Mittels applyTorque(x,y,z) wird ein Drehimpuls definiert.
DriveCar.prototype.update = function(dt) { //alternative Syntax für die Bewegung in Richtung Vorwärts Achse //this.impulse = new pc.Vec3(); //this.impulse.copy(this.entity.forward).scale(-this.speed); var backForce = this.entity.forward.clone().scale(this.speed); var forwardForce = this.entity.forward.clone().scale(-this.speed); if(this.app.keyboard.isPressed(pc.KEY_UP)){ this.entity.rigidbody.applyImpulse(forwardForce); } if(this.app.keyboard.isPressed(pc.KEY_DOWN)){ this.entity.rigidbody.applyImpulse(backForce); } if(this.app.keyboard.isPressed(pc.KEY_RIGHT)){ this.entity.rigidbody.applyTorque(0,-0.2, 0); } if(this.app.keyboard.isPressed(pc.KEY_LEFT)){ this.entity.rigidbody.applyTorque(0, 0.2, 0); } };
In den Beispielen befinden sich Scripte unter Assets. Diese kann man sich anschauen oder Editieren und auch herunterladen, beispielsweise um Sie zu ändern.
Um ein neues Script zu erstellen, reicht es nicht aus, dieses hochzuladen, vielmehr muss ein neues Asset hinzufügen und diesem einen Namen vergeben, der sozusagen als Klassenname fungiert und sich im Grundgerüst eines neuen Scripts wiederfindet.
Mittels Script Attributes kann man im Editor Variablenwerte eintragen. So haben auch Nichtprogrammierer die Möglichkeit im Editor Werte zu ändern.
Siehe dazu das User Manual Script Attributes
Im Script wird ganz oben nach der Deklaration der Scriptinstanz
var MyScript = pc.createScript('myScript');
ein Script Attribute erzeugt.
MyScript.attributes.add('speed', { type: 'number', default: 80 });
Auf die hier erzeugte Variable speed kann man dann im weiteren Code mit this.speed zugreifen.
Wenn man anschließend im Editor im Scriptfenster auf das Parse-Symbol klickt (Loop Pfeil), sollte die Variable erscheinen.
Über die Script Attribute kann man auf ein anderes Entity zugreifen
MyScript.attributes.add('target', { type: 'entity' })
Bewegungen und Rotationen
Das Script für einen Szenenwechsel weist man einer Kamera zu.
Siehe dazu Chaning Scenes
Radians in Winkel pc.math.DEG_TO_RAD
Winkel in Radians pc.math.RAD_TO_DEG
Beispiel 90 Grad in Radians umwandeln.
this.angelRad = 90 * pc.math.DEG_TO_RAD;
pc.math.lerp(a,b,alpha);
Hiermit lässt sich ein Wert zwischen a und b ermitteln. Mittels alpha gibt man an, wo der Wert liegt. alpha erwartet einen Wert von 0 bis 1, dabei ist 0 = a und 1 = b und 0.5 läge genau in er Mitte zwischen a und b.
pc.math.lerp(0, 20, 0.5) // 10
Wähle das Objekt in Sketchup aus und wähle Bearbeiten / Entsperren. Entferne alle ungewünschten Elemente. Bei Häusern auch den Boden.
Exportiere ein Modell in Scetchup als dae Datei. Es entsteht eine dae Datei und ein Ordner mit Bildern.
Erstelle dir einen neuen Ordner im Assets Ordner für das Modell. Wähle den Ordner aus, und importiere die dae Datei. In diesem Ordner erscheint eine dae Datei sowie eine json Datei und einige Materialien. Den Materiealien sind keine Bilder zugewiesen, das muss händisch gemacht werden.
Importiere dir in den gleichen Ordner alle Bilder, die beim Export von Scetchup entstanden sind. Wähle ein Material aus, wähle im Inspector "Diffuse" und weise das Bild gleichen Namens zu. Verfahre so mit allen anderen Materialien.
Ziehe das json Modell auf die Bühne. Um es für Collision Detection einzurichten, wähle, im Inspector, "Add Component" " Rigid Body" und "Collision". Unter Collision wähle als "type" Eigenschaft "mesh" und weise die entstandene json Datei aus dem Assets Ordner zu.
siehe Manual
Erstelle eine Cubemap (siehe Toast Map), klicke oben auf den Namen deiner Scene, wähle Rendering, Skybox und weise die Cubemap zu.