main.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. import * as THREE from 'three';
  2. import { KeyCode } from './KeyCode.js';
  3. import { Bee } from './Bee.js';
  4. import { Hive } from './Hive.js';
  5. import { Flower } from './Flower.js';
  6. import { Waypoint } from './Waypoint.js';
  7. // scene size
  8. var WIDTH = window.innerWidth;
  9. var HEIGHT = window.innerHeight;
  10. // camera
  11. var VIEW_ANGLE = 45;
  12. var ASPECT = WIDTH / HEIGHT;
  13. var NEAR = 1;
  14. var FAR = 10000;
  15. var camera, scene, renderer, raycaster;
  16. var clock = new THREE.Clock();
  17. var intersects;
  18. export var keys = [];
  19. var mouse, dragStart, dragOffset;
  20. var selected;
  21. var ground;
  22. var draggingOnGround;
  23. function init() {
  24. for (let i = 0; i < 256; i++) {
  25. keys[i] = false;
  26. }
  27. raycaster = new THREE.Raycaster();
  28. mouse = new THREE.Vector2(-1, -1);
  29. dragStart = new THREE.Vector3(0, 0, 0);
  30. dragOffset = new THREE.Vector3(0, 0, 0);
  31. intersects = [];
  32. // renderer
  33. renderer = new THREE.WebGLRenderer({
  34. antialias: true,
  35. });
  36. renderer.setPixelRatio(window.devicePixelRatio);
  37. renderer.setSize(WIDTH, HEIGHT);
  38. renderer.shadowMap.enabled = true;
  39. renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  40. renderer.outputColorSpace = THREE.SRGBColorSpace;
  41. renderer.alias
  42. // scene
  43. scene = new THREE.Scene();
  44. // camera
  45. camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
  46. camera.focus = new THREE.Vector3(0, 0, 0);
  47. camera.focusTarget = new THREE.Vector3(0, 0, 0);
  48. camera.offset = new THREE.Vector3(160, 220, 160);
  49. camera.position.set(camera.focus.x + camera.offset.x, camera.focus.y + camera.offset.y, camera.focus.z + camera.offset.z);
  50. camera.follow = false;
  51. camera.lookAt(camera.focus);
  52. draggingOnGround = false;
  53. var container = document.getElementById('container');
  54. container.appendChild(renderer.domElement);
  55. }
  56. function fillScene() {
  57. //sky
  58. let cubeloader = new THREE.CubeTextureLoader();
  59. let texture = cubeloader.load([
  60. './cubemapsimple/posx.png',
  61. './cubemapsimple/negx.png',
  62. './cubemapsimple/posy.png',
  63. './cubemapsimple/negy.png',
  64. './cubemapsimple/posz.png',
  65. './cubemapsimple/negz.png',
  66. ]);
  67. scene.background = texture;
  68. //ground
  69. let textureLoader = new THREE.TextureLoader();
  70. let lawnTex = textureLoader.load("textures/lawn.jpg");
  71. var planeGeo = new THREE.PlaneGeometry(1000, 1000, 32, 32);
  72. let floorMat = new THREE.MeshPhongMaterial({ map: lawnTex });
  73. floorMat.flatShading = true;
  74. floorMat.shininess = 0;
  75. lawnTex.wrapS = lawnTex.wrapT = THREE.RepeatWrapping;
  76. lawnTex.repeat.set(5, 5);
  77. ground = new THREE.Mesh(planeGeo, floorMat);
  78. ground.rotateX(- Math.PI / 2);
  79. ground.receiveShadow = true;
  80. scene.add(ground);
  81. // lights
  82. var sunlight = new THREE.DirectionalLight(0xffffff, 2.8, 0, 2);
  83. sunlight.position.x = 400;
  84. sunlight.position.y = 400;
  85. sunlight.position.z = 100;
  86. const shadowSize = 1000
  87. sunlight.castShadow = true
  88. sunlight.shadow.camera.left = -shadowSize
  89. sunlight.shadow.camera.right = shadowSize
  90. sunlight.shadow.camera.top = -shadowSize
  91. sunlight.shadow.camera.bottom = shadowSize
  92. sunlight.shadow.camera.far = 800
  93. sunlight.shadow.mapSize.width = Math.min(renderer.capabilities.maxTextureSize, 2048)
  94. sunlight.shadow.mapSize.height = Math.min(renderer.capabilities.maxTextureSize, 2048)
  95. sunlight.shadow.bias = -0.005
  96. sunlight.shadow.radius = 6
  97. //sunlight.shadow.camera.far = 1600;
  98. scene.add(sunlight);
  99. var mainLight = new THREE.HemisphereLight(0xB1E1FF, 0xB97A20, 0.6);
  100. mainLight.position.x = 1;
  101. mainLight.position.y = 1;
  102. mainLight.position.z = 1;
  103. mainLight.lookAt(0, 0, 0);
  104. scene.add(mainLight);
  105. // var light = new THREE.AmbientLight(0xcccccc, 1);
  106. // scene.add(light);
  107. //set pieces
  108. Hive.collection = [];
  109. Flower.collection = [];
  110. Bee.collection = [];
  111. Promise.all([Hive.loadModel(), Flower.loadModel(), Bee.loadModel()]).then(async result => {
  112. for (let i = 0; i < 3; i++) {
  113. let hive = new Hive(scene);
  114. await hive.load(result[0]);
  115. hive.init(i);
  116. Hive.collection.push(hive);
  117. }
  118. Hive.collection.forEach(hive => hive.addToScene(scene));
  119. for (let i = 0; i < 24; i++) {
  120. let flower = new Flower();
  121. await flower.load(result[1]);
  122. flower.position.x = ((i % 6) / 6 * 400) - 200;
  123. flower.position.z = (Math.floor(i / 6) / 6 * 300) + 150;
  124. flower.rotation.y = (2 * Math.PI) * Math.random();
  125. Flower.collection.push(flower);
  126. }
  127. Flower.collection.forEach(flower => flower.addToScene(scene));
  128. Bee.baseModel = result[2];
  129. Hive.collection[0].setSwarm(1);
  130. Hive.collection[0].honeyReserve = 20;
  131. Hive.collection[0].toggleFlower(Flower.collection[0]);
  132. Hive.collection[0].spawnBee();
  133. Hive.collection[2].setSwarm(2);
  134. Hive.collection[2].honeyReserve = 20;
  135. Hive.collection[2].toggleFlower(Flower.collection[5]);
  136. Hive.collection[2].spawnBee();
  137. for (let i = 0; i < Waypoint.collection.length; i++) {
  138. let waypoint = Waypoint.collection[i];
  139. waypoint.rebuildLines();
  140. }
  141. update();
  142. });
  143. }
  144. function setFocus(focus) {
  145. selected = focus;
  146. camera.focusTarget.set(selected.position.x, selected.position.y, selected.position.z);
  147. camera.follow = true;
  148. }
  149. function render() {
  150. renderer.render(scene, camera);
  151. }
  152. function update() {
  153. window.requestAnimationFrame(update);
  154. var delta = clock.getDelta();
  155. var timer = Date.now();
  156. let origin = new THREE.Vector3(0, camera.offset.y, 0);
  157. let distance = camera.offset.distanceTo(origin);
  158. var delta = camera.offset.clone().sub(origin);
  159. var theta = Math.atan2(delta.z, delta.x);
  160. let cameraSpeed = 3;
  161. if (keys[KeyCode.Left] || keys[KeyCode.A]) { //left
  162. let vector = new THREE.Vector3();
  163. camera.getWorldDirection(vector);
  164. vector.multiply(new THREE.Vector3(cameraSpeed, 0, -cameraSpeed));
  165. camera.focusTarget.add(vector);
  166. }
  167. if (keys[KeyCode.Right] || keys[KeyCode.D]) { //right
  168. let vector = new THREE.Vector3();
  169. camera.getWorldDirection(vector);
  170. vector.multiply(new THREE.Vector3(-cameraSpeed, 0, cameraSpeed));
  171. camera.focusTarget.add(vector);
  172. }
  173. if (keys[KeyCode.Up] || keys[KeyCode.W]) { //up
  174. let vector = new THREE.Vector3();
  175. camera.getWorldDirection(vector);
  176. vector.multiply(new THREE.Vector3(cameraSpeed, 0, cameraSpeed));
  177. camera.focusTarget.add(vector);
  178. }
  179. if (keys[KeyCode.Down] || keys[KeyCode.S]) { //down
  180. let vector = new THREE.Vector3();
  181. camera.getWorldDirection(vector);
  182. vector.multiply(new THREE.Vector3(-cameraSpeed, 0, -cameraSpeed));
  183. camera.focusTarget.add(vector);
  184. }
  185. var rotation = (6/180) * Math.PI
  186. let cameraOffset = new THREE.Vector3(camera.offset.x, camera.offset.y, camera.offset.z);
  187. if (keys[KeyCode.Q]) {
  188. cameraOffset.x = distance * Math.cos(theta + rotation);
  189. cameraOffset.z = distance * Math.sin(theta + rotation);
  190. }
  191. if (keys[KeyCode.E]) {
  192. cameraOffset.x = distance * Math.cos(theta - rotation);
  193. cameraOffset.z = distance * Math.sin(theta - rotation);
  194. }
  195. if (camera.follow) {
  196. camera.focusTarget = selected.position.clone();
  197. }
  198. camera.offset.lerp(cameraOffset, 0.1);
  199. camera.focus.lerp(camera.focusTarget, 0.1);
  200. camera.position.set(camera.focus.x + camera.offset.x, camera.focus.y + camera.offset.y, camera.focus.z + camera.offset.z);
  201. camera.lookAt(camera.focus);
  202. raycaster.setFromCamera(mouse, camera);
  203. intersects = raycaster.intersectObjects(scene.children, true);
  204. Bee.collection.forEach(bee => bee.update(delta, timer));
  205. Hive.collection.forEach(hive => hive.update(delta, timer));
  206. Flower.collection.forEach(flower => flower.update(delta, timer));
  207. render();
  208. }
  209. document.addEventListener("DOMContentLoaded", () => {
  210. init();
  211. fillScene();
  212. });
  213. window.addEventListener("keydown", e => keys[e.keyCode] = true);
  214. window.addEventListener("keyup", e => keys[e.keyCode] = false);
  215. window.addEventListener("mousemove", event => {
  216. mouse.x = normalize(event.clientX / window.innerWidth);
  217. mouse.y = -normalize(event.clientY / window.innerHeight);
  218. event.target.style.cursor = "default";
  219. let hiveIntersects = getIntersectFromCollection(Hive.collection, intersects);
  220. if (hiveIntersects.length > 0) {
  221. event.target.style.cursor = "pointer";
  222. }
  223. let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects);
  224. if (flowerIntersects.length > 0) {
  225. event.target.style.cursor = "pointer";
  226. }
  227. let beeIntersects = getIntersectFromCollection(Bee.collection, intersects);
  228. if (beeIntersects.length > 0) {
  229. event.target.style.cursor = "pointer";
  230. }
  231. let groundIntersect = intersects.filter(i => i.object == ground);
  232. if (groundIntersect.length > 0) {
  233. if (draggingOnGround) {
  234. event.target.style.cursor = "move";
  235. dragOffset = camera.focus.clone().sub(groundIntersect[0].point);
  236. camera.focusTarget = dragStart.clone().add(dragOffset);
  237. }
  238. }
  239. });
  240. window.addEventListener("mousedown", event => {
  241. camera.follow = false;
  242. mouse.x = normalize(event.clientX / window.innerWidth);
  243. mouse.y = -normalize(event.clientY / window.innerHeight);
  244. let hiveIntersects = getIntersectFromCollection(Hive.collection, intersects);
  245. if (hiveIntersects.length > 0) {
  246. return;
  247. }
  248. let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects);
  249. if (flowerIntersects.length > 0) {
  250. return;
  251. }
  252. let beeIntersects = getIntersectFromCollection(Bee.collection, intersects);
  253. if (beeIntersects.length > 0) {
  254. setFocus(beeIntersects[0]);
  255. return;
  256. }
  257. let groundIntersect = intersects.filter(i => i.object == ground);
  258. if (groundIntersect.length > 0) {
  259. draggingOnGround = true;
  260. dragStart = groundIntersect[0].point.clone();
  261. dragOffset = camera.focus.clone().sub(groundIntersect[0].point);
  262. camera.focusTarget = dragStart.clone().add(dragOffset);
  263. }
  264. });
  265. window.addEventListener("contextmenu", event => {
  266. event.preventDefault();
  267. });
  268. window.addEventListener("mouseup", event => {
  269. if (draggingOnGround) {
  270. draggingOnGround = false;
  271. return;
  272. }
  273. draggingOnGround = false;
  274. if (event.button == 2) {
  275. if (selected instanceof Hive) {
  276. let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects);
  277. if (flowerIntersects.length > 0) {
  278. selected.toggleFlower(flowerIntersects[0]);
  279. addLines(selected);
  280. return;
  281. }
  282. return;
  283. }
  284. }
  285. let hiveIntersects = getIntersectFromCollection(Hive.collection, intersects);
  286. if (hiveIntersects.length > 0) {
  287. if (selected == hiveIntersects[0]) {
  288. setFocus(hiveIntersects[0]);
  289. }
  290. selected = hiveIntersects[0];
  291. addLines(selected);
  292. return;
  293. }
  294. let flowerIntersects = getIntersectFromCollection(Flower.collection, intersects);
  295. if (flowerIntersects.length > 0) {
  296. if (selected == flowerIntersects[0]) {
  297. setFocus(flowerIntersects[0]);
  298. }
  299. selected = flowerIntersects[0];
  300. addLines(selected);
  301. return;
  302. }
  303. let beeIntersects = getIntersectFromCollection(Bee.collection, intersects);
  304. if (beeIntersects.length > 0) {
  305. setFocus(beeIntersects[0]);
  306. addLines(selected);
  307. return;
  308. }
  309. });
  310. window.addEventListener("wheel", event => {
  311. let vector = new THREE.Vector3();
  312. camera.getWorldDirection(vector);
  313. vector.multiplyScalar(-event.deltaY / 4);
  314. camera.offset.add(vector);
  315. });
  316. let addLines = (focus) => {
  317. for (let i = 0; i < Waypoint.collection.length; i++) {
  318. let waypoint = Waypoint.collection[i];
  319. for (let j = 0; j < waypoint.lines.length; j++) {
  320. let line = waypoint.lines[j];
  321. scene.remove(line);
  322. }
  323. }
  324. if (focus.hasOwnProperty("entranceWaypoint")) {
  325. for (let i = 0; i < focus.entranceWaypoint.lines.length; i++) {
  326. scene.add(focus.entranceWaypoint.lines[i]);
  327. }
  328. }
  329. for (let i = 0; i < Hive.collection.length; i++) {
  330. let hive = Hive.collection[i];
  331. scene.remove(hive.billboard);
  332. if (hive == focus) {
  333. scene.add(hive.billboard);
  334. }
  335. }
  336. }
  337. let getIntersectFromCollection = (collection, intersectCollection) => {
  338. return collection.filter(target => intersectCollection.filter(i => crawlParent(target.model, i.object)).length > 0);
  339. }
  340. let crawlParent = (lookingFor, questionObj) => {
  341. if (questionObj == lookingFor) {
  342. return true;
  343. }
  344. if (questionObj.parent == null) {
  345. return false;
  346. }
  347. if (questionObj.parent == lookingFor) {
  348. return true;
  349. }
  350. return crawlParent(lookingFor, questionObj.parent);
  351. }
  352. window.addEventListener("touchmove", event => {
  353. mouse.x = normalize(event.touches[0].clientX / window.innerWidth);
  354. mouse.y = -normalize(event.touches[0].clientY / window.innerHeight);
  355. });
  356. function normalize(value) {
  357. return (2 * value) - 1;
  358. }