diff --git a/Client/.eslintrc.cjs b/Client/.eslintrc.cjs index 3e212e1..21daebc 100644 --- a/Client/.eslintrc.cjs +++ b/Client/.eslintrc.cjs @@ -1,21 +1,49 @@ module.exports = { + // Specifies that this is the root configuration file root: true, - env: { browser: true, es2020: true }, + + // Defines the environments in which the code is expected to run + env: { + browser: true, // Code is expected to run in the browser + es2020: true, // Code is using ECMAScript 2020 features + }, + + // Extends from base configurations and recommended rules extends: [ - 'eslint:recommended', - 'plugin:react/recommended', - 'plugin:react/jsx-runtime', - 'plugin:react-hooks/recommended', + 'eslint:recommended', // Uses the recommended ESLint rules + 'plugin:react/recommended', // Uses the recommended rules from the ESLint React plugin + 'plugin:react/jsx-runtime', // Enables rules for React's new JSX transform + 'plugin:react-hooks/recommended', // Uses recommended rules for React Hooks + ], + + // Specifies files and directories to ignore + ignorePatterns: [ + 'dist', // Ignore the 'dist' directory (typically used for build outputs) + '.eslintrc.cjs', // Ignore this ESLint configuration file itself ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, - settings: { react: { version: '18.2' } }, - plugins: ['react-refresh'], + + // Defines the parser options + parserOptions: { + ecmaVersion: 'latest', // Use the latest ECMAScript syntax + sourceType: 'module', // Specifies that the code uses ES modules + }, + + // Specifies settings for specific plugins + settings: { + react: { + version: '18.2', // Specifies the version of React to use (for linting rules compatibility) + }, + }, + + // Defines additional plugins to use + plugins: ['react-refresh'], // Includes the 'react-refresh' plugin for hot reloading support in development + + // Customizes specific rules rules: { - 'react/jsx-no-target-blank': 'off', + 'react/jsx-no-target-blank': 'off', // Disables the rule that prevents using `target="_blank"` without `rel="noopener noreferrer"` (you might want to manage this manually) 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, + 'warn', // Set the rule to show warnings instead of errors + { allowConstantExport: true }, // Allows exporting constants without triggering the rule ], }, -} +}; diff --git a/Client/index.html b/Client/index.html index e5fbb48..c1d148a 100644 --- a/Client/index.html +++ b/Client/index.html @@ -6,6 +6,7 @@ Flappy Bird + diff --git a/Client/public/Totem-l.png b/Client/public/Totem-l.png deleted file mode 100644 index a8f8bb5..0000000 Binary files a/Client/public/Totem-l.png and /dev/null differ diff --git a/Client/public/Totem-m.png b/Client/public/Totem-m.png deleted file mode 100644 index 40ae046..0000000 Binary files a/Client/public/Totem-m.png and /dev/null differ diff --git a/Client/public/Totem-s.png b/Client/public/Totem-s.png deleted file mode 100644 index 98c935d..0000000 Binary files a/Client/public/Totem-s.png and /dev/null differ diff --git a/Client/public/Totem-xl.png b/Client/public/Totem-xl.png deleted file mode 100644 index 785498d..0000000 Binary files a/Client/public/Totem-xl.png and /dev/null differ diff --git a/Client/public/Totem-xs.png b/Client/public/Totem-xs.png deleted file mode 100644 index 307a345..0000000 Binary files a/Client/public/Totem-xs.png and /dev/null differ diff --git a/Client/public/certificate_codecheflogo.png b/Client/public/certificate_codecheflogo.png deleted file mode 100644 index 5f3dab8..0000000 Binary files a/Client/public/certificate_codecheflogo.png and /dev/null differ diff --git a/Client/public/certificate_gamebg.png b/Client/public/certificate_gamebg.png deleted file mode 100644 index d0e27f7..0000000 Binary files a/Client/public/certificate_gamebg.png and /dev/null differ diff --git a/Client/public/certificate_phonebgg.png b/Client/public/certificate_phonebgg.png deleted file mode 100644 index 0c50544..0000000 Binary files a/Client/public/certificate_phonebgg.png and /dev/null differ diff --git a/Client/public/gameOver_bg.png b/Client/public/gameOver_bg.png deleted file mode 100644 index a1b8030..0000000 Binary files a/Client/public/gameOver_bg.png and /dev/null differ diff --git a/Client/public/gameOver_bg2.png b/Client/public/gameOver_bg2.png deleted file mode 100644 index ae8a51e..0000000 Binary files a/Client/public/gameOver_bg2.png and /dev/null differ diff --git a/Client/public/homePage_desktopBg.png b/Client/public/homePage_desktopBg.png deleted file mode 100644 index 8146383..0000000 Binary files a/Client/public/homePage_desktopBg.png and /dev/null differ diff --git a/Client/public/homePage_gameName.png b/Client/public/homePage_gameName.png deleted file mode 100644 index dae3414..0000000 Binary files a/Client/public/homePage_gameName.png and /dev/null differ diff --git a/Client/public/homePage_mobileBg.png b/Client/public/homePage_mobileBg.png deleted file mode 100644 index 3b2a64f..0000000 Binary files a/Client/public/homePage_mobileBg.png and /dev/null differ diff --git a/Client/public/homePage_startButton.png b/Client/public/homePage_startButton.png deleted file mode 100644 index 3fc3fef..0000000 Binary files a/Client/public/homePage_startButton.png and /dev/null differ diff --git a/Client/public/leaderBoard_bird.png b/Client/public/leaderBoard_bird.png deleted file mode 100644 index 01b6887..0000000 Binary files a/Client/public/leaderBoard_bird.png and /dev/null differ diff --git a/Client/public/leaderBoard_crown_r1.png b/Client/public/leaderBoard_crown_r1.png deleted file mode 100644 index b2071bd..0000000 Binary files a/Client/public/leaderBoard_crown_r1.png and /dev/null differ diff --git a/Client/public/leaderBoard_crown_r2.png b/Client/public/leaderBoard_crown_r2.png deleted file mode 100644 index 8c52b65..0000000 Binary files a/Client/public/leaderBoard_crown_r2.png and /dev/null differ diff --git a/Client/public/leaderBoard_crown_r3.png b/Client/public/leaderBoard_crown_r3.png deleted file mode 100644 index a7e6ed1..0000000 Binary files a/Client/public/leaderBoard_crown_r3.png and /dev/null differ diff --git a/Client/public/leaderBoard_image 9 (1).png b/Client/public/leaderBoard_image 9 (1).png deleted file mode 100644 index 3a7f7e4..0000000 Binary files a/Client/public/leaderBoard_image 9 (1).png and /dev/null differ diff --git a/Client/public/leaderBoard_image_bg.png b/Client/public/leaderBoard_image_bg.png deleted file mode 100644 index fdf144e..0000000 Binary files a/Client/public/leaderBoard_image_bg.png and /dev/null differ diff --git a/Client/public/leaderBoard_image_bg_sm.png b/Client/public/leaderBoard_image_bg_sm.png deleted file mode 100644 index 1ff6996..0000000 Binary files a/Client/public/leaderBoard_image_bg_sm.png and /dev/null differ diff --git a/Client/public/leaderBoard_tree_board.png b/Client/public/leaderBoard_tree_board.png deleted file mode 100644 index 3a7f7e4..0000000 Binary files a/Client/public/leaderBoard_tree_board.png and /dev/null differ diff --git a/Client/public/leaderBoard_tree_board_sm.png b/Client/public/leaderBoard_tree_board_sm.png deleted file mode 100644 index f29ccab..0000000 Binary files a/Client/public/leaderBoard_tree_board_sm.png and /dev/null differ diff --git a/Client/public/playscreen_ScoreBoard.png b/Client/public/playscreen_ScoreBoard.png deleted file mode 100644 index 33f877f..0000000 Binary files a/Client/public/playscreen_ScoreBoard.png and /dev/null differ diff --git a/Client/public/playscreen_bg.jpg b/Client/public/playscreen_bg.jpg deleted file mode 100644 index 17ea6c3..0000000 Binary files a/Client/public/playscreen_bg.jpg and /dev/null differ diff --git a/Client/public/playscreen_bird.png b/Client/public/playscreen_bird.png deleted file mode 100644 index afb3610..0000000 Binary files a/Client/public/playscreen_bird.png and /dev/null differ diff --git a/Client/public/playscreen_bird_big_eye.png b/Client/public/playscreen_bird_big_eye.png deleted file mode 100644 index fa6b004..0000000 Binary files a/Client/public/playscreen_bird_big_eye.png and /dev/null differ diff --git a/Client/public/playscreen_mobile-bg.png b/Client/public/playscreen_mobile-bg.png deleted file mode 100644 index 225aae0..0000000 Binary files a/Client/public/playscreen_mobile-bg.png and /dev/null differ diff --git a/Client/public/playscreen_obstacle.png b/Client/public/playscreen_obstacle.png deleted file mode 100644 index 10eeff9..0000000 Binary files a/Client/public/playscreen_obstacle.png and /dev/null differ diff --git a/Client/src/App.jsx b/Client/src/App.jsx index 5c051e0..94ea628 100644 --- a/Client/src/App.jsx +++ b/Client/src/App.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { Analytics } from '@vercel/analytics/react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; @@ -7,60 +7,56 @@ import PlayScreen from './screens/PlayScreen.jsx'; import LeaderBoard from './screens/LeaderBoard.jsx'; import SignInPage from './screens/SignInPage.jsx'; -const players = [ - { name: 'Player 1', score: 150 }, - { name: 'Player 2', score: 120 }, - { name: 'Player 3', score: 100 }, - { name: 'Player 4', score: 90 }, - { name: 'Player 5', score: 83 }, - { name: 'Player 6', score: 70 }, - { name: 'Player 7', score: 66 }, - { name: 'Player 8', score: 53 }, - { name: 'Player 9', score: 50 }, - { name: 'Player 10', score: 48 }, - { name: 'Player 11', score: 40 }, -]; +import { GameProvider } from './contexts/gameContext.jsx'; +// Main App component function App() { + // State to manage the current score and best score const [score, setScore] = useState(0); const [bestScore, setBestScore] = useState(0); - const [stayAnonymous, setStayAnonymous] = useState(false); - - //Backend part will be updated later - let leaderBoardData = []; return ( <> - - - } /> - - } - /> - - } - /> - } - /> - - - + {/* GameProvider is a context provider for managing game state */} + + {/* BrowserRouter is used to handle routing in the application */} + + {/* Routes define the different routes of the application */} + + {/* Route for the home page */} + } /> + + {/* Route for the play screen, passing score and bestScore as props */} + + } + /> + + {/* Route for the leaderboard screen */} + + } + /> + + {/* Route for the sign-in page */} + } + /> + + + {/* Analytics component for tracking application analytics */} + + ); } diff --git a/Client/src/assets/LoginPage_bg.png b/Client/src/assets/LoginPage_bg.png index 724a04a..1ddebb3 100644 Binary files a/Client/src/assets/LoginPage_bg.png and b/Client/src/assets/LoginPage_bg.png differ diff --git a/Client/src/assets/LoginPage_board.png b/Client/src/assets/LoginPage_board.png index 583f116..e590913 100644 Binary files a/Client/src/assets/LoginPage_board.png and b/Client/src/assets/LoginPage_board.png differ diff --git a/Client/src/assets/LoginPage_signboard1.png b/Client/src/assets/LoginPage_signboard1.png index bc938b3..440502c 100644 Binary files a/Client/src/assets/LoginPage_signboard1.png and b/Client/src/assets/LoginPage_signboard1.png differ diff --git a/Client/src/assets/Totem-l.png b/Client/src/assets/Totem-l.png new file mode 100644 index 0000000..0731cac Binary files /dev/null and b/Client/src/assets/Totem-l.png differ diff --git a/Client/src/assets/Totem-m.png b/Client/src/assets/Totem-m.png new file mode 100644 index 0000000..91f9bcb Binary files /dev/null and b/Client/src/assets/Totem-m.png differ diff --git a/Client/src/assets/Totem-s.png b/Client/src/assets/Totem-s.png new file mode 100644 index 0000000..85c9cb9 Binary files /dev/null and b/Client/src/assets/Totem-s.png differ diff --git a/Client/src/assets/Totem-xl.png b/Client/src/assets/Totem-xl.png new file mode 100644 index 0000000..f100e63 Binary files /dev/null and b/Client/src/assets/Totem-xl.png differ diff --git a/Client/src/assets/Totem-xs.png b/Client/src/assets/Totem-xs.png new file mode 100644 index 0000000..08e1a4f Binary files /dev/null and b/Client/src/assets/Totem-xs.png differ diff --git a/Client/src/assets/add_assets.txt b/Client/src/assets/add_assets.txt deleted file mode 100644 index e69de29..0000000 diff --git a/Client/src/assets/anonymous-icon.png b/Client/src/assets/anonymous-icon.png index 7e9b2b5..2aa9f42 100644 Binary files a/Client/src/assets/anonymous-icon.png and b/Client/src/assets/anonymous-icon.png differ diff --git a/Client/src/assets/certificate_gamebg.png b/Client/src/assets/certificate_gamebg.png deleted file mode 100644 index d0e27f7..0000000 Binary files a/Client/src/assets/certificate_gamebg.png and /dev/null differ diff --git a/Client/src/assets/certificate_phonebgg.png b/Client/src/assets/certificate_phonebgg.png deleted file mode 100644 index 0c50544..0000000 Binary files a/Client/src/assets/certificate_phonebgg.png and /dev/null differ diff --git a/Client/src/assets/gameOver_bg.png b/Client/src/assets/gameOver_bg.png new file mode 100644 index 0000000..0d74600 Binary files /dev/null and b/Client/src/assets/gameOver_bg.png differ diff --git a/Client/src/assets/gameOver_bg2.png b/Client/src/assets/gameOver_bg2.png new file mode 100644 index 0000000..c56421f Binary files /dev/null and b/Client/src/assets/gameOver_bg2.png differ diff --git a/Client/src/assets/google-icon.png b/Client/src/assets/google-icon.png index 1c18833..d4b86fb 100644 Binary files a/Client/src/assets/google-icon.png and b/Client/src/assets/google-icon.png differ diff --git a/Client/src/assets/homePage_desktopBg.png b/Client/src/assets/homePage_desktopBg.png index 8146383..424f63a 100644 Binary files a/Client/src/assets/homePage_desktopBg.png and b/Client/src/assets/homePage_desktopBg.png differ diff --git a/Client/src/assets/homePage_gameName.png b/Client/src/assets/homePage_gameName.png new file mode 100644 index 0000000..c930004 Binary files /dev/null and b/Client/src/assets/homePage_gameName.png differ diff --git a/Client/src/assets/homePage_mobileBg.png b/Client/src/assets/homePage_mobileBg.png index 3b2a64f..b1ca0e7 100644 Binary files a/Client/src/assets/homePage_mobileBg.png and b/Client/src/assets/homePage_mobileBg.png differ diff --git a/Client/src/assets/homePage_startButton.png b/Client/src/assets/homePage_startButton.png new file mode 100644 index 0000000..19b9f57 Binary files /dev/null and b/Client/src/assets/homePage_startButton.png differ diff --git a/Client/src/assets/leaderBoard_bird.png b/Client/src/assets/leaderBoard_bird.png new file mode 100644 index 0000000..acfd46b Binary files /dev/null and b/Client/src/assets/leaderBoard_bird.png differ diff --git a/Client/src/assets/leaderBoard_crown_r1.png b/Client/src/assets/leaderBoard_crown_r1.png new file mode 100644 index 0000000..65b103a Binary files /dev/null and b/Client/src/assets/leaderBoard_crown_r1.png differ diff --git a/Client/src/assets/leaderBoard_crown_r2.png b/Client/src/assets/leaderBoard_crown_r2.png new file mode 100644 index 0000000..a04ace1 Binary files /dev/null and b/Client/src/assets/leaderBoard_crown_r2.png differ diff --git a/Client/src/assets/leaderBoard_crown_r3.png b/Client/src/assets/leaderBoard_crown_r3.png new file mode 100644 index 0000000..1f6e0e4 Binary files /dev/null and b/Client/src/assets/leaderBoard_crown_r3.png differ diff --git a/Client/src/assets/leaderBoard_image_bg.png b/Client/src/assets/leaderBoard_image_bg.png new file mode 100644 index 0000000..d9469c5 Binary files /dev/null and b/Client/src/assets/leaderBoard_image_bg.png differ diff --git a/Client/src/assets/leaderBoard_image_bg_sm.png b/Client/src/assets/leaderBoard_image_bg_sm.png new file mode 100644 index 0000000..4d0b80b Binary files /dev/null and b/Client/src/assets/leaderBoard_image_bg_sm.png differ diff --git a/Client/src/assets/leaderBoard_tree_board.png b/Client/src/assets/leaderBoard_tree_board.png new file mode 100644 index 0000000..035143a Binary files /dev/null and b/Client/src/assets/leaderBoard_tree_board.png differ diff --git a/Client/src/assets/leaderBoard_tree_board_sm.png b/Client/src/assets/leaderBoard_tree_board_sm.png new file mode 100644 index 0000000..a2a813f Binary files /dev/null and b/Client/src/assets/leaderBoard_tree_board_sm.png differ diff --git a/Client/src/assets/logo.png b/Client/src/assets/logo.png new file mode 100644 index 0000000..fc0c2c5 Binary files /dev/null and b/Client/src/assets/logo.png differ diff --git a/Client/src/assets/playBackground.png b/Client/src/assets/playBackground.png index e2608ad..b7ae179 100644 Binary files a/Client/src/assets/playBackground.png and b/Client/src/assets/playBackground.png differ diff --git a/Client/src/assets/playscreen_ScoreBoard.png b/Client/src/assets/playscreen_ScoreBoard.png new file mode 100644 index 0000000..6d6be69 Binary files /dev/null and b/Client/src/assets/playscreen_ScoreBoard.png differ diff --git a/Client/src/assets/playscreen_bg.jpg b/Client/src/assets/playscreen_bg.jpg index 17ea6c3..1f4aba0 100644 Binary files a/Client/src/assets/playscreen_bg.jpg and b/Client/src/assets/playscreen_bg.jpg differ diff --git a/Client/src/assets/playscreen_bird.png b/Client/src/assets/playscreen_bird.png index afb3610..f15c91d 100644 Binary files a/Client/src/assets/playscreen_bird.png and b/Client/src/assets/playscreen_bird.png differ diff --git a/Client/src/assets/playscreen_bird_big_eye.png b/Client/src/assets/playscreen_bird_big_eye.png index fa6b004..db58823 100644 Binary files a/Client/src/assets/playscreen_bird_big_eye.png and b/Client/src/assets/playscreen_bird_big_eye.png differ diff --git a/Client/src/assets/playscreen_mobile-bg.png b/Client/src/assets/playscreen_mobile-bg.png index 225aae0..e2748fc 100644 Binary files a/Client/src/assets/playscreen_mobile-bg.png and b/Client/src/assets/playscreen_mobile-bg.png differ diff --git a/Client/src/assets/playscreen_obstacle.png b/Client/src/assets/playscreen_obstacle.png index 7ae77a8..0205953 100644 Binary files a/Client/src/assets/playscreen_obstacle.png and b/Client/src/assets/playscreen_obstacle.png differ diff --git a/Client/public/signboard.png b/Client/src/assets/signboard.png similarity index 100% rename from Client/public/signboard.png rename to Client/src/assets/signboard.png diff --git a/Client/src/contexts/gameContext.jsx b/Client/src/contexts/gameContext.jsx new file mode 100644 index 0000000..48f3658 --- /dev/null +++ b/Client/src/contexts/gameContext.jsx @@ -0,0 +1,18 @@ +import React, { createContext, useState, useContext } from 'react'; +import getRandomName from '../utils/utils'; + +const GameContext = createContext(); + +export const GameProvider = ({ children }) => { + const defaultName = getRandomName(); + const [playerName, setPlayerName] = useState(defaultName); + const [currentScore, setCurrentScore] = useState(0); + + return ( + + {children} + + ); +}; + +export const useGameContext = () => useContext(GameContext); diff --git a/Client/src/data/data.jsx b/Client/src/data/data.jsx deleted file mode 100644 index ce53b0e..0000000 --- a/Client/src/data/data.jsx +++ /dev/null @@ -1,28 +0,0 @@ -const animalAndBirdNames = [ - "Aardvark", "Albatross", "Alligator", "Alpaca", "Ant", "Anteater", "Antelope", "Ape", "Armadillo", "Donkey", - "Baboon", "Badger", "Barracuda", "Bat", "Bear", "Beaver", "Bee", "Bison", "Boar", "Buffalo", - "Butterfly", "Camel", "Capybara", "Caribou", "Cassowary", "Cat", "Caterpillar", "Cattle", "Chamois", "Cheetah", - "Chicken", "Chimpanzee", "Chinchilla", "Chough", "Clam", "Cobra", "Cockroach", "Cod", "Cormorant", "Coyote", - "Crab", "Crane", "Crocodile", "Crow", "Curlew", "Deer", "Dinosaur", "Dog", "Dogfish", "Dolphin", - "Dotterel", "Dove", "Dragonfly", "Duck", "Dugong", "Dunlin", "Eagle", "Echidna", "Eel", "Eland", - "Elephant", "Elk", "Emu", "Falcon", "Ferret", "Finch", "Fish", "Flamingo", "Fly", "Fox", - "Frog", "Gaur", "Gazelle", "Gerbil", "Giraffe", "Gnat", "Gnu", "Goat", "Goldfinch", "Goldfish", - "Goose", "Gorilla", "Goshawk", "Grasshopper", "Grouse", "Guanaco", "Gull", "Hamster", "Hare", "Hawk", - "Hedgehog", "Heron", "Herring", "Hippopotamus", "Hornet", "Horse", "Human", "Hummingbird", "Hyena", "Ibex" -]; - -const adjectives = [ - "Adorable", "Adventurous", "Aggressive", "Agreeable", "Alert", "Alive", "Amused", "Angry", "Annoyed", "Annoying", - "Anxious", "Arrogant", "Ashamed", "Attractive", "Average", "Awful", "Bad", "Beautiful", "Better", "Bewildered", - "Black", "Bloody", "Blue", "Blue-eyed", "Blushing", "Bored", "Brainy", "Brave", "Breakable", "Bright", - "Busy", "Calm", "Careful", "Cautious", "Charming", "Cheerful", "Clean", "Clear", "Clever", "Cloudy", - "Clumsy", "Colorful", "Combative", "Comfortable", "Concerned", "Condemned", "Confused", "Cooperative", "Courageous", "Crazy", - "Creepy", "Crowded", "Cruel", "Curious", "Cute", "Dangerous", "Dark", "Dead", "Defeated", "Defiant", - "Delightful", "Depressed", "Determined", "Different", "Difficult", "Disgusted", "Distinct", "Disturbed", "Dizzy", "Doubtful", - "Drab", "Dull", "Eager", "Easy", "Elated", "Elegant", "Embarrassed", "Enchanting", "Encouraging", "Energetic", - "Enthusiastic", "Envious", "Evil", "Excited", "Expensive", "Exuberant", "Fair", "Faithful", "Famous", "Fancy", - "Fantastic", "Fierce", "Filthy", "Fine", "Foolish", "Fragile", "Frail", "Frantic", "Friendly", "Frightened" -]; - -let data = [animalAndBirdNames,adjectives]; -export default data; \ No newline at end of file diff --git a/Client/src/index.css b/Client/src/index.css index 1f45792..995d91c 100644 --- a/Client/src/index.css +++ b/Client/src/index.css @@ -1,59 +1,98 @@ +/* Import Tailwind's base styles, component classes, and utility classes */ @tailwind base; @tailwind components; @tailwind utilities; +/* Define a custom font face for 'Post No Bills Colombo' */ @font-face { - font-family: 'Post No Bills Colombo'; - src: url('./PostNoBillsColombo-ExtraBold.woff') format('woff'); - font-weight: 800; - font-style: normal; + font-family: 'Post No Bills Colombo'; /* The name used to refer to this font in CSS */ + src: url('./PostNoBillsColombo-ExtraBold.woff') format('woff'); /* URL to the font file */ + font-weight: 800; /* Font weight for this font (ExtraBold) */ + font-style: normal; /* Font style (normal) */ } +/* Custom scrollbar styles for WebKit browsers (Chrome, Safari) */ ::-webkit-scrollbar { - width: 8px; - height: 12px; - margin: 4px; + width: 8px; /* Width of the vertical scrollbar */ + height: 12px; /* Height of the horizontal scrollbar */ + margin: 4px; /* Margin around the scrollbar */ } ::-webkit-scrollbar-track { - background: #4D2E13; - border-radius: 10px; + background: #4D2E13; /* Background color of the scrollbar track */ + border-radius: 10px; /* Rounded corners for the scrollbar track */ } ::-webkit-scrollbar-thumb { - background: #D8874F; - border-radius: 10px; + background: #D8874F; /* Background color of the scrollbar thumb */ + border-radius: 10px; /* Rounded corners for the scrollbar thumb */ } ::-webkit-scrollbar-thumb:hover { - background: #ffa15f; + background: #ffa15f; /* Background color of the scrollbar thumb on hover */ } +/* Custom font class for 'Post No Bills Colombo' with bold weight */ .font-postNoBills { - font-family: 'Post No Bills Colombo', sans-serif; - font-weight: 800; + font-family: 'Post No Bills Colombo', sans-serif; /* Uses the custom font with a fallback to sans-serif */ + font-weight: 800; /* Bold weight for this font */ } +/* Custom font class for 'Inter' */ .font-inter { - font-family: "Inter", sans-serif; - font-style: normal; + font-family: "Inter", sans-serif; /* Uses the Inter font with a fallback to sans-serif */ + font-style: normal; /* Normal font style */ } +/* Custom styling for text with a stroke */ .countdown-text { - -webkit-text-stroke-width: 3px; - -webkit-text-stroke-color: #311F04; + -webkit-text-stroke-width: 3px; /* Width of the text stroke */ + -webkit-text-stroke-color: #311F04; /* Color of the text stroke */ } +/* Background style for elements with the 'body' class */ .body { - background-image: linear-gradient(rgba(0, 0, 0, 0.527), rgba(0, 0, 0, 0.5)), url("/leaderBoard_image_bg.png"); + background-image: linear-gradient(rgba(0, 0, 0, 0.527), rgba(0, 0, 0, 0.5)), url("/leaderBoard_image_bg.png"); /* Linear gradient overlay with a background image */ } +/* Background style for elements with the 'out' class */ .out { - background-image: url('/leaderBoard_tree_board.png'); + background-image: url('/leaderBoard_tree_board.png'); /* Background image */ + background-size: contain; /* Scale background image to fit within its container */ + background-position: center; /* Center the background image */ + background-repeat: no-repeat; /* Prevent background image from repeating */ } +/* Animation for scrolling background */ +.bg-scroll { + animation: scrollBackground 120s linear infinite; /* Apply the scrollBackground animation for 120 seconds, infinitely */ +} + +/* Keyframes for the scrollBackground animation */ +@keyframes scrollBackground { + from { + background-position: 0 0; /* Starting position of the background */ + } + + to { + background-position: 1000% 0; /* Ending position of the background (scrolls horizontally) */ + } +} + +/* Responsive styles for screens with a max width of 1024px */ @media only screen and (max-width: 1024px) { .out { - background-image: url('/leaderBoard_tree_board_sm.png'); + background-image: url('/leaderBoard_tree_board_sm.png'); /* Different background image for smaller screens */ + background-size: 100% auto; /* Adjust background image size for smaller screens */ + background-position: center top; /* Adjust background image position */ + background-repeat: no-repeat; /* Prevent background image from repeating */ + padding-top: 20%; /* Add padding to the top of the element */ } -} \ No newline at end of file +} + +/* Styling for long text to break and wrap properly */ +.name-span { + word-break: break-word; /* Break long words onto the next line */ + overflow-wrap: break-word; /* Wrap text to avoid overflow */ + hyphens: auto; /* Automatically hyphenate text where appropriate */ +} diff --git a/Client/src/main.jsx b/Client/src/main.jsx index e2fc4f4..7309ded 100644 --- a/Client/src/main.jsx +++ b/Client/src/main.jsx @@ -1,9 +1,14 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import App from './App.jsx'; -import './index.css'; +// Import necessary modules and components +import React from 'react'; // React library for building user interfaces +import ReactDOM from 'react-dom/client'; // ReactDOM for rendering React components to the DOM +import App from './App.jsx'; // The main App component for your application +import './index.css'; // Import the global CSS file for styling + +// Create a root element to render your React application ReactDOM.createRoot(document.getElementById('root')).render( - + + {/* The React.StrictMode component helps identify potential problems in your application */} + {/* The App component is the top-level component of your React application */} ); diff --git a/Client/src/screens/Certificate.jsx b/Client/src/screens/Certificate.jsx deleted file mode 100644 index 9dd6bc1..0000000 --- a/Client/src/screens/Certificate.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import logo from '/certificate_codecheflogo.png'; - -const Certificate = ({ setScreen, playerName, bestScore }) => { - const handleClose = () => { - setScreen('gameover'); - }; - - return ( -
-
-
-
- Logo -
-

- CERTIFICATE -

-
-

- Congratulations -

- - {localStorage.getItem('username')} - -
-
-

- for achieving an -

- - impressive score of - -
- -

- - {bestScore} - -

-
-
-
- -
-
- ); -}; - -export default Certificate; diff --git a/Client/src/screens/GameOver.jsx b/Client/src/screens/GameOver.jsx index e3f9669..9a25534 100644 --- a/Client/src/screens/GameOver.jsx +++ b/Client/src/screens/GameOver.jsx @@ -1,21 +1,51 @@ import React, { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import bg1 from '/gameOver_bg.png'; -import bg2 from '/gameOver_bg2.png'; -import signboard from '/signboard.png'; +import bg1 from '../assets/gameOver_bg.png'; // Import background image for large screens +import bg2 from '../assets/gameOver_bg2.png'; // Import background image for small screens +import signboard from '../assets/signboard.png'; // Import image for the signboard -const GameOver = ({ score, bestScore, username }) => { - const navigate = useNavigate(); - useEffect(() => { +// The GameOver component displays the game over screen with the user's score, best score, and buttons for actions + +const GameOver = ({ score, bestScore, username, resetGame}) => { + const navigate = useNavigate();// Hook for programmatic navigation + + // Function to submit the score to the API + + const submitScore = async (username, score) => { + try { + const data = { username, score };// Prepare data to send to the API + console.log("started fetch");// Log fetch initiation + const response = await fetch('https://flappy-api.poseidon0z.com/api/gameusers', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data),// Convert data to JSON format + }); + console.log("completed fetch");// Log fetch completion + + if (!response.ok) throw new Error('Failed to submit game data');// Check for errors + + const result = await response.json();// Parse response data + console.log(result.message);// Log success message from API + } catch (error) { + console.error('Error submitting game data:', error); + } + }; + + // Effect hook to add and remove keydown event listener for spacebar + useEffect(() => { const handleKeyDown = (event) => { - if (event.key === ' ' && !event.repeat) { - event.preventDefault(); - location.reload(); + if (event.key === ' ' && !event.repeat) {// Check if the spacebar key is pressed + event.preventDefault(); // Prevent the default action + resetGame();// Call the function to restart the game } }; - window.addEventListener('keydown', handleKeyDown); + window.addEventListener('keydown', handleKeyDown); // Add event listener for keydown + // Clean up the event listener when the component is unmounted + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; }, []); return ( @@ -83,20 +113,23 @@ const GameOver = ({ score, bestScore, username }) => { {/* Buttons section */}
-

+

User : {username}

diff --git a/Client/src/screens/HomePage.jsx b/Client/src/screens/HomePage.jsx index 8b0cad9..058a72d 100644 --- a/Client/src/screens/HomePage.jsx +++ b/Client/src/screens/HomePage.jsx @@ -1,40 +1,52 @@ -import React, { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React, { useState, useEffect } from 'react'; // Import React and hooks +import { useNavigate } from 'react-router-dom'; // Import useNavigate for routing -import logo from '/homePage_gameName.png'; -import button from '/homePage_startButton.png'; +import logo from '../assets/homePage_gameName.png'; // Import the logo image +import button from '../assets/homePage_startButton.png'; // Import the start button image -const HomePage = ({}) => { - const navigate = useNavigate(); +const HomePage = () => { + const navigate = useNavigate(); // Hook to navigate programmatically + + // Function to handle screen changes based on key presses const handleScreen = (event) => { - if (event.code === 'Space') { - navigate('/play'); + if (event.code === 'Space') { // Check if the pressed key is the space bar + navigate('/play'); // Navigate to the play screen } }; + // useEffect hook to add and clean up the keydown event listener useEffect(() => { - window.addEventListener('keydown', handleScreen); + window.addEventListener('keydown', handleScreen); // Add event listener on mount + return () => { - window.removeEventListener('keydown', handleScreen); + window.removeEventListener('keydown', handleScreen); // Remove event listener on unmount }; - }, []); + }, []); // Empty dependency array means this effect runs once on mount and cleanup on unmount + // Function to handle button click const handleClick = () => { - navigate('/play'); + navigate('/play'); // Navigate to the play screen when the button is clicked }; return (
- logo + {/* Container with background images and full-height */} + + logo + {/* Logo image with responsive width and bottom padding */} + button -

+ +

Click / Press The Space Bar to Start

+ {/* Instruction text centered and white-colored */}
); }; diff --git a/Client/src/screens/LeaderBoard.jsx b/Client/src/screens/LeaderBoard.jsx index 5ece887..050ab9d 100644 --- a/Client/src/screens/LeaderBoard.jsx +++ b/Client/src/screens/LeaderBoard.jsx @@ -1,55 +1,71 @@ -import { React, useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { React, useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; -import bird from '/leaderBoard_bird.png'; -import crownGold from '/leaderBoard_crown_r1.png'; -import crownSilver from '/leaderBoard_crown_r2.png'; -import crownBronze from '/leaderBoard_crown_r3.png'; +// Import images for the leaderboard +import bird from "../assets/leaderBoard_bird.png"; +import crownGold from "../assets/leaderBoard_crown_r1.png"; +import crownSilver from "../assets/leaderBoard_crown_r2.png"; +import crownBronze from "../assets/leaderBoard_crown_r3.png"; -const LeaderBoard = ({ setScreen, players }) => { - const navigate = useNavigate(); - const [playersData, setPlayers] = useState([]); +const LeaderBoard = ({ stayAnonymous, isLoggedIn }) => { + const navigate = useNavigate(); // Hook to navigate programmatically + const [playersData, setPlayers] = useState([]); // State to hold player data + // useEffect hook to fetch player data when the component mounts useEffect(() => { const fetchPlayers = async () => { try { - const response = await fetch('https://flappy-api.poseidon0z.com/api/gameusers'); + const response = await fetch("https://flappy-api.poseidon0z.com/api/gameusers"); const data = await response.json(); - const sortedPlayers = data.sort((a, b) => a.rank - b.rank); - setPlayers(sortedPlayers); + setPlayers(data); // Update state with fetched player data } catch (error) { - console.error('Error fetching players:', error); + console.error("Error fetching players:", error); // Log errors if fetch fails } }; - fetchPlayers(); - }, []); + fetchPlayers(); // Call fetch function + }, []); // Empty dependency array means this effect runs once on mount - console.log(playersData); return (
- {/* Div for larger screens */} + {/* Main container for the leaderboard */} +
+ {/* Large screen leaderboard container */} +
+ {/* Container for the leaderboard title with images */} + CodeChef Bird + {/* Image on the left of the title */} +

LEADERBOARD

+ {/* Title of the leaderboard */} + CodeChef Bird + {/* Image on the right of the title, mirrored horizontally */}
    + {/* List of leaderboard entries */} +
    - {players[2] && ( -
  • + {/* Container for top three players */} + + {playersData[2] && ( +
  • + {/* Third place player */} + { className="absolute crown3 h-80px top-[-45px] left-[-90px]" /> - - {!(playersData[2] === undefined) - ? playersData[2].username - : ''} + {/* Bronze crown */} + + + {playersData[2].username} + {/* Player's username */} + - {!(playersData[2] === undefined) ? playersData[2].score : ''} + {playersData[2].score} + {/* Player's score */}
  • )} - {players[0] && ( -
  • + {playersData[0] && ( +
  • + {/* First place player */} + { className="absolute crown1 -top-45px -left-110px w-100px h-90px" /> - - {!(playersData[0] === undefined) - ? playersData[0].username - : ''} + {/* Gold crown */} + + + {playersData[0].username} + {/* Player's username */} + - {!(playersData[0] === undefined) ? playersData[0].score : ''} + {playersData[0].score} + {/* Player's score */}
  • )} - {players[1] && ( -
  • + {playersData[1] && ( +
  • + {/* Second place player */} + { className="absolute crown2 w-90% h-80px top-[-45px] left-[-90px]" /> - - {!(playersData[1] === undefined) - ? playersData[1].username - : ''} + {/* Silver crown */} + + + {playersData[1].username} - - {!(playersData[1] === undefined) ? playersData[1].score : ''} + {/* Player's username */} + + + {playersData[1].score} + {/* Player's score */}
  • )}
    -
    +
    + {/* List of remaining players */} + {playersData.slice(3).map((player, index) => (
  • { #{index + 4} - + {/* Player's rank */} + + {player.username} + {/* Player's username */} + {player.score} + {/* Player's score */}
  • ))}
+ + {/* Button to navigate back to the play screen */}
- {/* Div for smaller screens */}
- {/* Mobile version content */} + {/* Mobile screen leaderboard container */} +
+ {/* Container for the leaderboard title with images */} + CodeChef Bird + {/* Image on the left of the title */} +

LEADERBOARD

+ {/* Title of the leaderboard */} + CodeChef Bird + {/* Image on the right of the title, mirrored horizontally */}
    + {/* List of leaderboard entries */} +
    - {players[0] && ( + {/* Container for top three players */} + + {playersData[0] && (
  • + {/* First place player */} + Crown - - - {!(playersData[0] === undefined) - ? playersData[0].username - : ''} + {/* Gold crown */} + + + {playersData[0].username} + {/* Player's username */} + - {!(playersData[0] === undefined) ? playersData[0].score : ''} - -
  • - )} -
    - -
    - {players[2] && ( -
  • - Crown - - - {!(playersData[2] === undefined) - ? playersData[2].username - : ''} - - - {!(playersData[2] === undefined) ? playersData[2].score : ''} + {playersData[0].score} + {/* Player's score */}
  • )} - {players[1] && ( -
  • - Crown +
    + {/* Container for second and third place players */} + + {playersData[2] && ( +
  • + {/* Third place player */} + + Crown + {/* Bronze crown */} + + + {playersData[2].username} + + {/* Player's username */} + + + {playersData[2].score} + + {/* Player's score */} +
  • + )} - - {!(playersData[1] === undefined) - ? playersData[1].username - : ''} - - - {!(playersData[1] === undefined) ? playersData[1].score : ''} - - - )} -
    + {playersData[1] && ( +
  • + {/* Second place player */} + + Crown + {/* Silver crown */} + + + {playersData[1].username} + + {/* Player's username */} + + + {playersData[1].score} + + {/* Player's score */} +
  • + )} +
-
- {playersData.slice(3).map((player, index) => ( -
  • - - #{index + 4} - - - {player.username} - - - {player.score} - -
  • - ))} +
    + {/* List of remaining players */} + + {playersData.slice(3).map((player, index) => ( +
  • + + #{index + 4} + + {/* Player's rank */} + + + {player.username} + + {/* Player's username */} + + + {player.score} + + {/* Player's score */} +
  • + ))} +
    + + {/* Button to navigate back to the play screen */}
    ); }; -export default LeaderBoard; \ No newline at end of file +export default LeaderBoard; diff --git a/Client/src/screens/Objects/Bird.jsx b/Client/src/screens/Objects/Bird.jsx index fb9fca3..302b310 100644 --- a/Client/src/screens/Objects/Bird.jsx +++ b/Client/src/screens/Objects/Bird.jsx @@ -1,15 +1,22 @@ +import React from 'react'; + +// The Bird component displays the bird in the game. const Bird = (props) => { return (
    ); diff --git a/Client/src/screens/Objects/CountDown.jsx b/Client/src/screens/Objects/CountDown.jsx index 72aef7c..8d690f3 100644 --- a/Client/src/screens/Objects/CountDown.jsx +++ b/Client/src/screens/Objects/CountDown.jsx @@ -1,32 +1,40 @@ import React, { useEffect, useState } from 'react'; +// CountDown component to display a countdown timer before starting the game function CountDown({ count, setGameStopped }) { + // State to keep track of the current countdown value const [countdown, setCountdown] = useState(count); + + // Use effect to set up a timer when the component mounts useEffect(() => { - const always = setInterval(() => { + // Set up an interval that decreases the countdown value every second + const timer = setInterval(() => { setCountdown((prevCount) => prevCount - 1); }, 1000); + // Cleanup function to clear the interval when the component unmounts return () => { - clearInterval(always); + clearInterval(timer); }; - }, []); + }, []); // Empty dependency array means this effect runs once when the component mounts + // Use effect to update game state when countdown reaches zero useEffect(() => { - if (countdown == 0) { + if (countdown === 0) { + // Set game to not stopped, indicating the game can start setGameStopped(false); } - }, [countdown]); + }, [countdown]); // This effect runs whenever the countdown value changes return ( -
    -
    -

    -

    Get ready to

    -

    flap in

    +
    +
    +

    +

    Get ready to

    +

    flap in

    - {countdown} + {countdown} {/* Display the current countdown value */}

    diff --git a/Client/src/screens/Objects/Pipe.jsx b/Client/src/screens/Objects/Pipe.jsx index 7a187d1..253e42a 100644 --- a/Client/src/screens/Objects/Pipe.jsx +++ b/Client/src/screens/Objects/Pipe.jsx @@ -1,19 +1,20 @@ +// Pipe component renders an image of a pipe that represents an obstacle in the game const Pipe = ({ x, height, pipeImg }) => { return ( pipe ); }; -export default Pipe; + +export default Pipe; // Export the component for use in other parts of the application diff --git a/Client/src/screens/Objects/PipeBottom.jsx b/Client/src/screens/Objects/PipeBottom.jsx index fedf710..7d59323 100644 --- a/Client/src/screens/Objects/PipeBottom.jsx +++ b/Client/src/screens/Objects/PipeBottom.jsx @@ -1,18 +1,20 @@ +// PipeBottom component renders an image of the bottom part of a pipe obstacle const PipeBottom = ({ pipeImg, x, height }) => { return ( pipe ); }; -export default PipeBottom; + +export default PipeBottom; // Export the component for use in other parts of the application diff --git a/Client/src/screens/Objects/ScoreBoard.jsx b/Client/src/screens/Objects/ScoreBoard.jsx index 16f1019..a15afe2 100644 --- a/Client/src/screens/Objects/ScoreBoard.jsx +++ b/Client/src/screens/Objects/ScoreBoard.jsx @@ -1,18 +1,27 @@ import React from 'react'; -import ScoreBoardImg from '/playscreen_ScoreBoard.png'; +import ScoreBoardImg from '../../assets/playscreen_ScoreBoard.png'; // Import the background image for the scoreboard function ScoreBoard({ score }) { + // Format the score: round it and ensure it's a string, default to '0' if not a number const formattedScore = isNaN(score) ? '0' : Math.round(score).toString(); return ( -
    +
    Score Board -
    - {formattedScore} +
    + {formattedScore} {/* Display the formatted score */}
    ); diff --git a/Client/src/screens/PlayScreen.jsx b/Client/src/screens/PlayScreen.jsx index 119a9ed..10806e3 100644 --- a/Client/src/screens/PlayScreen.jsx +++ b/Client/src/screens/PlayScreen.jsx @@ -1,13 +1,14 @@ import React, { useEffect, useState } from 'react'; +import { useGameContext } from '../contexts/gameContext'; -import pipe_xs from '/Totem-xs.png'; -import pipe_s from '/Totem-s.png'; -import pipe_m from '/Totem-m.png'; -import pipe_l from '/Totem-l.png'; -import pipe_xl from '/Totem-xl.png'; - -import './play.css'; +// Importing images for different sizes of pipes +import pipe_xs from '../assets/Totem-xs.png'; +import pipe_s from '../assets/Totem-s.png'; +import pipe_m from '../assets/Totem-m.png'; +import pipe_l from '../assets/Totem-l.png'; +import pipe_xl from '../assets/Totem-xl.png'; +// Importing components used in the game import Bird from './Objects/Bird'; import Pipe from './Objects/Pipe'; import PipeBottom from './Objects/PipeBottom'; @@ -15,84 +16,124 @@ import ScoreBoard from './Objects/ScoreBoard'; import CountDown from './Objects/CountDown'; import GameOver from './GameOver'; +// Information about the obstacles const obstacle_info = [ - { name: 'xs', img: pipe_xs, height: 4 / 6 }, - { name: 's', img: pipe_s, height: 5 / 6 }, - { name: 'm', img: pipe_m, height: 1 }, - { name: 'l', img: pipe_l, height: 7 / 6 }, - { name: 'xl', img: pipe_xl, height: 8 / 6 }, + { name: 'xs', img: pipe_xs, height: 4 / 6 }, // Extra small pipe + { name: 's', img: pipe_s, height: 5 / 6 }, // Small pipe + { name: 'm', img: pipe_m, height: 1 }, // Medium pipe + { name: 'l', img: pipe_l, height: 7 / 6 }, // Large pipe + { name: 'xl', img: pipe_xl, height: 8 / 6 }, // Extra large pipe ]; function PlayScreen() { - const floorRatio = 0.092; - const gap = 150; - const availableHeight = - document.documentElement.clientHeight * (1 - floorRatio); - const totem_height = (availableHeight - gap) / 2; - const birdLeft = document.documentElement.clientWidth * 0.05; - const gravity = 1; - const obstacleCount = 4; - const totemGap = 750; - - const [gameStopped, setGameStopped] = useState(true); - const [distance, setDistance] = useState(0); + // Game context to get and set the current score and player name + const { setCurrentScore, playerName, currentScore } = useGameContext(); + + // Get username from localStorage or use the default player name + const uname = (localStorage.getItem("isLoggedIn") === "true") ? localStorage.getItem("UserInfo") : playerName; + + // Game parameters + const floorRatio = 0.092; // Ratio of the screen taken up by the floor + const gap = 150; // Gap between pipes + const availableHeight = document.documentElement.clientHeight * (1 - floorRatio); // Usable height for the game + const totem_height = (availableHeight - gap) / 2; // Height of the pipes + const birdLeft = document.documentElement.clientWidth * 0.05; // Initial horizontal position of the bird + const gravity = 1; // Gravity affecting the bird + const obstacleCount = 4; // Number of obstacles in view + const totemGap = 750; // Gap between obstacles + + // Game state + const [gameStopped, setGameStopped] = useState(true); // Indicates if the game is stopped + const [distance, setDistance] = useState(0); // Distance traveled by the bird const [obstacles, setObstacles] = useState([ - { index: 2, pos: totemGap }, + { index: 2, pos: totemGap }, // Initial positions of obstacles { index: 1, pos: totemGap * 2 }, { index: 3, pos: totemGap * 3 }, { index: 4, pos: totemGap * 4 }, { index: 0, pos: totemGap * 5 }, ]); - const [birdDead, setBirdDead] = useState(false); - const [birdTop, setBirdTop] = useState(availableHeight * 0.5); - const [velocity, setVelocity] = useState(0); - const [angle, setAngle] = useState(0); - const [bestScore, setBestScore] = useState(0); + const [birdDead, setBirdDead] = useState(false); // Indicates if the bird is dead + const [birdTop, setBirdTop] = useState(availableHeight * 0.5); // Vertical position of the bird + const [velocity, setVelocity] = useState(0); // Speed of the bird + const [angle, setAngle] = useState(0); // Angle of the bird + const [bestScore, setBestScore] = useState(0); // Best score in the game - const score = Math.floor(distance / totemGap); + const score = Math.floor(distance / totemGap); // Calculate the current score + // Function to reset the game state + const resetGame = () => { + setDistance(0); + setObstacles([ + { index: 2, pos: totemGap }, + { index: 1, pos: totemGap * 2 }, + { index: 3, pos: totemGap * 3 }, + { index: 4, pos: totemGap * 4 }, + { index: 0, pos: totemGap * 5 }, + ]); + setBirdDead(false); + setBirdTop(availableHeight * 0.5); + setVelocity(0); + setAngle(0); + setGameStopped(true); + }; + + // Function to handle bird flapping const clicked = () => { if (birdTop > 58) { - setVelocity(-10); - setAngle(-30); + setVelocity(-10); // Move the bird up + setAngle(-30); // Change the angle of the bird } }; + // Event listener for key presses (spacebar for flapping) useEffect(() => { const handleKeyDown = (event) => { if (event.key === ' ' && !event.repeat) { - event.preventDefault(); - + event.preventDefault(); // Prevent the default action of the spacebar clicked(); } }; window.addEventListener('keydown', handleKeyDown); + + // Cleanup event listener on component unmount + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; }, []); + // Game loop for updating distance and velocity useEffect(() => { if (!gameStopped) { const always = setInterval(() => { - setDistance((prevDistance) => prevDistance + 10); + var amount = document.documentElement.clientWidth > 500 ? 10 : 5; // Adjust speed based on screen size + setDistance( + (prevDistance) => prevDistance + amount + prevDistance / 1000 + ); setVelocity((prevVelocity) => prevVelocity + gravity); }, 25); + // Cleanup interval on component unmount return () => { clearInterval(always); }; } }, [gameStopped]); + // Update bird position and angle based on velocity useEffect(() => { setBirdTop((prevBirdTop) => prevBirdTop + velocity); setAngle(Math.min(90, Math.max(-30, velocity * 3))); }, [velocity]); + // Check for collisions and update obstacles useEffect(() => { + // Remove obstacles that are out of view if (obstacles[0].pos < distance - 200) { var ob = obstacles; ob.shift(); setObstacles(ob); } + // Add new obstacles as needed if (obstacles[obstacles.length - 1].pos - distance < totemGap * 10) { var ob = obstacles; setObstacles([ @@ -103,6 +144,7 @@ function PlayScreen() { }, ]); } + // Check for collisions with obstacles or floor if ( (obstacles[0].pos - distance + (totem_height * 4) / 18 < birdLeft + 60 && obstacles[0].pos - distance + (totem_height * 4) / 18 > birdLeft && @@ -113,20 +155,23 @@ function PlayScreen() { totem_height)) || birdTop > availableHeight - 60 ) { - localStorage.setItem("currentScore",score); setGameStopped(true); if (score > bestScore) { setBestScore(score); + setCurrentScore(score); + console.log("best: " + bestScore + " Current: " + currentScore); } setBirdDead(true); } }, [distance]); + + // Render the game screen if (!birdDead) { return (
    {obstacles.length > 0 && - obstacles.map((item, index) => { - return ( -
    - - -
    - ); - })} + obstacles.map((item, index) => ( +
    + + +
    + ))} {gameStopped && }
    ); } else { - return ; + return ; } } diff --git a/Client/src/screens/SignInPage.jsx b/Client/src/screens/SignInPage.jsx index b1bb513..9baa7f5 100644 --- a/Client/src/screens/SignInPage.jsx +++ b/Client/src/screens/SignInPage.jsx @@ -1,129 +1,122 @@ import React, { useState } from "react"; -import { auth, provider, signInWithPopup, signOut } from '../../../Server/src/firebase/firebase'; -import { useNavigate } from 'react-router-dom'; +import { auth, provider, signInWithPopup } from '../../../Server/src/firebase/firebase'; // Firebase authentication +import { useNavigate } from 'react-router-dom'; // For navigation after authentication +import { useGameContext } from '../contexts/gameContext'; // Game context for getting player name and score +// Importing images used in the sign-in page import Note from "../assets/LoginPage_board.png"; import signb from "../assets/LoginPage_signboard1.png"; import GoogleIcon from "../assets/google-icon.png"; import AnonyPersonIcon from "../assets/anonymous-icon.png"; -import getRandomName from "../utils/utils"; - +// Function to submit the score to the server const submitScore = async (username, score) => { - try { - const rank = -1; - const data = { - username, - score, - rank, - }; - - const response = await fetch('https://flappy-api.poseidon0z.com/api/gameusers', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - throw new Error('Failed to submit game data'); - } - - const result = await response.json(); - console.log(result.message); - } catch (error) { - console.error('Error submitting game data:', error); - } - }; + try { + const data = { username, score }; + console.log("started fetch"); + // Send POST request to the server with the username and score + const response = await fetch('https://flappy-api.poseidon0z.com/api/gameusers', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + console.log("completed fetch"); -const SignInPage = ({ setStayAnonymous }) => { - const navigate = useNavigate(); + if (!response.ok) throw new Error('Failed to submit game data'); + const result = await response.json(); + console.log(result.message); + } catch (error) { + console.error('Error submitting game data:', error); + } +}; - let [isSigningIn, setIsSigningIn] = useState(false); - let [errorMessage, setErrorMessage] = useState(''); - - const handleSignIn = () => { - setIsSigningIn(true); - signInWithPopup(auth, provider) - .then(async (result) => { - const nameArr = result.user.displayName.split(" "); - const name = nameArr[0]+" "+nameArr[1]; - const score = localStorage.getItem("currentScore"); - console.log('User info:', name); - await submitScore(name,score); - navigate("/leaderboard"); - }) - .catch((error) => { - const errorCode = error.code; - errorMessage = error.message; - console.log('Error code:', errorCode); - console.log('Error message:', errorMessage); - setErrorMessage(errorMessage); - setIsSigningIn(false); - }); - }; +const SignInPage = ({ setStayAnonymous, setLoggedIn }) => { + const navigate = useNavigate(); // Hook to programmatically navigate + const { playerName, currentScore, setPlayerName } = useGameContext(); // Game context values + let [isSigningIn, setIsSigningIn] = useState(false); // State for managing the sign-in process + let [errorMessage, setErrorMessage] = useState(''); // State for storing any error messages - /*const handleSignOut = () => { - signOut(auth) - .then(() => { - console.log('User signed out'); - }) - .catch((error) => { - console.log('Sign out error:', error); - }); - };*/ + // Handle Google sign-in with Firebase + const handleSignIn = () => { + setIsSigningIn(true); // Set signing-in state to true + signInWithPopup(auth, provider) // Trigger sign-in popup + .then(async (result) => { + const nameArr = result.user.displayName.split(" "); // Split display name into first and last names + const name = nameArr[0] + " " + nameArr[1]; // Concatenate first and last names + setPlayerName(name); // Set player name in the game context + localStorage.setItem("UserInfo", name); // Store user name in localStorage + console.log('User info:', name); + await submitScore(name, currentScore); // Submit score to the server + console.log("submitted"); + localStorage.setItem('isLoggedIn', 'true'); // Set login status in localStorage + localStorage.setItem('stayAnonymous', 'false'); // Update anonymous status + navigate("/leaderboard"); // Navigate to the leaderboard page + }) + .catch((error) => { + const errorCode = error.code; + const errorMessage = error.message; + console.log('Error code:', errorCode); + console.log('Error message:', errorMessage); + setErrorMessage(errorMessage); // Update error message state + setIsSigningIn(false); // Set signing-in state to false + setStayAnonymous(false); // Ensure stay anonymous state is false + }); + }; - const newAnonymous = async () => { - const name = getRandomName(); - const score = localStorage.getItem("currentScore"); - console.log("Submit Data: ",{name,score}); - await submitScore(name,score); - navigate("/leaderboard"); - setStayAnonymous(true); - }; + // Handle anonymous login + const newAnonymous = async () => { + const name = playerName; // Use current player name + const score = currentScore; // Use current score + console.log("Submit Data: ", { name, score }); + await submitScore(name, score); // Submit score to the server + localStorage.setItem('isLoggedIn', 'false'); // Set login status to false + localStorage.setItem('stayAnonymous', 'true'); // Update anonymous status + navigate("/leaderboard"); // Navigate to the leaderboard page + }; - return ( -
    -
    - -
    -

    Login to have your name

    -

    on the leaderboard

    -
    -
    + return ( +
    + {/* Background and title section */} +
    + +
    +

    Login to have your name

    +

    on the leaderboard

    +
    +
    -
    - Signboard - -
    - -
    + {/* Sign-in and anonymous buttons */} +
    + Signboard + +
    + +
    -
    - -
    -
    +
    +
    - ); +
    +
    + ); }; -export default SignInPage; \ No newline at end of file +export default SignInPage; diff --git a/Client/src/screens/play.css b/Client/src/screens/play.css deleted file mode 100644 index 1162cb6..0000000 --- a/Client/src/screens/play.css +++ /dev/null @@ -1,20 +0,0 @@ -@keyframes scrollBackground { - from { - background-position: 0 0; - } - - to { - background-position: 1000% 0; - } -} - -.background-stuff { - background-image: url('../assets/playBackground.png'); - background-repeat: repeat-x; - background-size: cover; - position: relative; -} - -.bg-scroll { - animation: scrollBackground 120s linear infinite; -} \ No newline at end of file diff --git a/Client/src/utils/utils.js b/Client/src/utils/utils.js index 2dcb9f2..bd43111 100644 --- a/Client/src/utils/utils.js +++ b/Client/src/utils/utils.js @@ -1,3 +1,5 @@ +// Array of animal and bird names + const animalsAndBirds = [ 'Lion', 'Elephant', @@ -83,14 +85,26 @@ const animalsAndBirds = [ 'Exotic', 'Scavenging', ]; + // Function to generate a random name + const getRandomName = () => { + // Randomly select an adjective from the adjectives array + const randomAdjective = adjectives[Math.floor(Math.random() * adjectives.length)]; + // Randomly select an animal or bird from the animalsAndBirds array + const randomAnimalOrBird = animalsAndBirds[Math.floor(Math.random() * animalsAndBirds.length)]; + // Combine the selected adjective and animal/bird name to form a random name + const randomName = randomAdjective + randomAnimalOrBird; + // Save the generated random name to local storage under the key 'username' + localStorage.setItem('username', randomName); + // Return the generated random name + return randomName; }; diff --git a/Client/tailwind.config.js b/Client/tailwind.config.js index d867cbf..cfc665e 100644 --- a/Client/tailwind.config.js +++ b/Client/tailwind.config.js @@ -1,76 +1,91 @@ /** @type {import('tailwindcss').Config} */ module.exports = { + // Specifies the files Tailwind should scan for class names content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'], + theme: { extend: { + // Custom font families for the project fontFamily: { - fonts: ['"Post No Bills Colombo ExtraBold"', 'sans-serif'], - fam: ['"Post No Bills Jaffna ExtraBold"', 'sans-serif'], + fonts: ['"Post No Bills Colombo ExtraBold"', 'sans-serif'], // Custom font for "fonts" key + fam: ['"Post No Bills Jaffna ExtraBold"', 'sans-serif'], // Custom font for "fam" key }, + + // Custom background images backgroundImage: { - playbg: 'url(./assets/playBackground.png)', - 'signin-bg': 'url(./assets/LoginPage_bg.png)', - 'flappybird-playbg': "url('./assets/playscreen_bg.jpg')", - 'flappybird-mobbg': "url('./assets/playscreen_mobile-bg.png')", - pipe: "url('./assets/playscreen_obstacle.png')", - flappybird: "url('./assets/playscreen_bird.png')", - flappybirdbigeye: "url('./assets/playscreen_bird_big_eye.png')", - 'flappybird-desk': "url('./assets/homePage_desktopBg.png')", - 'flappybird-mob': "url('./assets/homePage_mobileBg.png')", - deskview: "url('./assets/certificate_gamebg.png')", - phoneview: "url('./assets/certificate_phonebgg.png')", - }, + playbg: 'url(./src/assets/playBackground.png)', + 'signin-bg': "url('./src/assets/homePage_desktopBg.png')", + 'flappybird-playbg': "url('./src/assets/playscreen_bg.jpg')", + 'flappybird-mobbg': "url('./src/assets/playscreen_mobile-bg.png')", + pipe: "url('./src/assets/playscreen_obstacle.png')", + flappybird: "url('./src/assets/playscreen_bird.png')", + flappybirdbigeye: "url('./src/assets/playscreen_bird_big_eye.png')", + 'flappybird-desk': "url('./src/assets/homePage_desktopBg.png')", + 'flappybird-mob': "url('./src/assets/homePage_mobileBg.png')", + "background-stuff" : "url('./src/assets/playBackground.png')", +      }, + + // Custom screen sizes for responsive design screens: { - 'max-w-600px': { max: '600px' }, - 'min-w-600px': { min: '600px' }, - '927px': '927px', - '741px':'741px', - 'custom-xs':'400px', + 'max-w-600px': { max: '600px' }, // Maximum width of 600px + 'min-w-600px': { min: '600px' }, // Minimum width of 600px + '927px': '927px', // Custom screen size at 927px + '741px': '741px', // Custom screen size at 741px + 'custom-xs': '400px', // Custom screen size at 400px }, + + // Custom border-radius values borderRadius: { - custom: '50px', - 'custom-tl': '15px', - 'custom-br-tr': '50px', - 'custom-bl': '50px', + custom: '50px', // Custom border-radius of 50px + 'custom-tl': '15px', // Custom border-radius for top-left corner + 'custom-br-tr': '50px', // Custom border-radius for bottom-right and top-right corners + 'custom-bl': '50px', // Custom border-radius for bottom-left corner }, + // Custom font sizes fontSize: { - 'custom-large': '57px', - 'custom-30px': '30px', - 'custom-27px': '27px', - 'custom-20px': '20px', - 'custom-22px': '22px', - 'custom-25px': '25px', + 'custom-large': '57px', // Custom large font size + 'custom-30px': '30px', // Custom font size of 30px + 'custom-27px': '27px', // Custom font size of 27px + 'custom-20px': '20px', // Custom font size of 20px + 'custom-22px': '22px', // Custom font size of 22px + 'custom-25px': '25px', // Custom font size of 25px }, + // Custom spacing values spacing: { - 16: '65px', - 'custom-width': '230px', - 'custom-margin-top': '100px', - '-45px': '-45px', - '-110px': '-110px', - '50px': '50px', - '200px': '200px', - '150px': '150px', - '110px': '110px', - '80px': '80px', - '-90px': '-90px', - '180px': '180px', - '130px': '130px', - '30px': '30px', - '25px': '25px', - '40px': '40px', - '90px': '90px', - '100px': '100px', + 16: '65px', // Custom spacing of 65px + 'custom-width': '230px', // Custom width of 230px + 'custom-margin-top': '100px', // Custom margin-top of 100px + '-45px': '-45px', // Custom negative spacing of -45px + '-110px': '-110px', // Custom negative spacing of -110px + '50px': '50px', // Custom spacing of 50px + '200px': '200px', // Custom spacing of 200px + '150px': '150px', // Custom spacing of 150px + '110px': '110px', // Custom spacing of 110px + '80px': '80px', // Custom spacing of 80px + '-90px': '-90px', // Custom negative spacing of -90px + '180px': '180px', // Custom spacing of 180px + '130px': '130px', // Custom spacing of 130px + '30px': '30px', // Custom spacing of 30px + '25px': '25px', // Custom spacing of 25px + '40px': '40px', // Custom spacing of 40px + '90px': '90px', // Custom spacing of 90px + '100px': '100px', // Custom spacing of 100px }, + // Custom letter spacing letterSpacing: { - 'custom-spacing': '1px', + 'custom-spacing': '1px', // Custom letter spacing of 1px }, + + // Custom height values height: { - '95px': '95px', + '95px': '95px', // Custom height of 95px }, }, + + // No additional plugins used plugins: [], }, }; diff --git a/Server/src/firebase/firebase.js b/Server/src/firebase/firebase.js index 4bf3c97..a54a92c 100644 --- a/Server/src/firebase/firebase.js +++ b/Server/src/firebase/firebase.js @@ -2,15 +2,16 @@ import { initializeApp } from 'firebase/app'; import { getAuth, GoogleAuthProvider,signInWithPopup, signOut } from 'firebase/auth'; const firebaseConfig = { - apiKey: "AIzaSyDLVc3eY_nDJIN456OtwK-BNzmLZPGV6xI", - authDomain: "flappy-bird-73f3e.firebaseapp.com", - projectId: "flappy-bird-73f3e", - storageBucket: "flappy-bird-73f3e.appspot.com", - messagingSenderId: "280886096397", - appId: "1:280886096397:web:d7966ad1c7bd2e52979b44", - measurementId: "G-Q7LT2VR698" + apiKey: "AIzaSyCe9jnQ_hwakzp0xQXXxcp6kdpr5OOY3mk", + authDomain: "flappy-bird-codechef.firebaseapp.com", + projectId: "flappy-bird-codechef", + storageBucket: "flappy-bird-codechef.appspot.com", + messagingSenderId: "292086757103", + appId: "1:292086757103:web:9b752cc035f33b52810d1a", + measurementId: "G-36K0VEV71M" }; + const app = initializeApp(firebaseConfig); const auth = getAuth(app); const provider = new GoogleAuthProvider(); diff --git a/Server/src/gameUserModel.js b/Server/src/gameUserModel.js index bc2a10b..22cf6f1 100644 --- a/Server/src/gameUserModel.js +++ b/Server/src/gameUserModel.js @@ -3,7 +3,6 @@ import mongoose from 'mongoose'; const gameUserSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true }, score: { type: Number, required: true }, - rank: { type: Number, required: true } }); const GameUser = mongoose.model('GameUser', gameUserSchema); diff --git a/Server/src/index.js b/Server/src/index.js index 245eebb..1702ba1 100644 --- a/Server/src/index.js +++ b/Server/src/index.js @@ -1,6 +1,4 @@ import express from 'express'; -import https from 'https'; -import fs from 'fs'; import bodyParser from 'body-parser'; import cors from 'cors'; import mongoose from 'mongoose'; @@ -21,6 +19,7 @@ mongoose.connect(MONGO_URI, { app.use(cors()); app.use(bodyParser.json()); + app.use('/api', userRoutes); if (process.env.NODE_ENV !== 'test') { diff --git a/Server/src/routes.js b/Server/src/routes.js index 557b658..b61559d 100644 --- a/Server/src/routes.js +++ b/Server/src/routes.js @@ -1,39 +1,30 @@ import express from 'express'; import GameUser from './gameUserModel.js'; -const updateAllRanks = async () => { - try { - const users = await GameUser.find().sort({ score: -1 }); - for (let i = 0; i < users.length; i++) { - users[i].rank = i + 1; - await users[i].save(); - } - } catch (error) { - console.error('Error updating ranks:', error); - } -}; const router = express.Router(); router.post('/gameusers', async (req, res) => { - const { username, score, rank } = req.body; + const { username, score } = req.body; - if (!username || !score || !rank) { + if (!username || !score) { return res.status(400).json({ error: 'All fields are required' }); } try { const existingUser = await GameUser.findOne({ username }); if (existingUser) { - return res.status(400).json({ error: 'User already exists' }); + if (score > existingUser.score) { + await GameUser.updateOne({ username }, { score }); + return res.status(200).json({ message: 'User score updated successfully' }); + } else { + return res.status(200).json({ message: 'New score is not higher than existing score' }); + } + }else{ + const newUser = new GameUser({ username, score}); + await newUser.save(); + res.status(201).json({ message: 'Game user created successfully' }); } - - const newUser = new GameUser({ username, score, rank }); - await newUser.save(); - - await updateAllRanks(); - - res.status(201).json({ message: 'Game user created successfully' }); } catch (error) { console.error('Error creating game user:', error); res.status(500).json({ error: 'Internal server error' }); @@ -58,7 +49,7 @@ router.delete('/gameusers/:username', async (req, res) => { router.get('/gameusers', async (_req, res) => { try { - const users = await GameUser.find().sort({ rank: 1 }); + const users = await GameUser.find().sort({ score: -1 }).limit(100); res.status(200).json(users); } catch (error) { console.error('Error fetching game users:', error);