diff --git a/app/assets/styles/app.css b/app/assets/styles/app.css
index 1ed8d11..18537f2 100755
--- a/app/assets/styles/app.css
+++ b/app/assets/styles/app.css
@@ -103,8 +103,6 @@ menu[eicmenu] [menuitem] > a > button, menu[eicmenu] [menuitem] > .nolink button
overflow: hidden;
z-index: 2;
grid-template-rows: min-content 1fr;
- max-height: 90vh;
- max-width: 90vw;
display: flex;
flex-direction: column;
border-radius: .3rem;
diff --git a/app/helpers/activeAttributes.js b/app/helpers/activeAttributes.js
index ad5cbc3..4c35b7f 100644
--- a/app/helpers/activeAttributes.js
+++ b/app/helpers/activeAttributes.js
@@ -39,7 +39,7 @@ app.helpers.activeAttributes = {
* setupRefs is re-entrant: it can be called again after refreshing part of the view
* @param {eicui-components []} components : the view's components (usually result of ui.eicfy(this.el) )
*/
- setupRefs(components){
+ setupRefs(components = []){
if(!this.components) this.components = {}
for(let component of components.filter(component => component.el.hasAttribute('data-ref'))) {
this.components[component.el.dataset.ref] = component
@@ -61,6 +61,7 @@ app.helpers.activeAttributes = {
}
},
+
/**
* output (singular) : this.output('mydiv', '
Some markup
') places markup in a data-output node
* @param {*} name
diff --git a/app/helpers/helpers3D.module.js b/app/helpers/helpers3D.module.js
index 1d2b7a6..5414ace 100644
--- a/app/helpers/helpers3D.module.js
+++ b/app/helpers/helpers3D.module.js
@@ -110,4 +110,10 @@ app.helpers.helpers3D = {
return pivot
},
+ getNamedParent(obj) {
+ while (obj && !obj.name) {
+ obj = obj.parent
+ }
+ return obj
+ },
}
\ No newline at end of file
diff --git a/app/views/editors/KeyframeView.html b/app/views/editors/KeyframeView.html
index 74a193a..0eab4c1 100644
--- a/app/views/editors/KeyframeView.html
+++ b/app/views/editors/KeyframeView.html
@@ -57,7 +57,16 @@
.kf-editor button[data-trigger="onResetKF"] { background-color: #A00; }
.kf-editor section[data-output="agentProperties"] label{ font-size: 0.9em; }
.kf-editor section[data-output="agentProperties"] div.cols-2 { grid-template-columns: 4fr 3fr; }
-
+ .kf-editor div[data-output="agentId"] {
+ border: 1px solid #574;
+ border-radius: 5px;
+ background-color: #231;
+ box-shadow: 0px 0px 7px #0B69;
+ height: 2em;
+ padding: .2em 5px .2em 5px;
+ margin-top: 1em;
+ font-size: .8em;
+ }
diff --git a/app/views/editors/KeyframeView.js b/app/views/editors/KeyframeView.js
index 9ee24cb..9bb9bfe 100644
--- a/app/views/editors/KeyframeView.js
+++ b/app/views/editors/KeyframeView.js
@@ -42,6 +42,7 @@ class KeyframeView extends WindozDomContent {
this.agentPreview.animation = true
this.kfArena = new app.LoadedModules.kfArena(this.outputs.kfArenaCanvas, this.agentSprites)
+ this.kfArena.onclickAgent = this.onclickAgent.bind(this)
this.kfArena.startRendering()
this.outputs.btnAddAgent.disabled = true
@@ -53,20 +54,37 @@ class KeyframeView extends WindozDomContent {
if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value)
if(!this.outputs.agentsSelector.value) return
const agent = await this.models.agents.getProperties(this.outputs.agentsSelector.value)
- this.fillAgentProperties(agent.atp_props)
+ this.fillAgentProperties('', agent.atp_props)
+ }
+
+ onclickAgent(aid){
+ console.log('Agent clicked:', aid)
+ this.updateKfButtons()
}
onAddAgent(event){
+ //TODO prevent collisions !
+
const aid = crypto.randomUUIDv7()
+ this.output('agentId', `ID: ${aid}`)
this.kfArena.addAgent(this.outputs.agentsSelector.value, aid, {
- x: document.querySelector('[name="position.x"]').value,
- y: document.querySelector('[name="position.y"]').value,
- z: document.querySelector('[name="position.z"]').value,
+ position: {
+ x: document.querySelector('[name="position.x"]').value,
+ y: document.querySelector('[name="position.y"]').value,
+ z: document.querySelector('[name="position.z"]').value,
+ }
})
+ this.updateKfButtons()
}
- fillAgentProperties(agentProps){
- this.outputs.agentProperties.innerHTML=''
+ updateKfButtons(){
+ if(this.kfArena.agents.length > 0) this.outputs.btnSaveKF.disabled = false
+ }
+
+ fillAgentProperties(aid, agentProps){
+ this.outputs.agentProperties.innerHTML = `
+ ID: ${aid}
+ `
this.outputs.agentProperties.append(...this.fieldsFromJSON(agentProps, 'Internal properties'))
this.outputs.agentProperties.append(...this.fieldsFromJSON({
"position.x": {
@@ -103,8 +121,10 @@ class KeyframeView extends WindozDomContent {
},
}, 'Speed vector'))
this.outputs.btnAddAgent.disabled = false
+ this.setupRefs()
}
+
}
app.registerClass('KeyframeView', KeyframeView)
diff --git a/app/views/editors/modules/kfArena.module.js b/app/views/editors/modules/kfArena.module.js
index b65e457..da4b32d 100644
--- a/app/views/editors/modules/kfArena.module.js
+++ b/app/views/editors/modules/kfArena.module.js
@@ -3,29 +3,32 @@ import { OrbitControls } from '/app/thirdparty/Three/OrbitControls.module.js'
import * as TWEEN from '/app/thirdparty/Three/tween.module.js'
export class kfArena{
-
+
constructor(canvasEl, agentSprites){
Object.assign(this, app.helpers.helpers3D)
this.agentSprites = app.Assets.Store.json.agentSprites
this.canvasEl = canvasEl
this.agentSprites = agentSprites
this.renderer = null
- this.mode='3D'
+ this.mode = '3D'
this.sceneSize = app.Assets.Store.json.arenaConfig.arenaSize
this.initScene()
+ this.raycaster = new THREE.Raycaster()
+ this.agents = []
+ this.onclickAgent = null
}
-
+
initScene(){
// Scene
this.scene = new THREE.Scene()
-
+
// Camera
this.camera = new THREE.PerspectiveCamera(75, this.canvasEl.clientWidth / this.canvasEl.clientHeight, 0.1, 1000)
this.camera.position.set(3, 3, 5)
this.camera.lookAt(0, 0, 0)
this.camera.layers.enable(1)
this.camera.layers.enable(2)
-
+
// Lights
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(5, 5, 5)
@@ -36,7 +39,7 @@ export class kfArena{
this.grid = new THREE.GridHelper(this.sceneSize.x, this.sceneSize.x, 0x8888AA, 0x8888AA)
this.grid.layers.set(1)
this.scene.add(this.grid)
-
+
// Base plane
const planeGeo = new THREE.PlaneGeometry(100, 100)
const planeMat = new THREE.MeshBasicMaterial({
@@ -49,19 +52,20 @@ export class kfArena{
this.basePlane.rotation.x = -Math.PI / 2 // lay it flat (like the grid)
this.basePlane.position.y=-0.01 // to avoid artefacts on objets bases
this.scene.add(this.basePlane)
-
+
this.axes = new THREE.AxesHelper(this.sceneSize.x/2)
this.axes.layers.set(2)
this.scene.add(this.axes)
-
+
this.renderer = new THREE.WebGLRenderer({ antialias: true, canvas: this.canvasEl })
+ this.canvasEl.addEventListener('click', this.onSceneClick.bind(this))
}
-
+
startRendering(){
this.addControls()
this.render()
}
-
+
render() {
TWEEN.update()
if(this.resizeRendererToDisplaySize()) {
@@ -71,8 +75,8 @@ export class kfArena{
this.renderer.render(this.scene, this.camera)
requestAnimationFrame(this.render.bind(this))
}
-
-
+
+
resizeRendererToDisplaySize() {
const width = this.canvasEl.clientWidth
const height = this.canvasEl.clientHeight
@@ -82,7 +86,7 @@ export class kfArena{
}
return false
}
-
+
addControls(){
this.controls = new OrbitControls(this.camera, this.canvasEl)
if(this.mode=='2D'){
@@ -97,22 +101,51 @@ export class kfArena{
RIGHT: THREE.MOUSE.DOLLY // zoom with right-click
}
}
+
- addAgent(typeId, aid, position){
+ onSceneClick(event){ // ray from the mouse, through the camera lens, to find the first (most foreground) object
+ if(typeof(this.onclickAgent) != 'function') return
+ const normalizedPointer = new THREE.Vector2()
+ const rect = this.canvasEl.getBoundingClientRect()
+ normalizedPointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
+ normalizedPointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1
+ this.raycaster.setFromCamera(normalizedPointer, this.camera)
+ const intersects = this.raycaster.intersectObjects(this.scene.children, true)
+
+ if (intersects.length > 0) {
+ const hit = this.getNamedParent(intersects[0].object)
+ if(hit) this.onclickAgent(hit.name)
+ }
+ }
+
+
+ addAgent(typeId, aid, properties){
const agentSprite = this.agentSprites.find(item => item.atp_id==typeId)
if(!agentSprite) return
const agentObj = this.agentFromJSON(aid, agentSprite.asp_3d)
-
- agentObj.position.set(position.x, position.z, position.y )
+
+ agentObj.position.set(properties.position.x, properties.position.z, properties.position.y )
+ //TODO Speed vector
this.scene.add(agentObj)
+
+ this.agents.push({
+ aid: aid,
+ props: properties,
+ })
}
-
- removeAgent(id){
- //find obj by id
- //this.scene.remove(this.currentAgentObj)
+
+ removeAgent(aid){
+ const obj3d = scene.getObjectByName(aid)
+ this.scene.remove(obj3d)
+ this.agents = this.agents.filter(a => a.aid !== aid)
}
+
+ // getAllAgents(){
+ // const agents = []
+ // scene.traverse(o => o.name && names.push(o.name))
}
+
// Make this module available to common JS
if(!app.LoadedModules) app.LoadedModules = {}
app.LoadedModules.kfArena = kfArena