From 947eced43aad020561a275ae67d0b2f85e7797c9 Mon Sep 17 00:00:00 2001 From: Gugustinette Date: Sun, 1 Sep 2024 13:53:35 +0200 Subject: [PATCH] feat: add controller system --- apps/playground-2d/src/main.ts | 24 +++---- apps/playground-3d/src/main.ts | 7 +- packages/2d/src/cameras/FAttachedCamera.ts | 4 +- packages/2d/src/cameras/FCamera.ts | 2 +- packages/2d/src/cameras/FFixedCamera.ts | 2 +- packages/2d/src/cameras/FFreeCamera.ts | 2 +- .../2d/src/character/FCharacterDynamic.ts | 57 --------------- packages/2d/src/character/FCharacterKP.ts | 44 ------------ packages/2d/src/character/FCharacterKV.ts | 44 ------------ .../FCharacterController.ts} | 63 +++++------------ .../src/controllers/FCharacterControllerD.ts | 54 +++++++++++++++ .../FCharacterControllerK.ts} | 31 ++------- .../src/controllers/FCharacterControllerKP.ts | 42 +++++++++++ .../src/controllers/FCharacterControllerKV.ts | 42 +++++++++++ packages/2d/src/controllers/FController.ts | 27 ++++++++ packages/2d/src/{ => core}/FCollider.ts | 2 +- packages/2d/src/{ => core}/FComponent.ts | 6 ++ packages/2d/src/{ => core}/FComponentEmpty.ts | 0 packages/2d/src/{ => core}/FRigidBody.ts | 2 +- packages/2d/src/{ => core}/FScene.ts | 6 +- packages/2d/src/{ => core}/FTransform.ts | 0 packages/2d/src/index.ts | 31 +++++---- packages/2d/src/polygons/FCircle.ts | 4 +- packages/2d/src/polygons/FPolygon.ts | 6 +- packages/2d/src/polygons/FRectangle.ts | 6 +- packages/2d/src/sprite/FSprite.ts | 6 +- packages/3d/src/cameras/FAttachedCamera.ts | 2 +- packages/3d/src/cameras/FCamera.ts | 4 +- packages/3d/src/cameras/FOrbitCamera.ts | 2 +- packages/3d/src/cameras/FPointerLockCamera.ts | 2 +- .../3d/src/character/FCharacterDynamic.ts | 69 ------------------- packages/3d/src/character/FCharacterKP.ts | 53 -------------- .../FCharacterController.ts} | 55 ++++----------- .../src/controllers/FCharacterControllerD.ts | 66 ++++++++++++++++++ .../FCharacterControllerK.ts} | 14 ++-- .../src/controllers/FCharacterControllerKP.ts | 49 +++++++++++++ .../FCharacterControllerKV.ts} | 39 +++++------ packages/3d/src/controllers/FController.ts | 27 ++++++++ packages/3d/src/{ => core}/FCollider.ts | 2 +- packages/3d/src/{ => core}/FComponent.ts | 6 ++ packages/3d/src/{ => core}/FComponentEmpty.ts | 0 packages/3d/src/{ => core}/FRigidBody.ts | 2 +- packages/3d/src/{ => core}/FScene.ts | 6 +- packages/3d/src/{ => core}/FTransform.ts | 0 packages/3d/src/index.ts | 31 +++++---- packages/3d/src/model/FFBX.ts | 2 +- packages/3d/src/model/FGLB.ts | 2 +- packages/3d/src/model/FGLTF.ts | 2 +- packages/3d/src/model/FModel.ts | 6 +- packages/3d/src/model/FOBJ.ts | 2 +- packages/3d/src/polyhedrons/FCapsule.ts | 8 +-- packages/3d/src/polyhedrons/FCuboid.ts | 4 +- packages/3d/src/polyhedrons/FPolyhedron.ts | 6 +- packages/3d/src/polyhedrons/FSphere.ts | 8 +-- packages/core/src/FComponent.ts | 19 ++++- packages/core/src/FController.ts | 31 +++++++++ packages/core/src/index.ts | 4 ++ 57 files changed, 528 insertions(+), 509 deletions(-) delete mode 100644 packages/2d/src/character/FCharacterDynamic.ts delete mode 100644 packages/2d/src/character/FCharacterKP.ts delete mode 100644 packages/2d/src/character/FCharacterKV.ts rename packages/2d/src/{character/FCharacter.ts => controllers/FCharacterController.ts} (56%) create mode 100644 packages/2d/src/controllers/FCharacterControllerD.ts rename packages/2d/src/{character/FCharacterKinematic.ts => controllers/FCharacterControllerK.ts} (73%) create mode 100644 packages/2d/src/controllers/FCharacterControllerKP.ts create mode 100644 packages/2d/src/controllers/FCharacterControllerKV.ts create mode 100644 packages/2d/src/controllers/FController.ts rename packages/2d/src/{ => core}/FCollider.ts (99%) rename packages/2d/src/{ => core}/FComponent.ts (98%) rename packages/2d/src/{ => core}/FComponentEmpty.ts (100%) rename packages/2d/src/{ => core}/FRigidBody.ts (99%) rename packages/2d/src/{ => core}/FScene.ts (98%) rename packages/2d/src/{ => core}/FTransform.ts (100%) delete mode 100644 packages/3d/src/character/FCharacterDynamic.ts delete mode 100644 packages/3d/src/character/FCharacterKP.ts rename packages/3d/src/{character/FCharacter.ts => controllers/FCharacterController.ts} (61%) create mode 100644 packages/3d/src/controllers/FCharacterControllerD.ts rename packages/3d/src/{character/FCharacterKinematic.ts => controllers/FCharacterControllerK.ts} (86%) create mode 100644 packages/3d/src/controllers/FCharacterControllerKP.ts rename packages/3d/src/{character/FCharacterKV.ts => controllers/FCharacterControllerKV.ts} (53%) create mode 100644 packages/3d/src/controllers/FController.ts rename packages/3d/src/{ => core}/FCollider.ts (99%) rename packages/3d/src/{ => core}/FComponent.ts (98%) rename packages/3d/src/{ => core}/FComponentEmpty.ts (100%) rename packages/3d/src/{ => core}/FRigidBody.ts (99%) rename packages/3d/src/{ => core}/FScene.ts (97%) rename packages/3d/src/{ => core}/FTransform.ts (100%) create mode 100644 packages/core/src/FController.ts diff --git a/apps/playground-2d/src/main.ts b/apps/playground-2d/src/main.ts index b7f97b50..f8bbfa26 100644 --- a/apps/playground-2d/src/main.ts +++ b/apps/playground-2d/src/main.ts @@ -1,5 +1,5 @@ import './style.css' -import { FAttachedCamera, FCharacterKP, FCircle, FComponentEmpty, FRectangle, FScene, FShapes, FSprite } from '@fibbojs/2d' +import { FAttachedCamera, FCharacterControllerKP, FCircle, FComponentEmpty, FRectangle, FScene, FShapes, FSprite } from '@fibbojs/2d' import { fDebug } from '@fibbojs/devtools' import { FKeyboard } from '@fibbojs/event' import MySquare from './classes/MySquare' @@ -70,25 +70,19 @@ import { loadLevel } from './level' circle.initRigidBody() scene.addComponent(circle) - // Create a sprite - const sprite = new FSprite(scene, { - texture: 'bunny.png', - position: { x: 2, y: 3 }, - }) - sprite.onLoaded(() => { - sprite.initRigidBody({ - lockRotations: true, - }) - sprite.setScaleWidth(0.5) - }) - scene.addComponent(sprite) - /** * Create character */ - const character = new FCharacterKP(scene, { + const character = new FSprite(scene, { + texture: 'character_0000.png', position: { x: 0, y: 5 }, }) + character.controller = new FCharacterControllerKP(scene, { + component: character, + }) + character.onLoaded(() => { + character.setScaleWidth(0.5) + }) character.onCollisionWith(FRectangle, () => { console.log('Sprite collided with a square!') }) diff --git a/apps/playground-3d/src/main.ts b/apps/playground-3d/src/main.ts index b9b346ee..842aec70 100644 --- a/apps/playground-3d/src/main.ts +++ b/apps/playground-3d/src/main.ts @@ -1,5 +1,5 @@ import * as THREE from 'three' -import { FCapsule, FCharacterKP, FComponentEmpty, FCuboid, FFBX, FGLB, FGameCamera, FOBJ, FScene, FShapes, FSphere } from '@fibbojs/3d' +import { FCapsule, FCharacterControllerKP, FComponentEmpty, FCuboid, FFBX, FGLB, FGameCamera, FOBJ, FScene, FShapes, FSphere } from '@fibbojs/3d' import { fDebug } from '@fibbojs/devtools' import Duck from './classes/Duck' import GltfCube from './classes/GltfCube' @@ -118,9 +118,12 @@ import MyCustomCube from './classes/MyCustomCube' scene.addComponent(ground2) // Create a character - const character = new FCharacterKP(scene, { + const character = new FCapsule(scene, { position: { x: 0, y: 10, z: 0 }, }) + character.controller = new FCharacterControllerKP(scene, { + component: character, + }) scene.addComponent(character) // Attach a camera to the character diff --git a/packages/2d/src/cameras/FAttachedCamera.ts b/packages/2d/src/cameras/FAttachedCamera.ts index 7ab60af1..355dd986 100644 --- a/packages/2d/src/cameras/FAttachedCamera.ts +++ b/packages/2d/src/cameras/FAttachedCamera.ts @@ -1,5 +1,5 @@ -import type { FComponent } from '../FComponent' -import type { FScene } from '../FScene' +import type { FComponent } from '../core/FComponent' +import type { FScene } from '../core/FScene' import type { FCameraOptions } from './FCamera' import { FCamera } from './FCamera' diff --git a/packages/2d/src/cameras/FCamera.ts b/packages/2d/src/cameras/FCamera.ts index 48a883db..687b401f 100644 --- a/packages/2d/src/cameras/FCamera.ts +++ b/packages/2d/src/cameras/FCamera.ts @@ -1,5 +1,5 @@ import { FCamera as FCameraCore } from '@fibbojs/core' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' export interface FCameraOptions { position?: { x: number, y: number } diff --git a/packages/2d/src/cameras/FFixedCamera.ts b/packages/2d/src/cameras/FFixedCamera.ts index b386fceb..ca5668be 100644 --- a/packages/2d/src/cameras/FFixedCamera.ts +++ b/packages/2d/src/cameras/FFixedCamera.ts @@ -1,4 +1,4 @@ -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import type { FCameraOptions } from './FCamera' import { FCamera } from './FCamera' diff --git a/packages/2d/src/cameras/FFreeCamera.ts b/packages/2d/src/cameras/FFreeCamera.ts index 24e3e793..f6bd8ad0 100644 --- a/packages/2d/src/cameras/FFreeCamera.ts +++ b/packages/2d/src/cameras/FFreeCamera.ts @@ -1,4 +1,4 @@ -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import type { FCameraOptions } from './FCamera' import { FCamera } from './FCamera' diff --git a/packages/2d/src/character/FCharacterDynamic.ts b/packages/2d/src/character/FCharacterDynamic.ts deleted file mode 100644 index b1182d67..00000000 --- a/packages/2d/src/character/FCharacterDynamic.ts +++ /dev/null @@ -1,57 +0,0 @@ -import RAPIER from '@dimforge/rapier2d' -import { FKeyboard } from '@fibbojs/event' -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import { FCharacter } from './FCharacter' - -/** - * @description A pre-defined character controller based on a Dynamic RigidBody. - * @category Character - * @example - * ```ts - * import { FScene, FCharacterDynamic } from '@fibbojs/2d' - * - * const scene = new FScene() - * - * const capsule = new FCharacterDynamic(scene) - * scene.addComponent(capsule) - * ``` - */ -export class FCharacterDynamic extends FCharacter { - constructor(scene: FScene, options?: FComponentOptions) { - super(scene, options) - - const fKeyboard = new FKeyboard(scene) - fKeyboard.on(' ', () => { - this.rigidBody?.rigidBody.applyImpulse({ x: 0, y: 0.5 }, true) - }) - } - - onFrame(_delta: number): void { - // Apply movement on the y axis - if (this.inputs.up) { - this.rigidBody?.rigidBody.applyImpulse({ x: 0, y: 0.15 * this.speed }, true) - } - else if (this.inputs.down) { - this.rigidBody?.rigidBody.applyImpulse({ x: 0, y: -0.15 * this.speed }, true) - } - // Apply movement on the x axis - if (this.inputs.left) { - this.rigidBody?.rigidBody.applyImpulse({ x: -0.15 * this.speed, y: 0 }, true) - } - else if (this.inputs.right) { - this.rigidBody?.rigidBody.applyImpulse({ x: 0.15 * this.speed, y: 0 }, true) - } - - super.onFrame(_delta) - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - rigidBodyType: RAPIER.RigidBodyType.Dynamic, - lockRotations: true, - ...options, - }) - } -} diff --git a/packages/2d/src/character/FCharacterKP.ts b/packages/2d/src/character/FCharacterKP.ts deleted file mode 100644 index 002a9a6c..00000000 --- a/packages/2d/src/character/FCharacterKP.ts +++ /dev/null @@ -1,44 +0,0 @@ -import RAPIER from '@dimforge/rapier2d' -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import { FCharacterKinematic } from './FCharacterKinematic' - -/** - * @description A pre-defined character controller based on a Kinematic Position RigidBody. - * @category Character - * @example - * ```ts - * import { FScene, FCharacterKP } from '@fibbojs/2d' - * - * const scene = new FScene() - * - * const capsule = new FCharacterKP(scene) - * scene.addComponent(capsule) - * ``` - */ -export class FCharacterKP extends FCharacterKinematic { - constructor(scene: FScene, options?: FComponentOptions) { - super(scene, options) - } - - onFrame(delta: number): void { - // Get the corrected movement - const correctedMovement = this.getCorrectedMovements(delta) - - // Apply the movement to the rigid body - this.rigidBody?.rigidBody.setNextKinematicTranslation({ - x: this.rigidBody.rigidBody.translation().x + correctedMovement.x * delta * this.speed * 64, - y: this.rigidBody.rigidBody.translation().y + correctedMovement.y * delta * this.speed * 64, - }) - - super.onFrame(delta) - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - rigidBodyType: RAPIER.RigidBodyType.KinematicPositionBased, - ...options, - }) - } -} diff --git a/packages/2d/src/character/FCharacterKV.ts b/packages/2d/src/character/FCharacterKV.ts deleted file mode 100644 index e1e62c22..00000000 --- a/packages/2d/src/character/FCharacterKV.ts +++ /dev/null @@ -1,44 +0,0 @@ -import RAPIER from '@dimforge/rapier2d' -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import { FCharacterKinematic } from './FCharacterKinematic' - -/** - * @description A pre-defined character controller based on a Kinematic Velocity RigidBody. - * @category Character - * @example - * ```ts - * import { FScene, FCharacterKV } from '@fibbojs/2d' - * - * const scene = new FScene() - * - * const capsule = new FCharacterKV(scene) - * scene.addComponent(capsule) - * ``` - */ -export class FCharacterKV extends FCharacterKinematic { - constructor(scene: FScene, options?: FComponentOptions) { - super(scene, options) - } - - onFrame(delta: number): void { - // Get the corrected movement - const correctedMovement = this.getCorrectedMovements(delta) - - // Apply the movement to the rigid body - this.rigidBody?.rigidBody.setLinvel({ - x: correctedMovement.x / delta, - y: correctedMovement.y / delta, - }, true) - - super.onFrame(delta) - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - rigidBodyType: RAPIER.RigidBodyType.KinematicVelocityBased, - ...options, - }) - } -} diff --git a/packages/2d/src/character/FCharacter.ts b/packages/2d/src/controllers/FCharacterController.ts similarity index 56% rename from packages/2d/src/character/FCharacter.ts rename to packages/2d/src/controllers/FCharacterController.ts index 8012ae79..b271cece 100644 --- a/packages/2d/src/character/FCharacter.ts +++ b/packages/2d/src/controllers/FCharacterController.ts @@ -1,13 +1,13 @@ import * as PIXI from 'pixi.js' import { FKeyboard } from '@fibbojs/event' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import { FShapes } from '../types/FShapes' -import type { FComponentOptions } from '../FComponent' -import { FComponent } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import type { FColliderOptions } from '../FCollider' +import { FComponent } from '../core/FComponent' +import type { FRigidBodyOptions } from '../core/FRigidBody' +import type { FColliderOptions } from '../core/FCollider' +import { FController, type FControllerOptions } from './FController' -export interface FCharacterOptions extends FComponentOptions { +export interface FCharacterControllerOptions extends FControllerOptions { /** * The speed of the character. */ @@ -18,7 +18,7 @@ export interface FCharacterOptions extends FComponentOptions { * @description An abstract pre-defined character controller. * @category Character */ -export abstract class FCharacter extends FComponent { +export abstract class FCharacterController extends FController { /** * The inputs that will be used to move the character. */ @@ -34,11 +34,13 @@ export abstract class FCharacter extends FComponent { */ speed: number - constructor(scene: FScene, options?: FCharacterOptions) { - super(scene, { - scale: { x: 0.5, y: 1 }, - ...options, - }) + /** + * The scene where the character is. + */ + scene: FScene + + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(options) // Define default values const DEFAULT_OPTIONS = { @@ -50,7 +52,8 @@ export abstract class FCharacter extends FComponent { if (!options.speed) throw new Error('FibboError: FCharacter requires speed option') - // Store speed + // Store options + this.scene = scene this.speed = options.speed // Map of the movements (will be updated by the keyboard) @@ -61,13 +64,6 @@ export abstract class FCharacter extends FComponent { right: false, } - // Create a square - this.container = new PIXI.Graphics() - .rect(this.transform.position.x, this.transform.position.y, this.transform.scale.x * 100, this.transform.scale.y * 100) - .fill(new PIXI.FillGradient(0, 0, this.transform.scale.x * 100, this.transform.scale.y * 100).addColorStop(0, 0xFF00FF).addColorStop(1, 0xFFFF00)) - // Set the pivot of the container to the center - this.container.pivot.set(this.container.width / 2, this.container.height / 2) - // Create a keyboard instance const fKeyboard = new FKeyboard(scene) @@ -112,32 +108,5 @@ export abstract class FCharacter extends FComponent { fKeyboard.onKeyUp('q', () => { this.inputs.left = false }) - - // Initialize the rigid body - this.initRigidBody() - // Initialize the sensor - this.initSensor() - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - shape: FShapes.SQUARE, - ...options, - }) - } - - initCollider(options?: FColliderOptions): void { - super.initCollider({ - shape: FShapes.SQUARE, - ...options, - }) - } - - initSensor(options?: FColliderOptions): void { - super.initSensor({ - scale: { x: 1.2, y: 1.2 }, - shape: FShapes.SQUARE, - ...options, - }) } } diff --git a/packages/2d/src/controllers/FCharacterControllerD.ts b/packages/2d/src/controllers/FCharacterControllerD.ts new file mode 100644 index 00000000..c57c8ee0 --- /dev/null +++ b/packages/2d/src/controllers/FCharacterControllerD.ts @@ -0,0 +1,54 @@ +import RAPIER from '@dimforge/rapier2d' +import { FKeyboard } from '@fibbojs/event' +import type { FScene } from '../core/FScene' +import type { FCharacterControllerOptions } from './FCharacterController' +import { FCharacterController } from './FCharacterController' + +/** + * @description A pre-defined character controller based on a Dynamic RigidBody. + * @category Controller + * @example + * ```ts + * import { FCapsule, FCharacterControllerD, FScene } from '@fibbojs/3d' + * + * const scene = new FScene() + * + * const capsule = new FCapsule(scene) + * capsule.controller = new FCharacterControllerD(scene) + * scene.addComponent(capsule) + * ``` + */ +export class FCharacterControllerD extends FCharacterController { + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(scene, options) + + const fKeyboard = new FKeyboard(scene) + fKeyboard.on(' ', () => { + this.component.rigidBody?.rigidBody.applyImpulse({ x: 0, y: 0.5 }, true) + }) + + // Initialize the rigid body + this.component.initRigidBody({ + rigidBodyType: RAPIER.RigidBodyType.Dynamic, + lockRotations: true, + ...options, + }) + } + + onFrame(_delta: number): void { + // Apply movement on the y axis + if (this.inputs.up) { + this.component.rigidBody?.rigidBody.applyImpulse({ x: 0, y: 0.15 * this.speed }, true) + } + else if (this.inputs.down) { + this.component.rigidBody?.rigidBody.applyImpulse({ x: 0, y: -0.15 * this.speed }, true) + } + // Apply movement on the x axis + if (this.inputs.left) { + this.component.rigidBody?.rigidBody.applyImpulse({ x: -0.15 * this.speed, y: 0 }, true) + } + else if (this.inputs.right) { + this.component.rigidBody?.rigidBody.applyImpulse({ x: 0.15 * this.speed, y: 0 }, true) + } + } +} diff --git a/packages/2d/src/character/FCharacterKinematic.ts b/packages/2d/src/controllers/FCharacterControllerK.ts similarity index 73% rename from packages/2d/src/character/FCharacterKinematic.ts rename to packages/2d/src/controllers/FCharacterControllerK.ts index 3ed69122..0e63f0bb 100644 --- a/packages/2d/src/character/FCharacterKinematic.ts +++ b/packages/2d/src/controllers/FCharacterControllerK.ts @@ -1,17 +1,14 @@ import RAPIER from '@dimforge/rapier2d' import { FKeyboard } from '@fibbojs/event' -import type { FScene } from '../FScene' -import { FShapes } from '../types/FShapes' -import type { FRigidBodyOptions } from '../FRigidBody' -import type { FColliderOptions } from '../FCollider' -import type { FCharacterOptions } from './FCharacter' -import { FCharacter } from './FCharacter' +import type { FScene } from '../core/FScene' +import type { FCharacterControllerOptions } from './FCharacterController' +import { FCharacterController } from './FCharacterController' /** * @description An abstract pre-defined character controller based on Kinematic rigidbodies. - * @category Character + * @category Controller */ -export abstract class FCharacterKinematic extends FCharacter { +export abstract class FCharacterControllerK extends FCharacterController { /** * The y velocity of the character. Used to simulate gravity. */ @@ -22,7 +19,7 @@ export abstract class FCharacterKinematic extends FCharacter { */ characterController: RAPIER.KinematicCharacterController - constructor(scene: FScene, options?: FCharacterOptions) { + constructor(scene: FScene, options: FCharacterControllerOptions) { super(scene, options) // Initialize the y velocity @@ -57,7 +54,7 @@ export abstract class FCharacterKinematic extends FCharacter { } // Compute the desired movement this.characterController.computeColliderMovement( - this.collider?.collider as RAPIER.Collider, + this.component.collider?.collider as RAPIER.Collider, desiredMovement, // I don't why this flag works, I would expect QueryFilterFlags.EXCLUDE_SENSORS to work but anyway RAPIER.QueryFilterFlags.EXCLUDE_SOLIDS, @@ -74,18 +71,4 @@ export abstract class FCharacterKinematic extends FCharacter { // Get the corrected movement return this.characterController.computedMovement() } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - shape: FShapes.SQUARE, - ...options, - }) - } - - initCollider(options?: FColliderOptions): void { - super.initCollider({ - shape: FShapes.SQUARE, - ...options, - }) - } } diff --git a/packages/2d/src/controllers/FCharacterControllerKP.ts b/packages/2d/src/controllers/FCharacterControllerKP.ts new file mode 100644 index 00000000..6c58e1c9 --- /dev/null +++ b/packages/2d/src/controllers/FCharacterControllerKP.ts @@ -0,0 +1,42 @@ +import RAPIER from '@dimforge/rapier2d' +import type { FScene } from '../core/FScene' +import { FCharacterControllerK } from './FCharacterControllerK' +import type { FCharacterControllerOptions } from './FCharacterController' + +/** + * @description A pre-defined character controller based on a Kinematic Position RigidBody. + * @category Controller + * @example + * ```ts + * import { FCapsule, FCharacterControllerKP, FScene } from '@fibbojs/3d' + * + * const scene = new FScene() + * + * const capsule = new FCapsule(scene) + * capsule.controller = new FCharacterControllerKP(scene) + * scene.addComponent(capsule) + * ``` + */ +export class FCharacterControllerKP extends FCharacterControllerK { + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(scene, options) + + // Initialize the rigid body + this.component.initRigidBody({ + rigidBodyType: RAPIER.RigidBodyType.KinematicPositionBased, + lockRotations: true, + ...options, + }) + } + + onFrame(delta: number): void { + // Get the corrected movement + const correctedMovement = this.getCorrectedMovements(delta) + + // Apply the movement to the rigid body + this.component.rigidBody?.rigidBody.setNextKinematicTranslation({ + x: this.component.rigidBody.rigidBody.translation().x + correctedMovement.x * delta * this.speed * 64, + y: this.component.rigidBody.rigidBody.translation().y + correctedMovement.y * delta * this.speed * 64, + }) + } +} diff --git a/packages/2d/src/controllers/FCharacterControllerKV.ts b/packages/2d/src/controllers/FCharacterControllerKV.ts new file mode 100644 index 00000000..ad0b2e00 --- /dev/null +++ b/packages/2d/src/controllers/FCharacterControllerKV.ts @@ -0,0 +1,42 @@ +import RAPIER from '@dimforge/rapier2d' +import type { FScene } from '../core/FScene' +import { FCharacterControllerK } from './FCharacterControllerK' +import type { FCharacterControllerOptions } from './FCharacterController' + +/** + * @description A pre-defined character controller based on a Kinematic Velocity RigidBody. + * @category Controller + * @example + * ```ts + * import { FCapsule, FCharacterControllerKV, FScene } from '@fibbojs/3d' + * + * const scene = new FScene() + * + * const capsule = new FCapsule(scene) + * capsule.controller = new FCharacterControllerKV(scene) + * scene.addComponent(capsule) + * ``` + */ +export class FCharacterControllerKV extends FCharacterControllerK { + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(scene, options) + + // Initialize the rigid body + this.component.initRigidBody({ + rigidBodyType: RAPIER.RigidBodyType.KinematicVelocityBased, + lockRotations: true, + ...options, + }) + } + + onFrame(delta: number): void { + // Get the corrected movement + const correctedMovement = this.getCorrectedMovements(delta) + + // Apply the movement to the rigid body + this.component.rigidBody?.rigidBody.setLinvel({ + x: correctedMovement.x / delta, + y: correctedMovement.y / delta, + }, true) + } +} diff --git a/packages/2d/src/controllers/FController.ts b/packages/2d/src/controllers/FController.ts new file mode 100644 index 00000000..c0a3d3d6 --- /dev/null +++ b/packages/2d/src/controllers/FController.ts @@ -0,0 +1,27 @@ +import { FController as FControllerCore } from '@fibbojs/core' +import type { FControllerOptions as FControllerOptionsCore } from '@fibbojs/core' +import type { FComponent } from '../core/FComponent' + +export interface FControllerOptions extends FControllerOptionsCore { + component: FComponent +} + +/** + * @description The base class for 2D controllers in Fibbo. + */ +export abstract class FController extends FControllerCore { + /** + * The component attached to the controller. + * It is redefined here to get the correct type (with 2D properties). + */ + public component: FComponent + + /** + * @param options The options for the controller. + * @param options.component The component that the controller is controlling. + */ + constructor(options: FControllerOptions) { + super(options) + this.component = options.component + } +} diff --git a/packages/2d/src/FCollider.ts b/packages/2d/src/core/FCollider.ts similarity index 99% rename from packages/2d/src/FCollider.ts rename to packages/2d/src/core/FCollider.ts index 23403cf2..5c28a964 100644 --- a/packages/2d/src/FCollider.ts +++ b/packages/2d/src/core/FCollider.ts @@ -1,5 +1,5 @@ import * as RAPIER from '@dimforge/rapier2d' -import { FShapes } from './types/FShapes' +import { FShapes } from '../types/FShapes' import type { FComponent } from './FComponent' export interface FColliderOptions { diff --git a/packages/2d/src/FComponent.ts b/packages/2d/src/core/FComponent.ts similarity index 98% rename from packages/2d/src/FComponent.ts rename to packages/2d/src/core/FComponent.ts index 0e7f8a7a..d88e36bd 100644 --- a/packages/2d/src/FComponent.ts +++ b/packages/2d/src/core/FComponent.ts @@ -1,6 +1,7 @@ import { FComponent as FComponentCore } from '@fibbojs/core' import { Container } from 'pixi.js' import * as RAPIER from '@dimforge/rapier2d' +import type { FController } from '../controllers/FController' import type { FScene } from './FScene' import type { FColliderOptions } from './FCollider' import { FCollider } from './FCollider' @@ -30,6 +31,10 @@ export abstract class FComponent extends FComponentCore { */ scene: FScene + // The controller attached to the component. + // Redefined here to be able to use the updated FController type. + declare controller?: FController + /** * PIXI container */ @@ -96,6 +101,7 @@ export abstract class FComponent extends FComponentCore { } onFrame(_delta: number): void { + super.onFrame(_delta) // If the rigid body exist, update the container position and rotation according to the rigid body if (this.rigidBody) { const newContainerPosition = this.rigidBody.rigidBody.translation() diff --git a/packages/2d/src/FComponentEmpty.ts b/packages/2d/src/core/FComponentEmpty.ts similarity index 100% rename from packages/2d/src/FComponentEmpty.ts rename to packages/2d/src/core/FComponentEmpty.ts diff --git a/packages/2d/src/FRigidBody.ts b/packages/2d/src/core/FRigidBody.ts similarity index 99% rename from packages/2d/src/FRigidBody.ts rename to packages/2d/src/core/FRigidBody.ts index 5b124304..3badf7d7 100644 --- a/packages/2d/src/FRigidBody.ts +++ b/packages/2d/src/core/FRigidBody.ts @@ -1,5 +1,5 @@ import * as RAPIER from '@dimforge/rapier2d' -import { FShapes } from './types/FShapes' +import { FShapes } from '../types/FShapes' import type { FComponent } from './FComponent' import { FCollider } from './FCollider' diff --git a/packages/2d/src/FScene.ts b/packages/2d/src/core/FScene.ts similarity index 98% rename from packages/2d/src/FScene.ts rename to packages/2d/src/core/FScene.ts index e0176c76..6da9a863 100644 --- a/packages/2d/src/FScene.ts +++ b/packages/2d/src/core/FScene.ts @@ -3,10 +3,10 @@ import { FScene as FSceneCore } from '@fibbojs/core' import * as PIXI from 'pixi.js' import { Viewport } from 'pixi-viewport' import type RAPIER from '@dimforge/rapier2d' +import { FSprite } from '../sprite/FSprite' +import type { FCamera } from '../cameras/FCamera' +import { FFreeCamera } from '../cameras/FFreeCamera' import type { FComponent } from './FComponent' -import { FSprite } from './sprite/FSprite' -import type { FCamera } from './cameras/FCamera' -import { FFreeCamera } from './cameras/FFreeCamera' export interface FSceneOptions { gravity?: { x: number, y: number, z: number } diff --git a/packages/2d/src/FTransform.ts b/packages/2d/src/core/FTransform.ts similarity index 100% rename from packages/2d/src/FTransform.ts rename to packages/2d/src/core/FTransform.ts diff --git a/packages/2d/src/index.ts b/packages/2d/src/index.ts index 1d55b068..a9952fa4 100644 --- a/packages/2d/src/index.ts +++ b/packages/2d/src/index.ts @@ -2,10 +2,10 @@ * Export Core */ // Core -export { FScene } from './FScene' -export { FComponent } from './FComponent' -export { FComponentEmpty } from './FComponentEmpty' -export { FTransform } from './FTransform' +export { FScene } from './core/FScene' +export { FComponent } from './core/FComponent' +export { FComponentEmpty } from './core/FComponentEmpty' +export { FTransform } from './core/FTransform' // Cameras export { FCamera } from './cameras/FCamera' @@ -14,11 +14,11 @@ export { FFixedCamera } from './cameras/FFixedCamera' export { FFreeCamera } from './cameras/FFreeCamera' // Character controllers -export { FCharacter } from './character/FCharacter' -export { FCharacterDynamic } from './character/FCharacterDynamic' -export { FCharacterKinematic } from './character/FCharacterKinematic' -export { FCharacterKP } from './character/FCharacterKP' -export { FCharacterKV } from './character/FCharacterKV' +export { FCharacterController } from './controllers/FCharacterController' +export { FCharacterControllerD } from './controllers/FCharacterControllerD' +export { FCharacterControllerK } from './controllers/FCharacterControllerK' +export { FCharacterControllerKP } from './controllers/FCharacterControllerKP' +export { FCharacterControllerKV } from './controllers/FCharacterControllerKV' // Polygons export { FPolygon } from './polygons/FPolygon' @@ -30,11 +30,12 @@ export { FSprite } from './sprite/FSprite' // Types export { FShapes } from './types/FShapes' -export type { FComponentOptions } from './FComponent' -export type { FColliderOptions } from './FCollider' -export type { FRigidBodyOptions } from './FRigidBody' +export type { FComponentOptions } from './core/FComponent' +export type { FColliderOptions } from './core/FCollider' +export type { FRigidBodyOptions } from './core/FRigidBody' export type { FCameraOptions } from './cameras/FCamera' -export type { FCharacterOptions } from './character/FCharacter' -export type { FSceneOptions } from './FScene' +export type { FControllerOptions } from './controllers/FController' +export type { FCharacterControllerOptions } from './controllers/FCharacterController' +export type { FSceneOptions } from './core/FScene' export type { FSpriteOptions } from './sprite/FSprite' -export type { FTransformOptions } from './FTransform' +export type { FTransformOptions } from './core/FTransform' diff --git a/packages/2d/src/polygons/FCircle.ts b/packages/2d/src/polygons/FCircle.ts index 861e2d89..7dfeb737 100644 --- a/packages/2d/src/polygons/FCircle.ts +++ b/packages/2d/src/polygons/FCircle.ts @@ -1,6 +1,6 @@ import * as PIXI from 'pixi.js' -import type { FComponentOptions } from '../FComponent' -import type { FScene } from '../FScene' +import type { FComponentOptions } from '../core/FComponent' +import type { FScene } from '../core/FScene' import { FShapes } from '../types/FShapes' import { FPolygon } from './FPolygon' diff --git a/packages/2d/src/polygons/FPolygon.ts b/packages/2d/src/polygons/FPolygon.ts index ae7cf662..21fe6cd2 100644 --- a/packages/2d/src/polygons/FPolygon.ts +++ b/packages/2d/src/polygons/FPolygon.ts @@ -1,7 +1,7 @@ import * as PIXI from 'pixi.js' -import type { FComponentOptions } from '../FComponent' -import { FComponent } from '../FComponent' -import type { FScene } from '../FScene' +import type { FComponentOptions } from '../core/FComponent' +import { FComponent } from '../core/FComponent' +import type { FScene } from '../core/FScene' /** * @description A simple polygon in Fibbo. diff --git a/packages/2d/src/polygons/FRectangle.ts b/packages/2d/src/polygons/FRectangle.ts index b7302cd3..d51c516a 100644 --- a/packages/2d/src/polygons/FRectangle.ts +++ b/packages/2d/src/polygons/FRectangle.ts @@ -1,7 +1,5 @@ -import * as PIXI from 'pixi.js' -import type { FComponentOptions } from '../FComponent' -import { FComponent } from '../FComponent' -import type { FScene } from '../FScene' +import type { FComponentOptions } from '../core/FComponent' +import type { FScene } from '../core/FScene' import { FPolygon } from './FPolygon' /** diff --git a/packages/2d/src/sprite/FSprite.ts b/packages/2d/src/sprite/FSprite.ts index 4914bd20..4f5e9d9e 100644 --- a/packages/2d/src/sprite/FSprite.ts +++ b/packages/2d/src/sprite/FSprite.ts @@ -1,7 +1,7 @@ import * as PIXI from 'pixi.js' -import type { FComponentOptions } from '../FComponent' -import { FComponent } from '../FComponent' -import type { FScene } from '../FScene' +import type { FComponentOptions } from '../core/FComponent' +import { FComponent } from '../core/FComponent' +import type { FScene } from '../core/FScene' export interface FSpriteOptions extends FComponentOptions { texture: string diff --git a/packages/3d/src/cameras/FAttachedCamera.ts b/packages/3d/src/cameras/FAttachedCamera.ts index fb8aeddf..93e818e2 100644 --- a/packages/3d/src/cameras/FAttachedCamera.ts +++ b/packages/3d/src/cameras/FAttachedCamera.ts @@ -1,5 +1,5 @@ import * as THREE from 'three' -import type { FComponent } from '../FComponent' +import type { FComponent } from '../core/FComponent' import type { FCameraOptions } from './FCamera' import { FCamera } from './FCamera' diff --git a/packages/3d/src/cameras/FCamera.ts b/packages/3d/src/cameras/FCamera.ts index 75aedb12..22fb3730 100644 --- a/packages/3d/src/cameras/FCamera.ts +++ b/packages/3d/src/cameras/FCamera.ts @@ -1,7 +1,7 @@ import * as THREE from 'three' import type { FCamera as FCameraCore } from '@fibbojs/core' -import type { FTransformOptions } from '../FTransform' -import { FTransform } from '../FTransform' +import type { FTransformOptions } from '../core/FTransform' +import { FTransform } from '../core/FTransform' export interface FCameraOptions extends FTransformOptions {} diff --git a/packages/3d/src/cameras/FOrbitCamera.ts b/packages/3d/src/cameras/FOrbitCamera.ts index 494a38d7..e3a953d9 100644 --- a/packages/3d/src/cameras/FOrbitCamera.ts +++ b/packages/3d/src/cameras/FOrbitCamera.ts @@ -1,5 +1,5 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js' -import type { FComponent } from '../FComponent' +import type { FComponent } from '../core/FComponent' import { FCamera } from './FCamera' import type { FAttachedCameraOptions } from './FAttachedCamera' diff --git a/packages/3d/src/cameras/FPointerLockCamera.ts b/packages/3d/src/cameras/FPointerLockCamera.ts index 1effd69a..94f093f2 100644 --- a/packages/3d/src/cameras/FPointerLockCamera.ts +++ b/packages/3d/src/cameras/FPointerLockCamera.ts @@ -1,5 +1,5 @@ import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js' -import type { FComponent } from '../FComponent' +import type { FComponent } from '../core/FComponent' import { FCamera } from './FCamera' import type { FAttachedCameraOptions } from './FAttachedCamera' diff --git a/packages/3d/src/character/FCharacterDynamic.ts b/packages/3d/src/character/FCharacterDynamic.ts deleted file mode 100644 index 73d26ae2..00000000 --- a/packages/3d/src/character/FCharacterDynamic.ts +++ /dev/null @@ -1,69 +0,0 @@ -import * as THREE from 'three' -import RAPIER from '@dimforge/rapier3d' -import { FKeyboard } from '@fibbojs/event' -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import { FCharacter } from './FCharacter' - -/** - * @description A pre-defined character controller based on a Dynamic RigidBody. - * @category Character - * @example - * ```ts - * import { FScene, FCharacterDynamic } from '@fibbojs/3d' - * - * const scene = new FScene() - * - * const capsule = new FCharacterDynamic(scene) - * scene.addComponent(capsule) - * ``` - */ -export class FCharacterDynamic extends FCharacter { - constructor(scene: FScene, options?: FComponentOptions) { - super(scene, options) - - const fKeyboard = new FKeyboard(scene) - fKeyboard.on(' ', () => { - this.rigidBody?.rigidBody.applyImpulse(new THREE.Vector3(0, 1, 0), true) - }) - - // Initialize the rigid body - this.initRigidBody() - // Initialize a sensor - this.initSensor() - } - - onFrame(_delta: number): void { - // Get camera direction - const cameraDirection = this.scene.camera.getCameraDirection() - // Ignore the y axis - cameraDirection.y = 0 - - // Apply movement on the x axis - if (this.inputs.forward) { - this.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(0.4 * this.speed), true) - } - else if (this.inputs.backward) { - this.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(-0.4 * this.speed), true) - } - - // Apply movement on the z axis - if (this.inputs.left) { - this.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(0.4 * this.speed).applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2), true) - } - else if (this.inputs.right) { - this.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(-0.4 * this.speed).applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2), true) - } - - super.onFrame(_delta) - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - rigidBodyType: RAPIER.RigidBodyType.Dynamic, - lockRotations: true, - ...options, - }) - } -} diff --git a/packages/3d/src/character/FCharacterKP.ts b/packages/3d/src/character/FCharacterKP.ts deleted file mode 100644 index c74b6da8..00000000 --- a/packages/3d/src/character/FCharacterKP.ts +++ /dev/null @@ -1,53 +0,0 @@ -import RAPIER from '@dimforge/rapier3d' -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import { FCharacterKinematic } from './FCharacterKinematic' - -/** - * @description A pre-defined character controller based on a Kinematic Position RigidBody. - * @category Character - * @example - * ```ts - * import { FScene, FCharacterKP } from '@fibbojs/3d' - * - * const scene = new FScene() - * - * const capsule = new FCharacterKP(scene) - * scene.addComponent(capsule) - * ``` - */ -export class FCharacterKP extends FCharacterKinematic { - constructor(scene: FScene, options?: FComponentOptions) { - super(scene, options) - - // Initialize the rigid body - this.initRigidBody() - // Initialize a sensor - this.initSensor() - } - - onFrame(delta: number): void { - /** - * Get the corrected movements for the current frame - */ - const correctedMovement = this.getCorrectedMovements(delta) - - // Apply the movement to the rigid body - this.rigidBody?.rigidBody.setNextKinematicTranslation({ - x: this.rigidBody.rigidBody.translation().x + correctedMovement.x * delta * this.speed * 64, - y: this.rigidBody.rigidBody.translation().y + correctedMovement.y * delta * this.speed * 64, - z: this.rigidBody.rigidBody.translation().z + correctedMovement.z * delta * this.speed * 64, - }) - - // Call the super onFrame method - super.onFrame(delta) - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - rigidBodyType: RAPIER.RigidBodyType.KinematicPositionBased, - ...options, - }) - } -} diff --git a/packages/3d/src/character/FCharacter.ts b/packages/3d/src/controllers/FCharacterController.ts similarity index 61% rename from packages/3d/src/character/FCharacter.ts rename to packages/3d/src/controllers/FCharacterController.ts index de57b433..055ae4f8 100644 --- a/packages/3d/src/character/FCharacter.ts +++ b/packages/3d/src/controllers/FCharacterController.ts @@ -1,13 +1,9 @@ -import * as THREE from 'three' import { FKeyboard } from '@fibbojs/event' -import type { FScene } from '../FScene' -import { FShapes } from '../types/FShapes' -import type { FComponentOptions } from '../FComponent' -import { FComponent } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import type { FColliderOptions } from '../FCollider' +import type { FScene } from '../core/FScene' +import type { FControllerOptions } from './FController' +import { FController } from './FController' -export interface FCharacterOptions extends FComponentOptions { +export interface FCharacterControllerOptions extends FControllerOptions { /** * The speed of the character. */ @@ -16,9 +12,9 @@ export interface FCharacterOptions extends FComponentOptions { /** * @description An abstract pre-defined character controller. - * @category Character + * @category Controller */ -export abstract class FCharacter extends FComponent { +export abstract class FCharacterController extends FController { /** * The inputs that will be used to move the character. */ @@ -34,8 +30,13 @@ export abstract class FCharacter extends FComponent { */ speed: number - constructor(scene: FScene, options?: FCharacterOptions) { - super(scene, options) + /** + * The scene where the character is. + */ + scene: FScene + + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(options) // Define default values const DEFAULT_OPTIONS = { @@ -47,7 +48,8 @@ export abstract class FCharacter extends FComponent { if (!options.speed) throw new Error('FibboError: FCharacter requires speed option') - // Store speed + // Store options + this.scene = scene this.speed = options.speed // Map of the movements (will be updated by the keyboard) @@ -58,11 +60,6 @@ export abstract class FCharacter extends FComponent { right: false, } - // Create a capsule mesh - const geometry = new THREE.CapsuleGeometry(0.5, 1, 32) - const material = new THREE.MeshBasicMaterial({ color: 0xA0FFA0 }) - this.mesh = new THREE.Mesh(geometry, material) - // Create a keyboard instance const fKeyboard = new FKeyboard(scene) @@ -108,26 +105,4 @@ export abstract class FCharacter extends FComponent { this.inputs.left = false }) } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - shape: FShapes.CAPSULE, - ...options, - }) - } - - initCollider(options?: FColliderOptions): void { - super.initCollider({ - shape: FShapes.CAPSULE, - ...options, - }) - } - - initSensor(options?: FColliderOptions): void { - super.initSensor({ - scale: { x: 1.1, y: 1.1, z: 1.1 }, - shape: FShapes.CAPSULE, - ...options, - }) - } } diff --git a/packages/3d/src/controllers/FCharacterControllerD.ts b/packages/3d/src/controllers/FCharacterControllerD.ts new file mode 100644 index 00000000..562239f6 --- /dev/null +++ b/packages/3d/src/controllers/FCharacterControllerD.ts @@ -0,0 +1,66 @@ +import * as THREE from 'three' +import RAPIER from '@dimforge/rapier3d' +import { FKeyboard } from '@fibbojs/event' +import type { FScene } from '../core/FScene' +import { FShapes } from '../types/FShapes' +import type { FCharacterControllerOptions } from './FCharacterController' +import { FCharacterController } from './FCharacterController' + +/** + * @description A pre-defined character controller based on a Dynamic RigidBody. + * @category Controller + * @example + * ```ts + * import { FCapsule, FCharacterControllerD, FScene } from '@fibbojs/3d' + * + * const scene = new FScene() + * + * const capsule = new FCapsule(scene) + * capsule.controller = new FCharacterControllerD(scene) + * scene.addComponent(capsule) + * ``` + */ +export class FCharacterControllerD extends FCharacterController { + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(scene, options) + + const fKeyboard = new FKeyboard(scene) + fKeyboard.on(' ', () => { + this.component.rigidBody?.rigidBody.applyImpulse(new THREE.Vector3(0, 1, 0), true) + }) + + // Initialize the rigid body + this.component.initRigidBody({ + rigidBodyType: RAPIER.RigidBodyType.Dynamic, + lockRotations: true, + ...options, + }) + // Initialize a sensor + this.component.initSensor({ + shape: FShapes.CAPSULE, + }) + } + + onFrame(_delta: number): void { + // Get camera direction + const cameraDirection = this.scene.camera.getCameraDirection() + // Ignore the y axis + cameraDirection.y = 0 + + // Apply movement on the x axis + if (this.inputs.forward) { + this.component.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(0.4 * this.speed), true) + } + else if (this.inputs.backward) { + this.component.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(-0.4 * this.speed), true) + } + + // Apply movement on the z axis + if (this.inputs.left) { + this.component.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(0.4 * this.speed).applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2), true) + } + else if (this.inputs.right) { + this.component.rigidBody?.rigidBody.applyImpulse(cameraDirection.multiplyScalar(-0.4 * this.speed).applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2), true) + } + } +} diff --git a/packages/3d/src/character/FCharacterKinematic.ts b/packages/3d/src/controllers/FCharacterControllerK.ts similarity index 86% rename from packages/3d/src/character/FCharacterKinematic.ts rename to packages/3d/src/controllers/FCharacterControllerK.ts index 8e93ff7b..7fd738c3 100644 --- a/packages/3d/src/character/FCharacterKinematic.ts +++ b/packages/3d/src/controllers/FCharacterControllerK.ts @@ -1,15 +1,15 @@ import * as THREE from 'three' import RAPIER from '@dimforge/rapier3d' import { FKeyboard } from '@fibbojs/event' -import type { FScene } from '../FScene' -import type { FCharacterOptions } from './FCharacter' -import { FCharacter } from './FCharacter' +import type { FScene } from '../core/FScene' +import type { FCharacterControllerOptions } from './FCharacterController' +import { FCharacterController } from './FCharacterController' /** * @description An abstract pre-defined character controller based on Kinematic rigidbodies. - * @category Character + * @category Controller */ -export abstract class FCharacterKinematic extends FCharacter { +export abstract class FCharacterControllerK extends FCharacterController { /** * The y velocity of the character. Used to apply gravity. */ @@ -20,7 +20,7 @@ export abstract class FCharacterKinematic extends FCharacter { */ characterController: RAPIER.KinematicCharacterController - constructor(scene: FScene, options?: FCharacterOptions) { + constructor(scene: FScene, options: FCharacterControllerOptions) { super(scene, options) // Set the default yVelocity @@ -64,7 +64,7 @@ export abstract class FCharacterKinematic extends FCharacter { } // Compute the desired movement this.characterController.computeColliderMovement( - this.collider?.collider as RAPIER.Collider, + this.component.collider?.collider as RAPIER.Collider, desiredMovement, // I don't why this flag works, I would expect QueryFilterFlags.EXCLUDE_SENSORS to work but anyway RAPIER.QueryFilterFlags.EXCLUDE_SOLIDS, diff --git a/packages/3d/src/controllers/FCharacterControllerKP.ts b/packages/3d/src/controllers/FCharacterControllerKP.ts new file mode 100644 index 00000000..c850a84d --- /dev/null +++ b/packages/3d/src/controllers/FCharacterControllerKP.ts @@ -0,0 +1,49 @@ +import RAPIER from '@dimforge/rapier3d' +import type { FScene } from '../core/FScene' +import { FShapes } from '../types/FShapes' +import { FCharacterControllerK } from './FCharacterControllerK' +import type { FCharacterControllerOptions } from './FCharacterController' + +/** + * @description A pre-defined character controller based on a Kinematic Position RigidBody. + * @category Controller + * @example + * ```ts + * import { FCapsule, FCharacterControllerKP, FScene } from '@fibbojs/3d' + * + * const scene = new FScene() + * + * const capsule = new FCapsule(scene) + * capsule.controller = new FCharacterControllerKP(scene) + * scene.addComponent(capsule) + * ``` + */ +export class FCharacterControllerKP extends FCharacterControllerK { + constructor(scene: FScene, options: FCharacterControllerOptions) { + super(scene, options) + + // Initialize the rigid body + this.component.initRigidBody({ + rigidBodyType: RAPIER.RigidBodyType.KinematicPositionBased, + ...options, + }) + // Initialize a sensor + this.component.initSensor({ + shape: FShapes.CAPSULE, + }) + } + + onFrame(delta: number): void { + /** + * Get the corrected movements for the current frame + */ + const correctedMovement = this.getCorrectedMovements(delta) + + // Apply the movement to the rigid body + this.component.rigidBody?.rigidBody.setNextKinematicTranslation({ + x: this.component.rigidBody.rigidBody.translation().x + correctedMovement.x * delta * this.speed * 64, + y: this.component.rigidBody.rigidBody.translation().y + correctedMovement.y * delta * this.speed * 64, + z: this.component.rigidBody.rigidBody.translation().z + correctedMovement.z * delta * this.speed * 64, + }) + } +} diff --git a/packages/3d/src/character/FCharacterKV.ts b/packages/3d/src/controllers/FCharacterControllerKV.ts similarity index 53% rename from packages/3d/src/character/FCharacterKV.ts rename to packages/3d/src/controllers/FCharacterControllerKV.ts index 31caf8b4..e43556ff 100644 --- a/packages/3d/src/character/FCharacterKV.ts +++ b/packages/3d/src/controllers/FCharacterControllerKV.ts @@ -1,31 +1,36 @@ -import * as THREE from 'three' import RAPIER from '@dimforge/rapier3d' -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import { FCharacterKinematic } from './FCharacterKinematic' +import type { FScene } from '../core/FScene' +import { FShapes } from '../types/FShapes' +import { FCharacterControllerK } from './FCharacterControllerK' +import type { FCharacterControllerOptions } from './FCharacterController' /** * @description A pre-defined character controller based on a Kinematic Velocity RigidBody. * @category Character * @example * ```ts - * import { FScene, FCharacterKV } from '@fibbojs/3d' + * import { FCapsule, FCharacterControllerKV, FScene } from '@fibbojs/3d' * * const scene = new FScene() * - * const capsule = new FCharacterKV(scene) + * const capsule = new FCapsule(scene) + * capsule.controller = new FCharacterControllerKV(scene) * scene.addComponent(capsule) * ``` */ -export class FCharacterKV extends FCharacterKinematic { - constructor(scene: FScene, options?: FComponentOptions) { +export class FCharacterControllerKV extends FCharacterControllerK { + constructor(scene: FScene, options: FCharacterControllerOptions) { super(scene, options) // Initialize the rigid body - this.initRigidBody() + this.component.initRigidBody({ + rigidBodyType: RAPIER.RigidBodyType.KinematicVelocityBased, + ...options, + }) // Initialize a sensor - this.initSensor() + this.component.initSensor({ + shape: FShapes.CAPSULE, + }) } onFrame(delta: number): void { @@ -35,20 +40,10 @@ export class FCharacterKV extends FCharacterKinematic { const correctedMovement = this.getCorrectedMovements(delta) // Apply the movement to the rigid body - this.rigidBody?.rigidBody.setLinvel({ + this.component.rigidBody?.rigidBody.setLinvel({ x: correctedMovement.x / delta, y: correctedMovement.y / delta, z: correctedMovement.z / delta, }, true) - - // Call the super onFrame method - super.onFrame(delta) - } - - initRigidBody(options?: FRigidBodyOptions): void { - super.initRigidBody({ - rigidBodyType: RAPIER.RigidBodyType.KinematicVelocityBased, - ...options, - }) } } diff --git a/packages/3d/src/controllers/FController.ts b/packages/3d/src/controllers/FController.ts new file mode 100644 index 00000000..88f0b0ad --- /dev/null +++ b/packages/3d/src/controllers/FController.ts @@ -0,0 +1,27 @@ +import { FController as FControllerCore } from '@fibbojs/core' +import type { FControllerOptions as FControllerOptionsCore } from '@fibbojs/core' +import type { FComponent } from '../core/FComponent' + +export interface FControllerOptions extends FControllerOptionsCore { + component: FComponent +} + +/** + * @description The base class for 3D controllers in Fibbo. + */ +export abstract class FController extends FControllerCore { + /** + * The component attached to the controller. + * It is redefined here to get the correct type (with 3D properties). + */ + public component: FComponent + + /** + * @param options The options for the controller. + * @param options.component The component that the controller is controlling. + */ + constructor(options: FControllerOptions) { + super(options) + this.component = options.component + } +} diff --git a/packages/3d/src/FCollider.ts b/packages/3d/src/core/FCollider.ts similarity index 99% rename from packages/3d/src/FCollider.ts rename to packages/3d/src/core/FCollider.ts index a1366181..fdd24881 100644 --- a/packages/3d/src/FCollider.ts +++ b/packages/3d/src/core/FCollider.ts @@ -1,6 +1,6 @@ import * as THREE from 'three' import * as RAPIER from '@dimforge/rapier3d' -import { FShapes } from './types/FShapes' +import { FShapes } from '../types/FShapes' import type { FComponent } from './FComponent' export interface FColliderOptions { diff --git a/packages/3d/src/FComponent.ts b/packages/3d/src/core/FComponent.ts similarity index 98% rename from packages/3d/src/FComponent.ts rename to packages/3d/src/core/FComponent.ts index f87e771d..8ad3568d 100644 --- a/packages/3d/src/FComponent.ts +++ b/packages/3d/src/core/FComponent.ts @@ -1,6 +1,7 @@ import * as THREE from 'three' import * as RAPIER from '@dimforge/rapier3d' import { FComponent as FComponentCore } from '@fibbojs/core' +import type { FController } from '../controllers/FController' import type { FScene } from './FScene' import type { FColliderOptions } from './FCollider' import { FCollider } from './FCollider' @@ -30,6 +31,10 @@ export abstract class FComponent extends FComponentCore { */ scene: FScene + // The controller attached to the component. + // Redefined here to be able to use the updated FController type. + declare controller?: FController + /** * Mesh */ @@ -100,6 +105,7 @@ export abstract class FComponent extends FComponentCore { } onFrame(_delta: number): void { + super.onFrame(_delta) // If the rigid body and mesh exist, update the mesh position and rotation according to the rigid body if (this.rigidBody && this.mesh) { // Get the new transforms from the rigid body diff --git a/packages/3d/src/FComponentEmpty.ts b/packages/3d/src/core/FComponentEmpty.ts similarity index 100% rename from packages/3d/src/FComponentEmpty.ts rename to packages/3d/src/core/FComponentEmpty.ts diff --git a/packages/3d/src/FRigidBody.ts b/packages/3d/src/core/FRigidBody.ts similarity index 99% rename from packages/3d/src/FRigidBody.ts rename to packages/3d/src/core/FRigidBody.ts index 80c065db..3949e7dd 100644 --- a/packages/3d/src/FRigidBody.ts +++ b/packages/3d/src/core/FRigidBody.ts @@ -1,6 +1,6 @@ import * as THREE from 'three' import * as RAPIER from '@dimforge/rapier3d' -import { FShapes } from './types/FShapes' +import { FShapes } from '../types/FShapes' import type { FComponent } from './FComponent' import { FCollider } from './FCollider' diff --git a/packages/3d/src/FScene.ts b/packages/3d/src/core/FScene.ts similarity index 97% rename from packages/3d/src/FScene.ts rename to packages/3d/src/core/FScene.ts index 45fd2f6d..c5e014b9 100644 --- a/packages/3d/src/FScene.ts +++ b/packages/3d/src/core/FScene.ts @@ -1,10 +1,10 @@ import * as THREE from 'three' import { FScene as FSceneCore } from '@fibbojs/core' import type RAPIER from '@dimforge/rapier3d' +import type { FCamera } from '../cameras/FCamera' +import { FFixedCamera } from '../cameras/FFixedCamera' +import { FModel } from '../model/FModel' import type { FComponent } from './FComponent' -import type { FCamera } from './cameras/FCamera' -import { FFixedCamera } from './cameras/FFixedCamera' -import { FModel } from './model/FModel' export interface FSceneOptions { gravity?: { x: number, y: number, z: number } diff --git a/packages/3d/src/FTransform.ts b/packages/3d/src/core/FTransform.ts similarity index 100% rename from packages/3d/src/FTransform.ts rename to packages/3d/src/core/FTransform.ts diff --git a/packages/3d/src/index.ts b/packages/3d/src/index.ts index 7e2d7f94..31ff130a 100644 --- a/packages/3d/src/index.ts +++ b/packages/3d/src/index.ts @@ -2,17 +2,17 @@ * Export Core */ // Core 3d Classes -export { FScene } from './FScene' -export { FComponent } from './FComponent' -export { FComponentEmpty } from './FComponentEmpty' -export { FTransform } from './FTransform' +export { FScene } from './core/FScene' +export { FComponent } from './core/FComponent' +export { FComponentEmpty } from './core/FComponentEmpty' +export { FTransform } from './core/FTransform' // Character controllers -export { FCharacter } from './character/FCharacter' -export { FCharacterDynamic } from './character/FCharacterDynamic' -export { FCharacterKinematic } from './character/FCharacterKinematic' -export { FCharacterKP } from './character/FCharacterKP' -export { FCharacterKV } from './character/FCharacterKV' +export { FCharacterController } from './controllers/FCharacterController' +export { FCharacterControllerD } from './controllers/FCharacterControllerD' +export { FCharacterControllerK } from './controllers/FCharacterControllerK' +export { FCharacterControllerKP } from './controllers/FCharacterControllerKP' +export { FCharacterControllerKV } from './controllers/FCharacterControllerKV' // Models export { FModel } from './model/FModel' @@ -37,12 +37,13 @@ export { FPointerLockCamera } from './cameras/FPointerLockCamera' // Types export { FShapes } from './types/FShapes' -export type { FComponentOptions } from './FComponent' -export type { FSceneOptions } from './FScene' -export type { FCharacterOptions } from './character/FCharacter' +export type { FComponentOptions } from './core/FComponent' +export type { FSceneOptions } from './core/FScene' +export type { FControllerOptions } from './controllers/FController' +export type { FCharacterControllerOptions } from './controllers/FCharacterController' export type { FModelOptions } from './model/FModel' -export type { FRigidBodyOptions } from './FRigidBody' -export type { FColliderOptions } from './FCollider' -export type { FTransformOptions } from './FTransform' +export type { FRigidBodyOptions } from './core/FRigidBody' +export type { FColliderOptions } from './core/FCollider' +export type { FTransformOptions } from './core/FTransform' export type { FCameraOptions } from './cameras/FCamera' export type { FAttachedCameraOptions } from './cameras/FAttachedCamera' diff --git a/packages/3d/src/model/FFBX.ts b/packages/3d/src/model/FFBX.ts index 6c76f2db..68fa0699 100644 --- a/packages/3d/src/model/FFBX.ts +++ b/packages/3d/src/model/FFBX.ts @@ -1,6 +1,6 @@ import * as THREE from 'three' import { FBXLoader } from 'three/addons/loaders/FBXLoader.js' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import { FModel } from './FModel' import type { FModelOptions } from './FModel' diff --git a/packages/3d/src/model/FGLB.ts b/packages/3d/src/model/FGLB.ts index d063b4ff..d4b5d190 100644 --- a/packages/3d/src/model/FGLB.ts +++ b/packages/3d/src/model/FGLB.ts @@ -1,4 +1,4 @@ -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import type { FModelOptions } from './FModel' import { FGLTF } from './FGLTF' diff --git a/packages/3d/src/model/FGLTF.ts b/packages/3d/src/model/FGLTF.ts index 0a012798..49578bf9 100644 --- a/packages/3d/src/model/FGLTF.ts +++ b/packages/3d/src/model/FGLTF.ts @@ -1,5 +1,5 @@ import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import { FModel } from './FModel' import type { FModelOptions } from './FModel' diff --git a/packages/3d/src/model/FModel.ts b/packages/3d/src/model/FModel.ts index b82c086c..0441f5fc 100644 --- a/packages/3d/src/model/FModel.ts +++ b/packages/3d/src/model/FModel.ts @@ -1,7 +1,7 @@ import * as THREE from 'three' -import type { FScene } from '../FScene' -import { FComponent } from '../FComponent' -import type { FComponentOptions } from '../FComponent' +import type { FScene } from '../core/FScene' +import { FComponent } from '../core/FComponent' +import type { FComponentOptions } from '../core/FComponent' export interface FModelOptions extends FComponentOptions { name: string diff --git a/packages/3d/src/model/FOBJ.ts b/packages/3d/src/model/FOBJ.ts index a3f6aa91..39a68a5e 100644 --- a/packages/3d/src/model/FOBJ.ts +++ b/packages/3d/src/model/FOBJ.ts @@ -1,6 +1,6 @@ import * as THREE from 'three' import { OBJLoader } from 'three/addons/loaders/OBJLoader.js' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import { FModel } from './FModel' import type { FModelOptions } from './FModel' diff --git a/packages/3d/src/polyhedrons/FCapsule.ts b/packages/3d/src/polyhedrons/FCapsule.ts index daee5bff..2f4a71b8 100644 --- a/packages/3d/src/polyhedrons/FCapsule.ts +++ b/packages/3d/src/polyhedrons/FCapsule.ts @@ -1,9 +1,9 @@ import * as THREE from 'three' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import { FShapes } from '../types/FShapes' -import type { FComponentOptions } from '../FComponent' -import type { FColliderOptions } from '../FCollider' -import type { FRigidBodyOptions } from '../FRigidBody' +import type { FComponentOptions } from '../core/FComponent' +import type { FColliderOptions } from '../core/FCollider' +import type { FRigidBodyOptions } from '../core/FRigidBody' import { FPolyhedron } from './FPolyhedron' /** diff --git a/packages/3d/src/polyhedrons/FCuboid.ts b/packages/3d/src/polyhedrons/FCuboid.ts index 788fdc6f..468856af 100644 --- a/packages/3d/src/polyhedrons/FCuboid.ts +++ b/packages/3d/src/polyhedrons/FCuboid.ts @@ -1,5 +1,5 @@ -import type { FScene } from '../FScene' -import type { FComponentOptions } from '../FComponent' +import type { FScene } from '../core/FScene' +import type { FComponentOptions } from '../core/FComponent' import { FPolyhedron } from './FPolyhedron' /** diff --git a/packages/3d/src/polyhedrons/FPolyhedron.ts b/packages/3d/src/polyhedrons/FPolyhedron.ts index 5e41fd88..b1800ec0 100644 --- a/packages/3d/src/polyhedrons/FPolyhedron.ts +++ b/packages/3d/src/polyhedrons/FPolyhedron.ts @@ -1,7 +1,7 @@ import * as THREE from 'three' -import type { FScene } from '../FScene' -import { FComponent } from '../FComponent' -import type { FComponentOptions } from '../FComponent' +import type { FScene } from '../core/FScene' +import { FComponent } from '../core/FComponent' +import type { FComponentOptions } from '../core/FComponent' /** * @description A simple polyhedron model in Fibbo. diff --git a/packages/3d/src/polyhedrons/FSphere.ts b/packages/3d/src/polyhedrons/FSphere.ts index b04ec46a..9a48f93e 100644 --- a/packages/3d/src/polyhedrons/FSphere.ts +++ b/packages/3d/src/polyhedrons/FSphere.ts @@ -1,9 +1,9 @@ import * as THREE from 'three' -import type { FScene } from '../FScene' +import type { FScene } from '../core/FScene' import { FShapes } from '../types/FShapes' -import type { FComponentOptions } from '../FComponent' -import type { FRigidBodyOptions } from '../FRigidBody' -import type { FColliderOptions } from '../FCollider' +import type { FComponentOptions } from '../core/FComponent' +import type { FRigidBodyOptions } from '../core/FRigidBody' +import type { FColliderOptions } from '../core/FCollider' import { FPolyhedron } from './FPolyhedron' /** diff --git a/packages/core/src/FComponent.ts b/packages/core/src/FComponent.ts index 1dd69f70..b9c7e8d9 100644 --- a/packages/core/src/FComponent.ts +++ b/packages/core/src/FComponent.ts @@ -1,3 +1,5 @@ +import type { FController } from './FController' + /** * ID_COUNTER is used to generate unique identifiers for components. */ @@ -25,16 +27,27 @@ export abstract class FComponent { */ public __CALLBACKS_ON_COLLISION__: { [key: string]: (() => void)[] } = {} + /** + * The controller attached to the component. + */ + public controller?: FController + constructor() { this.__ID__ = ID_COUNTER++ } /** - * @description Update the component. - * Should be called every frame. + * @description Update the component. Should be called every frame. + * The purpose of `onFrame` on FComponent is really to render the component, its mesh/sprite and its properties. + * Any changes on its transform should be done on the controller, not here. * @param delta The time since the last frame. */ - abstract onFrame(delta: number): void + onFrame(delta: number): void { + // If a controller is attached, update it + if (this.controller) { + this.controller.onFrame(delta) + } + } /** * @description Add a callback to be called when a collision occurs. diff --git a/packages/core/src/FController.ts b/packages/core/src/FController.ts new file mode 100644 index 00000000..ec3d92fe --- /dev/null +++ b/packages/core/src/FController.ts @@ -0,0 +1,31 @@ +import type { FComponent } from './FComponent' + +export interface FControllerOptions { + component: FComponent +} + +/** + * @description The base class for all 2D and 3D controllers in Fibbo. + */ +export abstract class FController { + /** + * The component attached to the controller. + */ + public component: FComponent + + /** + * @param options The options for the controller. + * @param options.component The component that the controller is controlling. + */ + constructor(options: FControllerOptions) { + this.component = options.component + } + + /** + * @description Update the controller. Should be called every frame. + * The purpose of `onFrame` on FController is to update the component's transform in the desired way. + * Any rendering process should be done on the component, not here. + * @param delta The time since the last frame. + */ + abstract onFrame(delta: number): void +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 25e2fc8e..37ae5d36 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -4,5 +4,9 @@ // Core export { FCamera } from './FCamera' export { FComponent } from './FComponent' +export { FController } from './FController' export { FGroup } from './FGroup' export { FScene } from './FScene' + +// Types +export type { FControllerOptions } from './FController'