Quellcode durchsuchen

Ready room view.

Cixo Develop vor 8 Monaten
Ursprung
Commit
31de597e79

BIN
example_config/textures/example_room.exr


BIN
example_config/textures/example_room.jpg


+ 17 - 0
source/scripts/assets/assets-getter.js

@@ -1,3 +1,5 @@
+import { room } from "./room.js";
+
 /**
  * This class is responsible for loading assets from the server.
  */
@@ -47,6 +49,20 @@ export class assets_getter {
         return await result.text();
     }
 
+    /**
+     * This return url for texture, from texture name or room.
+     * 
+     * @param {string, room} target - Name or room of the texture
+     * @returns {string} Link to the texture
+     */
+    texture(target) {
+        if (target instanceof room) {
+            target = target.texture;
+        }
+
+        return this.#get_url(`textures/${target}`);
+    }
+
     /**
      * @async
      * @returns {object} - Return enviroment json as object
@@ -71,6 +87,7 @@ export class assets_getter {
         return this.load("rooms.json");
     }
 
+
     /**
      * @returns {string} - Base config directory on server
      */

+ 110 - 0
source/scripts/assets/controler.js

@@ -0,0 +1,110 @@
+import { point } from "./point.js";
+
+/**
+ * This is controler. Controler is responsible for managing events after 
+ * mouse move. App can create controler for each view, and ads more
+ * listeners, which could be removed with one instruction. Listeners get 
+ * point with mouse move difference as parameter.
+ */
+export class controler {
+    #last;
+    #event;
+    #listeners;
+
+    /**
+     * This create new controler.
+     * @return {controler} - New controler
+     */
+    constructor() {
+        this.#last = null;
+        this.#event = null;
+        this.#listeners = [];
+    }
+
+    /**
+     * This is inside function, which calculate mouse move, and save it new
+     * position, to calculate it after next move. It also run all listeners.
+     * 
+     * @param {MouseEvent} event - Event from mousemove 
+     */
+    #moved(event) {
+        const current = new point(event.screenX, event.screenY);
+
+        if (this.#last === null) {
+            this.#last = current;
+            return;
+        }
+
+        const difference = this.#last.compare(current);
+        this.#last = current;
+        
+        this.#run(difference);
+    }
+
+    /**
+     * This run all listeners, and give them as parameter difference between 
+     * last and current mouse position.
+     * 
+     * @param {point} target - Difference between mouse positions
+     */
+    #run(target) {
+        this.#listeners.forEach(item => item(target));
+    }
+
+    /**
+     * This enable event listening on window.
+     */
+    enable() {
+        if (this.#event) {
+            return;
+        }
+
+        this.#event = (event) => { this.#moved(event); };
+        window.addEventListener("mousemove", this.#event);
+    }
+
+    /**
+     * This disable even listening on window. It is recomended to use, when
+     * view is changing. 
+     */
+    clean() {
+        if (this.#event === null) {
+            return;
+        }
+
+        window.removeEventListener("mousemove", this.#event);
+        this.#event = null;
+    }
+
+    /**
+     * This add new listener. Listener get point with difference between
+     * old and new mouse position as argument. 
+     * 
+     * @param {function} target - New listener
+     * @returns {bool} - True when added, false when already exists
+     */
+    add_listener(target) {
+        if (this.#listeners.includes(target)) {
+            return false;
+        }
+
+        this.#listeners.push(target);
+        return true;
+    }
+
+    /**
+     * This remove listener which is given as argument.
+     * 
+     * @param {function} target - Function to remove
+     * @returns {?function} - Null when function is not removed, or function
+     */
+    remove_listener(target) {
+        const where = this.#listeners.indexOf(target);
+
+        if (where === -1) {
+            return null;
+        }
+
+        return this.#listeners.pop(where);
+    }
+}

+ 74 - 0
source/scripts/assets/point.js

@@ -0,0 +1,74 @@
+/**
+ * This class is responsible for storing point in 2D.
+ */
+export class point {
+    #x;
+    #y;
+    
+    /**
+     * This create new point, can be setup by new position.
+     * 
+     * @param {number} x - X position
+     * @param {number} y - Y position
+     */
+    constructor(x = 0, y = 0) {
+        this.#x = x;
+        this.#y = y;
+    }
+
+    /**
+     * @returns {number} - X value of point
+     */
+    get x() {
+        return this.#x;
+    }
+
+    /**
+     * @returns {number} - Y value of point
+     */
+    get y() {
+        return this.#y;
+    }
+
+    /**
+     * @param {number} target - New X value
+     */
+    set x(target) {
+        this.#x = target;
+    }  
+    
+    /**
+     * @param {number} target - New Y value
+     */
+    set y(target) {
+        this.#y = target;
+    }
+
+    /**
+     * This compare two points, and return compare result. 
+     * 
+     * @example (point(5, 4).compare(point(10, 10)) => point(5, 6))
+     * @param {point} target - Point to calculate 
+     * @returns {point} - Compare result
+     */
+    compare(target) {
+        return new point(
+            target.x - this.x,
+            target.y - this.y
+        );
+    }
+
+    /**
+     * This calculate distance between two points.
+     * 
+     * @param {point} target - Second point to calculate distance between
+     * @returns {number} - Distance between this point and given point
+     */
+    distance(target) {
+        const compared = this.compare(target);
+        const summary = Math.pow(compared.x, 2) + Math.pow(compared.y, 2);
+        const result = Math.sqrt(summary);
+
+        return result;
+    }
+}

+ 13 - 6
source/scripts/assets/screen.js

@@ -1,12 +1,17 @@
-import { view } from "./view.js";
 import { loading_screen } from "./loading-screen.js";
 
 export class screen {
     #root;
     #view;
-    
-    constructor(root) {
+    #loader;
+
+    constructor(root, loader) {
         this.#root = root;
+        this.#loader = loader;
+    }
+
+    get loader() {
+        return this.#loader;
     }
 
     get root() {
@@ -41,11 +46,13 @@ export class screen {
         this.#loading.hide();
     }
 
-    set view(target) {
-        if (!(target instanceof view)) {
-            throw new Error("Target must be instance of view.");
+    set view(which) {
+        if (typeof(which) !== "function") {
+            throw new Error("Target must be class extends view.");
         }
 
+        const target = new which(this);
+
         if (this.#loading.visible) {
             this.#change_view(target)
             return;

+ 2 - 9
source/scripts/assets/selector.js

@@ -5,19 +5,12 @@ import { shelf } from "./shelf.js";
 import { space } from "./space.js";
 
 export class selector extends view {
-    #manager;
-
     #shelf() {
-        this.#manager.view = new shelf(this.#manager);
+        this.manager.view = shelf;
     }
 
     #space() {
-        this.#manager.view = new space(this.#manager);
-    }
-
-    constructor(manager) {
-        super();
-        this.#manager = manager;
+        this.manager.view = space;
     }
 
     show() {

+ 2 - 9
source/scripts/assets/shelf.js

@@ -1,21 +1,14 @@
 import { cx_ui } from "./cx-ui";
 import { dictionary } from "./dictionary";
 import { phrase } from "./phrase";
-import { selector } from "./selector";
+import { selector } from "./selector.js";
 import { view } from "./view";
 
 export class shelf extends view {
-    #manager;
-
-    constructor(manager) {
-        super();
-        this.#manager = manager;
-    }
-
     show() {
         const back = new phrase("selector.return");
         const return_button = cx_ui.push("return", back, () => {
-            this.#manager.view = new selector(this.#manager);
+            this.manager.view = selector;
         });
         
         return return_button;

+ 57 - 6
source/scripts/assets/space-scene.js

@@ -1,19 +1,33 @@
 export class space_scene {
+    #manager;
     #renderer;
-    #canvas;
     #camera;
     #scene;
     #working;
     #framerate;
 
-    constructor(canvas, context) {
-        this.#framerate = 30;
-        this.#canvas = canvas;
+    constructor(manager) {
+        this.#manager = manager;
+
+        const canvas = manager.canvas;
+        const context = manager.context;
+
+        this.#framerate = 60;
         this.#renderer = new THREE.WebGLRenderer({canvas, context: context});
         this.#camera = new THREE.PerspectiveCamera(75, 1);
         this.#scene = new THREE.Scene();
-        
+       
+        this.set_room();
         this.update_size();
+        this.manager.mouse.add_listener((move) => this.#camera_rotate(move));
+    }
+
+    get manager() {
+        return this.#manager;
+    }
+
+    get #canvas() {
+        return this.manager.canvas;
     }
 
     update_size(width, height) {
@@ -39,9 +53,46 @@ export class space_scene {
         this.#working = false;
     }
 
+    set_room() {
+        const url = this.manager.loader.texture("example_room.jpg");
+        
+        const texture = new THREE.TextureLoader().load(url, () => {
+            texture.mapping = THREE.EquirectangularReflectionMapping;
+            texture.colorSpace = THREE.SRGBColorSpace;
+            this.scene.background = texture;    
+        });
+    }
+
+    get camera() {
+        return this.#camera;
+    }   
+
+    #animate() {
+    }
+
+    get maximum_rotation() {
+        return Math.PI / 3;
+    }
+
+    #camera_rotate(move) {
+        this.camera.rotation.reorder("YXZ");
+
+        this.camera.rotation.x -= move.y / 100;
+        this.camera.rotation.y -= move.x / 100;
+        
+        if (this.camera.rotation.x > this.maximum_rotation) {
+            this.camera.rotation.x = this.maximum_rotation;
+        }
+
+        if (this.camera.rotation.x < -this.maximum_rotation) {
+            this.camera.rotation.x = -this.maximum_rotation;
+        }
+    }
+
     #rendering() {
         const before = performance.now();
 
+        this.#animate();
         this.#renderer.render(this.#scene, this.#camera);
         
         if (!this.#working) {
@@ -50,7 +101,7 @@ export class space_scene {
 
         const after = performance.now();
         const delta = after - before;
-        const next = 1000 / 30 - ((delta >= 0) ? delta : 0);
+        const next = 1000 / this.#framerate - ((delta >= 0) ? delta : 0);
 
         setTimeout(() => {
             requestAnimationFrame(() => { this.#rendering(); });

+ 11 - 8
source/scripts/assets/space.js

@@ -3,23 +3,23 @@ import { cx_ui } from "./cx-ui.js";
 import { selector } from "./selector.js";
 import { phrase } from "./phrase.js";
 import { space_scene } from "./space-scene.js";
+import { controler } from "./controler.js";
 
 export class space extends view {
-    #manager;
     #canvas;
     #context;
     #scene;
     #on_resize;
-
-    constructor(manager) {
-        super();
-        this.#manager = manager;
-    }
+    #mouse;
 
     get canvas() {
         return this.#canvas;
     }
 
+    get mouse() {
+        return this.#mouse;
+    }
+
     get context() {
         return this.#context;
     }
@@ -45,17 +45,18 @@ export class space extends view {
 
         const back = new phrase("selector.return");
         const return_button = cx_ui.push("return", back, () => {
-            this.#manager.view = new selector(this.#manager);
+            this.manager.view = selector;
         });
 
         this.#canvas = cx_ui.canvas("space-render");
+        this.#mouse = new controler();
 
         ui.appendChild(return_button);
         render.appendChild(this.canvas);
 
         try {
             this.#init_canvas();
-            this.#scene = new space_scene(this.canvas, this.context);
+            this.#scene = new space_scene(this);
             this.update_size();
             this.#scene.start();
         } catch (fail) {
@@ -70,6 +71,7 @@ export class space extends view {
         }
 
         this.#on_resize = () => { this.update_size(); };
+        this.#mouse.enable();
         window.addEventListener("resize", this.#on_resize);
 
         return cx_ui.div("container", null, (container) => {
@@ -80,6 +82,7 @@ export class space extends view {
 
     destroy() {
         this.#scene.stop();
+        this.#mouse.clean();
         window.removeEventListener("resize", this.#on_resize);
     }
 }

+ 52 - 0
source/scripts/assets/view.js

@@ -1,8 +1,60 @@
+import { screen } from "./screen.js";
+import { assets_getter } from "./assets-getter.js";
+
 export class view {
+    #manager;
+
+    /**
+     * This function build new view instance. Basically, it require view
+     * manager, and assets loader. Views are builded by screen manager, 
+     * when view on screen had been changing.
+     *  
+     * @param {screen} manager - Screen manager
+     */
+    constructor(manager) {
+        if (!(manager instanceof screen)) {
+            throw new TypeError("Screen manager is in bad type.");
+        }
+
+        this.#manager = manager;
+    }
+
+    /**
+     * @returns {screen} - This return screen manager
+     */
+    get manager() {
+        return this.#manager;
+    }
+
+    /** 
+     * Determinate that view is ready to interaction after show function. 
+     * When return true, then after show() function manager would 
+     * 
+     * @returns {bool} - True 
+     */
+
+    /**
+     * @returns {assets_getter} - This return assets loader
+     */
+    get loader() {
+        return this.#manager.loader;
+    }
+
+    /**
+     * This function is responsible for creating new view items.
+     * 
+     * @abstract
+     * @returns {HTMLElement} - New view container
+     */
     show() {
         throw new Error("This function must be override.");
     }
 
+    /**
+     * This function is responsibke for cleanup after view. It is empty by
+     * default, but when it is required, it can be overwrite. It is called
+     * before view destroy.
+     */
     destroy() {
 
     }

+ 2 - 2
source/scripts/loader.js

@@ -10,10 +10,10 @@ document.addEventListener("DOMContentLoaded", () => {
     }
 
     const app = document.querySelector(".app");
-    const view_manager = new screen(app);
     const assets_loader = new assets_getter(document.location.href);
+    const view_manager = new screen(app, assets_loader);
 
     setTimeout(() => {
-        view_manager.view = new selector(view_manager);
+        view_manager.view = selector;
     }, 500);
 });