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');
};
const physicsLoadedEvent = () => {
this.events.emit('initialized');
};
window.addEventListener('keydown', keyDownEvent);
window.addEventListener('keyup', keyUpEvent);
this.events.addListener('initialized', initializedEvent);
this.events.addListener('loadComplete', worldLoadedEvent);
this.events.addListener('physicsComplete', physicsLoadedEvent);
return () => {
window.removeEventListener('keydown', keyDownEvent);
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 { EventEmitter } from '../utils/events';
import { Environment } from '../gameobjects/environment.object';
import { environmentDefaults } from '..';
/**
* This component manages game environment and world lighting.
@ -25,11 +26,17 @@ export class EnvironmentComponent extends EngineComponent {
initialize(): void {
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.directional = new DirectionalLight(0xffffff, 1);
this.directional.position.set(1, 1, 1);
this.ambient = new AmbientLight(
environmentDefaults.ambientColor,
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.directional);

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
import { PhysicsObject } from './physics.object';
import { gameObjectGeometries } from './geometries';
import { BufferGeometry, Mesh, MeshPhongMaterial } from 'three';
import { BufferGeometry, Mesh, MeshPhongMaterial, Vector3 } from 'three';
import type Rapier from '@dimforge/rapier3d';
export class Brick extends PhysicsObject {
@ -20,7 +20,7 @@ export class Brick extends PhysicsObject {
world: Rapier.World,
body?: Rapier.RigidBody
) {
const scale = this.scale.clone().divideScalar(2);
const scale = this.getWorldScale(new Vector3()).divideScalar(2);
const collider = factory.ColliderDesc.cuboid(
Math.abs(scale.x),
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 { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d';
@ -17,12 +17,10 @@ export class Capsule extends Brick {
world: Rapier.World,
body?: Rapier.RigidBody
) {
const height = this.scale.y / 2;
const radius = (this.scale.x / 2 + this.scale.z / 2) / 2;
const collider = factory.ColliderDesc.capsule(
Math.abs(height),
Math.abs(radius)
);
const scale = this.getWorldScale(new Vector3());
const height = Math.abs(scale.y) / 2;
const radius = (Math.abs(scale.x) + Math.abs(scale.z)) / 2;
const collider = factory.ColliderDesc.capsule(height, radius);
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 { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d';
@ -17,12 +17,10 @@ export class Cylinder extends Brick {
world: Rapier.World,
body?: Rapier.RigidBody
) {
const height = this.scale.y / 2;
const radius = (this.scale.x / 2 + this.scale.z / 2) / 2;
const collider = factory.ColliderDesc.cylinder(
Math.abs(height),
Math.abs(radius)
);
const scale = this.getWorldScale(new Vector3());
const height = Math.abs(scale.y) / 2;
const radius = (Math.abs(scale.x) / 2 + Math.abs(scale.z) / 2) / 2;
const collider = factory.ColliderDesc.cylinder(height, radius);
return world.createCollider(collider, body);
}
}

View File

@ -320,7 +320,7 @@ export class Humanoid extends GameObject implements PhysicsTicking {
}
private applyRotation(quat: Quaternion) {
this.rigidBody?.setNextKinematicRotation(quat);
this.rigidBody?.setRotation(quat, false);
}
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 type Rapier from '@dimforge/rapier3d';
@ -26,7 +32,7 @@ export class MeshPart extends Brick {
world: Rapier.World,
body?: Rapier.RigidBody
) {
const scale = this.scale.clone().divideScalar(2);
const scale = this.getWorldScale(new Vector3()).divideScalar(2);
const collider = factory.ColliderDesc.cuboid(
Math.abs(scale.x),
Math.abs(scale.y),

View File

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

View File

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

View File

@ -17,11 +17,12 @@ export class Torus extends Brick {
world: Rapier.World,
body?: Rapier.RigidBody
) {
const height = this.scale.y * 0.4;
const radius = (this.scale.x + this.scale.z) / 2;
const scale = this.getWorldScale(new Vector3());
const height = Math.abs(scale.y) * 0.4;
const radius = (Math.abs(scale.x) + Math.abs(scale.z)) / 2;
const collider = factory.ColliderDesc.cylinder(
Math.abs(height),
Math.abs(radius) * 1.4
height,
radius * 1.4
).setRotation(
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 { gameObjectGeometries } from './geometries';
import type Rapier from '@dimforge/rapier3d';
@ -17,8 +17,9 @@ export class WedgeCorner extends Brick {
world: Rapier.World,
body?: Rapier.RigidBody
) {
const scale = this.getWorldScale(new Vector3());
const mat = new Matrix4();
mat.makeScale(...this.scale.toArray());
mat.makeScale(...scale.toArray());
const points = this.getGeometry()
.getAttribute('position')
.clone()

View File

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

View File

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

View File

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