diff --git a/app/assets/styles/app.css b/app/assets/styles/app.css
index a8d0dd9..acaa435 100755
--- a/app/assets/styles/app.css
+++ b/app/assets/styles/app.css
@@ -357,6 +357,12 @@ input{
border: none;
}
+button[eicbutton][rounded] {
+ min-height: 2em;
+ padding: 0;
+ color: #DDD;
+}
+
/* Customizations to buildoz*/
bz-select > button{
background: linear-gradient( to bottom, #251, #372 15%, #483 50%, #372 85%, #251 ) !important;
diff --git a/app/controllers/editors/EditorsController.json b/app/controllers/editors/EditorsController.json
index dbe8de3..586ca59 100644
--- a/app/controllers/editors/EditorsController.json
+++ b/app/controllers/editors/EditorsController.json
@@ -23,7 +23,7 @@
"AgentsModel"
],
"views": [
- {"view":"editors/KeyframeView", "dependencies": ["editors/modules/agentPreview.module"]}
+ {"view":"editors/KeyframeView", "dependencies": ["editors/modules/agentPreview.module", "editors/modules/kfArena.module"]}
],
"controllerDependencies": [
"/helpers/basicDialogs",
@@ -41,7 +41,8 @@
"html": [
{ "id":"spaceViewSetting", "name": "spaceViewSetting.html"}
],
- "json": [
+ "json": [
+ {"id":"arenaConfig", "name": "arena/arenaConfig1.json"}
]
}
}
\ No newline at end of file
diff --git a/app/views/editors/KeyframeView.html b/app/views/editors/KeyframeView.html
index 00566ab..b39d307 100644
--- a/app/views/editors/KeyframeView.html
+++ b/app/views/editors/KeyframeView.html
@@ -10,12 +10,18 @@
}
.kf-editor > article, .kf-editor > article header{ border-color: #473; }
.kf-editor article.agent-preview header { padding:0; }
- .kf-editor article.agent-preview canvas{ width:100%; aspect-ratio: 1 / 1;}
+ .kf-editor canvas[data-output="agentSampleCanvas"]{ width:100%; aspect-ratio: 1 / 1;}
+ .kf-editor canvas[data-output="kfArenaCanvas"]{ width:100%; height:100%; }
.kf-editor article.agent-preview section, .kf-editor article.agent-properties section{
display: grid;
grid-template-rows: auto 2em;
height: 100%;
- }
+ }
+ .kf-editor article.kfArena section{
+ padding: 0;
+ height: 100%;
+
+ }
.kf-editor article.agent-preview section div.actions button{
color: #DDD;
padding: 0 0 0 0;
@@ -25,11 +31,11 @@
.kf-editor button[data-trigger="onRemoveAgent"] { 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; }
-
+
-
+
@@ -37,9 +43,9 @@
-
+
@@ -52,7 +58,7 @@
-
-
+
+
diff --git a/app/views/editors/KeyframeView.js b/app/views/editors/KeyframeView.js
index a2970db..2a92b2c 100644
--- a/app/views/editors/KeyframeView.js
+++ b/app/views/editors/KeyframeView.js
@@ -41,19 +41,31 @@ class KeyframeView extends WindozDomContent {
this.agentPreview.startRendering()
this.agentPreview.animation = true
+ this.kfArena = new app.LoadedModules.kfArena(this.outputs.kfArenaCanvas, this.agentSprites)
+ this.kfArena.startRendering()
+
+
+ this.outputs.btnAddAgent.disabled = true
+ this.outputs.btnRemoveAgent.disabled = true
}
-
-
async onChangeAgent(event){
if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value)
if(!this.outputs.agentsSelector.value) return
- console.log('onChangeAgent',this.outputs.agentsSelector.value)
const agent = await this.models.agents.getProperties(this.outputs.agentsSelector.value)
this.fillAgentProperties(agent.atp_props)
}
- fillAgentProperties(agentProps){ console.log('fillAgentProperties', agentProps)
+ onAddAgent(event){
+ const aid = crypto.randomUUIDv7()
+ 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,
+ })
+ }
+
+ fillAgentProperties(agentProps){
this.outputs.agentProperties.innerHTML=''
this.outputs.agentProperties.append(...this.fieldsFromJSON(agentProps, 'Internal properties'))
this.outputs.agentProperties.append(...this.fieldsFromJSON({
@@ -90,8 +102,10 @@ class KeyframeView extends WindozDomContent {
default: "0"
},
}, 'Speed vector'))
+ this.outputs.btnAddAgent.disabled = false
}
}
app.registerClass('KeyframeView', KeyframeView)
+
diff --git a/app/views/editors/modules/agentPreview.module.js b/app/views/editors/modules/agentPreview.module.js
index 8693b07..279cae7 100644
--- a/app/views/editors/modules/agentPreview.module.js
+++ b/app/views/editors/modules/agentPreview.module.js
@@ -1,6 +1,4 @@
import * as THREE from '/app/thirdparty/Three/three.module.js'
-import { OrbitControls } from '/app/thirdparty/Three/OrbitControls.module.js'
-import * as TWEEN from '/app/thirdparty/Three/tween.module.js'
export class AgentPreview{
diff --git a/app/views/editors/modules/kfArena.module.js b/app/views/editors/modules/kfArena.module.js
new file mode 100644
index 0000000..4e931a0
--- /dev/null
+++ b/app/views/editors/modules/kfArena.module.js
@@ -0,0 +1,106 @@
+import * as THREE from '/app/thirdparty/Three/three.module.js'
+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.sceneSize = app.Assets.Store.json.arenaConfig.arenaSize
+ this.initScene()
+ }
+
+ 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)
+ light.intensity = 2
+ this.scene.add(light)
+ this.scene.add(new THREE.AmbientLight(0xffffff, 0.4))
+
+ this.grid = new THREE.GridHelper(this.sceneSize.x, this.sceneSize.y, 0x8888AA, 0x8888AA)
+ this.grid.layers.set(1)
+ this.scene.add(this.grid)
+
+ this.axes = new THREE.AxesHelper(this.sceneSize.x/2, this.sceneSize.y/2)
+ this.axes.layers.set(2)
+ this.scene.add(this.axes)
+
+ this.renderer = new THREE.WebGLRenderer({ antialias: true, canvas: this.canvasEl })
+ }
+
+ startRendering(){
+ this.addControls()
+ this.render()
+ }
+
+ render() {
+ TWEEN.update()
+ if(this.resizeRendererToDisplaySize()) {
+ this.camera.aspect = this.renderer.domElement.clientWidth / this.canvasEl.clientHeight
+ this.camera.updateProjectionMatrix()
+ }
+ 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
+ }
+
+ addControls(){
+ this.controls = new OrbitControls(this.camera, this.canvasEl)
+ if(this.mode=='2D'){
+ this.controls.maxPolarAngle = 0 // Math.PI / 2
+ this.controls.minPolarAngle = 0 // Math.PI / 2
+ } else if(this.mode=='3D'){
+ }
+
+ this.controls.mouseButtons = {
+ LEFT: THREE.MOUSE.ROTATE, // keep orbit on left
+ MIDDLE: THREE.MOUSE.PAN, // pan with middle-click
+ RIGHT: THREE.MOUSE.DOLLY // zoom with right-click
+ }
+ }
+
+ addAgent(typeId, aid, position){
+ 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 )
+ this.scene.add(agentObj)
+ }
+
+ removeAgent(id){
+ //find obj by id
+ //this.scene.remove(this.currentAgentObj)
+ }
+}
+
+// Make this module available to common JS
+if(!app.LoadedModules) app.LoadedModules = {}
+app.LoadedModules.kfArena = kfArena
+
diff --git a/core/Sparc-core-1.0.js b/core/Sparc-core-1.0.js
index 3e3189a..eb89309 100755
--- a/core/Sparc-core-1.0.js
+++ b/core/Sparc-core-1.0.js
@@ -539,7 +539,8 @@ class Loader {
*/
if(typeof(crypto.randomUUID)!='function'){
- crypto.randomUUID = () => {
+ crypto.randomUUID = () => {
+ console.log('Polyfilled crypt !')
var buf = new Uint8Array(14);
crypto.getRandomValues(buf);
var uuid = Array.from(buf, byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
@@ -550,8 +551,22 @@ if(typeof(crypto.randomUUID)!='function'){
uuid.substring(18,4) + '-' +
uuid.substring(22)
);
- }
+ }
}
+crypto.randomUUIDv7 = () => {
+ const now = BigInt(Date.now())
+ const time = now << 16n | BigInt(crypto.getRandomValues(new Uint16Array(1))[0])
+ const bytes = new Uint8Array(16)
+ new DataView(bytes.buffer).setBigUint64(0, time)
+ crypto.getRandomValues(bytes.subarray(8))
+ bytes[6] = (bytes[6] & 0x0f) | 0x70 // version 7
+ bytes[8] = (bytes[8] & 0x3f) | 0x80 // variant
+ return [...bytes].map((b,i) =>
+ (b + 0x100).toString(16).substring(1) + ([3,5,7,9].includes(i) ? '-' : '')
+ ).join('')
+}
+
+
if(typeof(typeof(Promise.allSettled))!='function'){
Promise.allSettled = ((promises) => Promise.all(