This commit is contained in:
Evert Prants 2023-06-24 21:33:01 +03:00
parent 77149c180b
commit 2f48411212
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
17 changed files with 93 additions and 60 deletions

View File

@ -122,17 +122,23 @@ export class GameplayComponent extends EngineComponent {
} }
}; };
const initializedEvent = () => { const worldLoadedEvent = () => {
this.loadCharacter('Diamond'); this.loadCharacter('Diamond');
}; };
const physicsLoadedEvent = () => {
this.events.emit('initialized');
};
window.addEventListener('keydown', keyDownEvent); window.addEventListener('keydown', keyDownEvent);
window.addEventListener('keyup', keyUpEvent); window.addEventListener('keyup', keyUpEvent);
this.events.addListener('initialized', initializedEvent); this.events.addListener('loadComplete', worldLoadedEvent);
this.events.addListener('physicsComplete', physicsLoadedEvent);
return () => { return () => {
window.removeEventListener('keydown', keyDownEvent); window.removeEventListener('keydown', keyDownEvent);
window.removeEventListener('keyup', keyUpEvent); window.removeEventListener('keyup', keyUpEvent);
this.events.removeEventListener('initialized', initializedEvent); this.events.removeEventListener('loadComplete', worldLoadedEvent);
this.events.removeEventListener('physicsComplete', physicsLoadedEvent);
}; };
} }
} }

View File

