diff --git a/painter-js/index.html b/painter-js/index.html index 6ff48a0..ab2608c 100644 --- a/painter-js/index.html +++ b/painter-js/index.html @@ -7,8 +7,9 @@ Pixel War - -
+ +
+
@@ -22,20 +23,20 @@
-

Your selected color COLOR

-
You can place a pixel now
-
+

Your selected color COLOR

+
You can place a pixel now
+
-
+

-
+
-
+

Current soldiers: 0

diff --git a/painter-js/package.json b/painter-js/package.json index 6a2ff50..3688d4a 100644 --- a/painter-js/package.json +++ b/painter-js/package.json @@ -16,6 +16,7 @@ "vite": "^5.2.0" }, "dependencies": { - "socket.io-client": "^4.7.5" + "socket.io-client": "^4.7.5", + "three": "^0.164.1" } } diff --git a/painter-js/pnpm-lock.yaml b/painter-js/pnpm-lock.yaml index 3d62c51..6819446 100644 --- a/painter-js/pnpm-lock.yaml +++ b/painter-js/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: socket.io-client: specifier: ^4.7.5 version: 4.7.5 + three: + specifier: ^0.164.1 + version: 0.164.1 devDependencies: autoprefixer: specifier: ^10.4.19 @@ -714,6 +717,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + three@0.164.1: + resolution: {integrity: sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1411,6 +1417,8 @@ snapshots: dependencies: any-promise: 1.3.0 + three@0.164.1: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 diff --git a/painter-js/src/Astronaut.glb b/painter-js/src/Astronaut.glb new file mode 100644 index 0000000..b0b85d7 Binary files /dev/null and b/painter-js/src/Astronaut.glb differ diff --git a/painter-js/src/challenge.js b/painter-js/src/challenge.js new file mode 100644 index 0000000..e6494df --- /dev/null +++ b/painter-js/src/challenge.js @@ -0,0 +1,139 @@ +import * as three from 'three'; +import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; + +let scene, camera, renderer, character, mixer, clock; +let walkAction, idleAction; +let moving = false; +const keys = {} + +let boxes = []; + +const container = document.getElementById('challenge'); + +const onWindowResize = () => { + camera.aspect = container.clientWidth / container.clientHeight; + camera.updateProjectionMatrix(); + renderer.setSize(container.clientWidth, container.clientHeight); +} + +const onKeyDown = (e) => { + keys[e.code] = true; +} + +const onKeyUp = (e) => { + keys[e.code] = false; +} + +const init = () => { + scene = new three.Scene(); + camera = new three.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); + renderer = new three.WebGLRenderer({ antialias: true}); + renderer.setSize(window.innerWidth, window.innerHeight); + container.appendChild(renderer.domElement); + + clock = new three.Clock(); + + // Adjust light positions and intensity + const light = new three.DirectionalLight(0xffffff, 1); + light.position.set(5, 10, 7.5); + light.castShadow = true; + scene.add(light); + + + + for (let i = 0; i < 10; i++) { + const box = new three.Mesh( + new three.BoxGeometry(1, 1, 1), + new three.MeshStandardMaterial({ color: 0x00ff00 }) + ); + box.position.set(Math.random() * 10 - 5, 0.5, Math.random() * 10 - 5); + box.castShadow = true; + scene.add(box); + boxes.push(box); + } + + const loader = new GLTFLoader(); + loader.load('src/Astronaut.glb',(gltf) => { + character = gltf.scene; + scene.add(character); + + mixer = new three.AnimationMixer(character); + gltf.animations.forEach((clip) => { + if (clip.name === 'CharacterArmature|Walk') { + walkAction = mixer.clipAction(clip); + } + if (clip.name === 'CharacterArmature|Idle') { + idleAction = mixer.clipAction(clip); + } + }); + + if (walkAction) walkAction.play(); + if (idleAction) idleAction.play(); + + character.position.set(-10, 0, -60); + character.rotation.y = Math.PI; + }) + + //blue sky + scene.background = new three.Color(0x87ceeb); + + camera.position.set(20, 10, 10) + camera.lookAt(0, 10, 0) + + window.addEventListener('resize', onWindowResize, false); + document.addEventListener('keydown', onKeyDown, false); + document.addEventListener('keyup', onKeyUp, false); +} + +const animate = () => { + requestAnimationFrame(animate); + + const delta = clock.getDelta(); + if (mixer) mixer.update(delta); + + if (character) { + if (keys['KeyW']) { + character.position.z -= 0.1; + character.rotation.y = Math.PI; // North + } + + if (keys['KeyS']) { + character.position.z += 0.1; + character.rotation.y = 0; // South + } + + if (keys['KeyA']) { + character.position.x -= 0.1; + character.rotation.y = Math.PI / 2; // West + } + + if (keys['KeyD']) { + character.position.x += 0.1; + character.rotation.y = -Math.PI / 2; // East + } + + // check if any key is pressed + if (keys['KeyW'] || keys['KeyS'] || keys['KeyA'] || keys['KeyD']) { + moving = true; + } else { + moving = false; + } + + // Play walking animation if moving + if (mixer) { + if (walkAction && idleAction) { + walkAction.enabled = moving; + idleAction.enabled = !moving; + } + } + } + + renderer.render(scene, camera); +} + +const threejs = import.meta.env.VITE_THREE_JS === "true"; +if (threejs) { + init(); + animate(); +} diff --git a/painter-js/src/main.js b/painter-js/src/main.js index 2c55247..99c1b20 100644 --- a/painter-js/src/main.js +++ b/painter-js/src/main.js @@ -4,6 +4,7 @@ import "./counter.js"; import { updateCountdown } from "./counter.js"; import { checkEndpoint, pixelSize } from "./constants.js"; import { handleSocketEvents } from "./canvas.js"; +import "./challenge.js" const isDebug = import.meta.env.VITE_IS_DEBUG === "true";