fixed move & rotate tweens + mapping to child OK
|
After Width: | Height: | Size: 626 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 716 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 129 KiB |
@@ -6,7 +6,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"type": "Mesh",
|
"type": "Mesh",
|
||||||
"idSuffix": "head",
|
"childSuffix": "head",
|
||||||
"geometry": { "type": "SphereGeometry", "args": [0.3, 16, 16] },
|
"geometry": { "type": "SphereGeometry", "args": [0.3, 16, 16] },
|
||||||
"material": { "type": "MeshStandardMaterial", "color": "blue" },
|
"material": { "type": "MeshStandardMaterial", "color": "blue" },
|
||||||
"position": [0, 0.5, 0]
|
"position": [0, 0.5, 0]
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"arenaSize": {
|
||||||
|
"x": 100,
|
||||||
|
"y": 100,
|
||||||
|
"z": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"chan": "gps:agents",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"eventName": "move",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"id": "aid",
|
||||||
|
"assign": {
|
||||||
|
"position.x": "coords.x",
|
||||||
|
"position.z": "coords.y",
|
||||||
|
"position.y": "coords.z"
|
||||||
|
},
|
||||||
|
"tween": true,
|
||||||
|
"tweenDelay": 1000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chan": "agent:*",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"eventName": "age",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"id": "aid",
|
||||||
|
"assign": {
|
||||||
|
"fill": {
|
||||||
|
"arguments": ["age"],
|
||||||
|
"transformer": "rgb(${Math.round(255 * age / 10)},0,${Math.round(255 * (1 - age / 10))})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventName": "rotate",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"id": "aid",
|
||||||
|
"assign": {
|
||||||
|
"rotation.x": "facing.x",
|
||||||
|
"rotation.y": "facing.y",
|
||||||
|
"rotation.z": "facing.z"
|
||||||
|
},
|
||||||
|
"tween": true,
|
||||||
|
"tweenDelay": 500
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"chan": "gps:agents",
|
"chan": "gps:agents",
|
||||||
"events": [
|
"events": [
|
||||||
{
|
{
|
||||||
"eventName": "moving",
|
"eventName": "move",
|
||||||
"mappings": [
|
"mappings": [
|
||||||
{
|
{
|
||||||
"id": "aid",
|
"id": "aid",
|
||||||
@@ -16,35 +16,46 @@
|
|||||||
"tweenDelay": 1000
|
"tweenDelay": 1000
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"eventName": "rotating",
|
"chan": "agents:*",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"eventName": "age",
|
||||||
"mappings": [
|
"mappings": [
|
||||||
{
|
{
|
||||||
"id": "aid",
|
"id": "aid",
|
||||||
"assign": {
|
"assign": {
|
||||||
"r": "rotangle"
|
"material.color": "color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"eventName": "rotate",
|
||||||
|
"mappings": [
|
||||||
|
{
|
||||||
|
"id": "aid",
|
||||||
|
"assign": {
|
||||||
|
"rotation.x": "facing.x",
|
||||||
|
"rotation.y": "facing.y",
|
||||||
|
"rotation.z": "facing.z"
|
||||||
},
|
},
|
||||||
"tween": true,
|
"tween": true,
|
||||||
"tweenDelay": 500
|
"tweenDelay": 500
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"chan": "agent:*",
|
"eventName": "polarize",
|
||||||
"events": [
|
|
||||||
{
|
|
||||||
"eventName": "aging",
|
|
||||||
"mappings": [
|
"mappings": [
|
||||||
{
|
{
|
||||||
"id": "aid",
|
"id": "aid",
|
||||||
|
"child": "head",
|
||||||
"assign": {
|
"assign": {
|
||||||
"fill": {
|
"material.color": "color"
|
||||||
"arguments": ["age"],
|
|
||||||
"transformer": "rgb(${Math.round(255 * age / 10)},0,${Math.round(255 * (1 - age / 10))})"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ body[eicapp] {
|
|||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window {
|
[eicapp] .app-workspace .window {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
padding: 3px;
|
padding: 5px;
|
||||||
background: var(--app-color-secondary);
|
background: var(--app-color-secondary);
|
||||||
box-shadow: 0 0 13px rgba(147, 255, 255, 0.55);
|
box-shadow: 0 0 13px rgba(147, 255, 255, 0.55);
|
||||||
right: auto;
|
right: auto;
|
||||||
@@ -107,6 +107,7 @@ body[eicapp] {
|
|||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window > header {
|
[eicapp] .app-workspace .window > header {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window > header h1 {
|
[eicapp] .app-workspace .window > header h1 {
|
||||||
padding: var(--eicui-base-spacing-xs);
|
padding: var(--eicui-base-spacing-xs);
|
||||||
@@ -127,13 +128,11 @@ body[eicapp] {
|
|||||||
[eicapp] .app-workspace .window > header .controls button.expand { display: inline-flex; }
|
[eicapp] .app-workspace .window > header .controls button.expand { display: inline-flex; }
|
||||||
[eicapp] .app-workspace .window > header .controls button.shrink { display: none; }
|
[eicapp] .app-workspace .window > header .controls button.shrink { display: none; }
|
||||||
[eicapp] .app-workspace .window > section {
|
[eicapp] .app-workspace .window > section {
|
||||||
padding: var(--eicui-base-spacing-2xs) var(--eicui-base-spacing-2xs);
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: all 0.5s;
|
transition: all 0.5s;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window[device="tablet"] > section {
|
[eicapp] .app-workspace .window[device="tablet"] > section {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -189,35 +188,35 @@ body[eicapp] {
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="n"] {
|
[eicapp] .app-workspace .window .handle[data-side="n"] {
|
||||||
top: -5px; left: 5px; right: 5px; height: 10px;
|
top: 0; left: 6px; right: 6px; height: 5px;
|
||||||
cursor: n-resize;
|
cursor: n-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="e"] {
|
[eicapp] .app-workspace .window .handle[data-side="e"] {
|
||||||
top: 5px; right: -5px; bottom: 5px; width: 10px;
|
top: 6px; right: 0; bottom: 6px; width: 5px;
|
||||||
cursor: e-resize;
|
cursor: e-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="w"] {
|
[eicapp] .app-workspace .window .handle[data-side="w"] {
|
||||||
top: 5px; left: -5px; bottom: 5px; width: 10px;
|
top: 6px; left: 0; bottom: 6px; width: 5px;
|
||||||
cursor: w-resize;
|
cursor: w-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="nw"] {
|
[eicapp] .app-workspace .window .handle[data-side="nw"] {
|
||||||
top: -5px; left: -5px; width: 10px; height: 10px;
|
top: 0px; left: 0px; width: 6px; height: 6px;
|
||||||
cursor: nw-resize;
|
cursor: nw-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="ne"] {
|
[eicapp] .app-workspace .window .handle[data-side="ne"] {
|
||||||
top: -5px; right: -5px; width: 10px; height: 10px;
|
top: 0; right: 0; width: 6px; height: 6px;
|
||||||
cursor: ne-resize;
|
cursor: ne-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="s"] {
|
[eicapp] .app-workspace .window .handle[data-side="s"] {
|
||||||
bottom: -5px; left: 5px; right: 5px; height: 10px;
|
bottom: 0; left: 6px; right: 6px; height: 5px;
|
||||||
cursor: s-resize;
|
cursor: s-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="sw"] {
|
[eicapp] .app-workspace .window .handle[data-side="sw"] {
|
||||||
bottom: -5px; left: -5px; width: 10px; height: 10px;
|
bottom: -0; left: 0; width: 6px; height: 6px;
|
||||||
cursor: sw-resize;
|
cursor: sw-resize;
|
||||||
}
|
}
|
||||||
[eicapp] .app-workspace .window .handle[data-side="se"] {
|
[eicapp] .app-workspace .window .handle[data-side="se"] {
|
||||||
bottom: -5px; right: -5px; width: 10px; height: 10px;
|
bottom: 0; right: 0; width: 6px; height: 6px;
|
||||||
cursor: se-resize;
|
cursor: se-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ class DashboardsController extends EICController {
|
|||||||
|
|
||||||
constructor(params) {
|
constructor(params) {
|
||||||
super(params)
|
super(params)
|
||||||
|
this.arenaConfig = app.Assets.Store.json.arenaConfig
|
||||||
this.agentDefs = app.Assets.Store.json.agentDefs
|
this.agentDefs = app.Assets.Store.json.agentDefs
|
||||||
this.eventsMapping = app.Assets.Store.json.eventsMapping
|
this.eventsMapping = app.Assets.Store.json.eventsMapping
|
||||||
}
|
}
|
||||||
@@ -16,6 +17,7 @@ class DashboardsController extends EICController {
|
|||||||
|
|
||||||
const ttb = new app.LoadedModules.Threetobus({
|
const ttb = new app.LoadedModules.Threetobus({
|
||||||
eventsMapping: this.eventsMapping,
|
eventsMapping: this.eventsMapping,
|
||||||
|
sceneSize: this.arenaConfig.arenaSize,
|
||||||
})
|
})
|
||||||
ttb.initScene({
|
ttb.initScene({
|
||||||
axes: true,
|
axes: true,
|
||||||
@@ -24,27 +26,6 @@ class DashboardsController extends EICController {
|
|||||||
|
|
||||||
const m1 = ttb.agentFromJSON('agent42', this.agentDefs.molecule1)
|
const m1 = ttb.agentFromJSON('agent42', this.agentDefs.molecule1)
|
||||||
ttb.scene.add(m1)
|
ttb.scene.add(m1)
|
||||||
// setTimeout(() => {
|
|
||||||
// ttb.smoothMove({
|
|
||||||
// object: m1,
|
|
||||||
// dX: 5,
|
|
||||||
// dY:0,
|
|
||||||
// dZ:0,
|
|
||||||
// delay: 1500,
|
|
||||||
// easing: 'Quadratic',
|
|
||||||
// easingMode: 'InOut',
|
|
||||||
// })
|
|
||||||
// },3000)
|
|
||||||
|
|
||||||
//TODO : side switches
|
|
||||||
// window.addEventListener('keydown', (e) => {
|
|
||||||
// if (e.key.toLowerCase() === 'g') {
|
|
||||||
// ttb.grid.visible = !grid.visible
|
|
||||||
// }
|
|
||||||
// if (e.key.toLowerCase() === 'a') {
|
|
||||||
// ttb.axes.visible = !axes.visible
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
//TODO: eventsMapping: address child by suffix in assignations
|
//TODO: eventsMapping: address child by suffix in assignations
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
{ "id":"sapceViewSetting", "name": "sapceViewSetting.html"}
|
{ "id":"sapceViewSetting", "name": "sapceViewSetting.html"}
|
||||||
],
|
],
|
||||||
"json": [
|
"json": [
|
||||||
|
{"id":"arenaConfig", "name": "arena/arenaConfig1.json"},
|
||||||
{"id":"agentDefs", "name": "agents/basic3D.json"},
|
{"id":"agentDefs", "name": "agents/basic3D.json"},
|
||||||
{"id":"eventsMapping", "name": "threetobus/eventsMapping.json"}
|
{"id":"eventsMapping", "name": "threetobus/eventsMapping.json"}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ class myUser extends app.LoadedClasses.User {
|
|||||||
} else if(!jsonresp.payload.authenticated){
|
} else if(!jsonresp.payload.authenticated){
|
||||||
document.querySelector('div.loginerr').classList.remove('show')
|
document.querySelector('div.loginerr').classList.remove('show')
|
||||||
document.getElementById('login-dialog').classList.add('show')
|
document.getElementById('login-dialog').classList.add('show')
|
||||||
|
document.querySelector('input[name="username"]').focus()
|
||||||
document.getElementById('login-dialog').addEventListener('keyup',(event)=>{
|
document.getElementById('login-dialog').addEventListener('keyup',(event)=>{
|
||||||
if(event.key=='Enter') this.launchLogin(callBack)
|
if(event.key=='Enter') this.launchLogin(callBack)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,11 +7,19 @@ export class Threetobus{
|
|||||||
constructor(options){
|
constructor(options){
|
||||||
this._curEventsMapping = []
|
this._curEventsMapping = []
|
||||||
this._stagedEventsMapping = options.eventsMapping
|
this._stagedEventsMapping = options.eventsMapping
|
||||||
|
this.sceneSize = options.sceneSize
|
||||||
this.commitConfig()
|
this.commitConfig()
|
||||||
|
|
||||||
this.cameras = {}
|
this.cameras = {}
|
||||||
this.renderers = []
|
this.renderers = []
|
||||||
this.tweensRegistry = {}
|
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 }
|
get EventsMapping() { return this._stagedEventsMapping }
|
||||||
@@ -22,7 +30,6 @@ export class Threetobus{
|
|||||||
const chansToAdd = []
|
const chansToAdd = []
|
||||||
const chansToKeep = []
|
const chansToKeep = []
|
||||||
for(const chanObj of this._stagedEventsMapping){
|
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)
|
if(this._curEventsMapping.map(item => item.chan).includes(chanObj.chan)) chansToKeep.push(chanObj)
|
||||||
else chansToAdd.push(chanObj)
|
else chansToAdd.push(chanObj)
|
||||||
}
|
}
|
||||||
@@ -70,12 +77,15 @@ export class Threetobus{
|
|||||||
|
|
||||||
|
|
||||||
processBusEvent(eventType, chan, payload, userId, x){
|
processBusEvent(eventType, chan, payload, userId, x){
|
||||||
const chanObj = this._curEventsMapping.find(item => item.chan==chan)
|
const chanObj = this._curEventsMapping.find(item => app.MessageBus.chanMatch(chan, item.chan))
|
||||||
if(!chanObj) return
|
if(!chanObj) { console.warn('Not a configured chan!'); return }
|
||||||
const eventObj = chanObj.events.find(item => item.eventName==eventType)
|
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){
|
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){
|
if(id){
|
||||||
const obj3D = this.scene.getObjectByName(id)
|
const obj3D = this.scene.getObjectByName(id)
|
||||||
this.assignFromConfig(payload, mapping, obj3D)
|
this.assignFromConfig(payload, mapping, obj3D)
|
||||||
@@ -84,7 +94,16 @@ export class Threetobus{
|
|||||||
}
|
}
|
||||||
|
|
||||||
assignFromConfig(payload, mapping, obj3D) {
|
assignFromConfig(payload, mapping, obj3D) {
|
||||||
const toTween = {}
|
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)) {
|
for (const [path, rule] of Object.entries(mapping.assign)) {
|
||||||
let value
|
let value
|
||||||
if(typeof rule === 'string') { // plain path
|
if(typeof rule === 'string') { // plain path
|
||||||
@@ -94,17 +113,26 @@ export class Threetobus{
|
|||||||
value = rule.transformer(...fnargs)
|
value = rule.transformer(...fnargs)
|
||||||
}
|
}
|
||||||
if(value !== undefined) {
|
if(value !== undefined) {
|
||||||
if(mapping.tween && path.startsWith('position.')){ //TODO allow other tweenables
|
if(mapping.tween){
|
||||||
toTween[path.substring(9)] = value
|
if(path.startsWith('position.')){
|
||||||
|
tweenProps.position.props[path.substring(9)] = value
|
||||||
|
} else if(path.startsWith('rotation.')){
|
||||||
|
tweenProps.rotation.props[path.substring(9)] = value
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.setProp(obj3D, path, value)
|
this.setProp(obj3D, path, value)
|
||||||
}
|
}
|
||||||
|
} // else console.warn('Could not get value from rule:',rule)
|
||||||
}
|
}
|
||||||
|
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)}
|
||||||
}
|
}
|
||||||
if(mapping.tween && (Object.keys(toTween).length>0)){
|
|
||||||
toTween.object = obj3D
|
|
||||||
toTween.delay = mapping.tweenDelay
|
|
||||||
this.smoothMove(toTween)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,12 +162,12 @@ export class Threetobus{
|
|||||||
this.scene = new THREE.Scene()
|
this.scene = new THREE.Scene()
|
||||||
|
|
||||||
if(options.grid){
|
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.grid.layers.set(1)
|
||||||
this.scene.add(this.grid)
|
this.scene.add(this.grid)
|
||||||
}
|
}
|
||||||
if(options.axes){
|
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.axes.layers.set(2)
|
||||||
this.scene.add(this.axes)
|
this.scene.add(this.axes)
|
||||||
}
|
}
|
||||||
@@ -206,12 +234,12 @@ export class Threetobus{
|
|||||||
// Recursively add children
|
// Recursively add children
|
||||||
if(desc.children) {
|
if(desc.children) {
|
||||||
desc.children.forEach(childDesc => {
|
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.add(this.agentFromJSON(childId, childDesc))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
obj.name = id
|
obj.name = id
|
||||||
this.tweensRegistry[id] = { 'move': null }
|
this.tweensRegistry[id] = { 'move': null, 'rotate': null }
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +277,41 @@ export class Threetobus{
|
|||||||
.onComplete(() => this.tweensRegistry[options.object.name]['move']=null)
|
.onComplete(() => this.tweensRegistry[options.object.name]['move']=null)
|
||||||
.start()
|
.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{
|
class RenderingEngine{
|
||||||
@@ -300,3 +363,6 @@ class RenderingEngine{
|
|||||||
// Make this module available to common JS
|
// Make this module available to common JS
|
||||||
if(!app.LoadedModules) app.LoadedModules = {}
|
if(!app.LoadedModules) app.LoadedModules = {}
|
||||||
app.LoadedModules.Threetobus = Threetobus
|
app.LoadedModules.Threetobus = Threetobus
|
||||||
|
|
||||||
|
|
||||||
|
//TODO resubscribe on connection loss & re-open
|
||||||
@@ -323,7 +323,7 @@ class MessageBus {
|
|||||||
* Helper method to match a chan with globbing
|
* Helper method to match a chan with globbing
|
||||||
*
|
*
|
||||||
* @param {string} myChan (no glob)
|
* @param {string} myChan (no glob)
|
||||||
* @param {string} targetChan (possible glob)
|
* @param {string} targetChan PATTERN (possible glob)
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
chanMatch(myChan, targetChan) {
|
chanMatch(myChan, targetChan) {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 15 KiB |