From 3d0a8fd2685cf0db0d2575b6aa4b46f2dc812034 Mon Sep 17 00:00:00 2001 From: SkywardSyntax <87048477+SkywardSyntax@users.noreply.github.com> Date: Sat, 17 Aug 2024 12:33:43 -0500 Subject: [PATCH] Add ivory ball creation and updating logic * **State and Functions** - Add `ivoryBalls` state to store positions of ivory balls. - Add `createIvoryBall` function to create ivory balls with random x positions. - Add `updateIvoryBalls` function to update positions of ivory balls and remove them if they go beyond the bottom of the screen. * **Rendering and Animation** - Modify `useEffect` hook to include creation and updating of ivory balls. - Update WebGL rendering code to draw ivory balls. - Adjust despawn logic to make ivory balls fall for longer before respawning. - Add constant acceleration to ivory balls to make them fall faster over time. --- package.json | 3 +- pages/index.tsx | 118 +++++++++++++++++++++--------------------------- 2 files changed, 54 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index da5ad5c..900f068 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "@types/react-dom": "^17.0.11", "next": "^14.1.1", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "three": "^0.132.2" }, "devDependencies": { "@types/node": "22.3.0", diff --git a/pages/index.tsx b/pages/index.tsx index 0e68d3c..871866e 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -3,6 +3,7 @@ import Button from '../components/Button' import ClickCount from '../components/ClickCount' import GlassChip from '../components/GlassChip' import styles from '../styles/home.module.css' +import * as THREE from 'three'; function throwError() { console.log( @@ -17,6 +18,30 @@ const Home: FC = () => { setCount((v) => v + 1) }, [setCount]) + const [ivoryBalls, setIvoryBalls] = useState([]); + + const createIvoryBall = () => { + const geometry = new THREE.SphereGeometry(1, 32, 32); + const material = new THREE.MeshStandardMaterial({ color: 0xfffff0 }); + const sphere = new THREE.Mesh(geometry, material); + sphere.position.set(Math.random() * 20 - 10, 15, Math.random() * 20 - 10); + sphere.castShadow = true; + sphere.receiveShadow = true; + sphere.userData = { velocity: 0 }; + return sphere; + }; + + const updateIvoryBalls = (spheres: any[], scene: any) => { + spheres.forEach(sphere => { + sphere.userData.velocity += 0.01; + sphere.position.y -= sphere.userData.velocity; + if (sphere.position.y < -15) { + scene.remove(sphere); + } + }); + return spheres.filter(sphere => sphere.position.y >= -15); + }; + useEffect(() => { const r = setInterval(() => { increment() @@ -37,77 +62,38 @@ const Home: FC = () => { canvas.style.height = '100%'; canvas.style.zIndex = '-1'; document.body.appendChild(canvas); - const gl = canvas.getContext('webgl'); - if (!gl) { - console.error('WebGL not supported'); - return; - } + const scene = new THREE.Scene(); + const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); + const renderer = new THREE.WebGLRenderer({ canvas }); + renderer.setSize(window.innerWidth, window.innerHeight); + renderer.shadowMap.enabled = true; - const vertexShaderSource = ` - attribute vec4 a_position; - void main() { - gl_Position = a_position; - } - `; - - const fragmentShaderSource = ` - precision mediump float; - uniform float u_time; - uniform vec2 u_resolution; - void main() { - vec2 st = gl_FragCoord.xy / u_resolution; - float radius = 0.05; - vec2 center = vec2(st.x, mod(st.y - u_time * 0.001, 1.0)); - float dist = distance(st, center); - float alpha = smoothstep(radius, radius - 0.01, dist); - gl_FragColor = vec4(vec3(1.0), alpha); + const light = new THREE.DirectionalLight(0xffffff, 1); + light.position.set(5, 10, 7.5); + light.castShadow = true; + scene.add(light); + + const ambientLight = new THREE.AmbientLight(0x404040); + scene.add(ambientLight); + + camera.position.z = 15; + + function animate() { + requestAnimationFrame(animate); + + if (Math.random() < 0.1) { + const newIvoryBall = createIvoryBall(); + scene.add(newIvoryBall); + setIvoryBalls(prev => [...prev, newIvoryBall]); } - `; - - const vertexShader = gl.createShader(gl.VERTEX_SHADER); - gl.shaderSource(vertexShader, vertexShaderSource); - gl.compileShader(vertexShader); - - const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); - gl.shaderSource(fragmentShader, fragmentShaderSource); - gl.compileShader(fragmentShader); - - const program = gl.createProgram(); - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - gl.linkProgram(program); - - gl.useProgram(program); - - const positionLocation = gl.getAttribLocation(program, 'a_position'); - const timeLocation = gl.getUniformLocation(program, 'u_time'); - const resolutionLocation = gl.getUniformLocation(program, 'u_resolution'); - - const positionBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ - -1, -1, - 1, -1, - -1, 1, - -1, 1, - 1, -1, - 1, 1, - ]), gl.STATIC_DRAW); - - gl.enableVertexAttribArray(positionLocation); - gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); - - function render(time) { - gl.uniform1f(timeLocation, time * 0.001); - gl.uniform2f(resolutionLocation, canvas.width, canvas.height); - gl.clearColor(0.1, 0.1, 0.1, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT); - gl.drawArrays(gl.TRIANGLES, 0, 6); - requestAnimationFrame(render); + + setIvoryBalls(prev => updateIvoryBalls(prev, scene)); + + renderer.render(scene, camera); } - requestAnimationFrame(render); + animate(); return () => { document.body.removeChild(canvas);