Three.jsとCannonjsを使用したメタバスコンストラクタ(1/?)


開始前の簡単な紹介項目


Metabusでは、中古品をオークションにかけてリアルタイムで販売・購入できるアイテムです.

なぜMetabusなの?


オークションの入札方式では、公開入札方式の特徴は面と向かって、リアルタイムで行うことである.3 D仮想空間と私の仮想マシンを作成することで、似たような環境を作成できると考えています.

ゲームエンジンみたい(?)作成


本当はCannon jsを放さなければならないのか悩んでいます.最初に使用したライブラリなので、開発時間が遅くなり、パフォーマンスも低下します.しかし,これは実際のサービスよりも学習目的のあるプロジェクトであり,ユーザが複数のオブジェクトとのインタラクションを楽しむことを望んでいるため,直接採用した.

Three.jsは簡単な設定から


設定する前に、簡単なテクノロジースタックを分析します.
  • Typescript-は現在不可欠な重要な友人である.自動完了からコードメンテナンスまで、彼には多くの利点があります.
  • Three.js-3 Dグラフィックスを実現するために、WebGLというライブラリを使用して開発されます.このライブラリのレベルが低すぎて、WebGLをより使いやすくします.jsを使用しました.
  • Cannon.js-3 D物理エンジンライブラリ.Cannonは3 D物理エンジンの開発に十分な数学的知識と時間を持っていない.jsという名前のライブラリを使用しました.
  • Parcel-設定なしで使用できるバンドルパッケージ.多くの人がWebpackのようなパッケージを使用していますが、パッケージ設定で時間を使いたくないので、今は使いやすいParelパッケージを使用しています.
  • まず再配置しましょう。


    主にES 6クラスを用いて開発されている.従来のプロジェクトとは異なり,コード設計と開発を行うためにコードメンテナンスのモジュール化を重視する.
    まずはThreejsのデフォルト設定はRender、Scene、Cameraです.
    /src/index.ts
    
    import * as THREE from 'three';
    
    class Main {
    	renderer: THREE.WebGLRenderer;
        camera: THREE.PerspectiveCamera;
        scene: THREE.Scene;
        
        constructor() {
        	this.renderer = new THREE.WebGLRenderer();
            this.renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(this.renderer.domElement);
            
            this.camera = new THREE.PerspectiveCamera(
                75,
                window.innerWidth / window.innerHeight,
                0.1,
                1000
            );
            this.camera.position.z = 10;
            this.camera.position.y = 5;
            this.camera.lookAt(new THREE.Vector3(0, 0, 0));
            
            this.scene = new THREE.Scene();
        
        	this.init();
        }
        
        init() {
        	this.animate();
        }
        
        animate() {
        	this.renderer.render(this.scene, this.camera);
            
            requestAnimationFrame(this.animate.bind(this));
        }
    }
    
    //@ts-ignore
    window.m = new Main();
    基本的なThreejs設定終了Cannonjsもセットしておきましょう
    /src/physicsManager.ts
    
    import * as CANNON from 'cannon-es';
    
    export class PhysicsManager {
        world: CANNON.World;
    
        constructor() {
            this.world = new CANNON.World();
    
            this.init();
        }
    
        init() {
            this.world.gravity.set(0, -9, 0);
        }
    
        animate(delta: number) {
            this.world.step(1 / 60, delta, 5);
        }
    }
    Main Classでインスタンスを作成します.
    /src/index.ts
    
    import { PhysicsManager } from './physcisManager';
    
    class Main {
        physicsManager: PhysicsManager;
        clock: THREE.Clock;
        lastTime: number;
        
        constructor() {
            this.clock = new THREE.Clock();
            this.lastTime = 0;
            
            this.physicsManager = new PhysicsManager();
        }
        
        animate() {
            const currentTime = this.clock.getElapsedTime();
            const delta = currentTime - this.lastTime;
            this.lastTime = currentTime;
        
        	this.physicsManager.animate(delta);
        }
    }
    
    ...

    Three.jsとCannonjsを加算する


    Three.jsとCannonjsは独立したライブラリです.Cannonだからjsで計算したEntity情報とThreeを利用する.js情報は従属でなければ、私たちが考えているゲームエンジンを生成できません.この依存管理はEntityというクラスで行います.
    /src/entityManager/Entity.ts
    
    import * as CANNON from 'cannon-es';
    import * as THREE from 'three';
    import { Utils } from "../utils";
    
    interface Option {
        type?: CannonShapeType;
        mass?: number;
    }
    
    export class Entity {
        three: THREE.Object3D;
        cannon: CANNON.Body;
        sizeVector?: THREE.Vector3;
    
        constructor(three: Object3D, cannon: CANNON.Body) {
            this.three = three,
            this.cannon = cannon;
    
            this.init();
        }
    
        init() {
            this.three.traverse(child => {
                child.castShadow = true;
                child.receiveShadow = true;
            });
        }
    
        animate() {
            this.three.position.copy(Utils.cToT().vector3(this.cannon.position));
            this.three.quaternion.copy(Utils.cToT().quaternion(this.cannon.quaternion));
        }
    }
    これらのEntityインスタンスはEntity Managerクラスによって管理されます.
    /src/entityManager/index.ts
    
    import * as CANNON from 'cannon-es';
    import * as THREE from 'three';
    import { threeToCannon, ShapeType as CannonShapeType } from 'three-to-cannon';
    import { Entity } from "./entity";
    import { Utils } from "../utils";
    
    interface Option {
        type?: CannonShapeType;
        mass?: number;
    }
    
    export class EntityManager {
        world: CANNON.World;
        scene: THREE.Scene;
        entities: Entity[];
    
        constructor(scene: THREE.Scene, world: CANNON.World) {
            this.world = world;
            this.scene = scene;
            this.entities = [];
        }
    
        addObject3D(object: THREE.Object3D, option?: Option) {
            const result = threeToCannon(object as any, { type: option?.type });
            const body = new CANNON.Body({
                mass: option?.mass ?? 1,
                position: result?.offset,
                shape: result?.shape,
            });
            this.world.addBody(body);
    
            const entity = new Entity(object, body);
            this.scene.add(object);
    
            this.entities.push(entity);
    
            return entity;
        }
    
        animate() {
            this.entities.forEach(e => e.animate());
        }
    }
    Main Classでインスタンスを作成します.
    /src/index.ts
    
    import { EntityManager } from './entityManager';
    
    class Main {
        entityManager: EntityManager;
        
        constructor() {
            this.entityManager = new EntityManager(this.scene, this.physicsManager.world);
        }
        
        animate() {
        	this.entityManager.animate();
        }
    }
    
    ...
    操作検証のためにDirectionLightを追加し、EntityManagerインスタンスを使用して簡単な球と立方体を追加します.
    /src/index.ts
    
    import { ShapeType } from 'three-to-cannon';
    
    class Main {
        constructor() {
        	this.scene.add(new THREE.DirectionalLight(0xffffff));
            
            this.entityManager.addObject3D(
            	new THREE.Mesh(
                	new THREE.SphereGeometry(.2), 
                    new THREE.MeshToonMaterial()
                ), 
                { 
                	mass: .5, 
                    type: ShapeType.SPHERE 
                }
            ).cannon.position.y = 5;
        
            this.entityManager.addObject3D(
            	new THREE.Mesh(
                	new THREE.BoxGeometry(10, .1, 10), 
                    new THREE.MeshToonMaterial()
                ), 
                { 
                	mass: 0, 
                    type: ShapeType.BOX
                }
            );
        }
    }
    
    ...
    CodeSandbox: https://codesandbox.io/s/runtime-resonance-znjb4h?file=/src/index.ts
    Project Github: https://github.com/syi0808/MetaAuction
    次の開発エピソードは必要な人がいたら書きますモデル物理エンジンとモデルの作成に関連する場合があります.
    気になる質問があればメッセージをお願いします
    フロントエンド開発者名芸能人.
    Intro: https://notion.castle-monkey.shop
    Github: https://github.com/syi0808
    Contact: [email protected]