diff --git a/README.md b/README.md index e240001b..2558d25b 100644 --- a/README.md +++ b/README.md @@ -1 +1,200 @@ -REPLACE THIS WITH A DESCRIPTION OF YOUR GAME (in the README.md file). +# Git Cat + +## Elevator Pitch + +In the game there will be checkpoints placed within the platformer levels (similar to mario) that act as respawn/progress checkpoints. To unlock these checkpoints, the player must enter a terminal. Inside this terminal there will be three options; a minigame, a problem/learning objective and hints/tips. These hints and tips will be obtained by discovering them in various levels, interacting with NPCs or completing the Among Us style minigames. + + +## Influences (Brief) + +- “Wall-E” + - Medium: Movie + - Explanation: World-building and story +- “Among Us” + - Medium: Game + - Explanation: Mechanics mainly focused around “mini games” within a grander game +- “Risk of Rain 2” + - Medium: Game + - Explanation: Music/soundtrack from the game +- “Mario (platformers)” + - Medium: Game + - Explanation: Gameplay (progression) style + +## Core Gameplay Mechanics (Brief) + +- Basic Platformer Movement Mechanics +- Git terminal + - Button’s to input commands initially + - Typing to insert commands at later levels. +- Among Us Style Mini Games. Drag matches together. Flick switches by clicking. +- Collect coins +- Spike respawn +- Enemy interaction, projectiles, jump on to damage. + +# Learning Aspects + +## Learning Domains + +* Git knowledge + *Interacting with a git repo + *Using the console + *Learning commands + *Solving merge conflicts + +## Target Audiences + +* Beginner programmers +* Freshman in college or in AP programming courses (beyond 8th grade) + +## Target Contexts + +* The most likely use for this game is in an informal setting. A professor might recommend it as an external resource to get used to the git commands and using github without having the stress of an assignment. +* This game would not be suitable for a formal in class setting due to its use of audio and the time it might take to learn the content. + +## Learning Objectives + +- Git Commands: By the end of instruction students will be able to identify the proper situations to use git commands and execute them. +- GitHub Structure: By the end of instruction students will be able to explain how github repositories are structured and where the code is held. +- Git Errors: By the end of instruction students will be able to select the proper solutions to a github error. + +## Prerequisite Knowledge + +- Very basic programming knowledge (if, for, types) +- Know what github is. Don't have to know much about it. + +## Assessment Measures + +* Pre/Post Test + * Multiple-Choice Questions like: How would you handle this git error? + * What does this command do? etc. + +# What sets this project apart? + +- The game will be adaptable to the learning needs of the player +- The game will have a heavy narrative/set and setting that will not only drive the plot, but also the players interest and engagement +- Our approach to designing a platformer game will include ideas from a variety of other platformer titles such as difficulty through movement, time constraints, enemy types, etc… + +# Player Interaction Patterns and Modes + +## Player Interaction Pattern + +Players will interact with the game in a solo setting as the game is intended to be played single player. There will be 3 distinct game modes with possible variation added in the future. These modes include the platformer mode, learning/terminal mode and minigame mode. The game will be played primarily using a mouse and keyboard with players using the keyboard to control player movement and their mouse to navigate through the UI elements of the game. + +## Player Modes + +- Main Menu: The player, when starting the game, will be greeted with a main menu giving them an option to play the game where they left off (continue), level select, options and help/tutorial +- Narrative: In between levels and UI menus, there will be a series of cutscenes that convey a story. Levels are locked until the prior level is completed (linear structure) +- Platformer: The main gameplay/level design will follow classic platformer structure +- Terminal: The terminal or checkpoints that are placed throughout the level are interactable and will contain the + +# Gameplay Objectives + +- Complete all Platformer Levels + - Description: Make it through the platformer levels and collect as many coins as possible. + - Alignment: Along the way will gain information on git commands or various errors as they progress. +- Complete Git Terminal. Bosses: + - Description: Given a particular git situation and have to find the solution + - Alignment: Assesses and refreshes the memory of knowledge gained throughout the platformer. Can use logs to help recall. + +# Procedures/Actions + +* You can walk and collect by colliding +* Interact with certain elements with e for example to pick up a log +* Typing in the terminal to solve issues + +# Rules + +* If the player reaches a certain point in the platformer they will get tips about git +* When the player collects coins they will know they’re on the right path +* When found logs will be given that give knowledge that can be used to fight the terminal boss. (These can be accessed at any time) +* If the player tries too many times and gets the wrong answer a hint will be given via relevant log. +* Over time the terminal bosses will range from: + * Easier where the git command is already on the screen (either in buttons or in tiles that need to be connected) and all the player has to do is select the proper order. + * Players need to type their own commands into the terminal. + +# Objects/Entities + +* There’s the main character who’s a small space cat +* There’s a couple other cats of similar style to the main character cat (differing in colors) that will act as NPCs. Some will have space outfits similar to the main characters and others will have outfits matching their planet/situation +* There’s blocks of broken up git commands in the terminal interface +* There’s various different enemies +* Platforms that will be collided with +* Coin counter +* A spaceship that the main character lands with +* A terminal that the main character interacts with (to be found while platforming) + +## Core Gameplay Mechanics (Detailed) + +- Basic Platformer Movement Mechanics: Wasd or arrow keys for movement. Space for jump. E to interact +- Git terminal: Navigate UI with mouse. Button’s to input commands initially. Typing to insert commands at later levels. +- Among Us Style Mini Games: Click and drag matches together. Flick switches by clicking. +- Collect coins: Walking over coins with wasd +- Spike respawn: Colliding with a spike or enemy will make you respawn at set checkpoints. +- Enemy interaction: Projectiles either fired by you or the enemies or both, Jump on or hit enemies with projectiles to damage. + +## Feedback + +* Sound when collecting coins +* Sound when finding a log +* Sound when reaching key checkpoints. +* Visual feedback when “winning a level” + +* As they progress levels will unlock and that will show progression +* Negative feedback via sound or visual when getting something incorrect + +# Story and Gameplay + +## Presentation of Rules + +The player will learn the core gameplay mechanics during the tutorial at the beginning of the game. It will teach them how to move (with which buttons) and how to jump. It will also show them that spikes or other enemies are dangerous to the player. There won’t be big walls of text and instead the player is expected to fail as many times as needed before understanding the mechanics of the game. + +For the terminal mechanics there will be a hint system. In the terminal there will be an option to open “Logs” of past space cats who were having trouble navigating the terminal. In the Logs will be hints as to how the player can proceed and what the player should do. + +## Presentation of Content + +The player will learn the core material of Git through their interaction with NPCs, Logs and mini games. If the player chooses to interact with NPCs they will receive Git hints and clues relating to the upcoming Git “test” in that level. In each level there will also be mini games that will teach them how to connect, order and write Git commands. These mini games will be accessed through the same object that the player will interact with to get to the terminal. The “final” terminal screen features a coding assessment-style game that will test them on their new Git knowledge from the mini games, NPC dialogue and Logs. The Logs are accessed through the same object that is interacted with to get to the mini games and terminal. If the player decides they want help or need more Git information, they will be able to click on “Logs” and see previous cat messages pertaining to how they tackled the issue or what a command means. + +## Story (Brief) + +TLDR: Many cats are working together to face the enemy. You play as different characters on different levels and your goal is to collect clues that aid in completing your final task within the terminal. + +## Storyboarding + +![alt text](https://github.com/UD-S24-CISC374/final-project-magenta/blob/df63f4e046fcd08c05c41fde732cf85ab6ba25de/docs/Git%20Cat%20storyboard.png) + +# Assets Needed + +## Aesthetics + +The primary aesthetic of the game will be “space/futuristic” including different planets, synth driven music and sound design and tying that all together through the narrative which fundamentally is a “space exploration game” where the player unlocks and travels to new planets (levels). Cave systems, secret areas or other similar ideas have been discussed and may slightly deviate from this aesthetic however not to the point where it feels like it doesn't fit, rather to throw some variety into the mix. + +## Graphical + +Link for all assets: +- Characters List + - Git: main character (player) + - Claw: antagonist +- Textures: https://github.com/UD-S24-CISC374/final-project-magenta/tree/main/assets/Art +- Environment Art/Textures :https://github.com/UD-S24-CISC374/final-project-magenta/tree/main/assets/Art + +## Audio + +- Music List (Ambient sound) + - https://github.com/UD-S24-CISC374/final-project-magenta/tree/main/assets/Sound + - all music/ambient sounds can be found inside this github repo link + - music and ambient noise is meant to feel spacy, futuristic, calming / increased tempo depending on in-game events. The player may be in space and the background music will contain synths and try to match that set/setting, on a planet, the music will change to reflect that environment more. + - inspiration for some of the music created: https://www.youtube.com/watch?v=EGXPAoyP_cg&list=PLLDf8Bnp1K1JPWia6_x8-1K2sVmXGYvJD&index=15 + +- Sound List (SFX) + - Item Collection: +- https://www.youtube.com/watch?v=TCD77mH0lYs +- https://www.youtube.com/watch?v=88Icb7OKexU + - UI interaction: +-https://www.youtube.com/watch?v=OOOm7jZicEg +-https://www.youtube.com/watch?v=V8JaLTqUx60 + +# Metadata + +* Template created by Austin Cory Bart , Mark Sheriff, Alec Markarian, and Benjamin Stanley. +* Version 0.0.3 + diff --git a/assets/Art/CommTerminal.png b/assets/Art/CommTerminal.png new file mode 100644 index 00000000..39225aa6 Binary files /dev/null and b/assets/Art/CommTerminal.png differ diff --git a/assets/Art/background-1-level1.png b/assets/Art/background-1-level1.png new file mode 100644 index 00000000..4b98a285 Binary files /dev/null and b/assets/Art/background-1-level1.png differ diff --git a/assets/Art/background-2-level1.png b/assets/Art/background-2-level1.png new file mode 100644 index 00000000..7094a02b Binary files /dev/null and b/assets/Art/background-2-level1.png differ diff --git a/assets/Art/blue_plat_1.png b/assets/Art/blue_plat_1.png new file mode 100644 index 00000000..611d7011 Binary files /dev/null and b/assets/Art/blue_plat_1.png differ diff --git a/assets/Art/brown_plat_1.png b/assets/Art/brown_plat_1.png new file mode 100644 index 00000000..a07ca178 Binary files /dev/null and b/assets/Art/brown_plat_1.png differ diff --git a/assets/Art/buttons.png b/assets/Art/buttons.png new file mode 100644 index 00000000..2b12c963 Binary files /dev/null and b/assets/Art/buttons.png differ diff --git a/assets/Art/cat_1.png b/assets/Art/cat_1.png new file mode 100644 index 00000000..4258329b Binary files /dev/null and b/assets/Art/cat_1.png differ diff --git a/assets/Art/level_1_bg.png b/assets/Art/level_1_bg.png new file mode 100644 index 00000000..0dcfd27e Binary files /dev/null and b/assets/Art/level_1_bg.png differ diff --git a/assets/Art/mars-tileset-1.png b/assets/Art/mars-tileset-1.png new file mode 100644 index 00000000..7093f68b Binary files /dev/null and b/assets/Art/mars-tileset-1.png differ diff --git a/assets/Art/mars_plat_1.png b/assets/Art/mars_plat_1.png new file mode 100644 index 00000000..f7c4fd2a Binary files /dev/null and b/assets/Art/mars_plat_1.png differ diff --git a/assets/Art/npc_1.png b/assets/Art/npc_1.png new file mode 100644 index 00000000..8fb8f1f8 Binary files /dev/null and b/assets/Art/npc_1.png differ diff --git a/assets/Art/npc_2.png b/assets/Art/npc_2.png new file mode 100644 index 00000000..f13ae69c Binary files /dev/null and b/assets/Art/npc_2.png differ diff --git a/assets/Art/npc_3.png b/assets/Art/npc_3.png new file mode 100644 index 00000000..993b0020 Binary files /dev/null and b/assets/Art/npc_3.png differ diff --git a/assets/Art/planet-1.png b/assets/Art/planet-1.png new file mode 100644 index 00000000..6531e151 Binary files /dev/null and b/assets/Art/planet-1.png differ diff --git a/assets/Art/planet-4.png b/assets/Art/planet-4.png new file mode 100644 index 00000000..9a9d621a Binary files /dev/null and b/assets/Art/planet-4.png differ diff --git a/assets/Art/red_plat_1.png b/assets/Art/red_plat_1.png new file mode 100644 index 00000000..ed5b2c7e Binary files /dev/null and b/assets/Art/red_plat_1.png differ diff --git a/assets/Art/space_bg.png b/assets/Art/space_bg.png new file mode 100644 index 00000000..21535541 Binary files /dev/null and b/assets/Art/space_bg.png differ diff --git a/assets/Art/spikes.png b/assets/Art/spikes.png new file mode 100644 index 00000000..a919b033 Binary files /dev/null and b/assets/Art/spikes.png differ diff --git a/assets/Art/spikes_hor.png b/assets/Art/spikes_hor.png new file mode 100644 index 00000000..7b02dba7 Binary files /dev/null and b/assets/Art/spikes_hor.png differ diff --git a/assets/Art/spikes_vert.png b/assets/Art/spikes_vert.png new file mode 100644 index 00000000..e42b3b89 Binary files /dev/null and b/assets/Art/spikes_vert.png differ diff --git a/assets/Art/star.png b/assets/Art/star.png new file mode 100644 index 00000000..bfc2d298 Binary files /dev/null and b/assets/Art/star.png differ diff --git a/assets/Sound/gitcat_chill_demo.mp3 b/assets/Sound/gitcat_chill_demo.mp3 new file mode 100644 index 00000000..53e86e8a Binary files /dev/null and b/assets/Sound/gitcat_chill_demo.mp3 differ diff --git a/assets/Sound/gitcat_chill_demo2.mp3 b/assets/Sound/gitcat_chill_demo2.mp3 new file mode 100644 index 00000000..96f81e7b Binary files /dev/null and b/assets/Sound/gitcat_chill_demo2.mp3 differ diff --git a/docs/Git Cat storyboard.png b/docs/Git Cat storyboard.png new file mode 100644 index 00000000..de65d717 Binary files /dev/null and b/docs/Git Cat storyboard.png differ diff --git a/docs/egdd.md b/docs/egdd.md index 51ed6536..2558d25b 100644 --- a/docs/egdd.md +++ b/docs/egdd.md @@ -1 +1,200 @@ -REPLACE THIS TEXT WITH YOUR EGDD MARKDOWN. +# Git Cat + +## Elevator Pitch + +In the game there will be checkpoints placed within the platformer levels (similar to mario) that act as respawn/progress checkpoints. To unlock these checkpoints, the player must enter a terminal. Inside this terminal there will be three options; a minigame, a problem/learning objective and hints/tips. These hints and tips will be obtained by discovering them in various levels, interacting with NPCs or completing the Among Us style minigames. + + +## Influences (Brief) + +- “Wall-E” + - Medium: Movie + - Explanation: World-building and story +- “Among Us” + - Medium: Game + - Explanation: Mechanics mainly focused around “mini games” within a grander game +- “Risk of Rain 2” + - Medium: Game + - Explanation: Music/soundtrack from the game +- “Mario (platformers)” + - Medium: Game + - Explanation: Gameplay (progression) style + +## Core Gameplay Mechanics (Brief) + +- Basic Platformer Movement Mechanics +- Git terminal + - Button’s to input commands initially + - Typing to insert commands at later levels. +- Among Us Style Mini Games. Drag matches together. Flick switches by clicking. +- Collect coins +- Spike respawn +- Enemy interaction, projectiles, jump on to damage. + +# Learning Aspects + +## Learning Domains + +* Git knowledge + *Interacting with a git repo + *Using the console + *Learning commands + *Solving merge conflicts + +## Target Audiences + +* Beginner programmers +* Freshman in college or in AP programming courses (beyond 8th grade) + +## Target Contexts + +* The most likely use for this game is in an informal setting. A professor might recommend it as an external resource to get used to the git commands and using github without having the stress of an assignment. +* This game would not be suitable for a formal in class setting due to its use of audio and the time it might take to learn the content. + +## Learning Objectives + +- Git Commands: By the end of instruction students will be able to identify the proper situations to use git commands and execute them. +- GitHub Structure: By the end of instruction students will be able to explain how github repositories are structured and where the code is held. +- Git Errors: By the end of instruction students will be able to select the proper solutions to a github error. + +## Prerequisite Knowledge + +- Very basic programming knowledge (if, for, types) +- Know what github is. Don't have to know much about it. + +## Assessment Measures + +* Pre/Post Test + * Multiple-Choice Questions like: How would you handle this git error? + * What does this command do? etc. + +# What sets this project apart? + +- The game will be adaptable to the learning needs of the player +- The game will have a heavy narrative/set and setting that will not only drive the plot, but also the players interest and engagement +- Our approach to designing a platformer game will include ideas from a variety of other platformer titles such as difficulty through movement, time constraints, enemy types, etc… + +# Player Interaction Patterns and Modes + +## Player Interaction Pattern + +Players will interact with the game in a solo setting as the game is intended to be played single player. There will be 3 distinct game modes with possible variation added in the future. These modes include the platformer mode, learning/terminal mode and minigame mode. The game will be played primarily using a mouse and keyboard with players using the keyboard to control player movement and their mouse to navigate through the UI elements of the game. + +## Player Modes + +- Main Menu: The player, when starting the game, will be greeted with a main menu giving them an option to play the game where they left off (continue), level select, options and help/tutorial +- Narrative: In between levels and UI menus, there will be a series of cutscenes that convey a story. Levels are locked until the prior level is completed (linear structure) +- Platformer: The main gameplay/level design will follow classic platformer structure +- Terminal: The terminal or checkpoints that are placed throughout the level are interactable and will contain the + +# Gameplay Objectives + +- Complete all Platformer Levels + - Description: Make it through the platformer levels and collect as many coins as possible. + - Alignment: Along the way will gain information on git commands or various errors as they progress. +- Complete Git Terminal. Bosses: + - Description: Given a particular git situation and have to find the solution + - Alignment: Assesses and refreshes the memory of knowledge gained throughout the platformer. Can use logs to help recall. + +# Procedures/Actions + +* You can walk and collect by colliding +* Interact with certain elements with e for example to pick up a log +* Typing in the terminal to solve issues + +# Rules + +* If the player reaches a certain point in the platformer they will get tips about git +* When the player collects coins they will know they’re on the right path +* When found logs will be given that give knowledge that can be used to fight the terminal boss. (These can be accessed at any time) +* If the player tries too many times and gets the wrong answer a hint will be given via relevant log. +* Over time the terminal bosses will range from: + * Easier where the git command is already on the screen (either in buttons or in tiles that need to be connected) and all the player has to do is select the proper order. + * Players need to type their own commands into the terminal. + +# Objects/Entities + +* There’s the main character who’s a small space cat +* There’s a couple other cats of similar style to the main character cat (differing in colors) that will act as NPCs. Some will have space outfits similar to the main characters and others will have outfits matching their planet/situation +* There’s blocks of broken up git commands in the terminal interface +* There’s various different enemies +* Platforms that will be collided with +* Coin counter +* A spaceship that the main character lands with +* A terminal that the main character interacts with (to be found while platforming) + +## Core Gameplay Mechanics (Detailed) + +- Basic Platformer Movement Mechanics: Wasd or arrow keys for movement. Space for jump. E to interact +- Git terminal: Navigate UI with mouse. Button’s to input commands initially. Typing to insert commands at later levels. +- Among Us Style Mini Games: Click and drag matches together. Flick switches by clicking. +- Collect coins: Walking over coins with wasd +- Spike respawn: Colliding with a spike or enemy will make you respawn at set checkpoints. +- Enemy interaction: Projectiles either fired by you or the enemies or both, Jump on or hit enemies with projectiles to damage. + +## Feedback + +* Sound when collecting coins +* Sound when finding a log +* Sound when reaching key checkpoints. +* Visual feedback when “winning a level” + +* As they progress levels will unlock and that will show progression +* Negative feedback via sound or visual when getting something incorrect + +# Story and Gameplay + +## Presentation of Rules + +The player will learn the core gameplay mechanics during the tutorial at the beginning of the game. It will teach them how to move (with which buttons) and how to jump. It will also show them that spikes or other enemies are dangerous to the player. There won’t be big walls of text and instead the player is expected to fail as many times as needed before understanding the mechanics of the game. + +For the terminal mechanics there will be a hint system. In the terminal there will be an option to open “Logs” of past space cats who were having trouble navigating the terminal. In the Logs will be hints as to how the player can proceed and what the player should do. + +## Presentation of Content + +The player will learn the core material of Git through their interaction with NPCs, Logs and mini games. If the player chooses to interact with NPCs they will receive Git hints and clues relating to the upcoming Git “test” in that level. In each level there will also be mini games that will teach them how to connect, order and write Git commands. These mini games will be accessed through the same object that the player will interact with to get to the terminal. The “final” terminal screen features a coding assessment-style game that will test them on their new Git knowledge from the mini games, NPC dialogue and Logs. The Logs are accessed through the same object that is interacted with to get to the mini games and terminal. If the player decides they want help or need more Git information, they will be able to click on “Logs” and see previous cat messages pertaining to how they tackled the issue or what a command means. + +## Story (Brief) + +TLDR: Many cats are working together to face the enemy. You play as different characters on different levels and your goal is to collect clues that aid in completing your final task within the terminal. + +## Storyboarding + +![alt text](https://github.com/UD-S24-CISC374/final-project-magenta/blob/df63f4e046fcd08c05c41fde732cf85ab6ba25de/docs/Git%20Cat%20storyboard.png) + +# Assets Needed + +## Aesthetics + +The primary aesthetic of the game will be “space/futuristic” including different planets, synth driven music and sound design and tying that all together through the narrative which fundamentally is a “space exploration game” where the player unlocks and travels to new planets (levels). Cave systems, secret areas or other similar ideas have been discussed and may slightly deviate from this aesthetic however not to the point where it feels like it doesn't fit, rather to throw some variety into the mix. + +## Graphical + +Link for all assets: +- Characters List + - Git: main character (player) + - Claw: antagonist +- Textures: https://github.com/UD-S24-CISC374/final-project-magenta/tree/main/assets/Art +- Environment Art/Textures :https://github.com/UD-S24-CISC374/final-project-magenta/tree/main/assets/Art + +## Audio + +- Music List (Ambient sound) + - https://github.com/UD-S24-CISC374/final-project-magenta/tree/main/assets/Sound + - all music/ambient sounds can be found inside this github repo link + - music and ambient noise is meant to feel spacy, futuristic, calming / increased tempo depending on in-game events. The player may be in space and the background music will contain synths and try to match that set/setting, on a planet, the music will change to reflect that environment more. + - inspiration for some of the music created: https://www.youtube.com/watch?v=EGXPAoyP_cg&list=PLLDf8Bnp1K1JPWia6_x8-1K2sVmXGYvJD&index=15 + +- Sound List (SFX) + - Item Collection: +- https://www.youtube.com/watch?v=TCD77mH0lYs +- https://www.youtube.com/watch?v=88Icb7OKexU + - UI interaction: +-https://www.youtube.com/watch?v=OOOm7jZicEg +-https://www.youtube.com/watch?v=V8JaLTqUx60 + +# Metadata + +* Template created by Austin Cory Bart , Mark Sheriff, Alec Markarian, and Benjamin Stanley. +* Version 0.0.3 + diff --git a/package-lock.json b/package-lock.json index 279e7740..a8c3f17b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { - "name": "coding-3-phaser-scenes", + "name": "final-project", "version": "4.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "coding-3-phaser-scenes", + "name": "final-project", "version": "4.0.0", "license": "MIT", "dependencies": { - "phaser": "^3.70.0" + "phaser": "^3.70.0", + "phaser3-rex-plugins": "^1.80.2" }, "devDependencies": { "@types/jest": "^29.5.11", @@ -1820,7 +1821,6 @@ "version": "7.20.13", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -3943,8 +3943,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-differ": { "version": "3.0.0", @@ -4925,6 +4924,14 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6802,6 +6809,36 @@ "node": ">=10.17.0" } }, + "node_modules/i18next": { + "version": "22.5.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz", + "integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.20.6" + } + }, + "node_modules/i18next-http-backend": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.0.tgz", + "integrity": "sha512-Z/aQsGZk1gSxt2/DztXk92DuDD20J+rNudT7ZCdTrNOiK8uQppfvdjq9+DFQfpAnFPn3VZS+KQIr1S/W1KxhpQ==", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -8296,7 +8333,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -8789,6 +8825,14 @@ "node": ">=8" } }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8820,6 +8864,44 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -9069,6 +9151,11 @@ "node": ">=6" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -9195,6 +9282,25 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, + "node_modules/phaser3-rex-plugins": { + "version": "1.80.2", + "resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.2.tgz", + "integrity": "sha512-ZPA4c47WQRU6rqLdlOFizGU+ljtP4C2blhcpbYSsNMqNRHD7o8vRBEzEhl8w6CMGvcy+eVoA6v10cyL4eIZARw==", + "dependencies": { + "eventemitter3": "^3.1.2", + "i18next": "^22.5.1", + "i18next-http-backend": "^2.5.0", + "js-yaml": "^4.1.0", + "mustache": "^4.2.0", + "papaparse": "^5.4.1", + "webfontloader": "^1.6.28" + } + }, + "node_modules/phaser3-rex-plugins/node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -9541,8 +9647,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regenerator-transform": { "version": "0.15.1", @@ -11298,6 +11403,11 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webfontloader": { + "version": "1.6.28", + "resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz", + "integrity": "sha512-Egb0oFEga6f+nSgasH3E0M405Pzn6y3/9tOVanv/DLfa1YBIgcv90L18YyWnvXkRbIM17v5Kv6IT2N6g1x5tvQ==" + }, "node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", @@ -13408,7 +13518,6 @@ "version": "7.20.13", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.11" } @@ -15082,8 +15191,7 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "array-differ": { "version": "3.0.0", @@ -15814,6 +15922,14 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "requires": { + "node-fetch": "^2.6.12" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -17213,6 +17329,22 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "i18next": { + "version": "22.5.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz", + "integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==", + "requires": { + "@babel/runtime": "^7.20.6" + } + }, + "i18next-http-backend": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.5.0.tgz", + "integrity": "sha512-Z/aQsGZk1gSxt2/DztXk92DuDD20J+rNudT7ZCdTrNOiK8uQppfvdjq9+DFQfpAnFPn3VZS+KQIr1S/W1KxhpQ==", + "requires": { + "cross-fetch": "4.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -18311,7 +18443,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "requires": { "argparse": "^2.0.1" } @@ -18701,6 +18832,11 @@ } } }, + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -18729,6 +18865,35 @@ "tslib": "^2.0.3" } }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -18909,6 +19074,11 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -19013,6 +19183,27 @@ } } }, + "phaser3-rex-plugins": { + "version": "1.80.2", + "resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.2.tgz", + "integrity": "sha512-ZPA4c47WQRU6rqLdlOFizGU+ljtP4C2blhcpbYSsNMqNRHD7o8vRBEzEhl8w6CMGvcy+eVoA6v10cyL4eIZARw==", + "requires": { + "eventemitter3": "^3.1.2", + "i18next": "^22.5.1", + "i18next-http-backend": "^2.5.0", + "js-yaml": "^4.1.0", + "mustache": "^4.2.0", + "papaparse": "^5.4.1", + "webfontloader": "^1.6.28" + }, + "dependencies": { + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + } + } + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -19260,8 +19451,7 @@ "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "regenerator-transform": { "version": "0.15.1", @@ -20562,6 +20752,11 @@ "minimalistic-assert": "^1.0.0" } }, + "webfontloader": { + "version": "1.6.28", + "resolved": "https://registry.npmjs.org/webfontloader/-/webfontloader-1.6.28.tgz", + "integrity": "sha512-Egb0oFEga6f+nSgasH3E0M405Pzn6y3/9tOVanv/DLfa1YBIgcv90L18YyWnvXkRbIM17v5Kv6IT2N6g1x5tvQ==" + }, "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", diff --git a/package.json b/package.json index e285b2ae..55f69617 100644 --- a/package.json +++ b/package.json @@ -36,30 +36,31 @@ }, "license": "MIT", "dependencies": { - "phaser": "^3.70.0" + "phaser": "^3.70.0", + "phaser3-rex-plugins": "^1.80.2" }, "devDependencies": { + "@types/jest": "^29.5.11", + "@typescript-eslint/eslint-plugin": "^6.2.0", + "@typescript-eslint/parser": "^6.2.0", "@yandeu/prettier-config": "^0.0.3", "copy-webpack-plugin": "^10.1.0", + "eslint": "^8.46.0", "html-webpack-plugin": "^5.5.0", "javascript-obfuscator": "^4.0.0", + "jest": "^29.7.0", "prettier": "^2.5.1", "rimraf": "^3.0.2", "serve": "^14.1.2", + "ts-jest": "^29.1.1", "ts-loader": "^9.2.6", + "ts-node": "^10.9.2", "typescript": "^4.5.3", "webpack": "^5.65.0", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.6.0", "webpack-merge": "^5.8.0", "webpack-obfuscator": "^3.5.0", - "workbox-webpack-plugin": "^6.4.2", - "eslint": "^8.46.0", - "@types/jest": "^29.5.11", - "jest": "^29.7.0", - "ts-jest": "^29.1.1", - "ts-node": "^10.9.2", - "@typescript-eslint/eslint-plugin": "^6.2.0", - "@typescript-eslint/parser": "^6.2.0" + "workbox-webpack-plugin": "^6.4.2" } } diff --git a/src/Classes/LevelClass.ts b/src/Classes/LevelClass.ts new file mode 100644 index 00000000..9c547744 --- /dev/null +++ b/src/Classes/LevelClass.ts @@ -0,0 +1,15 @@ +import Phaser from "phaser"; + +export default abstract class LevelClass extends Phaser.Scene { + public terminalInputArr: string[] = []; + public CorrectTerminalArr: string[] = []; + public FeedbackText?: Phaser.GameObjects.Text; + + public setFeedbackText(text: Phaser.GameObjects.Text) { + this.FeedbackText = text; + } + constructor(config: string | Phaser.Types.Scenes.SettingsConfig) { + super(config); + this.terminalInputArr = []; + } +} diff --git a/src/components/buttonAndListeners.ts b/src/components/buttonAndListeners.ts new file mode 100644 index 00000000..07398c2c --- /dev/null +++ b/src/components/buttonAndListeners.ts @@ -0,0 +1,41 @@ +//import Phaser from "phaser"; +import TerminalButton from "./terminalButton"; +import { Listenter } from "./terminalListeners"; // Import the missing 'Listenter' class +import LevelClass from "../Classes/LevelClass"; +export class ButtonAndListensers { + constructor( + scene: LevelClass, + x: number, + y: number, + texture: string, + buttonNames: string[], + correctButtonOrder: string[], + feedbackFunction: ( + scene: LevelClass, + terminalInputArr: string[], + correctTerminalArr: string[] + ) => void + ) { + const SCENE_KEY = scene.scene.key; + + buttonNames.map((buttonName, index) => { + new TerminalButton( + scene, + x + index * 300, + y, + texture, + buttonName, + `${SCENE_KEY}_${buttonName}` + ); + new Listenter(scene, `${SCENE_KEY}_${buttonName}`); + }); + + scene.events.on("check_terminal_input", () => { + feedbackFunction( + scene, + scene.terminalInputArr, + scene.CorrectTerminalArr + ); + }); + } +} diff --git a/src/components/platform.ts b/src/components/platform.ts new file mode 100644 index 00000000..9064c6a2 --- /dev/null +++ b/src/components/platform.ts @@ -0,0 +1,36 @@ +import Phaser from "phaser"; + +export interface Platform { + x: number; + y: number; + texture: string; + frame?: number | string; + scale?: { x: number; y: number }; + dropEvent?: string; +} + +export function createPlatforms( + scene: Phaser.Scene, + platforms: Platform[], + platformGroup: Phaser.Physics.Arcade.StaticGroup, + colliders?: Phaser.Types.Physics.Arcade.ArcadeColliderType[] +) { + //setting the size of the groud (1, 2, 3) + + platforms.forEach((platform) => { + const plat = platformGroup.create( + platform.x, + platform.y, + platform.texture, + platform.frame + ); + if (platform.scale) { + plat.setScale(platform.scale.x, platform.scale.y).refreshBody(); + } + }); + + if (colliders) { + scene.physics.add.collider(colliders[0], platformGroup); + } + return platforms; +} diff --git a/src/components/terminalButton.ts b/src/components/terminalButton.ts new file mode 100644 index 00000000..db2fff49 --- /dev/null +++ b/src/components/terminalButton.ts @@ -0,0 +1,31 @@ +import Phaser from "phaser"; + +export default class TerminalButton extends Phaser.GameObjects.Sprite { + constructor( + scene: Phaser.Scene, + x: number, + y: number, + texture: string, + text: string, + eventID: string + ) { + const BUTTON_X = x; + const BUTTON_Y = y; + + super(scene, x, y, texture); + scene.add.existing(this); + this.setInteractive(); + this.on("pointerdown", () => { + this.scene.events.emit(eventID); + }); + + const fontSize = text.length > 12 ? "20px" : "32px"; + const textObject = scene.add.text(BUTTON_X, BUTTON_Y, text, { + fontSize: fontSize, + color: "#FFF", + }); + textObject.setOrigin(0.5, 0.5); + textObject.setWordWrapWidth(248); + textObject.setAlign("center"); + } +} diff --git a/src/components/terminalListeners.ts b/src/components/terminalListeners.ts new file mode 100644 index 00000000..bb30c99f --- /dev/null +++ b/src/components/terminalListeners.ts @@ -0,0 +1,12 @@ +//import Phaser from 'phaser'; +import LevelClass from '../Classes/LevelClass'; + +export class Listenter { + constructor(scene: LevelClass, eventID: string) { + scene.events.on(eventID, () => { + scene.terminalInputArr.push(eventID); + scene.events.emit("check_terminal_input"); + }); + } + +} \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 9776bc5c..2803d92a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,6 +2,18 @@ import Phaser from "phaser"; import MainScene from "./scenes/mainScene"; import PreloadScene from "./scenes/preloadScene"; +import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin"; + +import OptionsScene from "./scenes/optionsScene"; +import LevelScene from "./scenes/levelScene"; +import PauseScene from "./scenes/pauseScene"; +import StartScene from "./scenes/startScene"; +import Level_1_scene from "./scenes/level_1_scene"; +import RespawnScene from "./scenes/respawnScene"; +import Level_1_2_scene from "./scenes/level_1_2_scene"; +import Level_1_3_scene from "./scenes/level_1_3_scene"; +import TestScene from "./scenes/testScene"; + const DEFAULT_WIDTH = 1280; const DEFAULT_HEIGHT = 720; @@ -17,7 +29,21 @@ export const CONFIG = { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT, }, - scene: [PreloadScene, MainScene], + + scene: [ + PreloadScene, + MainScene, + OptionsScene, + LevelScene, + PauseScene, + StartScene, + Level_1_scene, + Level_1_2_scene, + Level_1_3_scene, + RespawnScene, + TestScene, + ], + physics: { default: "arcade", arcade: { @@ -35,4 +61,17 @@ export const CONFIG = { pixelArt: false, antialias: true, }, + dom: { + createContainer: true, + }, + transparent: true, + plugins: { + scene: [ + { + key: "rexUI", + plugin: UIPlugin, + mapping: "rexUI", + }, + ], + }, }; diff --git a/src/objects/phaserLogo.ts b/src/objects/phaserLogo.ts deleted file mode 100644 index 84324120..00000000 --- a/src/objects/phaserLogo.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Phaser from "phaser"; - -export default class PhaserLogo extends Phaser.Physics.Arcade.Sprite { - constructor(scene: Phaser.Scene, x: number, y: number) { - super(scene, x, y, "phaser-logo"); - scene.add.existing(this); - scene.physics.add.existing(this); - - this.setCollideWorldBounds(true) - .setBounce(0.6) - .setInteractive() - .on("pointerdown", () => { - this.setVelocityY(-400); - }); - } -} diff --git a/src/objects/player.ts b/src/objects/player.ts new file mode 100644 index 00000000..581fe73b --- /dev/null +++ b/src/objects/player.ts @@ -0,0 +1,72 @@ +import Phaser from "phaser"; + +export class Player extends Phaser.Physics.Arcade.Sprite { + //private cursors: Phaser.Types.Input.Keyboard.CursorKeys; + constructor(scene: Phaser.Scene, x: number, y: number) { + super(scene, x, y, "cat", 1); + this.setVisible(true); + this.setScale(2); //set scale 2 (32x32 -> 64x64) + scene.add.existing(this); + scene.physics.world.enable(this); + + this.setDepth(10); //set player to top layer + + this.initAnimations(); + //this.initPhysics(); + } + + private initAnimations(): void { + this.scene.anims.create({ + key: "left", + frames: this.anims.generateFrameNumbers("cat", { + start: 3, + end: 5, + }), + frameRate: 10, + repeat: -1, + }); + this.scene.anims.create({ + key: "turn", + frames: [{ key: "cat", frame: 1 }], + frameRate: 20, + }); + this.scene.anims.create({ + key: "right", + frames: this.anims.generateFrameNumbers("cat", { + start: 6, + end: 8, + }), + frameRate: 10, + repeat: -1, + }); + } + + //currently disabled as it was only used to set world bounds true + //may be needed in the future + /* + private initPhysics(): void { + const body = this.body as Phaser.Physics.Arcade.Body; + //body.setGravityY(300); + body.setCollideWorldBounds(true); + } + */ + + update(cursors?: Phaser.Types.Input.Keyboard.CursorKeys) { + const body = this.body as Phaser.Physics.Arcade.Body; + + if (cursors?.left.isDown) { + body.setVelocityX(-160); + this.anims.play("left", true); + } else if (cursors?.right.isDown) { + body.setVelocityX(160); + this.anims.play("right", true); + } else { + body.setVelocityX(0); + this.anims.play("turn", true); + } + + if (cursors?.up.isDown && body.touching.down) { + body.setVelocityY(-330); + } + } +} diff --git a/src/scenes/currentLevel.ts b/src/scenes/currentLevel.ts new file mode 100644 index 00000000..6ba31d99 --- /dev/null +++ b/src/scenes/currentLevel.ts @@ -0,0 +1,5 @@ +export let currentLevel = ""; + +export function updateCurrentLevel(level: string) { + currentLevel = level; +} diff --git a/src/scenes/levelScene.ts b/src/scenes/levelScene.ts new file mode 100644 index 00000000..11cf6400 --- /dev/null +++ b/src/scenes/levelScene.ts @@ -0,0 +1,99 @@ +import Phaser from "phaser"; + +export default class LevelScene extends Phaser.Scene { + backButton: Phaser.GameObjects.Text; + + level1: Phaser.GameObjects.Text; + level2: Phaser.GameObjects.Text; + + constructor() { + super({ key: "LevelScene" }); + } + + create() { + /* --------------- BACKGROUND ------------------- */ + const level_1_bg = this.add.image(640, 360, "level_1_bg"); + level_1_bg.setScale(1); + /* --------------- LEVEL PLANETS ------------------- */ + const lvl1 = this.add.image(200, 600, "planet-1"); + const lvl2 = this.add.image(400, 550, "planet-4"); + lvl1.setScale(0.1); + lvl2.setScale(0.1); + /* --------------- BACK BUTTON ------------------- */ + this.backButton = this.add + .text(100, 100, "Back", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateBackClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.backButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.backButton); + }); + /* --------------- LEVEL 1 ------------------- */ + this.level1 = this.add + .text(170, 595, "level1", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateLevelClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.level1); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.level1); + }); + /* --------------- LEVEL 2 ------------------- */ + this.level2 = this.add + .text(375, 545, "level2", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateLevelClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.level2); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.level2); + }); + /* --------------- Test Scene ------------------- */ + this.level2 = this.add + .text(300, 100, "Test-Scene", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.gotoTestScene(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.level2); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.level2); + }); + } + + //update back clicked and update level clicked need to be implemented proporly, + //currently have them set up this way for testing purposes + gotoTestScene() { + this.scene.start("TestScene"); + } + + updateBackClicked() { + this.scene.start("MainScene"); + } + + updateLevelClicked() { + this.scene.start("Level_1_scene"); + } + + enterButtonHoverState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#ff0" }); + } + + enterButtonRestState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#0f0" }); + } + + update() {} +} diff --git a/src/scenes/level_1_2_scene.ts b/src/scenes/level_1_2_scene.ts new file mode 100644 index 00000000..a16b0c47 --- /dev/null +++ b/src/scenes/level_1_2_scene.ts @@ -0,0 +1,285 @@ +import Phaser from "phaser"; +import { updateCurrentLevel } from "./currentLevel"; +import LevelClass from "../Classes/LevelClass"; +import { ButtonAndListensers } from "../components/buttonAndListeners"; + +export default class Level_1_2_scene extends LevelClass { + private platforms?: Phaser.Physics.Arcade.StaticGroup; + private player?: Phaser.Physics.Arcade.Sprite; + private cursors?: Phaser.Types.Input.Keyboard.CursorKeys; + private stars?: Phaser.Physics.Arcade.Group; + private spikes?: Phaser.Physics.Arcade.Group; + private platforms2?: Phaser.Physics.Arcade.Group; + private terminal?: Phaser.Physics.Arcade.Group; + private score = 0; + private scoreText?: Phaser.GameObjects.Text; + private terminalCorrect: boolean = false; + private gameOver = false; + private textSpawned = false; + + constructor() { + const key = "Level_1_2_scene"; + super({ key: key }); + this.CorrectTerminalArr = [ + `${key}_git add blue`, + `${key}_git commit -m 'Add New Platform'`, + `${key}_git push`, + ]; + } + + private setTerminalCorrect(correct: boolean) { + console.log("here"); + this.terminalCorrect = correct; + } + + create() { + const level_1_bg = this.add.image(640, 360, "level_1_bg"); + level_1_bg.setScale(1); + + this.add.text(400, 400, "git add blue -> commit -> push", { + color: "#0f0", + }); + this.add.text( + 400, + 425, + "currently, the terminal is buggy and will only spawn a blue platform", + { + color: "#0f0", + } + ); + + const npc_1 = this.add.image(1000, 620, "npc_1", 1); + npc_1.setScale(2); + + //This is createing a solid object + this.platforms = this.physics.add.staticGroup(); + const ground = this.platforms.create( + 640, + 720, + "brown_plat_1" + ) as Phaser.Physics.Arcade.Sprite; + + //setting the size of the groud (1, 2, 3) + ground.setScale(40, 2).refreshBody(); + + //platform 1 + this.platforms.create(200, 625, "brown_plat_1"); + + this.player = this.physics.add.sprite(70, 600, "dude"); + this.player.setBounce(0.05); + this.player.setCollideWorldBounds(true); + this.player.body?.setSize(32, 32); + this.player.setScale(2); + + this.anims.create({ + key: "left", + frames: this.anims.generateFrameNumbers("cat", { + start: 3, + end: 5, + }), + frameRate: 10, + repeat: -1, + }); + this.anims.create({ + key: "turn", + frames: [{ key: "cat", frame: 1 }], + frameRate: 20, + }); + this.anims.create({ + key: "right", + frames: this.anims.generateFrameNumbers("cat", { + start: 6, + end: 8, + }), + frameRate: 10, + repeat: -1, + }); + + this.physics.add.collider(this.player, this.platforms); + this.cursors = this.input.keyboard?.createCursorKeys(); + + this.stars = this.physics.add.group(); + this.physics.add.collider(this.stars, this.platforms); + this.physics.add.overlap( + this.player, + this.stars, + this.handleCollectStar, + undefined, + this + ); + this.stars.create(1100, 680, "star"); + this.stars.create(1150, 680, "star"); + this.stars.create(1200, 680, "star"); + + this.scoreText = this.add.text(16, 16, "Score: 0", { + fontSize: "32px", + color: "#000", + }); + + this.spikes = this.physics.add.group(); + this.spikes.create(400, 625, "spikes_hor"); + this.spikes.create(550, 625, "spikes_hor"); + this.spikes.create(700, 625, "spikes_hor"); + + this.physics.add.collider(this.spikes, this.platforms); + this.physics.add.collider( + this.player, + this.spikes, + this.handleHitSpike, + undefined, + this + ); + + this.platforms2 = this.physics.add.group(); + + this.physics.add.collider(this.platforms2, this.platforms); + this.physics.add.collider(this.player, this.platforms2, undefined); + + this.terminal = this.physics.add.group(); + this.physics.add.collider(this.terminal, this.platforms); + this.terminal.create(200, 500, "terminal"); + this.physics.add.collider(this.terminal, this.platforms); + this.physics.add.overlap( + this.player, + this.terminal, + () => { + this.handleTerminal(); + }, + undefined, + this + ); + + //Create terminal Buttons and Events + this.events.on("correct_terminal_input", () => { + this.terminalCorrect = true; + }); + this.events.once("terminalCollison", () => { + new ButtonAndListensers( + this, + 200, + 100, + "button", + [ + "git add red", + "git add blue", + "git commit -m 'Add New Platform'", + "git push", + ], + this.CorrectTerminalArr, + this.handleFeedback + ); + }); + } + + private handleTerminal() { + this.events.emit("terminalCollison"); + } + + private handleHitSpike() { + this.physics.pause(); + this.player?.setTint(0xff0000); + this.player?.anims.play("turn"); + this.gameOver = true; + } + + private handleCollectStar( + player: + | Phaser.Types.Physics.Arcade.GameObjectWithBody + | Phaser.Tilemaps.Tile, + s: Phaser.Types.Physics.Arcade.GameObjectWithBody | Phaser.Tilemaps.Tile + ) { + const star = s as Phaser.Physics.Arcade.Image; + star.disableBody(true, true); + + this.score += 10; + this.scoreText?.setText(`score: ${this.score}`); + } + + private handlePlat() { + let canSpawn = true; + while (canSpawn) { + this.platforms2?.create(500, 200, "blue_plat_1"); + this.terminalCorrect = false; + canSpawn = false; + } + } + + private handleNPC() { + let canSpawn = true; + while (canSpawn) { + this.add.text( + 800, + 500, + "Hello! We have been waiting for you! \nPlease carry on to meet the rest of our crew!", + { + color: "#FFF", + //fontSize: 20, + } + ); + this.textSpawned = true; + canSpawn = false; + } + } + private handleFeedback( + scene: LevelClass, + input: string[], + correctInput: string[] + ): boolean { + console.log(input); + console.log(correctInput); + //Can get alot more in depth with the feeback this is just a proof of concept + if (input.length > correctInput.length) { + scene.FeedbackText = scene.add.text( + 400, + 500, + "Too many commands! Try Again", + { + fontSize: "32px", + color: "#880808", + } + ); + //Clear the input array for next time + scene.terminalInputArr = []; + } + if (JSON.stringify(input) === JSON.stringify(correctInput)) { + scene.events.emit("correct_terminal_input"); + return true; + } + return false; + } + + update() { + if (this.cursors?.left.isDown) { + this.player?.setVelocityX(-200); + this.player?.anims.play("left", true); + } else if (this.cursors?.right.isDown) { + this.player?.setVelocityX(200); + this.player?.anims.play("right", true); + } else { + this.player?.setVelocityX(0); + this.player?.anims.play("turn", true); + } + + if (this.cursors?.up.isDown && this.player?.body?.touching.down) { + this.player.setVelocityY(-300); + } + if (this.gameOver) { + this.gameOver = false; + updateCurrentLevel(this.scene.key); + this.scene.start("RespawnScene"); + this.scene.stop(); + } + if (this.terminalCorrect) { + //this.platforms2?.create(500, 200, "blue_plat_1"); + this.handlePlat(); + } + if (this.player) { + if (this.player.x > 800 && !this.textSpawned) { + this.handleNPC(); + } + if (this.player.x > 1240) { + this.scene.start("Level_1_3_scene"); + } + } + } +} diff --git a/src/scenes/level_1_3_scene.ts b/src/scenes/level_1_3_scene.ts new file mode 100644 index 00000000..fb599c7b --- /dev/null +++ b/src/scenes/level_1_3_scene.ts @@ -0,0 +1,163 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import Phaser from "phaser"; +import { updateCurrentLevel } from "./currentLevel"; +import LevelClass from "../Classes/LevelClass"; + +export default class Level_1_3_scene extends LevelClass { + private platforms?: Phaser.Physics.Arcade.StaticGroup; + private player?: Phaser.Physics.Arcade.Sprite; + private cursors?: Phaser.Types.Input.Keyboard.CursorKeys; + private scoreText?: Phaser.GameObjects.Text; + private gameOver = false; + private textSpawned = false; + + private d1: Phaser.GameObjects.Text; + private d2: Phaser.GameObjects.Text; + private d3: Phaser.GameObjects.Text; + private d4: Phaser.GameObjects.Text; + + constructor() { + super({ key: "Level_1_3_scene" }); + } + + create() { + const level_1_bg = this.add.image(640, 360, "level_1_bg"); + level_1_bg.setScale(1); + + //This is createing a solid object + this.platforms = this.physics.add.staticGroup(); + const ground = this.platforms.create( + 640, + 720, + "brown_plat_1" + ) as Phaser.Physics.Arcade.Sprite; + //setting the size of the groud (1, 2, 3) + ground.setScale(40, 2).refreshBody(); + + this.player = this.physics.add.sprite(70, 600, "dude"); + this.player.setBounce(0.05); + this.player.setCollideWorldBounds(true); + this.player.body?.setSize(32, 32); + this.player.setScale(2); + + this.anims.create({ + key: "left", + frames: this.anims.generateFrameNumbers("cat", { + start: 3, + end: 5, + }), + frameRate: 10, + repeat: -1, + }); + this.anims.create({ + key: "turn", + frames: [{ key: "cat", frame: 1 }], + frameRate: 20, + }); + this.anims.create({ + key: "right", + frames: this.anims.generateFrameNumbers("cat", { + start: 6, + end: 8, + }), + frameRate: 10, + repeat: -1, + }); + + this.physics.add.collider(this.player, this.platforms); + this.cursors = this.input.keyboard?.createCursorKeys(); + + this.scoreText = this.add.text(16, 16, "Score: 0", { + fontSize: "32px", + color: "#000", + }); + + this.add.image(1000, 630, "terminal"); + + const npc_1 = this.add.image(700, 620, "npc_1", 1); + npc_1.setScale(2); + const npc_2 = this.add.image(600, 620, "npc_2", 1); + npc_2.setScale(2); + const npc_3 = this.add.image(800, 620, "npc_3", 1); + npc_3.setScale(2); + + this.d1 = this.add + .text(500, 500, "Hello! My name is ####.", { + color: "#FFF", + //fontSize: 20, + }) + .setVisible(false); + this.d2 = this.add + .text(650, 520, "And im ####.", { + color: "#FFF", + //fontSize: 20, + }) + .setVisible(false); + this.d3 = this.add + .text(700, 540, "Im ####. Welcome to mars!", { + color: "#FFF", + //fontSize: 20, + }) + .setVisible(false); + this.d4 = this.add + .text( + 650, + 500, + "This here is a terminal. \nYou will find them all over this \nplanet as well as others.", + { + color: "#FFF", + //fontSize: 20, + } + ) + .setVisible(false); + } + + handleNPC() { + let canSpawn = true; + while (canSpawn) { + this.d1.setVisible(true); + setTimeout(() => { + this.d2.setVisible(true); + }, 2000); + setTimeout(() => { + this.d3.setVisible(true); + }, 4000); + setTimeout(() => { + this.d1.setVisible(false); + this.d2.setVisible(false); + this.d3.setVisible(false); + this.d4.setVisible(true); + }, 6000); + this.textSpawned = true; + canSpawn = false; + } + } + + update() { + if (this.cursors?.left.isDown) { + this.player?.setVelocityX(-200); + this.player?.anims.play("left", true); + } else if (this.cursors?.right.isDown) { + this.player?.setVelocityX(200); + this.player?.anims.play("right", true); + } else { + this.player?.setVelocityX(0); + this.player?.anims.play("turn", true); + } + if (this.cursors?.up.isDown && this.player?.body?.touching.down) { + this.player.setVelocityY(-300); + } + if (this.gameOver) { + this.gameOver = false; + updateCurrentLevel(this.scene.key); + this.scene.stop("TerminalScene"); + this.scene.start("RespawnScene"); + this.scene.stop(); + } + if (this.player) { + if (this.player.x > 450 && !this.textSpawned) { + this.handleNPC(); + } + } + } +} diff --git a/src/scenes/level_1_scene.ts b/src/scenes/level_1_scene.ts new file mode 100644 index 00000000..cb49c5df --- /dev/null +++ b/src/scenes/level_1_scene.ts @@ -0,0 +1,180 @@ +import Phaser from "phaser"; +import { updateCurrentLevel } from "./currentLevel"; +import LevelClass from "../Classes/LevelClass"; + +export default class Level_1_scene extends LevelClass { + private platforms?: Phaser.Physics.Arcade.StaticGroup; + private player?: Phaser.Physics.Arcade.Sprite; + private cursors?: Phaser.Types.Input.Keyboard.CursorKeys; + private stars?: Phaser.Physics.Arcade.Group; + private spikes?: Phaser.Physics.Arcade.Group; + private terminal?: Phaser.Physics.Arcade.Group; + private score = 0; + private scoreText?: Phaser.GameObjects.Text; + private terminalCorrect: boolean = false; + private terminalScene?: Phaser.Scene; + private gameOver = false; + + constructor() { + super({ key: "Level_1_scene" }); + } + + private setTerminalCorrect(correct: boolean) { + console.log("here"); + this.terminalCorrect = correct; + } + + create() { + //text for alpha sub + + const level_1_bg = this.add.image(640, 360, "level_1_bg"); + level_1_bg.setScale(1); + + this.add.text( + 400, + 250, + "use the arrow keys to move and mouse to click when needed", + { + color: "#0f0", + } + ); + + //This is createing a solid object + this.platforms = this.physics.add.staticGroup(); + const ground = this.platforms.create( + 640, + 720, + "brown_plat_1" + ) as Phaser.Physics.Arcade.Sprite; + + //setting the size of the groud (1, 2, 3) + ground.setScale(40, 2).refreshBody(); + + //platform 1 + this.platforms.create(230, 550, "brown_plat_1"); + + //platform 2 + this.platforms.create(600, 550, "brown_plat_1"); + + //platform 3 + this.platforms.create(970, 550, "brown_plat_1"); + + this.player = this.physics.add.sprite(100, 500, "dude"); + this.player.setBounce(0.05); + this.player.setCollideWorldBounds(true); + this.player.body?.setSize(32, 32); + this.player.setScale(2); + + this.anims.create({ + key: "left", + frames: this.anims.generateFrameNumbers("cat", { + start: 3, + end: 5, + }), + frameRate: 10, + repeat: -1, + }); + this.anims.create({ + key: "turn", + frames: [{ key: "cat", frame: 1 }], + frameRate: 20, + }); + this.anims.create({ + key: "right", + frames: this.anims.generateFrameNumbers("cat", { + start: 6, + end: 8, + }), + frameRate: 10, + repeat: -1, + }); + + this.physics.add.collider(this.player, this.platforms); + this.cursors = this.input.keyboard?.createCursorKeys(); + + this.stars = this.physics.add.group(); + this.physics.add.collider(this.stars, this.platforms); + this.physics.add.overlap( + this.player, + this.stars, + this.handleCollectStar, + undefined, + this + ); + this.stars.create(1100, 680, "star"); + this.stars.create(1150, 680, "star"); + this.stars.create(1200, 680, "star"); + + this.scoreText = this.add.text(16, 16, "Score: 0", { + fontSize: "32px", + color: "#000", + }); + + this.spikes = this.physics.add.group(); + + this.spikes.create(250, 625, "spikes_hor"); + this.spikes.create(400, 625, "spikes_hor"); + this.spikes.create(550, 625, "spikes_hor"); + this.spikes.create(700, 625, "spikes_hor"); + this.spikes.create(850, 625, "spikes_hor"); + this.spikes.create(1000, 625, "spikes_hor"); + + this.physics.add.collider(this.spikes, this.platforms); + this.physics.add.collider( + this.player, + this.spikes, + this.handleHitSpike, + undefined, + this + ); + } + + private handleHitSpike() { + this.physics.pause(); + this.player?.setTint(0xff0000); + this.player?.anims.play("turn"); + this.gameOver = true; + } + + private handleCollectStar( + player: + | Phaser.Types.Physics.Arcade.GameObjectWithBody + | Phaser.Tilemaps.Tile, + s: Phaser.Types.Physics.Arcade.GameObjectWithBody | Phaser.Tilemaps.Tile + ) { + const star = s as Phaser.Physics.Arcade.Image; + star.disableBody(true, true); + + this.score += 10; + this.scoreText?.setText(`score: ${this.score}`); + } + + update() { + if (this.cursors?.left.isDown) { + this.player?.setVelocityX(-200); + this.player?.anims.play("left", true); + } else if (this.cursors?.right.isDown) { + this.player?.setVelocityX(200); + this.player?.anims.play("right", true); + } else { + this.player?.setVelocityX(0); + this.player?.anims.play("turn", true); + } + + if (this.cursors?.up.isDown && this.player?.body?.touching.down) { + this.player.setVelocityY(-300); + } + if (this.gameOver) { + this.gameOver = false; + updateCurrentLevel(this.scene.key); + this.scene.stop("TerminalScene"); + this.scene.start("RespawnScene"); + this.scene.stop(); + } + if (this.player) { + if (this.player.x > 1240) { + this.scene.start("Level_1_2_scene"); + } + } + } +} diff --git a/src/scenes/mainScene.ts b/src/scenes/mainScene.ts index 1c6b6089..7b8b3e10 100644 --- a/src/scenes/mainScene.ts +++ b/src/scenes/mainScene.ts @@ -1,28 +1,112 @@ import Phaser from "phaser"; -import PhaserLogo from "../objects/phaserLogo"; -import FpsText from "../objects/fpsText"; export default class MainScene extends Phaser.Scene { - fpsText: FpsText; + /* --------------- START BUTTON ------------------- */ + startButton: Phaser.GameObjects.Text; + /* --------------- OPTION BUTTON ------------------- */ + optionsButton: Phaser.GameObjects.Text; + /* --------------- PLAY BUTTON ------------------- */ + playButton: Phaser.GameObjects.Text; + + private music: Phaser.Sound.BaseSound; constructor() { super({ key: "MainScene" }); } - create() { - new PhaserLogo(this, this.cameras.main.width / 2, 0); - this.fpsText = new FpsText(this); - - const message = `Phaser v${Phaser.VERSION}`; - this.add - .text(this.cameras.main.width - 15, 15, message, { - color: "#000000", - fontSize: "24px", + //play background music (music will stop when audio file ends or when promted to end) + //this.music = this.sound.add("bg_music_1", { loop: true, volume: 0.1 }); + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (!this.music) { + this.music = this.sound.add("bg_music_1", { + loop: true, + volume: 0.1, + }); + this.music.play(); + } + //this.music.play(); + + //text for alpha sub + this.add.text( + 400, + 200, + "please select 'play from level' -> 'level 1'", + { + color: "#0f0", + } + ); + this.add.text(400, 225, "start is currently not implemented", { + color: "#0f0", + }); + + /* --------------- BACKGROUND COLOUR ------------------- */ + this.cameras.main.setBackgroundColor("#702963"); + /* --------------- START BUTTON ------------------- */ + this.startButton = this.add + .text(400, 300, "Start", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateStartClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.startButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.startButton); + }); + + /* --------------- OPTIONS BUTTON ------------------- */ + this.optionsButton = this.add + .text(400, 400, "Options", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateOptionsClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.optionsButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.optionsButton); + }); + + /* --------------- PLAY BUTTON ------------------- */ + this.playButton = this.add + .text(400, 500, "Play From Level", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updatePlayClicked(); }) - .setOrigin(1, 0); + .on("pointerover", () => { + this.enterButtonHoverState(this.playButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.playButton); + }); + } + + /* --------------- START BUTTON ------------------- */ + updateStartClicked() { + this.scene.start("StartScene"); + } + + enterButtonHoverState(value: Phaser.GameObjects.Text) { + value.setStyle({ fill: "#ff0" }); } - update() { - this.fpsText.update(); + enterButtonRestState(value: Phaser.GameObjects.Text) { + value.setStyle({ fill: "#0f0" }); } + + /* --------------- OPTIONS BUTTON ------------------- */ + updateOptionsClicked() { + this.scene.start("OptionsScene"); + } + + /* --------------- PLAY BUTTON ------------------- */ + updatePlayClicked() { + this.scene.start("LevelScene"); + } + + update() {} } diff --git a/src/scenes/optionsScene.ts b/src/scenes/optionsScene.ts new file mode 100644 index 00000000..0e340d85 --- /dev/null +++ b/src/scenes/optionsScene.ts @@ -0,0 +1,43 @@ +import Phaser from "phaser"; + +export default class OptionsScene extends Phaser.Scene { + /* --------------- BACK BUTTON ------------------- */ + backButton: Phaser.GameObjects.Text; + + constructor() { + super({ key: "OptionsScene" }); + } + + create() { + /* --------------- BACKGROUND COLOUR ------------------- */ + this.cameras.main.setBackgroundColor("#9C9562"); + /* --------------- BACK BUTTON ------------------- */ + this.backButton = this.add + .text(400, 400, "Back", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateBackClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.backButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.backButton); + }); + } + + /* --------------- BACK BUTTON ------------------- */ + updateBackClicked() { + this.scene.start("MainScene"); + } + + enterButtonHoverState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#ff0" }); + } + + enterButtonRestState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#0f0" }); + } + + update() {} +} \ No newline at end of file diff --git a/src/scenes/pauseScene.ts b/src/scenes/pauseScene.ts new file mode 100644 index 00000000..9c265b8a --- /dev/null +++ b/src/scenes/pauseScene.ts @@ -0,0 +1,63 @@ +import Phaser from "phaser"; + +export default class PauseScene extends Phaser.Scene { + /* --------------- RESUME BUTTON ------------------- */ + resumeButton: Phaser.GameObjects.Text; + /* --------------- MAIN MENU BUTTON ------------------- */ + mainMenuButton: Phaser.GameObjects.Text; + + constructor() { + super({ key: "PauseScene" }); + } + + create() { + /* --------------- BACKGROUND COLOUR ------------------- */ + this.cameras.main.setBackgroundColor("#4B6E6E"); + /* --------------- RESUME BUTTON ------------------- */ + this.resumeButton = this.add + .text(400, 300, "Resume", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateResumeClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.resumeButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.resumeButton); + }); + + /* --------------- MAIN MENU BUTTON ------------------- */ + this.mainMenuButton = this.add + .text(400, 400, "Main Menu", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateMainMenuClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.mainMenuButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.mainMenuButton); + }); + } + + updateResumeClicked() { + this.scene.switch("StartScene"); + this.scene.stop(); + } + + updateMainMenuClicked() { + this.scene.start("MainScene"); + } + + enterButtonHoverState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#ff0" }); + } + + enterButtonRestState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#0f0" }); + } + + update() {} +} \ No newline at end of file diff --git a/src/scenes/preloadScene.ts b/src/scenes/preloadScene.ts index c17b81ba..a8fdcf53 100644 --- a/src/scenes/preloadScene.ts +++ b/src/scenes/preloadScene.ts @@ -6,7 +6,60 @@ export default class PreloadScene extends Phaser.Scene { } preload() { - this.load.image("phaser-logo", "assets/img/phaser-logo.png"); + //Images + this.load.image("plat_1", "assets/Art/mars_plat_1.png"); + this.load.image("spikes", "assets/Art/spikes.png"); + this.load.image("star", "assets/Art/star.png"); + this.load.image("planet-1", "assets/Art/planet-1.png"); + this.load.image("planet-4", "assets/Art/planet-4.png"); + this.load.image("terminal", "assets/Art/CommTerminal.png"); + this.load.image("blue_plat_1", "assets/Art/blue_plat_1.png"); + this.load.image("brown_plat_1", "assets/Art/brown_plat_1.png"); + this.load.image("red_plat_1", "assets/Art/red_plat_1.png"); + this.load.image("spikes_hor", "assets/Art/spikes_hor.png"); + this.load.image("spikes_vert", "assets/Art/spikes_vert.png"); + this.load.image("level_1_bg", "assets/Art/level_1_bg.png"); + this.load.image( + "background-1-level1", + "assets/Art/background-1-level1.png" + ); + this.load.image( + "background-2-level1", + "assets/Art/background-2-level1.png" + ); + + //Sprite sheets + this.load.spritesheet("button", "assets/Art/buttons.png", { + frameWidth: 256, + frameHeight: 64, + }); + this.load.spritesheet("cat", "assets/Art/cat_1.png", { + frameWidth: 32, + frameHeight: 32, + }); + this.load.spritesheet("npc_1", "assets/Art/npc_1.png", { + frameWidth: 32, + frameHeight: 32, + }); + this.load.spritesheet("npc_2", "assets/Art/npc_2.png", { + frameWidth: 32, + frameHeight: 32, + }); + this.load.spritesheet("npc_3", "assets/Art/npc_3.png", { + frameWidth: 32, + frameHeight: 32, + }); + this.load.spritesheet( + "mars-tileset-1", + "assets/Art/mars-tileset-1.png", + { + frameWidth: 64, + frameHeight: 64, + } + ); + + //Sounds + this.load.audio("bg_music_1", "assets/Sound/gitcat_chill_demo2.mp3"); } create() { diff --git a/src/scenes/respawnScene.ts b/src/scenes/respawnScene.ts new file mode 100644 index 00000000..7a309ab9 --- /dev/null +++ b/src/scenes/respawnScene.ts @@ -0,0 +1,64 @@ +import Phaser from "phaser"; +import { currentLevel } from "./currentLevel"; + +export default class RespawnScene extends Phaser.Scene { + /* --------------- RESUME BUTTON ------------------- */ + resumeButton: Phaser.GameObjects.Text; + /* --------------- MAIN MENU BUTTON ------------------- */ + mainMenuButton: Phaser.GameObjects.Text; + + constructor() { + super({ key: "RespawnScene" }); + } + + create() { + /* --------------- BACKGROUND COLOUR ------------------- */ + this.cameras.main.setBackgroundColor("#4B6E6E"); + /* --------------- RESUME BUTTON ------------------- */ + this.resumeButton = this.add + .text(400, 300, "Respawn", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateRespawnClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.resumeButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.resumeButton); + }); + + /* --------------- MAIN MENU BUTTON ------------------- */ + this.mainMenuButton = this.add + .text(400, 400, "Main Menu", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updateMainMenuClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.mainMenuButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.mainMenuButton); + }); + } + + updateRespawnClicked() { + this.scene.start(currentLevel); + this.scene.stop(); + } + + updateMainMenuClicked() { + this.scene.start("MainScene"); + } + + enterButtonHoverState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#ff0" }); + } + + enterButtonRestState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#0f0" }); + } + + update() {} +} diff --git a/src/scenes/startScene.ts b/src/scenes/startScene.ts new file mode 100644 index 00000000..f49fd227 --- /dev/null +++ b/src/scenes/startScene.ts @@ -0,0 +1,48 @@ +import Phaser from "phaser"; + +export default class StartScene extends Phaser.Scene { + startText: Phaser.GameObjects.Text; + pauseButton: Phaser.GameObjects.Text; + + constructor() { + super({ key: "StartScene" }); + } + + create() { + /* --------------- BACKGROUND COLOUR ------------------- */ + this.cameras.main.setBackgroundColor("#274E6C"); + + /* --------------- START TEXT ------------------- */ + this.startText = this.add.text(200, 200, "In a world...", { + color: "#0f0", + }); + + /* --------------- PAUSE BUTTON ------------------- */ + this.pauseButton = this.add + .text(400, 400, "Pause", { color: "#0f0" }) + .setInteractive() + .on("pointerdown", () => { + this.updatePauseClicked(); + }) + .on("pointerover", () => { + this.enterButtonHoverState(this.pauseButton); + }) + .on("pointerout", () => { + this.enterButtonRestState(this.pauseButton); + }); + } + + updatePauseClicked() { + this.scene.switch("PauseScene"); + } + + enterButtonHoverState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#ff0" }); + } + + enterButtonRestState(button: Phaser.GameObjects.Text) { + button.setStyle({ fill: "#0f0" }); + } + + update() {} +} \ No newline at end of file diff --git a/src/scenes/testScene.ts b/src/scenes/testScene.ts new file mode 100644 index 00000000..072688e2 --- /dev/null +++ b/src/scenes/testScene.ts @@ -0,0 +1,207 @@ +import Phaser from "phaser"; +import LevelClass from "../Classes/LevelClass"; +import { Player } from "../objects/player"; +import { Platform, createPlatforms } from "../components/platform"; + +export default class TestScene extends LevelClass { + private player: Player; + private cursors?: Phaser.Types.Input.Keyboard.CursorKeys; + private platforms?: Phaser.Physics.Arcade.StaticGroup; + private playerPos?: Phaser.GameObjects.Text; + private background1?: Phaser.Physics.Arcade.StaticGroup; + private background2?: Phaser.Physics.Arcade.StaticGroup; + private posX = 0; + private posY = 0; + private levelWidth: number = 2560; // Width of the level + private levelHeight: number = 1440; // Height of the level + private showGrid = false; + private showColl = false; + + constructor() { + super({ key: "TestScene" }); + } + + create() { + this.player = new Player(this, 100, 0); + this.cameras.main.startFollow(this.player, true, 0.08, 0.08); + this.cursors = this.input.keyboard?.createCursorKeys(); + + //will eventually make this a loop + this.background1 = this.physics.add.staticGroup(); + const sizeOfBackgroundY = 416; + const sizeOfBackgroundX = 640; + this.background1.create( + sizeOfBackgroundX * 0, + sizeOfBackgroundY, + "background-1-level1" + ); + this.background1.create( + sizeOfBackgroundX * 1, + sizeOfBackgroundY, + "background-1-level1" + ); + this.background1.create( + sizeOfBackgroundX * 2, + sizeOfBackgroundY, + "background-1-level1" + ); + this.background1.create( + sizeOfBackgroundX * 3, + sizeOfBackgroundY, + "background-1-level1" + ); + this.background1.create( + sizeOfBackgroundX * 4, + sizeOfBackgroundY, + "background-1-level1" + ); + //second bg + this.background2 = this.physics.add.staticGroup(); + this.background2.create( + sizeOfBackgroundX * 0, + sizeOfBackgroundY * 0, + "background-2-level1" + ); + this.background2.create( + sizeOfBackgroundX * 1, + sizeOfBackgroundY * 0, + "background-2-level1" + ); + this.background2.create( + sizeOfBackgroundX * 2, + sizeOfBackgroundY * 0, + "background-2-level1" + ); + this.background2.create( + sizeOfBackgroundX * 3, + sizeOfBackgroundY * 0, + "background-2-level1" + ); + this.background2.create( + sizeOfBackgroundX * 4, + sizeOfBackgroundY * 0, + "background-2-level1" + ); + + this.add.text(400, 250, "Test Scene", { + color: "#0f0", + }); + this.playerPos = this.add.text(400, 300, "Player Position: (0, 0)", { + color: "#0f0", + }); + + this.platforms = this.physics.add.staticGroup(); + + const unit = 64; + const offset = 32; + const platforms: Platform[] = [ + //plat 1 + // height=1, width=3, frame (2, 1, 3) in sprite sheet + { + x: offset + unit * 3, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 2, + }, + { + x: offset + unit * 4, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 1, + }, + { + x: offset + unit * 5, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 3, + }, + //plat 2 + { + x: offset + unit * 9, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 2, + }, + { + x: offset + unit * 10, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 1, + }, + { + x: offset + unit * 11, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 3, + }, + //plat 3 + { + x: offset + unit * 15, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 2, + }, + { + x: offset + unit * 16, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 1, + }, + { + x: offset + unit * 17, + y: offset + unit * 8, + texture: "mars-tileset-1", + frame: 3, + }, + { x: 640, y: 720, texture: "brown_plat_1", scale: { x: 40, y: 2 } }, // Ground + ]; + createPlatforms(this, platforms, this.platforms, [this.player]); + if (this.showGrid) { + this.drawGrid(64); + } + if (this.showColl) { + this.physics.world.createDebugGraphic(); + } + } + preload() { + this.load.spritesheet("cat", "assets/Art/cat_1.png", { + frameWidth: 32, + frameHeight: 32, + }); + } + drawGrid(gridSize: number): void { + const graphics = this.add.graphics({ + lineStyle: { width: 1, color: 0x00ff00 }, + }); + // Draw vertical lines + for (let x = 0; x < this.levelWidth; x += gridSize) { + graphics.lineBetween(x, 0, x, this.levelHeight); + } + // Draw horizontal lines + for (let y = 0; y < this.levelHeight; y += gridSize) { + graphics.lineBetween(0, y, this.levelWidth, y); + } + } + + private handlePrintPos() { + this.posX = this.player.x; + this.posY = this.player.y; + + //offset for where text appears relative to the player pos + const offsetX = -600; + const offsetY = -300; + + //create/update text (float -> int for readability) + this.playerPos?.setText( + `Player Position: (${Math.floor(this.posX)}, ${Math.floor( + this.posY + )})` + ); + this.playerPos?.setPosition(this.posX + offsetX, this.posY + offsetY); + } + + update() { + this.player.update(this.cursors); + this.handlePrintPos(); + } +}