bot propelMove
|
Before Width: | Height: | Size: 2.6 MiB |
@@ -1,11 +0,0 @@
|
||||
Model Information:
|
||||
* title: Mech Drone
|
||||
* source: https://sketchfab.com/3d-models/mech-drone-8d06874aac5246c59edb4adbe3606e0e
|
||||
* author: Willy Decarpentrie (https://sketchfab.com/skudgee)
|
||||
|
||||
Model License:
|
||||
* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
* requirements: Author must be credited. Commercial use is allowed.
|
||||
|
||||
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
|
||||
This work is based on "Mech Drone" (https://sketchfab.com/3d-models/mech-drone-8d06874aac5246c59edb4adbe3606e0e) by Willy Decarpentrie (https://sketchfab.com/skudgee) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
|
||||
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 275 KiB |
|
Before Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 6.9 MiB |
@@ -41,6 +41,14 @@ body[eicapp] {
|
||||
box-sizing: border-box;
|
||||
background: repeating-linear-gradient( -45deg, #000, #333 10px, #000 10px, #333 20px );
|
||||
}
|
||||
.helperBotCanvas{
|
||||
display: block;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
[eicapp] [eicapptoolbar] {
|
||||
display: flex;
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
"path": "/Windoz",
|
||||
"classes": [ "WindozController", "WindozDomContent", "WindozDialogContent", "WindozMetaData", "WindozModel", "WindozPluralModel", "WindozBusModel" ],
|
||||
"dependencies" : { "WindozPluralModel": [ "WindozModel" ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/HelperBot",
|
||||
"classes": [ "HelperBot.module" ],
|
||||
"dependencies" : { }
|
||||
}
|
||||
],
|
||||
"masterController": "WindozAppController",
|
||||
"defaultMasterTemplate": "templates/EICAppTemplate"
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
import * as THREE from 'three'
|
||||
import * as TWEEN from 'three/examples/jsm/libs/tween.module.js'
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
|
||||
class HelperBot{
|
||||
|
||||
constructor(canvasSelector){
|
||||
this.renderer = null
|
||||
this.canvasEl = document.querySelector(canvasSelector)
|
||||
this.initScene()
|
||||
window.bot=this
|
||||
}
|
||||
|
||||
initScene(){
|
||||
|
||||
this.canvasEl .width = window.innerWidth
|
||||
this.canvasEl .height = window.innerHeight
|
||||
|
||||
this.scene = new THREE.Scene()
|
||||
|
||||
this.camera = new THREE.PerspectiveCamera(30, this.canvasEl.clientWidth / this.canvasEl.clientHeight, 0.1, 1000)
|
||||
this.camera.position.set(0, 1, 10)
|
||||
this.camera.lookAt(0, 0, 0)
|
||||
|
||||
// Lights
|
||||
const dLight1 = new THREE.DirectionalLight(0xffffff, 1.5)
|
||||
dLight1.position.set(5, 5, 5)
|
||||
this.scene.add(dLight1)
|
||||
const dLight2 = new THREE.DirectionalLight(0xffffff, 1.5)
|
||||
dLight2.position.set(-5, -5, 5)
|
||||
this.scene.add(dLight2)
|
||||
this.scene.add(new THREE.AmbientLight(0xffffff, 1))
|
||||
|
||||
|
||||
|
||||
|
||||
this.renderer = new THREE.WebGLRenderer({
|
||||
canvas: this.canvasEl ,
|
||||
alpha: true
|
||||
})
|
||||
|
||||
this.renderer.setSize(this.canvasEl .width, this.canvasEl .height)
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio)
|
||||
this.renderer.setClearColor(0x000000, 0)
|
||||
|
||||
|
||||
this.threeClock = new THREE.Clock()
|
||||
const loader = new GLTFLoader().setPath('/app/assets/3dModels/')
|
||||
loader.load('mecha2.glb', async gltf => {
|
||||
this.mecha = new THREE.Group()
|
||||
this.scene.add(this.mecha)
|
||||
|
||||
this.mechaModel = gltf.scene
|
||||
this.mecha.add(this.mechaModel)
|
||||
|
||||
this.mechaModel.scale.set(5, 5, 5)
|
||||
this.mechaModel.rotation.set(0, 0, 0)
|
||||
this.mechaModel.position.set(0, -1.5, 0)
|
||||
this.mechaModel.updateMatrix()
|
||||
this.mechaModel.rotateY(-Math.PI) // 180deg so facing user
|
||||
|
||||
// GPU compilation (optimization)
|
||||
await this.renderer.compileAsync(this.mechaModel, this.camera, this.scene)
|
||||
|
||||
this.mechaModel.traverse(obj => {
|
||||
if (obj.isMesh && obj.material && obj.material.color) {
|
||||
const c = obj.material.color.clone()
|
||||
const boost = 0.1
|
||||
obj.material.emissive = c
|
||||
obj.material.emissiveIntensity = boost
|
||||
}
|
||||
})
|
||||
|
||||
if (gltf.animations && gltf.animations.length > 0) {
|
||||
this.mixer = new THREE.AnimationMixer(this.mechaModel)
|
||||
const action = this.mixer.clipAction(gltf.animations[0])
|
||||
action.play()
|
||||
}
|
||||
|
||||
|
||||
this.leftArm = this.mechaModel.getObjectByName('ArmL1_01')
|
||||
this.animate = true
|
||||
})
|
||||
|
||||
|
||||
this.resizeWindow()
|
||||
window.addEventListener('resize', this.resizeWindow.bind(this))
|
||||
this.render()
|
||||
|
||||
}
|
||||
|
||||
resizeWindow() {
|
||||
const w = window.innerWidth
|
||||
const h = window.innerHeight
|
||||
|
||||
this.canvasEl .width = w
|
||||
this.canvasEl .height = h
|
||||
|
||||
this.renderer.setSize(w, h)
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio)
|
||||
|
||||
this.camera.aspect = w / h
|
||||
this.camera.updateProjectionMatrix()
|
||||
}
|
||||
|
||||
startRendering(){
|
||||
this.addControls()
|
||||
this.render()
|
||||
}
|
||||
|
||||
render() {
|
||||
TWEEN.update()
|
||||
const resized = this.resizeRendererToDisplaySize()
|
||||
|
||||
const delta = this.threeClock.getDelta()
|
||||
if(this.mixer && this.animate) this.mixer.update(delta)
|
||||
|
||||
this.renderer.render(this.scene, this.camera)
|
||||
requestAnimationFrame(this.render.bind(this))
|
||||
}
|
||||
|
||||
resizeRendererToDisplaySize() {
|
||||
const width = this.canvasEl.clientWidth
|
||||
const height = this.canvasEl.clientHeight
|
||||
if (this.canvasEl.width !== width || this.canvasEl.height !== height) {
|
||||
this.renderer.setSize(width, height, false)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
translateBot(position, delay=500, endcb, updatecb){
|
||||
if(this.movingBotTween) this.movingBotTween.end()
|
||||
this.movingBotTween = new TWEEN.Tween(this.mecha.position)
|
||||
.to({ x: Number(position.x),
|
||||
y: Number(position.z),
|
||||
z: Number(position.y),
|
||||
}, delay)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut)
|
||||
if(typeof(endcb)=='function') this.movingBotTween.onComplete(endcb)
|
||||
if(typeof(updatecb)=='function') this.movingBotTween.onUpdate(updatecb)
|
||||
this.movingBotTween.start()
|
||||
}
|
||||
|
||||
rotateBot(rotation, delay=500, endcb, updatecb){
|
||||
//TODO : respect existing Z
|
||||
|
||||
if(this.rotatingBotTween) this.rotatingBotTween.end()
|
||||
this.rotatingBotTween = new TWEEN.Tween(this.mecha.rotation)
|
||||
.to({ x: Number(rotation.x*Math.PI/180),
|
||||
y: Number(rotation.z*Math.PI/180),
|
||||
z: Number(rotation.y*Math.PI/180),
|
||||
}, delay)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut)
|
||||
if(typeof(endcb)=='function') this.rotatingBotTween.onComplete(endcb)
|
||||
if(typeof(updatecb)=='function') this.rotatingBotTween.onUpdate(updatecb)
|
||||
this.rotatingBotTween.start()
|
||||
}
|
||||
|
||||
propelMove(position){
|
||||
//TODO : respect existing Z rotation
|
||||
|
||||
const moveDelay = 1000
|
||||
const dx = this.mecha.position.x - position.x
|
||||
const dy = this.mecha.position.z - position.y
|
||||
const dz = this.mecha.position.y - position.z
|
||||
const delay = Math.max(Math.abs(dx), Math.abs(dy), Math.abs(dz)) * moveDelay
|
||||
const ax = (dy>0.5) ? -10 : ((dy<-0.5) ? 10 : 0 )
|
||||
const ay = (dx>0.5) ? 10 : ((dx<-0.5) ? -10 : 0 )
|
||||
|
||||
console.log( this.mecha.position.x, this.mecha.position.y)
|
||||
console.log(dx,dy,ax,ay)
|
||||
|
||||
const rotationDelay = Math.min(delay/4, 500)
|
||||
this.rotateBot({x: ax, y: ay, z: 0}, rotationDelay)
|
||||
|
||||
let chkpt1 = true, chkpt2 = true, chkpt3 = true
|
||||
const startTime = Date.now()
|
||||
this.translateBot(position, delay, null, () => {
|
||||
const t = (Date.now()-startTime)/delay
|
||||
if(chkpt1 && (t >= 0.2)){ //Time to stop accelerating
|
||||
this.rotateBot({x: 0, y: 0, z: 0}, rotationDelay)
|
||||
chkpt1 = false
|
||||
}
|
||||
if(chkpt2 && (t >= 0.7)){ //Time to brake
|
||||
this.rotateBot({x: -ax, y: -ay, z: 0}, rotationDelay)
|
||||
chkpt2 = false
|
||||
}
|
||||
if(chkpt3 && (t >= 0.9)){ //Time to restore
|
||||
this.rotateBot({x: 0, y: 0, z: 0}, rotationDelay)
|
||||
chkpt3 = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
app.registerClass('HelperBot', HelperBot)
|
||||
@@ -89,7 +89,9 @@ export class Threetobus{
|
||||
if(mapping.child) id += '_'+mapping.child
|
||||
if(id){
|
||||
const obj3D = this.scene.getObjectByName(id)
|
||||
this.assignFromConfig(payload, mapping, obj3D)
|
||||
if(obj3D){
|
||||
this.assignFromConfig(payload, mapping, obj3D)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ API remove
|
||||
API listAgentTypes
|
||||
if unsavec changes in scene => confirm before reloading
|
||||
|
||||
agent rotation (param + tween)
|
||||
|
||||
Bugs
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as THREE from 'three'
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
|
||||
import * as TWEEN from 'three/examples/jsm/libs/tween.module.js'
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
||||
|
||||
export class kfArena{
|
||||
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
<menu eicmenu class="app-menu">
|
||||
</menu>
|
||||
<div class="app-workspace"></div>
|
||||
<div class="app-content-thesaurus"></div>
|
||||
<div class="app-content-thesaurus"></div>
|
||||
<canvas class="helperBotCanvas"></canvas>
|
||||
@@ -18,6 +18,8 @@ class EICAppTemplate extends WindozDomContent {
|
||||
|
||||
// todo : replace with something more dynamic
|
||||
this.loadAppMenu('global/app-menu-map.json');
|
||||
|
||||
new app.LoadedClasses.HelperBot('.helperBotCanvas')
|
||||
}
|
||||
|
||||
onGlobalResize() { WindozController.resize(); }
|
||||
@@ -117,6 +119,7 @@ class EICAppTemplate extends WindozDomContent {
|
||||
onBusConnected() { this.userIcon.online = true; }
|
||||
|
||||
onBusClosed() { this.userIcon.online = false; }
|
||||
|
||||
}
|
||||
|
||||
app.registerClass('EICAppTemplate', EICAppTemplate);
|
||||