+
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";