import * as THREE from 'three'; import { KeyCode } from './KeyCode.js'; import { Bee } from './Bee.js'; import { Hive } from './Hive.js'; import { Flower } from './Flower.js'; import { Waypoint } from './Waypoint.js'; // scene size var WIDTH = window.innerWidth; var HEIGHT = window.innerHeight; // camera var VIEW_ANGLE = 45; var ASPECT = WIDTH / HEIGHT; var NEAR = 1; var FAR = 10000; var camera, scene, renderer, raycaster; var clock = new THREE.Clock(); var intersects; export var keys = []; var mouse, dragStart, dragOffset; var selected; var ground; var draggingOnGround; function init() { for (let i = 0; i < 256; i++) { keys[i] = false; } raycaster = new THREE.Raycaster(); mouse = new THREE.Vector2(-1, -1); dragStart = new THREE.Vector3(0, 0, 0); dragOffset = new THREE.Vector3(0, 0, 0); intersects = []; // renderer renderer = new THREE.WebGLRenderer({ antialias: true, }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(WIDTH, HEIGHT); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.outputColorSpace = THREE.SRGBColorSpace; renderer.alias // scene scene = new THREE.Scene(); // camera camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); camera.focus = new THREE.Vector3(0, 0, 0); camera.focusTarget = new THREE.Vector3(0, 0, 0); camera.offset = new THREE.Vector3(160, 220, 160); camera.position.set(camera.focus.x + camera.offset.x, camera.focus.y + camera.offset.y, camera.focus.z + camera.offset.z); camera.follow = false; camera.lookAt(camera.focus); draggingOnGround = false; var container = document.getElementById('container'); container.appendChild(renderer.domElement); } function fillScene() { //sky let cubeloader = new THREE.CubeTextureLoader(); let texture = cubeloader.load([ './cubemapsimple/posx.png', './cubemapsimple/negx.png', './cubemapsimple/posy.png', './cubemapsimple/negy.png', './cubemapsimple/posz.png', './cubemapsimple/negz.png', ]); scene.background = texture; //ground let textureLoader = new THREE.TextureLoader(); let lawnTex = textureLoader.load("textures/lawn.jpg"); var planeGeo = new THREE.PlaneGeometry(1000, 1000, 32, 32); let floorMat = new THREE.MeshPhongMaterial({ map: lawnTex }); floorMat.flatShading = true; floorMat.shininess = 0; lawnTex.wrapS = lawnTex.wrapT = THREE.RepeatWrapping; lawnTex.repeat.set(5, 5); ground = new THREE.Mesh(planeGeo, floorMat); ground.rotateX(- Math.PI / 2); ground.receiveShadow = true; scene.add(ground); // lights var sunlight = new THREE.DirectionalLight(0xffffff, 2.8, 0, 2); sunlight.position.x = 400; sunlight.position.y = 400; sunlight.position.z = 100; const shadowSize = 1000 sunlight.castShadow = true sunlight.shadow.camera.left = -shadowSize sunlight.shadow.camera.right = shadowSize sunlight.shadow.camera.top = -shadowSize sunlight.shadow.camera.bottom = shadowSize sunlight.shadow.camera.far = 800 sunlight.shadow.mapSize.width = Math.min(renderer.capabilities.maxTextureSize, 2048) sunlight.shadow.mapSize.height = Math.min(renderer.capabilities.maxTextureSize, 2048) sunlight.shadow.bias = -0.005 sunlight.shadow.radius = 6 //sunlight.shadow.camera.far = 1600; scene.add(sunlight); var mainLight = new THREE.HemisphereLight(0xB1E1FF, 0xB97A20, 0.6); mainLight.position.x = 1; mainLight.position.y = 1; mainLight.position.z = 1; mainLight.lookAt(0, 0, 0); scene.add(mainLight); // var light = new THREE.AmbientLight(0xcccccc, 1); // scene.add(light); //set pieces Hive.collection = []; Flower.collection = []; Bee.collection = []; Promise.all([Hive.loadModel(), Flower.loadModel(), Bee.loadModel()]).then(async result => { for (let i = 0; i < 3; i++) { let hive = new Hive(scene); await hive.load(result[0]); hive.init(i); Hive.collection.push(hive); } Hive.collection.forEach(hive => hive.addToScene(scene)); for (let i = 0; i < 24; i++) { let flower = new Flower(); await flower.load(result[1]); flower.position.x = ((i % 6) / 6 * 400) - 200; flower.position.z = (Math.floor(i / 6) / 6 * 300) + 150; flower.rotation.y = (2 * Math.PI) * Math.random(); Flower.collection.push(flower); } Flower.collection.forEach(flower => flower.addToScene(scene)); Bee.baseModel = result[2]; Hive.collection[0].setSwarm(1); Hive.collection[0].honeyReserve = 20; Hive.collection[0].toggleFlower(Flower.collection[0]); Hive.collection[0].spawnBee(); Hive.collection[2].setSwarm(2); Hive.collection[2].honeyReserve = 20; Hive.collection[2].toggleFlower(Flower.collection[5]); Hive.collection[2].spawnBee(); for (let i = 0; i < Waypoint.collection.length; i++) { let waypoint = Waypoint.collection[i]; waypoint.rebuildLines(); } update(); }); } function setFocus(focus) { selected = focus; camera.focusTarget.set(selected.position.x, selected.position.y, selected.position.z); camera.follow = true; } function render() { renderer.render(scene, camera); } function update() { window.requestAnimationFrame(update); var delta = clock.getDelta(); var timer = Date.now(); let origin = new THREE.Vector3(0, camera.offset.y, 0); let distance = camera.offset.distanceTo(origin); var delta = camera.offset.clone().sub(origin); var theta = Math.atan2(delta.z, delta.x); let cameraSpeed = 3; if (keys[KeyCode.Left] || keys[KeyCode.A]) { //left let vector = new THREE.Vector3(); camera.getWorldDirection(vector); vector.multiply(new THREE.Vector3(cameraSpeed, 0, -cameraSpeed)); camera.focusTarget.add(vector); } if (keys[KeyCode.Right] || keys[KeyCode.D]) { //right let vector = new THREE.Vector3(); camera.getWorldDirection(vector); vector.multiply(new THREE.Vector3(-cameraSpeed, 0, cameraSpeed)); camera.focusTarget.add(vector); } if (keys[KeyCode.Up] || keys[KeyCode.W]) { //up let vector = new THREE.Vector3(); camera.getWorldDirection(vector); vector.multiply(new THREE.Vector3(cameraSpeed, 0, cameraSpeed)); camera.focusTarget.add(vector); } if (keys[KeyCode.Down] || keys[KeyCode.S]) { //down let vector = new THREE.Vector3(); camera.getWorldDirection(vector); vector.multiply(new THREE.Vector3(-cameraSpeed, 0, -cameraSpeed)); camera.focusTarget.add(vector); } var rotation = (6/180) * Math.PI let cameraOffset = new THREE.Vector3(camera.offset.x, camera.offset.y, camera.offset.z); if (keys[KeyCode.Q]) { cameraOffset.x = distance * Math.cos(theta + rotation); cameraOffset.z = distance * Math.sin(theta + rotation); } if (keys[KeyCode.E]) { cameraOffset.x = distance * Math.cos(theta - rotation); cameraOffset.z = distance * Math.sin(theta - rotation); } if (camera.follow) { camera.focusTarget = selected.position.clone(); } camera.offset.lerp(cameraOffset, 0.1); camera.focus.lerp(camera.focusTarget, 0.1); camera.position.set(camera.focus.x + camera.offset.x, camera.focus.y + camera.offset.y, camera.focus.z + camera.offset.z); camera.lookAt(camera.focus); raycaster.setFromCamera(mouse, camera); intersects = raycaster.intersectObjects(scene.children, true); Bee.collection.forEach(bee => bee.update(delta, timer)); Hive.collection.forEach(hive => hive.update(delta, timer)); Flower.collection.forEach(flower => flower.update(delta, timer)); render(); } document.addEventListener("DOMContentLoaded", () => { init(); fillScene(); }); window.addEventListener("keydown", e => keys[e.keyCode] = true); window.addEventListener("keyup", e => keys[e.keyCode] = false); window.addEventListener("mousemove", event => { mouse.x = normalize(event.clientX / window.innerWidth); mouse.y = -normalize(event.clientY / window.innerHeight); event.target.style.cursor = "default"; let hiveIntersects = getIntersectFromCollection(Hive.collection, intersects); if (hiveIntersects.length > 0) { event.target.style.cursor = "pointer"; } let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects); if (flowerIntersects.length > 0) { event.target.style.cursor = "pointer"; } let beeIntersects = getIntersectFromCollection(Bee.collection, intersects); if (beeIntersects.length > 0) { event.target.style.cursor = "pointer"; } let groundIntersect = intersects.filter(i => i.object == ground); if (groundIntersect.length > 0) { if (draggingOnGround) { event.target.style.cursor = "move"; dragOffset = camera.focus.clone().sub(groundIntersect[0].point); camera.focusTarget = dragStart.clone().add(dragOffset); } } }); window.addEventListener("mousedown", event => { camera.follow = false; mouse.x = normalize(event.clientX / window.innerWidth); mouse.y = -normalize(event.clientY / window.innerHeight); let hiveIntersects = getIntersectFromCollection(Hive.collection, intersects); if (hiveIntersects.length > 0) { return; } let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects); if (flowerIntersects.length > 0) { return; } let beeIntersects = getIntersectFromCollection(Bee.collection, intersects); if (beeIntersects.length > 0) { setFocus(beeIntersects[0]); return; } let groundIntersect = intersects.filter(i => i.object == ground); if (groundIntersect.length > 0) { draggingOnGround = true; dragStart = groundIntersect[0].point.clone(); dragOffset = camera.focus.clone().sub(groundIntersect[0].point); camera.focusTarget = dragStart.clone().add(dragOffset); } }); window.addEventListener("contextmenu", event => { event.preventDefault(); }); window.addEventListener("mouseup", event => { if (draggingOnGround) { draggingOnGround = false; return; } draggingOnGround = false; if (event.button == 2) { if (selected instanceof Hive) { let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects); if (flowerIntersects.length > 0) { selected.toggleFlower(flowerIntersects[0]); addLines(selected); return; } return; } } let hiveIntersects = getIntersectFromCollection(Hive.collection, intersects); if (hiveIntersects.length > 0) { if (selected == hiveIntersects[0]) { setFocus(hiveIntersects[0]); } selected = hiveIntersects[0]; addLines(selected); return; } let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects); if (flowerIntersects.length > 0) { if (selected == flowerIntersects[0]) { setFocus(flowerIntersects[0]); } selected = flowerIntersects[0]; addLines(selected); return; } let beeIntersects = getIntersectFromCollection(Bee.collection, intersects); if (beeIntersects.length > 0) { setFocus(beeIntersects[0]); addLines(selected); return; } }); window.addEventListener("wheel", event => { let vector = new THREE.Vector3(); camera.getWorldDirection(vector); vector.multiplyScalar(-event.deltaY / 4); camera.offset.add(vector); }); let addLines = (focus) => { for (let i = 0; i < Waypoint.collection.length; i++) { let waypoint = Waypoint.collection[i]; for (let j = 0; j < waypoint.lines.length; j++) { let line = waypoint.lines[j]; scene.remove(line); } } if (focus.hasOwnProperty("entranceWaypoint")) { for (let i = 0; i < focus.entranceWaypoint.lines.length; i++) { scene.add(focus.entranceWaypoint.lines[i]); } } for (let i = 0; i < Hive.collection.length; i++) { let hive = Hive.collection[i]; scene.remove(hive.billboard); if (hive == focus) { scene.add(hive.billboard); } } } let getIntersectFromCollection = (collection, intersectCollection) => { return collection.filter(target => intersectCollection.filter(i => crawlParent(target.model, i.object)).length > 0); } let crawlParent = (lookingFor, questionObj) => { if (questionObj == lookingFor) { return true; } if (questionObj.parent == null) { return false; } if (questionObj.parent == lookingFor) { return true; } return crawlParent(lookingFor, questionObj.parent); } window.addEventListener("touchmove", event => { mouse.x = normalize(event.touches[0].clientX / window.innerWidth); mouse.y = -normalize(event.touches[0].clientY / window.innerHeight); }); function normalize(value) { return (2 * value) - 1; }