Skip to content

Commit

Permalink
feat: clean code with FCharacter3dKinematic
Browse files Browse the repository at this point in the history
  • Loading branch information
Gugustinette committed Aug 22, 2024
1 parent 21d1353 commit cb7d92d
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 137 deletions.
4 changes: 2 additions & 2 deletions apps/playground-3d/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { F3dShapes, FCapsule, FCharacter3d, FCube, FGameCamera, FScene3d, FSphere } from '@fibbojs/3d'
import { F3dShapes, FCapsule, FCharacter3dKinematic, FCube, FGameCamera, FScene3d, FSphere } from '@fibbojs/3d'
import { fDebug } from '@fibbojs/devtools'
import Duck from './classes/Duck'
import GltfCube from './classes/GltfCube'
Expand Down Expand Up @@ -43,7 +43,7 @@ import MyCustomCube from './classes/MyCustomCube'
scene.addComponent(ground2)

// Create a character
const character = new FCharacter3d(scene)
const character = new FCharacter3dKinematic(scene)
scene.addComponent(character)

// Attach a camera to the character
Expand Down
134 changes: 0 additions & 134 deletions packages/3d/src/FCharacter3d.ts

This file was deleted.

102 changes: 102 additions & 0 deletions packages/3d/src/character/FCharacter3d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import * as THREE from 'three'
import { FKeyboard } from '@fibbojs/event'
import type RAPIER from '@dimforge/rapier3d'
import type { FScene3d } from '../FScene3d'
import { F3dShapes } from '../types/F3dShapes'
import type { FComponent3dOptions, FComponent3dOptions__initCollider, FComponent3dOptions__initRigidBody } from '../FComponent3d'
import { FComponent3d } from '../FComponent3d'

/**
* @description A pre-defined character controller.
* @category Model
* @example
* ```ts
* import { FScene3d, FCharacter } from '@fibbojs/3d'
*
* const scene = new FScene3d()
*
* const capsule = new FCharacter(scene)
* scene.addComponent(capsule)
* ```
*/
export abstract class FCharacter3d extends FComponent3d {
/**
* The character controller that will be used to move the character.
*/
characterController: RAPIER.KinematicCharacterController
/**
* The inputs that will be used to move the character.
*/
inputs: {
forward: boolean
backward: boolean
left: boolean
right: boolean
}

constructor(scene: FScene3d, options?: FComponent3dOptions) {
super(scene, options)
// Create a capsule
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)

// The gap the controller will leave between the character and its environment
const offset = 0.01
// Create the character controller
this.characterController = scene.world.createCharacterController(offset)

// Map of the movements (will be updated by the keyboard)
this.inputs = {
forward: false,
backward: false,
left: false,
right: false,
}

// Key down
fKeyboard.onKeyDown('ArrowUp', () => {
this.inputs.forward = true
})
fKeyboard.onKeyDown('ArrowDown', () => {
this.inputs.backward = true
})
fKeyboard.onKeyDown('ArrowLeft', () => {
this.inputs.left = true
})
fKeyboard.onKeyDown('ArrowRight', () => {
this.inputs.right = true
})

// Key up
fKeyboard.onKeyUp('ArrowUp', () => {
this.inputs.forward = false
})
fKeyboard.onKeyUp('ArrowDown', () => {
this.inputs.backward = false
})
fKeyboard.onKeyUp('ArrowLeft', () => {
this.inputs.left = false
})
fKeyboard.onKeyUp('ArrowRight', () => {
this.inputs.right = false
})
}

initRigidBody(options?: FComponent3dOptions__initRigidBody): void {
super.initRigidBody({
...options,
shape: F3dShapes.CAPSULE,
})
}

initCollider(options?: FComponent3dOptions__initCollider): void {
super.initCollider({
...options,
shape: F3dShapes.CAPSULE,
})
}
}
71 changes: 71 additions & 0 deletions packages/3d/src/character/FCharacter3dKinematic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as THREE from 'three'
import RAPIER from '@dimforge/rapier3d'
import type { FScene3d } from '../FScene3d'
import type { FComponent3dOptions, FComponent3dOptions__initRigidBody } from '../FComponent3d'
import { FCharacter3d } from './FCharacter3d'

/**
* @description A pre-defined character controller.
* @category Model
* @example
* ```ts
* import { FScene3d, FCharacter } from '@fibbojs/3d'
*
* const scene = new FScene3d()
*
* const capsule = new FCharacter(scene)
* scene.addComponent(capsule)
* ```
*/
export class FCharacter3dKinematic extends FCharacter3d {
constructor(scene: FScene3d, options?: FComponent3dOptions) {
super(scene, options)

/**
* Handle movements on each frame (gravity + character movement)
* For some reason, using the onFrame method will result in weird behavior with gravity
* (e.g. the character crossing the ground)
*/
scene.onFrame((delta) => {
let worldDirection = new THREE.Vector3(0, 0, 0)
// Compute the movement direction
worldDirection.x = this.inputs.left ? 1 : this.inputs.right ? -1 : 0
worldDirection.z = this.inputs.forward ? 1 : this.inputs.backward ? -1 : 0
// Normalize the movement direction
worldDirection = worldDirection.normalize()
// Apply the camera direction to the movement direction
const cameraDirection = scene.camera.getCameraDirection()
worldDirection.applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.atan2(cameraDirection.x, cameraDirection.z))

// Create movement vector
const desiredMovement = {
x: worldDirection.x * delta * 8,
y: this.scene.world.gravity.y * delta,
z: worldDirection.z * delta * 8,
}
// Compute the desired movement
this.characterController.computeColliderMovement(
this.collider as RAPIER.Collider,
desiredMovement,
)
// Get the corrected movement
const correctedMovement = this.characterController.computedMovement()
// Apply the movement to the rigid body
this.rigidBody?.setLinvel({
x: correctedMovement.x / delta,
y: correctedMovement.y / delta,
z: correctedMovement.z / delta,
}, true)
})

// Initialize the rigid body
this.initRigidBody()
}

initRigidBody(options?: FComponent3dOptions__initRigidBody): void {
super.initRigidBody({
...options,
rigidBodyType: RAPIER.RigidBodyType.KinematicVelocityBased,
})
}
}
3 changes: 2 additions & 1 deletion packages/3d/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
// Core 3d Classes
export { FScene3d } from './FScene3d'
export { FComponent3d } from './FComponent3d'
export { FCharacter3d } from './FCharacter3d'
export { FCharacter3d } from './character/FCharacter3d'
export { FCharacter3dKinematic } from './character/FCharacter3dKinematic'

// Models
export { FCapsule } from './model/FCapsule'
Expand Down

0 comments on commit cb7d92d

Please sign in to comment.