Refactor code for consistency and readability

- Updated import statements to use consistent formatting across files.
- Adjusted method definitions and class constructors for uniform spacing and style.
- Simplified promise handling and error messages in state handlers.
- Enhanced state transition logic in various state handlers.
- Improved quirk animation handling in WaitStateHandler.
- Streamlined animation loading and caching mechanisms in AnimationLoader.
- Updated Vite configuration for aliasing.
This commit is contained in:
2025-05-24 01:14:35 +02:00
parent 658e1e64b2
commit 60aad20b5e
23 changed files with 4217 additions and 1281 deletions

View File

@ -3,7 +3,7 @@
* @module core
*/
import { States, Emotions, Config } from '../constants.js';
import { States, Emotions, Config } from '../constants.js'
/**
* Main controller for the Owen animation system
@ -18,97 +18,97 @@ export class OwenAnimationContext {
* @param {AnimationClipFactory} animationClipFactory - Factory for creating clips
* @param {StateFactory} stateFactory - Factory for creating state handlers
*/
constructor(model, mixer, animationClipFactory, stateFactory) {
constructor (model, mixer, animationClipFactory, stateFactory) {
/**
* The 3D character model
* @type {THREE.Object3D}
*/
this.model = model;
this.model = model
/**
* The Three.js animation mixer
* @type {THREE.AnimationMixer}
*/
this.mixer = mixer;
this.mixer = mixer
/**
* Factory for creating animation clips
* @type {AnimationClipFactory}
*/
this.animationClipFactory = animationClipFactory;
this.animationClipFactory = animationClipFactory
/**
* Factory for creating state handlers
* @type {StateFactory}
*/
this.stateFactory = stateFactory;
this.stateFactory = stateFactory
/**
* Map of animation clips by name
* @type {Map<string, AnimationClip>}
*/
this.clips = new Map();
this.clips = new Map()
/**
* Map of state handlers by name
* @type {Map<string, StateHandler>}
*/
this.states = new Map();
this.states = new Map()
/**
* Current active state
* @type {string}
*/
this.currentState = States.WAIT;
this.currentState = States.WAIT
/**
* Current active state handler
* @type {StateHandler|null}
*/
this.currentStateHandler = null;
this.currentStateHandler = null
/**
* Timer for inactivity detection
* @type {number}
*/
this.inactivityTimer = 0;
this.inactivityTimer = 0
/**
* Inactivity timeout in milliseconds
* @type {number}
*/
this.inactivityTimeout = Config.INACTIVITY_TIMEOUT;
this.inactivityTimeout = Config.INACTIVITY_TIMEOUT
/**
* Whether the system is initialized
* @type {boolean}
*/
this.initialized = false;
this.initialized = false
}
/**
* Initialize the animation system
* @returns {Promise<void>}
*/
async initialize() {
if (this.initialized) return;
async initialize () {
if (this.initialized) return
// Create animation clips from model
this.clips = await this.animationClipFactory.createClipsFromModel(this.model);
this.clips = await this.animationClipFactory.createClipsFromModel(this.model)
// Create actions for all clips
for (const [ , clip ] of this.clips) {
clip.createAction(this.mixer);
for (const [, clip] of this.clips) {
clip.createAction(this.mixer)
}
// Initialize state handlers
this.initializeStates();
this.initializeStates()
// Start in wait state
await this.transitionTo(States.WAIT);
await this.transitionTo(States.WAIT)
this.initialized = true;
console.log('Owen Animation System initialized');
this.initialized = true
console.log('Owen Animation System initialized')
}
/**
@ -116,12 +116,12 @@ export class OwenAnimationContext {
* @private
* @returns {void}
*/
initializeStates() {
const stateNames = this.stateFactory.getAvailableStates();
initializeStates () {
const stateNames = this.stateFactory.getAvailableStates()
for (const stateName of stateNames) {
const handler = this.stateFactory.createStateHandler(stateName, this);
this.states.set(stateName, handler);
const handler = this.stateFactory.createStateHandler(stateName, this)
this.states.set(stateName, handler)
}
}
@ -132,28 +132,28 @@ export class OwenAnimationContext {
* @returns {Promise<void>}
* @throws {Error} If state is not found or transition is invalid
*/
async transitionTo(newStateName, emotion = Emotions.NEUTRAL) {
async transitionTo (newStateName, emotion = Emotions.NEUTRAL) {
if (!this.states.has(newStateName)) {
throw new Error(`State '${newStateName}' not found`);
throw new Error(`State '${newStateName}' not found`)
}
const oldState = this.currentState;
const newStateHandler = this.states.get(newStateName);
const oldState = this.currentState
const newStateHandler = this.states.get(newStateName)
console.log(`Transitioning from ${oldState} to ${newStateName}`);
console.log(`Transitioning from ${oldState} to ${newStateName}`)
// Exit current state
if (this.currentStateHandler) {
await this.currentStateHandler.exit(newStateName, emotion);
await this.currentStateHandler.exit(newStateName, emotion)
}
// Enter new state
this.currentState = newStateName;
this.currentStateHandler = newStateHandler;
await this.currentStateHandler.enter(oldState, emotion);
this.currentState = newStateName
this.currentStateHandler = newStateHandler
await this.currentStateHandler.enter(oldState, emotion)
// Reset inactivity timer
this.resetActivityTimer();
this.resetActivityTimer()
}
/**
@ -161,26 +161,26 @@ export class OwenAnimationContext {
* @param {string} message - The user message
* @returns {Promise<void>}
*/
async handleUserMessage(message) {
console.log(`Handling user message: "${message}"`);
async handleUserMessage (message) {
console.log(`Handling user message: "${message}"`)
this.onUserActivity();
this.onUserActivity()
// If sleeping, wake up first
if (this.currentState === States.SLEEP) {
await this.transitionTo(States.REACT);
await this.transitionTo(States.REACT)
}
// Let current state handle the message
if (this.currentStateHandler) {
await this.currentStateHandler.handleMessage(message);
await this.currentStateHandler.handleMessage(message)
}
// Transition to appropriate next state based on current state
if (this.currentState === States.WAIT) {
await this.transitionTo(States.REACT);
await this.transitionTo(States.REACT)
} else if (this.currentState === States.REACT) {
await this.transitionTo(States.TYPE);
await this.transitionTo(States.TYPE)
}
}
@ -188,12 +188,12 @@ export class OwenAnimationContext {
* Called when user activity is detected
* @returns {void}
*/
onUserActivity() {
this.resetActivityTimer();
onUserActivity () {
this.resetActivityTimer()
// Wake up if sleeping
if (this.currentState === States.SLEEP) {
this.transitionTo(States.WAIT);
this.transitionTo(States.WAIT)
}
}
@ -202,8 +202,8 @@ export class OwenAnimationContext {
* @private
* @returns {void}
*/
resetActivityTimer() {
this.inactivityTimer = 0;
resetActivityTimer () {
this.inactivityTimer = 0
}
/**
@ -211,9 +211,9 @@ export class OwenAnimationContext {
* @private
* @returns {Promise<void>}
*/
async handleInactivity() {
console.log('Inactivity detected, transitioning to sleep');
await this.transitionTo(States.SLEEP);
async handleInactivity () {
console.log('Inactivity detected, transitioning to sleep')
await this.transitionTo(States.SLEEP)
}
/**
@ -221,21 +221,21 @@ export class OwenAnimationContext {
* @param {number} deltaTime - Time elapsed since last update (ms)
* @returns {void}
*/
update(deltaTime) {
if (!this.initialized) return;
update (deltaTime) {
if (!this.initialized) return
// Update Three.js mixer
this.mixer.update(deltaTime / 1000); // Convert to seconds
this.mixer.update(deltaTime / 1000) // Convert to seconds
// Update current state
if (this.currentStateHandler) {
this.currentStateHandler.update(deltaTime);
this.currentStateHandler.update(deltaTime)
}
// Update inactivity timer
this.inactivityTimer += deltaTime;
this.inactivityTimer += deltaTime
if (this.inactivityTimer > this.inactivityTimeout && this.currentState !== States.SLEEP) {
this.handleInactivity();
this.handleInactivity()
}
}
@ -244,8 +244,8 @@ export class OwenAnimationContext {
* @param {string} name - The animation clip name
* @returns {AnimationClip|undefined} The animation clip or undefined if not found
*/
getClip(name) {
return this.clips.get(name);
getClip (name) {
return this.clips.get(name)
}
/**
@ -253,80 +253,80 @@ export class OwenAnimationContext {
* @param {string} pattern - Pattern to match (supports * wildcards)
* @returns {AnimationClip[]} Array of matching clips
*/
getClipsByPattern(pattern) {
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
const matches = [];
getClipsByPattern (pattern) {
const regex = new RegExp(pattern.replace(/\*/g, '.*'))
const matches = []
for (const [ name, clip ] of this.clips) {
for (const [name, clip] of this.clips) {
if (regex.test(name)) {
matches.push(clip);
matches.push(clip)
}
}
return matches;
return matches
}
/**
* Get the current state name
* @returns {string} The current state name
*/
getCurrentState() {
return this.currentState;
getCurrentState () {
return this.currentState
}
/**
* Get the current state handler
* @returns {StateHandler|null} The current state handler
*/
getCurrentStateHandler() {
return this.currentStateHandler;
getCurrentStateHandler () {
return this.currentStateHandler
}
/**
* Get available transitions from current state
* @returns {string[]} Array of available state transitions
*/
getAvailableTransitions() {
getAvailableTransitions () {
if (this.currentStateHandler) {
return this.currentStateHandler.getAvailableTransitions();
return this.currentStateHandler.getAvailableTransitions()
}
return [];
return []
}
/**
* Get all available animation clip names
* @returns {string[]} Array of clip names
*/
getAvailableClips() {
return Array.from(this.clips.keys());
getAvailableClips () {
return Array.from(this.clips.keys())
}
/**
* Get all available state names
* @returns {string[]} Array of state names
*/
getAvailableStates() {
return Array.from(this.states.keys());
getAvailableStates () {
return Array.from(this.states.keys())
}
/**
* Dispose of the animation system and clean up resources
* @returns {void}
*/
dispose() {
dispose () {
// Stop all animations
for (const [ , clip ] of this.clips) {
for (const [, clip] of this.clips) {
if (clip.action) {
clip.action.stop();
clip.action.stop()
}
}
// Clear caches
this.clips.clear();
this.states.clear();
this.animationClipFactory.clearCache();
this.clips.clear()
this.states.clear()
this.animationClipFactory.clearCache()
this.initialized = false;
console.log('Owen Animation System disposed');
this.initialized = false
console.log('Owen Animation System disposed')
}
}