@ -4,6 +4,7 @@ import { EngineComponent } from '../types/engine-component';
import { Renderer } from '../core/renderer'; import { Renderer } from '../core/renderer';
import { EventEmitter } from '../utils/events'; import { EventEmitter } from '../utils/events';
import { Environment } from '../gameobjects/environment.object'; import { Environment } from '../gameobjects/environment.object';
import { environmentDefaults } from '..';
/** /**
* This component manages game environment and world lighting. * This component manages game environment and world lighting.
@ -25,11 +26,17 @@ export class EnvironmentComponent extends EngineComponent {
initialize(): void { initialize(): void {
this.renderer.scene.add(this.object); this.renderer.scene.add(this.object);
this.renderer.renderer.setClearColor(0x00aaff); this.renderer.renderer.setClearColor(environmentDefaults.clearColor);
this.ambient = new AmbientLight(0x8a8a8a, 1.0); this.ambient = new AmbientLight(
this.directional = new DirectionalLight(0xffffff, 1); environmentDefaults.ambientColor,
this.directional.position.set(1, 1, 1); environmentDefaults.ambientStrength
);
this.directional = new DirectionalLight(
environmentDefaults.sunColor,
environmentDefaults.sunStrength
);
this.directional.position.copy(environmentDefaults.sunPosition);
this.renderer.scene.add(this.ambient); this.renderer.scene.add(this.ambient);
this.renderer.scene.add(this.directional); this.renderer.scene.add(this.directional);

View File

@ -105,6 +105,7 @@ export class LevelComponent extends EngineComponent {
// Load world // Load world
this.deserializeObject(save.world); this.deserializeObject(save.world);
this.world.deserialize(save.world);
this.events.emit('loadComplete'); this.events.emit('loadComplete');
} }

View File

@ -13,7 +13,6 @@ export class PhysicsWorldComponent extends EngineComponent {
private physicsWorld!: Rapier.World; private physicsWorld!: Rapier.World;
private physicsEngine!: typeof Rapier; private physicsEngine!: typeof Rapier;
private characterPhysics!: Rapier.KinematicCharacterController; private characterPhysics!: Rapier.KinematicCharacterController;
private initEventFiredBeforeEngineLoad = false;
private cleanUpEvents?: Function; private cleanUpEvents?: Function;
private sceneInitialized = false; private sceneInitialized = false;
private trackedObjects: PhysicsTicking[] = []; private trackedObjects: PhysicsTicking[] = [];
@ -21,7 +20,6 @@ export class PhysicsWorldComponent extends EngineComponent {
initialize(): void { initialize(): void {
this.world = this.renderer.scene.getObjectByName('World') as World; this.world = this.renderer.scene.getObjectByName('World') as World;
this.cleanUpEvents = this.bindEvents(); this.cleanUpEvents = this.bindEvents();
this.createRapier();
} }
update(delta: number): void { update(delta: number): void {
@ -43,21 +41,13 @@ export class PhysicsWorldComponent extends EngineComponent {
const world = new physicsEngine.World(gravity); const world = new physicsEngine.World(gravity);
this.physicsWorld = world; this.physicsWorld = world;
this.physicsEngine = physicsEngine; this.physicsEngine = physicsEngine;
this.initializePhysicsScene();
if (this.initEventFiredBeforeEngineLoad) {
this.initEventFiredBeforeEngineLoad = false;
this.initializePhysicsScene();
}
}); });
} }
private bindEvents() { private bindEvents() {
const initializeEvent = () => { const worldLoadEvent = () => {
if (!this.physicsWorld) { this.createRapier();
this.initEventFiredBeforeEngineLoad = true;
return;
}
this.initializePhysicsScene();
}; };
const sceneJoinEvent = (object: Object3D) => { const sceneJoinEvent = (object: Object3D) => {
@ -68,18 +58,19 @@ export class PhysicsWorldComponent extends EngineComponent {
this.removePhysics(object); this.removePhysics(object);
}; };
this.events.addListener('initialized', initializeEvent); this.events.addListener('loadComplete', worldLoadEvent);
this.events.addListener('sceneJoin', sceneJoinEvent); this.events.addListener('sceneJoin', sceneJoinEvent);
this.events.addListener('sceneLeave', sceneLeaveEvent); this.events.addListener('sceneLeave', sceneLeaveEvent);
return () => { return () => {
this.events.removeEventListener('initialized', initializeEvent); this.events.removeEventListener('loadComplete', worldLoadEvent);
this.events.removeEventListener('sceneJoin', sceneJoinEvent); this.events.removeEventListener('sceneJoin', sceneJoinEvent);
this.events.removeEventListener('sceneLeave', sceneLeaveEvent); this.events.removeEventListener('sceneLeave', sceneLeaveEvent);
}; };
} }
private applyPhysics(root: Object3D) { private applyPhysics(root: Object3D) {
if (!this.physicsEngine) return;
root.traverse((object) => { root.traverse((object) => {
// Prevent double-init // Prevent double-init
if (this.trackedObjects.some((entry) => entry.uuid === object.uuid)) if (this.trackedObjects.some((entry) => entry.uuid === object.uuid))
@ -139,5 +130,6 @@ export class PhysicsWorldComponent extends EngineComponent {
this.applyPhysics(this.world); this.applyPhysics(this.world);
this.sceneInitialized = true; this.sceneInitialized = true;
this.events.emit('physicsComplete');
} }
} }

View File

@ -6,5 +6,5 @@ export const environmentDefaults = {
sunStrength: 1, sunStrength: 1,
ambientColor: new Color(0x8a8a8a), ambientColor: new Color(0x8a8a8a),
ambientStrength: 1, ambientStrength: 1,
clearColor: new Color(0x00aaff), clearColor: new Color(0x47c2ff),
}; };

View File

@ -1,6 +1,6 @@
import { PhysicsObject } from './physics.object'; import { PhysicsObject } from './physics.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import { BufferGeometry, Mesh, MeshPhongMaterial } from 'three'; import { BufferGeometry, Mesh, MeshPhongMaterial, Vector3 } from 'three';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
export class Brick extends PhysicsObject { export class Brick extends PhysicsObject {
@ -20,7 +20,7 @@ export class Brick extends PhysicsObject {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const scale = this.scale.clone().divideScalar(2); const scale = this.getWorldScale(new Vector3()).divideScalar(2);
const collider = factory.ColliderDesc.cuboid( const collider = factory.ColliderDesc.cuboid(
Math.abs(scale.x), Math.abs(scale.x),
Math.abs(scale.y), Math.abs(scale.y),

View File

@ -1,4 +1,4 @@
import { Mesh } from 'three'; import { Mesh, Vector3 } from 'three';
import { Brick } from './brick.object'; import { Brick } from './brick.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -17,12 +17,10 @@ export class Capsule extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const height = this.scale.y / 2; const scale = this.getWorldScale(new Vector3());
const radius = (this.scale.x / 2 + this.scale.z / 2) / 2; const height = Math.abs(scale.y) / 2;
const collider = factory.ColliderDesc.capsule( const radius = (Math.abs(scale.x) + Math.abs(scale.z)) / 2;
Math.abs(height), const collider = factory.ColliderDesc.capsule(height, radius);
Math.abs(radius)
);
return world.createCollider(collider, body); return world.createCollider(collider, body);
} }
} }

View File

@ -1,4 +1,4 @@
import { Mesh } from 'three'; import { Mesh, Vector3 } from 'three';
import { Brick } from './brick.object'; import { Brick } from './brick.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -17,12 +17,10 @@ export class Cylinder extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const height = this.scale.y / 2; const scale = this.getWorldScale(new Vector3());
const radius = (this.scale.x / 2 + this.scale.z / 2) / 2; const height = Math.abs(scale.y) / 2;
const collider = factory.ColliderDesc.cylinder( const radius = (Math.abs(scale.x) / 2 + Math.abs(scale.z) / 2) / 2;
Math.abs(height), const collider = factory.ColliderDesc.cylinder(height, radius);
Math.abs(radius)
);
return world.createCollider(collider, body); return world.createCollider(collider, body);
} }
} }

View File

@ -320,7 +320,7 @@ export class Humanoid extends GameObject implements PhysicsTicking {
} }
private applyRotation(quat: Quaternion) { private applyRotation(quat: Quaternion) {
this.rigidBody?.setNextKinematicRotation(quat); this.rigidBody?.setRotation(quat, false);
} }
dispose(): void { dispose(): void {

View File

@ -1,4 +1,10 @@
import { BufferGeometry, Mesh, MeshPhongMaterial, SkinnedMesh } from 'three'; import {
BufferGeometry,
Mesh,
MeshPhongMaterial,
SkinnedMesh,
Vector3,
} from 'three';
import { Brick } from '.'; import { Brick } from '.';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -26,7 +32,7 @@ export class MeshPart extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const scale = this.scale.clone().divideScalar(2); const scale = this.getWorldScale(new Vector3()).divideScalar(2);
const collider = factory.ColliderDesc.cuboid( const collider = factory.ColliderDesc.cuboid(
Math.abs(scale.x), Math.abs(scale.x),
Math.abs(scale.y), Math.abs(scale.y),

View File

@ -1,7 +1,8 @@
import { EditorProperty } from '..'; import { EditorProperty, GameObject } from '..';
import { PhysicsTicking } from '../physics/ticking'; import { PhysicsTicking } from '../physics/ticking';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
import { PhysicalObject } from './physical.object'; import { PhysicalObject } from './physical.object';
import { Quaternion, Vector3 } from 'three';
export class PhysicsObject extends PhysicalObject implements PhysicsTicking { export class PhysicsObject extends PhysicalObject implements PhysicsTicking {
public objectType = 'PhysicsObject'; public objectType = 'PhysicsObject';
@ -23,6 +24,10 @@ export class PhysicsObject extends PhysicalObject implements PhysicsTicking {
@EditorProperty({ type: Number }) @EditorProperty({ type: Number })
public friction = 0.2; public friction = 0.2;
private _tempVec = new Vector3();
private _tempQuat = new Quaternion();
private _tempQuat2 = new Quaternion();
initialize(physicsEngine: typeof Rapier, physicsWorld: Rapier.World): void { initialize(physicsEngine: typeof Rapier, physicsWorld: Rapier.World): void {
if (this.virtual) return; if (this.virtual) return;
this.physicsWorldRef = physicsWorld; this.physicsWorldRef = physicsWorld;
@ -35,9 +40,14 @@ export class PhysicsObject extends PhysicalObject implements PhysicsTicking {
if (this.anchored) bodyDesc = physicsEngine.RigidBodyDesc.fixed(); if (this.anchored) bodyDesc = physicsEngine.RigidBodyDesc.fixed();
else bodyDesc = physicsEngine.RigidBodyDesc.dynamic(); else bodyDesc = physicsEngine.RigidBodyDesc.dynamic();
const position = this.position.clone();
const rotation = this.quaternion.clone();
this.getWorldPosition(position);
this.getWorldQuaternion(rotation);
bodyDesc bodyDesc
.setTranslation(...this.position.toArray()) .setTranslation(...position.toArray())
.setRotation(this.quaternion) .setRotation(rotation)
.setAdditionalMass(this.mass) .setAdditionalMass(this.mass)
.setLinearDamping(this.friction) .setLinearDamping(this.friction)
.setAngularDamping(this.friction); .setAngularDamping(this.friction);
@ -55,8 +65,16 @@ export class PhysicsObject extends PhysicalObject implements PhysicsTicking {
tick(dt: number): void { tick(dt: number): void {
if (!this.rigidBody || this.virtual) return; if (!this.rigidBody || this.virtual) return;
this.position.copy(this.rigidBody.translation() as any); this._tempVec.copy(this.rigidBody.translation() as any);
this.quaternion.copy(this.rigidBody.rotation() as any); this._tempQuat.copy(this.rigidBody.rotation() as any);
if ((this.parent as GameObject)?.objectType !== 'World') {
this.parent?.worldToLocal(this._tempVec);
this.parent?.getWorldQuaternion(this._tempQuat2);
this._tempQuat2.invert();
this._tempQuat.premultiply(this._tempQuat2);
}
this.position.copy(this._tempVec);
this.quaternion.copy(this._tempQuat);
} }
dispose(): void { dispose(): void {

View File

@ -1,4 +1,4 @@
import { Mesh } from 'three'; import { Mesh, Vector3 } from 'three';
import { Brick } from './brick.object'; import { Brick } from './brick.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -17,8 +17,10 @@ export class Sphere extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const radius = Math.max(this.scale.x, this.scale.y, this.scale.z) / 2; const scale = this.getWorldScale(new Vector3());
const collider = factory.ColliderDesc.ball(Math.abs(radius)); const radius =
Math.max(Math.abs(scale.x), Math.abs(scale.y), Math.abs(scale.z)) / 2;
const collider = factory.ColliderDesc.ball(radius);
return world.createCollider(collider, body); return world.createCollider(collider, body);
} }
} }

View File

@ -17,11 +17,12 @@ export class Torus extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const height = this.scale.y * 0.4; const scale = this.getWorldScale(new Vector3());
const radius = (this.scale.x + this.scale.z) / 2; const height = Math.abs(scale.y) * 0.4;
const radius = (Math.abs(scale.x) + Math.abs(scale.z)) / 2;
const collider = factory.ColliderDesc.cylinder( const collider = factory.ColliderDesc.cylinder(
Math.abs(height), height,
Math.abs(radius) * 1.4 radius * 1.4
).setRotation( ).setRotation(
new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2) new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2)
); );

View File

@ -1,4 +1,4 @@
import { Matrix4, Mesh } from 'three'; import { Matrix4, Mesh, Vector3 } from 'three';
import { Brick } from './brick.object'; import { Brick } from './brick.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -17,8 +17,9 @@ export class WedgeCorner extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const scale = this.getWorldScale(new Vector3());
const mat = new Matrix4(); const mat = new Matrix4();
mat.makeScale(...this.scale.toArray()); mat.makeScale(...scale.toArray());
const points = this.getGeometry() const points = this.getGeometry()
.getAttribute('position') .getAttribute('position')
.clone() .clone()

View File

@ -1,4 +1,4 @@
import { Matrix4, Mesh } from 'three'; import { Matrix4, Mesh, Vector3 } from 'three';
import { Brick } from './brick.object'; import { Brick } from './brick.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -17,8 +17,9 @@ export class WedgeInnerCorner extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const scale = this.getWorldScale(new Vector3());
const mat = new Matrix4(); const mat = new Matrix4();
mat.makeScale(...this.scale.toArray()); mat.makeScale(...scale.toArray());
const points = this.getGeometry() const points = this.getGeometry()
.getAttribute('position') .getAttribute('position')
.clone() .clone()

View File

@ -1,4 +1,4 @@
import { Matrix4, Mesh } from 'three'; import { Matrix4, Mesh, Vector3 } from 'three';
import { Brick } from './brick.object'; import { Brick } from './brick.object';
import { gameObjectGeometries } from './geometries'; import { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d'; import type Rapier from '@dimforge/rapier3d';
@ -17,8 +17,9 @@ export class Wedge extends Brick {
world: Rapier.World, world: Rapier.World,
body?: Rapier.RigidBody body?: Rapier.RigidBody
) { ) {
const scale = this.getWorldScale(new Vector3());
const mat = new Matrix4(); const mat = new Matrix4();
mat.makeScale(...this.scale.toArray()); mat.makeScale(...scale.toArray());
const points = this.getGeometry() const points = this.getGeometry()
.getAttribute('position') .getAttribute('position')
.clone() .clone()

View File

@ -81,6 +81,7 @@ export type EngineEvents = {
sceneLeave: (event: Object3D) => void; sceneLeave: (event: Object3D) => void;
queueFree: (event: Object3D) => void; queueFree: (event: Object3D) => void;
loadComplete: () => void; loadComplete: () => void;
physicsComplete: () => void;
initialized: () => void; initialized: () => void;
reset: () => void; reset: () => void;
}; };