fixed move & rotate tweens + mapping to child OK

This commit is contained in:
STEINNI
2025-10-01 19:09:54 +00:00
parent 7a50311fcd
commit b5b76d51cc
20 changed files with 196 additions and 74 deletions
+89 -23
View File
@@ -7,11 +7,19 @@ export class Threetobus{
constructor(options){
this._curEventsMapping = []
this._stagedEventsMapping = options.eventsMapping
this.sceneSize = options.sceneSize
this.commitConfig()
this.cameras = {}
this.renderers = []
this.tweensRegistry = {}
app.events.addEvent('MessageBus.Connected', this.busReconnect.bind(this), 'threetobus')
}
busReconnect(){
this.commitConfig() // To resubscribe...
//TODO : Not ideal because if we're in the middle of non-commited changes...
}
get EventsMapping() { return this._stagedEventsMapping }
@@ -22,7 +30,6 @@ export class Threetobus{
const chansToAdd = []
const chansToKeep = []
for(const chanObj of this._stagedEventsMapping){
console.log('staged chan:',chanObj.chan,' current ones:', this._curEventsMapping.map(item => item.chan))
if(this._curEventsMapping.map(item => item.chan).includes(chanObj.chan)) chansToKeep.push(chanObj)
else chansToAdd.push(chanObj)
}
@@ -70,12 +77,15 @@ export class Threetobus{
processBusEvent(eventType, chan, payload, userId, x){
const chanObj = this._curEventsMapping.find(item => item.chan==chan)
if(!chanObj) return
const chanObj = this._curEventsMapping.find(item => app.MessageBus.chanMatch(chan, item.chan))
if(!chanObj) { console.warn('Not a configured chan!'); return }
const eventObj = chanObj.events.find(item => item.eventName==eventType)
if(!eventObj) return
if(!eventObj) { console.warn('Not a configured event!'); return }
for(const mapping of eventObj.mappings){
const id = this.getValueByPath(payload, mapping.id)
let id = this.getValueByPath(payload, mapping.id)
//TODO Child selection is static in mapping... does it make sense to also have the event select the child ?
// if yes : how to discriminate static value from event-mapping definition ?
if(mapping.child) id += '_'+mapping.child
if(id){
const obj3D = this.scene.getObjectByName(id)
this.assignFromConfig(payload, mapping, obj3D)
@@ -83,28 +93,46 @@ export class Threetobus{
}
}
assignFromConfig(payload, mapping, obj3D) {
const toTween = {}
assignFromConfig(payload, mapping, obj3D) {
const tweenProps = {
position: {
props: {},
method: this.smoothMove.bind(this),
},
rotation:{
props: {},
method: this.smoothRotate.bind(this),
},
}
for (const [path, rule] of Object.entries(mapping.assign)) {
let value
if (typeof rule === 'string') { // plain path
if(typeof rule === 'string') { // plain path
value= this.getValueByPath(payload, rule)
} else if((typeof(rule) == 'object') && (typeof(rule.transformer) == 'function')) { // transformer
const fnargs = (rule.arguments || []).map(arg => this.getValueByPath(payload,arg))
value = rule.transformer(...fnargs)
}
if (value !== undefined) {
if(mapping.tween && path.startsWith('position.')){ //TODO allow other tweenables
toTween[path.substring(9)] = value
} else {
if(value !== undefined) {
if(mapping.tween){
if(path.startsWith('position.')){
tweenProps.position.props[path.substring(9)] = value
} else if(path.startsWith('rotation.')){
tweenProps.rotation.props[path.substring(9)] = value
}
} else {
this.setProp(obj3D, path, value)
}
}
} // else console.warn('Could not get value from rule:',rule)
}
if(mapping.tween && (Object.keys(toTween).length>0)){
toTween.object = obj3D
toTween.delay = mapping.tweenDelay
this.smoothMove(toTween)
if(mapping.tween){
for(const tweenGroup in tweenProps){
if((Object.keys(tweenProps[tweenGroup].props).length>0)
&& (typeof(tweenProps[tweenGroup].method)=='function')){
tweenProps[tweenGroup].props.object = obj3D
tweenProps[tweenGroup].props.delay = mapping.tweenDelay
tweenProps[tweenGroup].method(tweenProps[tweenGroup].props)
} // else { console.log('avoided tween', tweenGroup)}
}
}
}
@@ -134,12 +162,12 @@ export class Threetobus{
this.scene = new THREE.Scene()
if(options.grid){
this.grid = new THREE.GridHelper(20, 20, 0x8888AA, 0x8888AA)
this.grid = new THREE.GridHelper(this.sceneSize.x, this.sceneSize.y, 0x8888AA, 0x8888AA)
this.grid.layers.set(1)
this.scene.add(this.grid)
}
if(options.axes){
this.axes = new THREE.AxesHelper(5, 5)
this.axes = new THREE.AxesHelper(this.sceneSize.x/2, this.sceneSize.y/2)
this.axes.layers.set(2)
this.scene.add(this.axes)
}
@@ -206,12 +234,12 @@ export class Threetobus{
// Recursively add children
if(desc.children) {
desc.children.forEach(childDesc => {
const childId = (childDesc.idSuffix) ? `${id}_${childDesc.idSuffix}` : ''
const childId = (childDesc.childSuffix) ? `${id}_${childDesc.childSuffix}` : ''
obj.add(this.agentFromJSON(childId, childDesc))
})
}
obj.name = id
this.tweensRegistry[id] = { 'move': null }
this.tweensRegistry[id] = { 'move': null, 'rotate': null }
return obj
}
@@ -248,7 +276,42 @@ export class Threetobus{
.easing(TWEEN.Easing[options.easing][options.easingMode])
.onComplete(() => this.tweensRegistry[options.object.name]['move']=null)
.start()
}
}
smoothRotate(options){
// options: object, dX, dY, dZ, delay, easing, easingMode
// Absolute: x,y,z angle, in degrees
// Relative: dx,dy,dz angle in deg
// delay: ms
// easings: Linear, Quadratic, Cubic, Quartic, Quintic, Sinusoidal, Exponential, Circular, Elastic, Back, Bounce
// easingMode: In → starts slow, accelerates towards the end.
// Out → starts fast, decelerates smoothly.
// InOut → slow at both ends, faster in the middle.
options.easing = options.easing ? options.easing : 'Quadratic'
options.easingMode = options.easingMode ? options.easingMode : 'InOut'
let newX = parseFloat(options.x)
newX = isNaN(newX) ? options.object.rotation.x * Math.PI / 180: newX * Math.PI / 180
newX += (parseFloat(options.dx) || 0)
let newY = parseFloat(options.y)
newY = isNaN(newY) ? options.object.rotation.y * Math.PI / 180: newY * Math.PI / 180
newY += (parseFloat(options.dy) || 0)
let newZ = parseFloat(options.z)
newZ = isNaN(newZ) ? options.object.rotation.z* Math.PI / 180 : newZ * Math.PI / 180
newZ += (parseFloat(options.dz) || 0)
if(this.tweensRegistry[options.object.name]['rotate']) this.tweensRegistry[options.object.name]['rotate'].end()
this.tweensRegistry[options.object.name]['rotate'] = new TWEEN.Tween(options.object.rotation)
.to({ x: newX,
y: newY,
z: newZ,
}, options.delay)
.easing(TWEEN.Easing[options.easing][options.easingMode])
.onComplete(() => this.tweensRegistry[options.object.name]['rotate']=null)
.start()
}
}
class RenderingEngine{
@@ -299,4 +362,7 @@ class RenderingEngine{
// Make this module available to common JS
if(!app.LoadedModules) app.LoadedModules = {}
app.LoadedModules.Threetobus = Threetobus
app.LoadedModules.Threetobus = Threetobus
//TODO resubscribe on connection loss & re-open