153 lines
5.4 KiB
JavaScript
153 lines
5.4 KiB
JavaScript
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()
|
|
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)
|
|
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.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({
|
|
color: 0xaaaacc,
|
|
opacity: 0.3,
|
|
transparent: true, // needed for opacity < 1 to take effect
|
|
side: THREE.DoubleSide
|
|
})
|
|
this.basePlane = new THREE.Mesh(planeGeo, planeMat)
|
|
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()) {
|
|
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
|
|
}
|
|
}
|
|
|
|
|
|
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(properties.position.x, properties.position.z, properties.position.y )
|
|
//TODO Speed vector
|
|
this.scene.add(agentObj)
|
|
|
|
this.agents.push({
|
|
aid: aid,
|
|
props: properties,
|
|
})
|
|
}
|
|
|
|
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
|
|
|