diff --git a/src/app/components/Fruits/Fruits.tsx b/src/app/components/Fruits/Fruits.tsx index 9f88adb..eb61078 100644 --- a/src/app/components/Fruits/Fruits.tsx +++ b/src/app/components/Fruits/Fruits.tsx @@ -1,15 +1,14 @@ 'use client'; import './Fruits.scss'; -import { useEffect, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import Matter, { - Common, Mouse, MouseConstraint, - Vertices, + Vertices, Events, Body, - Query + Query, } from 'matter-js'; import 'pathseg'; @@ -18,17 +17,25 @@ import createEllipseVertices from './createEllipseVertices'; export default function Fruits() { const scene = useRef(null); - Common.setDecomp(require('poly-decomp')); + const [isDesktop, setIsDesktop] = useState(false); useEffect(() => { if (!scene.current) return; + console.log(window.innerWidth) + + if (window.innerWidth > 938) { + setIsDesktop(true); + console.log(isDesktop); + } + const Engine = Matter.Engine, Render = Matter.Render, Runner = Matter.Runner, Bodies = Matter.Bodies, Body = Matter.Body, - Composite = Matter.Composite; + Composite = Matter.Composite + const engine = Engine.create(); const render = Render.create({ @@ -43,7 +50,11 @@ export default function Fruits() { } }); - // Import the necessary modules from Matter.js + // Import the necessary modules from Matter.js + + + + engine.positionIterations = 10; engine.velocityIterations = 10; @@ -52,7 +63,7 @@ export default function Fruits() { const width = scene.current?.clientWidth ?? 0; // Provide default value of 0 if undefined const height = scene.current?.clientHeight ?? 0; // Provide default value of 0 if undefined - + render.bounds.max.x = width; render.bounds.max.y = height; render.options.width = width; @@ -63,106 +74,97 @@ export default function Fruits() { render.canvas.style.height = height + 'px'; console.log('Width:', width, 'Height:', height); - console.log(width / 2, height + barrierWidth / 2); - Body.setPosition(ground, { - x: width / 2, - y: (height + barrierWidth) / 2 - }); - - Body.setPosition(rightWall, { - x: (width + barrierWidth) / 2, - y: height / 2 - }); + console.log( width / 2, height + barrierWidth / 2) + Body.setPosition(ground, { x: width / 2, y: (height + barrierWidth) / 2}); + Body.setPosition(rightWall, { x: (width + barrierWidth) / 2, y: height / 2 }); + Engine.update(engine, 0); }; + + + + let barrierWidth = 500; const width = scene.current?.clientWidth ?? 0; // Provide default value of 0 if undefined const height = scene.current?.clientHeight ?? 0; // Provide default value of 0 if undefined - const ground = Bodies.rectangle( - width / 2, - height + barrierWidth / 2 - 10, - 20000, - barrierWidth, - { - isStatic: true, - friction: 0.1, // Adjust this value, 0 means no friction - restitution: 0.1, - render: { - fillStyle: 'transparent' - } + const ground = Bodies.rectangle(width/2, height + barrierWidth / 2 -10, 20000, barrierWidth, { + isStatic: true, + friction: 0.1, // Adjust this value, 0 means no friction + restitution: 0.1, + render: { + fillStyle: 'transparent', } - ); - const leftSlant = Bodies.rectangle( - -5 - barrierWidth / 2, - height / 2, - barrierWidth, - height * 5, - { - isStatic: true, - friction: 0.1, // Adjust this value, 0 means no friction - restitution: 0.1, - render: { - fillStyle: 'transparent' - } + }); + const leftSlant = Bodies.rectangle(-5 - barrierWidth / 2, height/2, barrierWidth, height * 5, { + isStatic: true, + friction: 0.1, // Adjust this value, 0 means no friction + restitution: 0.1, + render: { + fillStyle: 'transparent', } - ); - const rightSlant = Bodies.rectangle( - width + barrierWidth / 2 + 5, - height / 2, - barrierWidth, - height * 5, - { - isStatic: true, - - friction: 0.1, // Adjust this value, 0 means no friction - restitution: 0.1, - render: { - fillStyle: 'transparent' - } + }); + const rightSlant = Bodies.rectangle(width + barrierWidth / 2 + 5 , height / 2, barrierWidth, height * 5, { + isStatic: true, + + friction: 0.1, // Adjust this value, 0 means no friction + restitution: 0.1, + render: { + fillStyle: 'transparent', } - ); - const leftWall = Bodies.rectangle( - 0 - barrierWidth / 2, - height / 2, - barrierWidth, - height * 5, - { - isStatic: true, - friction: 0.1, // Adjust this value, 0 means no friction - restitution: 0.1, - render: { - fillStyle: 'transparent' - } + }); + const leftWall = Bodies.rectangle(0 - barrierWidth / 2, height/2, barrierWidth, height * 5, { + isStatic: true, + friction: 0.1, // Adjust this value, 0 means no friction + restitution: 0.1, + render: { + fillStyle: 'transparent', } - ); - const rightWall = Bodies.rectangle( - width + barrierWidth / 2, - height / 2, - barrierWidth, - height * 5, - { - isStatic: true, - - friction: 0.1, // Adjust this value, 0 means no friction - restitution: 0.1, - render: { - fillStyle: 'transparent' - } + }); + const rightWall = Bodies.rectangle(width + barrierWidth / 2 , height / 2, barrierWidth, height * 5, { + isStatic: true, + + friction: 0.1, // Adjust this value, 0 means no friction + restitution: 0.1, + render: { + fillStyle: 'transparent', } - ); + }); Body.rotate(leftSlant, -0.075 * Math.PI); Body.rotate(rightSlant, 0.075 * Math.PI); - let spriteWidth = width / 815; - let spriteHeight = (height * 0.5) / 385; - const basket = Bodies.rectangle( - width / 2, - height * 0.75, - width, - height * 0.5, - { + + + // Basket Desktop + let basketX; + let basketY; + let basketWidth; + let basketHeight; + let spriteWidth; + let spriteHeight; + + if (isDesktop == true) { + basketX = width / 2; + basketY = height * .75; + basketWidth = width; + basketHeight = height * .5; + spriteHeight = height * .5 / 385; + spriteWidth = width / 815; + } + else { + basketX = width / 2; + basketY = height * .85; + basketWidth = width; + basketHeight = height * .2; + spriteHeight = height * .3 / 385; + spriteWidth = width / 815; + + } + + + + const basket = Bodies.rectangle(basketX, basketY, basketWidth, basketHeight, { isStatic: true, friction: 0.1, // Adjust this value, 0 means no friction restitution: 0.1, @@ -170,35 +172,29 @@ export default function Fruits() { sprite: { texture: '/textures/basket.png', xScale: spriteWidth, - yScale: spriteHeight - } - } - } - ); - basket.collisionFilter = { - group: -1, - category: 2, - mask: 0 - }; + yScale: spriteHeight, + }, + }, + }); + basket.collisionFilter = { + 'group': -1, + 'category': 2, + 'mask': 0, + }; + + + + Composite.add(engine.world, [ground, leftWall, rightWall, leftSlant, rightSlant]); + - // Matter.Body.rotate(leftWall, -0.08 * Math.PI); - // Matter.Body.rotate(rightWall, 0.08 * Math.PI); - Composite.add(engine.world, [ - ground, - leftWall, - rightWall, - leftSlant, - rightSlant - ]); - - const words = [ + const wordsDesktop = [ { - // UP-GRADE - textWidth: 200, - textHeight: 40, - boxScale: 1.8, + // DESIGN + textWidth: 220, + textHeight: 60, + boxScale: 1.5, spriteScale: 0.8, - svgPath: '/textures/wordOne.svg' + svgPath: '/textures/wordFour.svg', }, { // CO @@ -208,6 +204,16 @@ export default function Fruits() { spriteScale: 0.8, svgPath: '/textures/wordTwo.svg' }, + + + { + // UP-GRADE + textWidth: 200, + textHeight: 40, + boxScale: 1.8, + spriteScale: 0.8, + svgPath: '/textures/wordOne.svg' + }, { // 2024 textWidth: 220, @@ -216,46 +222,196 @@ export default function Fruits() { spriteScale: 0.8, svgPath: '/textures/wordThree.svg' }, + ]; + const wordsMobile = [ { // DESIGN textWidth: 220, + textHeight: 80, + boxScale: .65, + spriteScale: 0.5, + svgPath: '/textures/wordFour.svg', + }, + { + // CO + textWidth: 220, + textHeight: 120, + boxScale: 0.3, + spriteScale: 0.5, + svgPath: '/textures/wordTwo.svg' + }, + + + { + // UP-GRADE + textWidth: 200, + textHeight: 40, + boxScale: 1, + spriteScale: 0.5, + svgPath: '/textures/wordOne.svg' + }, + { + // 2024 + textWidth: 220, textHeight: 60, - boxScale: 1.5, - spriteScale: 0.8, - svgPath: '/textures/wordFour.svg' - } + boxScale: .6, + spriteScale: 0.5, + svgPath: '/textures/wordThree.svg' + }, ]; + // Create Words + if (isDesktop == true) { + wordsDesktop.forEach((word, index) => { + const { textWidth, textHeight, boxScale, spriteScale, svgPath } = word; + const posX = index * (scene.current?.clientWidth ?? 0) * 0.25 + 100; + const posY = -300 - (index * (scene.current?.clientHeight ?? 0) * 0.4); + const rotationAngle = Math.random() * Math.PI; + const rotationSpeed = Math.random() * 0.1 - 0.05; + let width = textWidth * boxScale; + let height = textHeight * boxScale; + + // Create rectangle body + const rectangle = Bodies.rectangle(posX, posY, width, height, { + isStatic: false, + // velocity: { x: 0, y: 0 }, + // friction: 0.1, // Adjust this value, 0 means no friction + // restitution: 0.1, + render: { + strokeStyle: 'black', + fillStyle: 'black', + lineWidth: 1, + + sprite: { + texture: svgPath, + xScale: spriteScale, + yScale: spriteScale , + } + } + }); + Body.rotate(rectangle, rotationAngle); // Rotate the rectangle + Body.setAngularSpeed(rectangle, + rotationSpeed); // Set the angular speed of the rectangle + Composite.add(engine.world, rectangle); + + }); - words.forEach((word, index) => { - const { textWidth, textHeight, boxScale, spriteScale, svgPath } = word; - const posX = index * 200 + 200; - const posY = -200; - let width = textWidth * boxScale; - let height = textHeight * boxScale; - - // Create rectangle body - const rectangle = Bodies.rectangle(posX, posY, width, height, { - isStatic: false, - // velocity: { x: 0, y: 0 }, - // friction: 0.1, // Adjust this value, 0 means no friction - // restitution: 0.1, - render: { - strokeStyle: 'black', - fillStyle: 'black', - lineWidth: 1, - - sprite: { - texture: svgPath, - xScale: spriteScale, - yScale: spriteScale + } + else { + wordsMobile.forEach((word, index) => { + const { textWidth, textHeight, boxScale, spriteScale, svgPath } = word; + const posX = index * (scene.current?.clientWidth ?? 0) * 0.25 + 100; + const posY = -300 - (index * (scene.current?.clientHeight ?? 0) * 0.4); + const rotationAngle = Math.random() * Math.PI; + const rotationSpeed = Math.random() * 0.1 - 0.05; + let width = textWidth * boxScale; + let height = textHeight * boxScale; + + // Create rectangle body + const rectangle = Bodies.rectangle(posX, posY, width, height, { + isStatic: false, + // velocity: { x: 0, y: 0 }, + // friction: 0.1, // Adjust this value, 0 means no friction + // restitution: 0.1, + render: { + strokeStyle: 'black', + fillStyle: 'black', + lineWidth: 1, + + sprite: { + texture: svgPath, + xScale: spriteScale, + yScale: spriteScale , + } } - } + }); + Body.rotate(rectangle, rotationAngle); // Rotate the rectangle + Body.setAngularSpeed(rectangle, + rotationSpeed); // Set the angular speed of the rectangle + Composite.add(engine.world, rectangle); + }); + } - Composite.add(engine.world, rectangle); - }); + if (isDesktop == true ){ + + //Create Cherry + let cherryScale = 0.15; + + const cherryShape = createEllipseVertices({ + cx: 0, + cy: 0, + ry: scene.current?.clientWidth * cherryScale* 1, + rx: scene.current?.clientWidth * cherryScale*.6, + steps: 20 + }); + const textureWidth = 150; + const cherry = Bodies.fromVertices( + scene.current?.clientWidth*.3, scene.current?.clientHeight * -0.2, + [Vertices.hull(cherryShape)], + { + restitution: 0.6, //Bounciness + render: { + fillStyle: 'black', + sprite: { + texture: '/textures/cherry.png', + xScale: (cherryScale * scene.current?.clientWidth * 1.5) / textureWidth, + yScale: (cherryScale * scene.current?.clientWidth * 1.5 ) / textureWidth, + }, + }, + }); + Composite.add(engine.world, cherry); + + const watermelonScale = 0.25; + const watermelonShape = createEllipseVertices({ + cx: 0, + cy: 0, + ry: scene.current?.clientWidth * watermelonScale* 1.2, + rx: scene.current?.clientWidth * watermelonScale*1, + steps: 16 + }); + const watermelon = Bodies.fromVertices( + scene.current?.clientWidth *.6, scene.current?.clientHeight * -0.2, + [Vertices.hull(watermelonShape)], + { + restitution: 0.6, //Bounciness + render: { + fillStyle: 'black', + sprite: { + texture: '/textures/watermelon.webp', + xScale: (watermelonScale * scene.current?.clientWidth * 0.4) / textureWidth, + yScale: (watermelonScale * scene.current?.clientWidth * 0.4 ) / textureWidth, + }, + }, + }); + Composite.add(engine.world, watermelon); + + const apricotScale = 0.25; + const apricotShape = createEllipseVertices({ + cx: 0, + cy: 0, + ry: scene.current?.clientHeight * apricotScale*.9, + rx: scene.current?.clientWidth * apricotScale*.8, + steps: 20 + }); + const apricot = Bodies.fromVertices( + scene.current?.clientWidth*.2, scene.current?.clientHeight * -.8, + [Vertices.hull(apricotShape)], + { + restitution: 0.6, //Bounciness + render: { + fillStyle: 'black', + sprite: { + texture: '/textures/apricot.webp', + xScale: (apricotScale * scene.current?.clientWidth * .45) / textureWidth, + yScale: (apricotScale * scene.current?.clientWidth * .45 ) / textureWidth, + }, + }, + }); + Composite.add(engine.world, apricot); + } + else { //Create Cherry let cherryScale = 0.15; @@ -263,98 +419,87 @@ export default function Fruits() { const cherryShape = createEllipseVertices({ cx: 0, cy: 0, - ry: scene.current?.clientWidth * cherryScale * 1, - rx: scene.current?.clientWidth * cherryScale * 0.6, + ry: scene.current?.clientWidth * cherryScale* .8, + rx: scene.current?.clientWidth * cherryScale*.5, steps: 20 }); const textureWidth = 150; - // const textureHeight = 100; const cherry = Bodies.fromVertices( - scene.current?.clientWidth * 0.3, - scene.current?.clientHeight * -0.2, + scene.current?.clientWidth*.3, scene.current?.clientHeight * -0.2, [Vertices.hull(cherryShape)], { - restitution: 0.6, //Bounciness - render: { - fillStyle: 'black', - sprite: { - texture: '/textures/cherry.png', - xScale: - (cherryScale * scene.current?.clientWidth * 1.5) / textureWidth, - yScale: - (cherryScale * scene.current?.clientWidth * 1.5) / textureWidth - } - } - } - ); - Composite.add(engine.world, cherry); - - const watermelonScale = 0.25; - const watermelonShape = createEllipseVertices({ - cx: 0, - cy: 0, - ry: scene.current?.clientWidth * watermelonScale * 1.2, - rx: scene.current?.clientWidth * watermelonScale * 1, - steps: 16 - }); - const watermelon = Bodies.fromVertices( - scene.current?.clientWidth * 0.6, - scene.current?.clientHeight * -0.2, - [Vertices.hull(watermelonShape)], - { + restitution: 0.6, //Bounciness + render: { + fillStyle: 'black', + sprite: { + texture: '/textures/cherry.png', + xScale: (cherryScale * scene.current?.clientWidth * 1.5) / textureWidth, + yScale: (cherryScale * scene.current?.clientWidth * 1.5 ) / textureWidth, + }, + }, + }); + Composite.add(engine.world, cherry); + + const watermelonScale = 0.25; + const watermelonShape = createEllipseVertices({ + cx: 0, + cy: 0, + ry: scene.current?.clientWidth * watermelonScale* 1.2, + rx: scene.current?.clientWidth * watermelonScale*1, + steps: 16 + }); + const watermelon = Bodies.fromVertices( + scene.current?.clientWidth *.6, scene.current?.clientHeight * -0.2, + [Vertices.hull(watermelonShape)], + { restitution: 0.6, //Bounciness render: { fillStyle: 'black', sprite: { texture: '/textures/watermelon.webp', - xScale: - (watermelonScale * scene.current?.clientWidth * 0.4) / - textureWidth, - yScale: - (watermelonScale * scene.current?.clientWidth * 0.4) / - textureWidth - } - } - } - ); - Composite.add(engine.world, watermelon); + xScale: (watermelonScale * scene.current?.clientWidth * 0.4) / textureWidth, + yScale: (watermelonScale * scene.current?.clientWidth * 0.4 ) / textureWidth, + }, + }, + }); + Composite.add(engine.world, watermelon); + + const apricotScale = 0.15; + const apricotShape = createEllipseVertices({ + cx: 0, + cy: 0, + ry: scene.current?.clientHeight * apricotScale*.9, + rx: scene.current?.clientWidth * apricotScale*.8, + steps: 20 + }); + const apricot = Bodies.fromVertices( + scene.current?.clientWidth*.2, scene.current?.clientHeight * -.8, + [Vertices.hull(apricotShape)], + { + restitution: 0.6, //Bounciness + render: { + fillStyle: 'black', + sprite: { + texture: '/textures/apricot.webp', + xScale: (apricotScale * scene.current?.clientWidth * .8) / textureWidth, + yScale: (apricotScale * scene.current?.clientWidth * .8 ) / textureWidth, + }, + }, + }); + Composite.add(engine.world, apricot); + } + + - const apricotScale = 0.25; - const apricotShape = createEllipseVertices({ - cx: 0, - cy: 0, - ry: scene.current?.clientHeight * apricotScale * 0.9, - rx: scene.current?.clientWidth * apricotScale * 0.8, - steps: 20 - }); - const apricot = Bodies.fromVertices( - scene.current?.clientWidth * 0.2, - scene.current?.clientHeight * -0.8, - [Vertices.hull(apricotShape)], - { - restitution: 0.6, //Bounciness - render: { - fillStyle: 'black', - sprite: { - texture: '/textures/apricot.webp', - xScale: - (apricotScale * scene.current?.clientWidth * 0.45) / textureWidth, - yScale: - (apricotScale * scene.current?.clientWidth * 0.45) / textureWidth - } - } - } - ); - Composite.add(engine.world, apricot); - // Get the canvas element + // Get the canvas element const canvas = scene.current; if (canvas) { // Add a mouse click event listener to the canvas canvas.addEventListener('click', () => { console.log('Clicked'); - Composite.allBodies(engine.world).forEach(body => { + Composite.allBodies(engine.world).forEach((body) => { // For each fruit if (body.isStatic) return; // Skip static bodies @@ -368,7 +513,7 @@ export default function Fruits() { Body.applyForce(body, body.position, force); }); }); - } +} const mouse = Mouse.create(render.canvas); const mouseConstraint = MouseConstraint.create(engine, { @@ -385,8 +530,10 @@ export default function Fruits() { Composite.add(engine.world, mouseConstraint); + // ... + interface Event { source: { world: { @@ -400,14 +547,14 @@ export default function Fruits() { let maxSpeed: number = 10; Matter.Body.setVelocity(body, { x: Math.min(maxSpeed, Math.max(-maxSpeed, body.velocity.x)), - y: Math.min(maxSpeed, Math.max(-maxSpeed, body.velocity.y)) + y: Math.min(maxSpeed, Math.max(-maxSpeed, body.velocity.y)), }); }); }; - Matter.Events.on(engine, 'beforeUpdate', limitMaxSpeed); + Matter.Events.on(engine, 'beforeUpdate', limitMaxSpeed) let barriers = [ground, leftWall, rightWall]; - Events.on(mouseConstraint, 'startdrag', event => { + Events.on(mouseConstraint, 'startdrag', (event) => { const body = event.body; // Store the original inertia of the body @@ -423,7 +570,7 @@ export default function Fruits() { } }); - Events.on(mouseConstraint, 'enddrag', event => { + Events.on(mouseConstraint, 'enddrag', (event) => { const body = event.body; // Reset the inertia back to its original value @@ -435,6 +582,9 @@ export default function Fruits() { delete body.originalInertia; }); + + + Render.run(render); const runner = Runner.create(); Runner.run(runner, engine); @@ -447,7 +597,7 @@ export default function Fruits() { render.textures = {}; window.removeEventListener('resize', handleResize); }; - }, []); + }, [isDesktop]); return ( <>