three js frog for fun
This commit is contained in:
@@ -7,8 +7,9 @@
|
|||||||
<title>Pixel War</title>
|
<title>Pixel War</title>
|
||||||
<link rel="stylesheet" href="/src/style.css" />
|
<link rel="stylesheet" href="/src/style.css" />
|
||||||
</head>
|
</head>
|
||||||
<body class="flex flex-col items-center justify-center min-h-screen bg-slate-100">
|
<body class="relative flex flex-col items-center justify-center min-h-screen bg-slate-100">
|
||||||
<div class="flex flex-wrap gap-2 p-2">
|
<div id="challenge" class="absolute z-10 w-full min-h-screen"></div>
|
||||||
|
<div class="z-20 flex flex-wrap gap-2 p-2">
|
||||||
<button id="red" class="w-8 h-8 bg-red-500 border border-black shadow"></button>
|
<button id="red" class="w-8 h-8 bg-red-500 border border-black shadow"></button>
|
||||||
<button id="green" class="w-8 h-8 bg-green-500 border border-black shadow"></button>
|
<button id="green" class="w-8 h-8 bg-green-500 border border-black shadow"></button>
|
||||||
<button id="blue" class="w-8 h-8 bg-blue-500 border border-black shadow"></button>
|
<button id="blue" class="w-8 h-8 bg-blue-500 border border-black shadow"></button>
|
||||||
@@ -22,20 +23,20 @@
|
|||||||
<button id="brown" class="w-8 h-8 bg-orange-800 border border-black shadow"></button>
|
<button id="brown" class="w-8 h-8 bg-orange-800 border border-black shadow"></button>
|
||||||
<input class="w-8 h-8 border border-black shadow" type="color" id="color-picker" value="#000000" />
|
<input class="w-8 h-8 border border-black shadow" type="color" id="color-picker" value="#000000" />
|
||||||
</div>
|
</div>
|
||||||
<p>Your selected color <span id="current-color-span" class="text-white">COLOR</span></p>
|
<p class="z-20">Your selected color <span id="current-color-span" class="text-white">COLOR</span></p>
|
||||||
<div id="countdown">You can place a pixel now</div>
|
<div id="countdown" class="z-20">You can place a pixel now</div>
|
||||||
<div class="flex items-center gap-2 mx-1 my-4">
|
<div class="z-20 flex items-center gap-2 mx-1 my-4">
|
||||||
<label for="toggle-grid">Toggle Grid</label>
|
<label for="toggle-grid">Toggle Grid</label>
|
||||||
<input id="toggle-grid" type="checkbox" />
|
<input id="toggle-grid" type="checkbox" />
|
||||||
<button id="place-pixel" class="px-2 py-1 rounded-md shadow-lg bg-cyan-400 hover:bg-cyan-500 active:bg-cyan-600">Place Pixel</button>
|
<button id="place-pixel" class="px-2 py-1 rounded-md shadow-lg bg-cyan-400 hover:bg-cyan-500 active:bg-cyan-600">Place Pixel</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-1">
|
<div class="z-20 flex gap-1">
|
||||||
<p id="coords"></p>
|
<p id="coords"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative p-1 rainbow-border">
|
<div class="relative z-20 p-1 rainbow-border">
|
||||||
<canvas class="bg-white rounded-md" id="canvas" width="500" height="500"></canvas>
|
<canvas class="bg-white rounded-md" id="canvas" width="500" height="500"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 p-2">
|
<div class="z-20 flex flex-col gap-2 p-2">
|
||||||
<p>Current soldiers: <span id="current-soldiers" class="font-bold">0</span></p>
|
<p>Current soldiers: <span id="current-soldiers" class="font-bold">0</span></p>
|
||||||
<button id="save-canvas" class="px-2 py-1 bg-green-400 rounded-md shadow-lg hover:bg-green-500 active:bg-green-600">Save Canvas</button>
|
<button id="save-canvas" class="px-2 py-1 bg-green-400 rounded-md shadow-lg hover:bg-green-500 active:bg-green-600">Save Canvas</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"vite": "^5.2.0"
|
"vite": "^5.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"socket.io-client": "^4.7.5"
|
"socket.io-client": "^4.7.5",
|
||||||
|
"three": "^0.164.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
painter-js/pnpm-lock.yaml
generated
8
painter-js/pnpm-lock.yaml
generated
@@ -11,6 +11,9 @@ importers:
|
|||||||
socket.io-client:
|
socket.io-client:
|
||||||
specifier: ^4.7.5
|
specifier: ^4.7.5
|
||||||
version: 4.7.5
|
version: 4.7.5
|
||||||
|
three:
|
||||||
|
specifier: ^0.164.1
|
||||||
|
version: 0.164.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.19
|
specifier: ^10.4.19
|
||||||
@@ -714,6 +717,9 @@ packages:
|
|||||||
thenify@3.3.1:
|
thenify@3.3.1:
|
||||||
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
|
||||||
|
|
||||||
|
three@0.164.1:
|
||||||
|
resolution: {integrity: sha512-iC/hUBbl1vzFny7f5GtqzVXYjMJKaTPxiCxXfrvVdBi1Sf+jhd1CAkitiFwC7mIBFCo3MrDLJG97yisoaWig0w==}
|
||||||
|
|
||||||
to-regex-range@5.0.1:
|
to-regex-range@5.0.1:
|
||||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||||
engines: {node: '>=8.0'}
|
engines: {node: '>=8.0'}
|
||||||
@@ -1411,6 +1417,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
any-promise: 1.3.0
|
any-promise: 1.3.0
|
||||||
|
|
||||||
|
three@0.164.1: {}
|
||||||
|
|
||||||
to-regex-range@5.0.1:
|
to-regex-range@5.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|||||||
BIN
painter-js/src/Astronaut.glb
Normal file
BIN
painter-js/src/Astronaut.glb
Normal file
Binary file not shown.
139
painter-js/src/challenge.js
Normal file
139
painter-js/src/challenge.js
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import "./counter.js";
|
|||||||
import { updateCountdown } from "./counter.js";
|
import { updateCountdown } from "./counter.js";
|
||||||
import { checkEndpoint, pixelSize } from "./constants.js";
|
import { checkEndpoint, pixelSize } from "./constants.js";
|
||||||
import { handleSocketEvents } from "./canvas.js";
|
import { handleSocketEvents } from "./canvas.js";
|
||||||
|
import "./challenge.js"
|
||||||
|
|
||||||
const isDebug = import.meta.env.VITE_IS_DEBUG === "true";
|
const isDebug = import.meta.env.VITE_IS_DEBUG === "true";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user