Untitled

 avatar
unknown
html
a year ago
13 kB
24
Indexable
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>MULTIPLAYER ENABLE3D</title>
  <link rel="stylesheet" href="/css/examples.css" />
  <style>
    /* Centering using CSS */
    .centered {
      text-align: center;
    }
  </style>
  <script src="/lib/enable3d/enable3d.framework.0.25.4.min.js"></script>
  <script src="/js/examples.js"></script>
</head>
<body>
  <div class="centered" id="info-text">Use WASD, SPACE and your Mouse.<br />Try to play it on your mobile device :)</div>
  <br>
  <br>
  <br>
  <div class="centered" id="forms">
    <div id="login-form">
      <h2>Login</h2>
      <input type="text" id="login-username" placeholder="Username" /><br><Br>
      <input type="password" id="login-password" placeholder="Password" /><Br><Br><Br>
      <button onclick="login()">Login</button>
      <p><a href="#" onclick="toggleForms()">Register</a></p>
    </div>
    <div id="register-form" style="display:none;">
      <h2>Register</h2>
      <input type="text" id="register-username" placeholder="Username" /><Br><Br>
      <input type="password" id="register-password" placeholder="Password" /><Br><Br><Br>
      <button onclick="register()">Register</button>
      <p><a href="#" onclick="toggleForms()">Login</a></p>
    </div>
  </div>

  <script>
    function toggleForms() {
      const loginForm = document.getElementById('login-form');
      const registerForm = document.getElementById('register-form');
      loginForm.style.display = loginForm.style.display === 'none' ? 'block' : 'none';
      registerForm.style.display = registerForm.style.display === 'none' ? 'block' : 'none';
    }

    async function login() {
      const username = document.getElementById('login-username').value;
      const password = document.getElementById('login-password').value;
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      });
      const result = await response.json();
      if (result.success) {
        initGame(result.user);
        alert("Login success");
      } else {
        alert('Login failed');
      }
    }

    async function register() {
      const username = document.getElementById('register-username').value;
      const password = document.getElementById('register-password').value;
      const response = await fetch('/api/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      });
      const result = await response.json();
      if (result.success) {
        toggleForms();
      } else {
        alert('Registration failed');
      }
    }

    function initGame(user) {
      document.getElementById('forms').style.display = 'none';
      document.getElementById('info-text').style.display = 'none';
      // Initialize the game with user data
      startGame(user);
    }

    function startGame(user) {
      const { Project, PhysicsLoader, Scene3D, ExtendedObject3D, THREE, JoyStick, ThirdPersonControls, PointerLock, PointerDrag } = ENABLE3D;
      class MainScene extends Scene3D {
        constructor() {
          super('MainScene');
          this.user = user;
        }
		

        async init() {
          this.renderer.setPixelRatio(Math.max(1, window.devicePixelRatio / 2));
          this.canJump = true;
          this.move = false;
          this.moveTop = 0;
          this.moveRight = 0;
        }

        async preload() {
          try {
            const map = this.load.preload('map', '/assets/glb/map.glb');
            const character = this.load.preload('character', '/assets/glb/character.glb');
            await Promise.all([map, character]);
          } catch (error) {
            console.error('Error loading assets:', error);
          }
        }

        async create() {
          console.log("Creating scene...");
          await this.preload();

          const { lights } = await this.warpSpeed('-ground', '-orbitControls');
          const { hemisphereLight, ambientLight, directionalLight } = lights;
          const intensity = 1;
          hemisphereLight.intensity = intensity;
          ambientLight.intensity = intensity;
          directionalLight.intensity = intensity;

          const addMap = async () => {
            const object = await this.load.gltf('map');
            const scene = object.scenes[0];
            const map = new ExtendedObject3D();
            map.name = 'scene';
            map.add(scene);
            this.add.existing(map);
            object.animations.forEach((anim, i) => {
              map.mixer = this.animationMixers.create(map);
              map.action = [];
              map.action[i] = map.mixer.clipAction(anim);
              map.action[i].play();
            });
            map.traverse(child => {
              if (child.isMesh) {
                child.castShadow = child.receiveShadow = false;
                child.material.metalness = 0;
                child.material.roughness = 1;
                if (/mesh/i.test(child.name)) {
                  this.physics.add.existing(child, {
                    shape: 'concave',
                    mass: 0,
                    collisionFlags: 1,
                    autoCenter: false
                  });
                  child.body.setAngularFactor(0, 0, 0);
                  child.body.setLinearFactor(0, 0, 0);
                }
              }
            });
          };

          const addCharacter = async () => {
            const object = await this.load.gltf('character');
            const character = object.scene.children[0];
            this.character = new ExtendedObject3D();
            this.character.name = 'character';
            this.character.rotateY(Math.PI + 0.1);
            this.character.add(character);
            this.character.rotation.set(0, Math.PI * 1.5, 0);
            this.character.position.set(this.user.position.x, this.user.position.y, this.user.position.z);
            this.character.traverse(child => {
              if (child.isMesh) {
                child.castShadow = child.receiveShadow = false;
                child.material.roughness = 1;
                child.material.metalness = 0;
              }
            });
            this.animationMixers.add(this.character.animation.mixer);
            object.animations.forEach(animation => {
              if (animation.name) {
                this.character.animation.add(animation.name, animation);
              }
            });
            this.character.animation.play('idle');
            this.add.existing(this.character);
            this.physics.add.existing(this.character, {
              shape: 'sphere',
              radius: 0.25,
              width: 0.5,
              offset: { y: -0.25 }
            });
            this.character.body.setFriction(0.8);
            this.character.body.setAngularFactor(0, 0, 0);
            this.character.body.setCcdMotionThreshold(1e-7);
            this.character.body.setCcdSweptSphereRadius(0.25);
            this.controls = new ThirdPersonControls(this.camera, this.character, {
              offset: new THREE.Vector3(0, 1, 0),
              targetRadius: 3
            });
            this.controls.theta = 90;
            if (!isTouchDevice) {
              let pl = new PointerLock(this.canvas);
              let pd = new PointerDrag(this.canvas);
              pd.onMove(delta => {
                if (pl.isLocked()) {
                  this.controls.update(delta.x * 2, delta.y * 2);
                }
              });
            }
          };

          await addMap();
          await addCharacter();

          this.keys = {
            w: { isDown: false },
            a: { isDown: false },
            s: { isDown: false },
            d: { isDown: false },
            space: { isDown: false }
          };

          const press = (e, isDown) => {
            e.preventDefault();
            const { keyCode } = e;
            switch (keyCode) {
              case 87:
                this.keys.w.isDown = isDown;
                break;
              case 38:
                this.keys.w.isDown = isDown;
                break;
              case 32:
                this.keys.space.isDown = isDown;
                break;
            }
          };

          document.addEventListener('keydown', e => press(e, true));
          document.addEventListener('keyup', e => press(e, false));

          if (isTouchDevice) {
            const joystick = new JoyStick();
            const axis = joystick.add.axis({
              styles: { left: 35, bottom: 35, size: 100 }
            });
            axis.onMove(event => {
              const { top, right } = event;
              this.moveTop = top * 3;
              this.moveRight = right * 3;
            });
            const buttonA = joystick.add.button({
              letter: 'A',
              styles: { right: 35, bottom: 110, size: 80 }
            });
            buttonA.onClick(() => this.jump());
            const buttonB = joystick.add.button({
              letter: 'B',
              styles: { right: 110, bottom: 35, size: 80 }
            });
            buttonB.onClick(() => (this.move = true));
            buttonB.onRelease(() => (this.move = false));
          }

          setTimeout(() => {
            const placeholder = document.getElementById('welcome-game-placeholder');
            if (placeholder) placeholder.remove();
          }, 500);
        }

        jump() {
          if (!this.character || !this.canJump) return;
          this.canJump = false;
          this.character.animation.play('jump_running', 500, false);
          setTimeout(() => {
            this.canJump = true;
            this.character.animation.play('idle');
          }, 650);
          this.character.body.applyForceY(6);
        }

        update(time, delta) {
          if (this.character && this.character.body) {
            this.controls.update(this.moveRight * 2, -this.moveTop * 2);
            const speed = 4;
            const v3 = new THREE.Vector3();
            const rotation = this.camera.getWorldDirection(v3);
            const theta = Math.atan2(rotation.x, rotation.z);
            const rotationcharacter = this.character.getWorldDirection(v3);
            const thetacharacter = Math.atan2(rotationcharacter.x, rotationcharacter.z);
            this.character.body.setAngularVelocityY(0);
            const l = Math.abs(theta - thetacharacter);
            let rotationSpeed = isTouchDevice ? 2 : 4;
            let d = Math.PI / 24;
            if (l > d) {
              if (l > Math.PI - d) rotationSpeed *= -1;
              if (theta < thetacharacter) rotationSpeed *= -1;
              this.character.body.setAngularVelocityY(rotationSpeed);
            }
            if (this.keys.w.isDown || this.move) {
              if (this.character.animation.current === 'idle' && this.canJump) this.character.animation.play('run');
              const x = Math.sin(theta) * speed, y = this.character.body.velocity.y, z = Math.cos(theta) * speed;
              this.character.body.setVelocity(x, y, z);
            } else {
              if (this.character.animation.current === 'run' && this.canJump) this.character.animation.play('idle');
            }
            if (this.keys.space.isDown && this.canJump) {
              this.jump();
            }
            savePlayerState(this.user._id, this.character.position);
          }
        }
      }

      window.addEventListener('load', async () => {
        await PhysicsLoader('/lib/ammo/kripken');

        const project = new Project({
          antialias: false,
          maxSubSteps: 10,
          fixedTimeStep: 1 / 120,
          scenes: [MainScene]
        });

        // Since MainScene is constructed internally, you need to hook into it after initialization
        project.scenes.forEach(scene => {
          scene.on('start', async () => {
            await scene.create(); // Ensure create() is called after everything is loaded
          });
        });
      });

      async function savePlayerState(userId, position) {
        await fetch('/api/save', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ userId, position })
        });
      }
    }
  </script>
</body>
</html>
Editor is loading...
Leave a Comment