From f0c1c7ca508a581878c4a7a9d352d24c59ab8711 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Fri, 12 Nov 2021 15:57:27 -0500 Subject: [PATCH 001/164] Fixed Test Case ID --- Team A2/Test Cases/Test Case SCP-15.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-15.md b/Team A2/Test Cases/Test Case SCP-15.md index 74bf5ba..a345e64 100644 --- a/Team A2/Test Cases/Test Case SCP-15.md +++ b/Team A2/Test Cases/Test Case SCP-15.md @@ -1,5 +1,5 @@ ### Test Case Information -| TEST CASE ID | SCP-10| +| TEST CASE ID | SCP-15| | :--- | :--- | | Owner of Test | Ty Hutchison| | Test Name | Lower Base Volume | @@ -20,4 +20,4 @@ - **Tester**: Thomas Kwashnak - **Date of Test**: 11/9/2021 - **Test Result**: Passed -- **Notes:** *Thank god this is done now* \ No newline at end of file +- **Notes:** *Thank god this is done now* From 3d5dc56387bd1d19991e6629172dce057d24cbce Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Fri, 12 Nov 2021 15:59:59 -0500 Subject: [PATCH 002/164] Fixed Test Case ID for SCP-32 --- Team A2/Test Cases/Test Case SCP-32.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-32.md b/Team A2/Test Cases/Test Case SCP-32.md index 322cdb0..e565e94 100644 --- a/Team A2/Test Cases/Test Case SCP-32.md +++ b/Team A2/Test Cases/Test Case SCP-32.md @@ -1,5 +1,5 @@ ### Test Case Information -| TEST CASE ID | SCP-10| +| TEST CASE ID | SCP-32| | :--- | :--- | | Owner of Test | Ty Hutchison| | Test Name | Update Instructions | @@ -19,4 +19,4 @@ ### Test Completion - **Tester**: Thomas Kwashnak - **Date of Test**: 11/9/2021 -- **Test Result**: Passed \ No newline at end of file +- **Test Result**: Passed From 45e1175dd821c185194625e9c0d5a3cafec2be30 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 14:56:48 -0500 Subject: [PATCH 003/164] Created SCP-57 Test Case still in progress --- Team A2/Test Cases/Test Case SCP-57.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-57.md diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md new file mode 100644 index 0000000..1c198bf --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -0,0 +1,19 @@ +### Test Case Information +| TEST CASE ID | SCP-57 | +| :--- | :--- | +| Owner of Test | Thomas Kwashnak | +| Test Name | Test Player Functionality | +| Date of Last Revision | 11/16/2021 | +| Test Objective | Ensure that all current functionalities of the player is still implemented and functional | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens || +|2| Click "Play" |The tutorial level is entered|| + +### Test Completion +- **Tester**: [TESTER NAME] +- **Date of Test**: DATE OF TEST +- **Test Result**: TEST RESULT \ No newline at end of file From 4ce9348995fa2462e7defa3119e1750891e08fbb Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 15:41:55 -0500 Subject: [PATCH 004/164] Started adding steps to Test Case SCP-57 Leaving step numbers as `n` while I work on test case, will change to numbered steps once all test case steps are listed --- Team A2/Test Cases/Test Case SCP-57.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index 1c198bf..2f8642f 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -4,14 +4,24 @@ | Owner of Test | Thomas Kwashnak | | Test Name | Test Player Functionality | | Date of Last Revision | 11/16/2021 | -| Test Objective | Ensure that all current functionalities of the player is still implemented and functional | +| Test Objective | Ensure that all current functionalities of the player is implemented in new Player class and still functional | ### Procedure |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens || -|2| Click "Play" |The tutorial level is entered|| +|n| Run the game| The game successfully opens || +|n| Click "*Play*" |The tutorial level is entered, game does not crash|| +|n| Hold `A/Left Arrow` |The player moves to the left. The player does not fall off the map and is instead stopped at the edge|| +|n| Hold `D/Right Arrow`|The player moves to the right. The player is stopped once they hit the tree|| +|n| Hold both `A/Left Arrow` and `D/Right Arrow`|The player stands still|| +|n| Hit `Space/W/Up Arrow` | The player jumps|| +|n|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|| +|n|Hold `ctrl`|The player crouches|| +|n|Hit `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|| +|n|Hit `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|| + + ### Test Completion - **Tester**: [TESTER NAME] From ae9a60ed6ef469ece0a1e6f92ff1d1738766bfde Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 15:51:52 -0500 Subject: [PATCH 005/164] Created Test Case SCP-56 Test case differs from other test cases due to the nature of the testing / changed features. Will require multiple tests from multiple devices before it can be reviewed and marked as completed by a designated team member --- Team A2/Test Cases/Test Case SCP-56.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-56.md diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md new file mode 100644 index 0000000..19ceb66 --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -0,0 +1,26 @@ +### Test Case Information +| TEST CASE ID | SCP-56 | +| :--- | :--- | +| Owner of Test | Thomas Kwashnak | +| Test Name | Test Game Speed | +| Date of Last Revision | 11/16/2021 | +| Test Objective | Ensure that the game runs consistently through multiple distributions | +| Testing Notes| Due to the nature of this test, multiple tests must be made before the test can be considered complete. Testing must be performed on multiple devices with varied operating system and configuration| + +### Procedure + +|Step | Action | Expected Result | +|:---:| :--- | :---- | +|1| Run the game| The game successfully opens | + +### Test Completion +Instances of the test execution are listed below with results. On failed tests, steps that have failed are listed in the `Test Result` column + +|Tester Name| Computer Type / Operating System | Date of Test | Test Result +|:---|:---:|:---:|:---:| +|[NAME]|[TYPE], [OPERATING SYSTEM] | [DATE] | [RESULT] | + +**Marking Test as Complete** +- **Tester**: [TEST REVIEWER NAME] +- **Date of Test**: [TEST COMPLETION DATE] +- **Test Result**: [TEST RESULT] \ No newline at end of file From b1547e6229132945d4eb34e4ddbe7d6159d99e6e Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 15:53:06 -0500 Subject: [PATCH 006/164] Fix Typo in Test Case SCP-56 --- Team A2/Test Cases/Test Case SCP-56.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 19ceb66..9d053b2 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -5,7 +5,7 @@ | Test Name | Test Game Speed | | Date of Last Revision | 11/16/2021 | | Test Objective | Ensure that the game runs consistently through multiple distributions | -| Testing Notes| Due to the nature of this test, multiple tests must be made before the test can be considered complete. Testing must be performed on multiple devices with varied operating system and configuration| +| Test Notes| Due to the nature of this test, multiple tests must be made before the test can be considered complete. Testing must be performed on multiple devices with varied operating system and configuration| ### Procedure From b6321ba03048780caac9ee0c4693da1e2acaf976 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 16:04:59 -0500 Subject: [PATCH 007/164] Created Test Case SCP-59 --- Team A2/Test Cases/Test Case SCP-59.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-59.md diff --git a/Team A2/Test Cases/Test Case SCP-59.md b/Team A2/Test Cases/Test Case SCP-59.md new file mode 100644 index 0000000..d05844d --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-59.md @@ -0,0 +1,20 @@ +### Test Case Information +| TEST CASE ID | SCP-59 | +| :--- | :--- | +| Owner of Test | Thomas Kwashnak | +| Test Name | Test Level Select Navigation | +| Date of Last Revision | 11/16/2021 | +| Test Objective | Test the keyboard navigation of the level select screen | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens || +|2|Select "Level Select"|The level select screen is opened. Levels are listed in a grid formation|| +|3|Use `w/up arrow`,`a/left arrow`,`s/down arrow`,`d/right arrow` to navigate from and to each level listed|Navigating by a direction selects the first option visually in that direction. If the option is at the edge, the selection does not change.|| + +### Test Completion +- **Tester**: [TESTER NAME] +- **Date of Test**: DATE OF TEST +- **Test Result**: TEST RESULT \ No newline at end of file From bfdbdeb8d2afcba3c925b6a0a330ef8e84b60087 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 16:16:47 -0500 Subject: [PATCH 008/164] Added list of functionalities tested in Test Case SCP-57 Lists test cases that need to be tested in procedure --- Team A2/Test Cases/Test Case SCP-57.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index 2f8642f..8df910f 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -6,6 +6,14 @@ | Date of Last Revision | 11/16/2021 | | Test Objective | Ensure that all current functionalities of the player is implemented in new Player class and still functional | +Functionality of `Player.java` tested: + - Movement, and movement animations + - Jumping, including gravity and hitting floor + - Animation while jumping + - Collision with enemies + - Shooting, including animations while standing still and moving + - Collision with map boundaries and map walls + ### Procedure |Step | Action | Expected Result | Pass/Fail | From 8650d8829f7ada3e2c7327b562501f976be51b4f Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 16:35:50 -0500 Subject: [PATCH 009/164] Finalized current Test Case SCP-57 --- Team A2/Test Cases/Test Case SCP-57.md | 35 ++++++++++++++++++-------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index 8df910f..bcb63b1 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -18,16 +18,31 @@ Functionality of `Player.java` tested: |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|n| Run the game| The game successfully opens || -|n| Click "*Play*" |The tutorial level is entered, game does not crash|| -|n| Hold `A/Left Arrow` |The player moves to the left. The player does not fall off the map and is instead stopped at the edge|| -|n| Hold `D/Right Arrow`|The player moves to the right. The player is stopped once they hit the tree|| -|n| Hold both `A/Left Arrow` and `D/Right Arrow`|The player stands still|| -|n| Hit `Space/W/Up Arrow` | The player jumps|| -|n|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|| -|n|Hold `ctrl`|The player crouches|| -|n|Hit `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|| -|n|Hit `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|| +|0a| **Evaluated on Each Step:** | Player Animation changes as expected |`N/A`| +|1| Run the game| The game successfully opens || +|2| Click "*Play*" |The tutorial level is entered, game does not crash. 3 hearts are displayed on the top of the screen.|| +|3| Hold `A/Left Arrow` |The player moves to the left. The player does not fall off the map and is instead stopped at the edge|| +|4| Hold `D/Right Arrow`|The player moves to the right. The player is stopped once they hit the tree|| +|5| Hold both `A/Left Arrow` and `D/Right Arrow`|The player stands still|| +|6| Tap `Space/W/Up Arrow` | The player short-jumps. The player then falls back down after the button is let go and lands on the ground|| +|7|Hold `Space/W/Up Arrow` | The player high-jumps. The player falls back down after a certain height and and falls back down to the ground|| +|8|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|| +|9|Hold `ctrl`|The player crouches|| +|10|Tap `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|| +|11|Tap `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|| +|12|Tap `A/Left Arrow`, then tap `e` (*Attack Button*)|The player faces to the left, and attacks, sending a projectile to the left|| +|13|Hold `A/Left Arrow`, then tap `e` |The player moves to the left, and attacks while moving|| +|14|Tap `Space/W/Up Arrow`, then tap `e` while in the air|The player jumps while facing left, and then shoots a projectile while in the air|| +|15|Tap `D/Right Arrow`, then tap `e` |The player faces to the right, and attacks, sending a projectile to the right|| +|16|Hold `D/Right Arrow`, then tap `e` |The player moves to the right, and attacks while moving|| +|17|Tap `Space/W/Up Arrow`, then tap `e` while in the air|The player jumps while facing right, and then shoots a projectile while in the air|| +|18|Hold `e`|The player shoots once, then cannot shoot for a specified duration of time|| +|19|Navigate and run into enemy|The player's health is set to 0 and the player dies. Death animation is played and player falls down to the ground|| +|20|Restart the game|The level is loaded again, and the player's health is back to full|| +|21|Navigate and run into a projectile from an enemy|The player's health is now 2 (reduced by 1)|| +|22|Navigate and attempt to run off the right-most edge of the map (*without hitting the gold level-complete box*)|The player is stopped and cannot run off of the map|| +|23|Hit the complete-level gold box|The level is completed and the player walks off to the right of the screen|| + From 5e52c54d7907f69afeb5661352d7195adf447893 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 16:40:33 -0500 Subject: [PATCH 010/164] Deprecated Player.java to Player_Old.java --- src/Enemies/BugEnemy.java | 4 ++-- src/Enemies/CyborgEnemy.java | 5 ++--- src/Enemies/DinosaurEnemy.java | 4 ++-- src/Enemies/Dog.java | 4 ++-- src/Engine/GamePanel.java | 16 +++++----------- src/EnhancedMapTiles/EndLevelBox.java | 4 ++-- .../HorizontalMovingPlatform.java | 4 ++-- src/Level/Camera.java | 5 ++--- src/Level/Enemy.java | 4 ++-- src/Level/EnhancedMapTile.java | 2 +- src/Level/Map.java | 6 +++--- src/Level/NPC.java | 4 ++-- src/Level/PlayerAttack.java | 9 +++------ src/Level/{Player.java => Player_Old.java} | 5 +++-- src/Level/Projectile.java | 4 ++-- src/NPCs/Walrus.java | 4 ++-- src/Players/Avatar.java | 6 +++--- src/Players/Cat.java | 4 ++-- src/Projectiles/Bone.java | 6 +++--- src/Projectiles/Fireball.java | 7 +++---- src/Projectiles/LazerBeam.java | 6 +++--- src/Screens/LevelLoseScreen.java | 4 ++-- src/Screens/PauseScreen.java | 4 ++-- src/Screens/PlayLevelScreen.java | 4 ++-- 24 files changed, 57 insertions(+), 68 deletions(-) rename src/Level/{Player.java => Player_Old.java} (99%) diff --git a/src/Enemies/BugEnemy.java b/src/Enemies/BugEnemy.java index 71ff785..9a53e90 100644 --- a/src/Enemies/BugEnemy.java +++ b/src/Enemies/BugEnemy.java @@ -6,7 +6,7 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Enemy; -import Level.Player; +import Level.Player_Old; import Utils.AirGroundState; import Utils.Direction; import Utils.Point; @@ -43,7 +43,7 @@ public void initialize() { } @Override - public void update(Player player) { + public void update(Player_Old player) { float moveAmountX = 0; float moveAmountY = 0; diff --git a/src/Enemies/CyborgEnemy.java b/src/Enemies/CyborgEnemy.java index 2ff25f7..f7ded18 100644 --- a/src/Enemies/CyborgEnemy.java +++ b/src/Enemies/CyborgEnemy.java @@ -6,7 +6,7 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Enemy; -import Level.Player; +import Level.Player_Old; import Projectiles.LazerBeam; import Utils.AirGroundState; import Utils.Direction; @@ -14,7 +14,6 @@ import Utils.Stopwatch; import java.util.HashMap; -import java.util.Timer; // This class is for the cyborg // It walks back and forth between two set points (startLocation and endLocation) @@ -69,7 +68,7 @@ public void initialize() { } @Override - public void update(Player player) { + public void update(Player_Old player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index 3921528..f0afe11 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -6,7 +6,7 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Enemy; -import Level.Player; +import Level.Player_Old; import Projectiles.Fireball; import Utils.AirGroundState; import Utils.Direction; @@ -63,7 +63,7 @@ public void initialize() { } @Override - public void update(Player player) { + public void update(Player_Old player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index ab43a19..62eca58 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -5,7 +5,7 @@ import GameObject.Frame; import GameObject.SpriteSheet; import Level.Enemy; -import Level.Player; +import Level.Player_Old; import Projectiles.Bone; import Utils.AirGroundState; import Utils.Direction; @@ -62,7 +62,7 @@ public void initialize() { } @Override - public void update(Player player) { + public void update(Player_Old player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 313e7a1..c9e9228 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -1,15 +1,10 @@ package Engine; import GameObject.Rectangle; -import Level.Player; -import Players.Avatar; -import Players.Cat; -import Screens.OptionsScreen; -import SpriteFont.SpriteFont; +import Level.Player_Old; import Utils.Colors; import Utils.Stopwatch; -import javax.imageio.ImageIO; import javax.sound.sampled.*; //import sun.audio.AudioData; import javax.swing.*; @@ -21,7 +16,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -178,15 +172,15 @@ public void draw() { // Checks the players health and accordingly changes to the image with the corresponding number of hearts public void changeHealth() { if(coordinator.getGameState() == GameState.LEVEL) { - if(Player.playerHealth == 3) { + if(Player_Old.playerHealth == 3) { health.setIcon(new ImageIcon(ImageLoader.load("3 Hearts.png"))); } - else if(Player.playerHealth == 2) { + else if(Player_Old.playerHealth == 2) { health.setIcon(new ImageIcon(ImageLoader.load("2 Hearts.png"))); } - else if(Player.playerHealth == 1) { + else if(Player_Old.playerHealth == 1) { health.setIcon(new ImageIcon(ImageLoader.load("1 Heart.png"))); } @@ -196,7 +190,7 @@ else if(Player.playerHealth == 1) { } if(coordinator.getGameState() == GameState.MENU) { - Player.playerHealth = 3; + Player_Old.playerHealth = 3; } } diff --git a/src/EnhancedMapTiles/EndLevelBox.java b/src/EnhancedMapTiles/EndLevelBox.java index a6b031d..9a6ea50 100644 --- a/src/EnhancedMapTiles/EndLevelBox.java +++ b/src/EnhancedMapTiles/EndLevelBox.java @@ -5,7 +5,7 @@ import GameObject.Frame; import GameObject.SpriteSheet; import Level.EnhancedMapTile; -import Level.Player; +import Level.Player_Old; import Level.TileType; import Utils.Point; @@ -19,7 +19,7 @@ public EndLevelBox(Point location) { } @Override - public void update(Player player) { + public void update(Player_Old player) { super.update(player); if (intersects(player)) { player.completeLevel(); diff --git a/src/EnhancedMapTiles/HorizontalMovingPlatform.java b/src/EnhancedMapTiles/HorizontalMovingPlatform.java index 7fc36b6..215c171 100644 --- a/src/EnhancedMapTiles/HorizontalMovingPlatform.java +++ b/src/EnhancedMapTiles/HorizontalMovingPlatform.java @@ -4,7 +4,7 @@ import GameObject.ImageEffect; import GameObject.Rectangle; import Level.EnhancedMapTile; -import Level.Player; +import Level.Player_Old; import Level.TileType; import Utils.AirGroundState; import Utils.Direction; @@ -37,7 +37,7 @@ public void initialize() { } @Override - public void update(Player player) { + public void update(Player_Old player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Level/Camera.java b/src/Level/Camera.java index a2902cf..351d11f 100644 --- a/src/Level/Camera.java +++ b/src/Level/Camera.java @@ -1,6 +1,5 @@ package Level; -import Engine.Config; import Engine.GraphicsHandler; import Engine.ScreenManager; import GameObject.GameObject; @@ -50,7 +49,7 @@ public Point getTileIndexByCameraPosition() { } - public void update(Player player) { + public void update(Player_Old player) { updateMapTiles(); updateMapEntities(player); } @@ -70,7 +69,7 @@ private void updateMapTiles() { // update map entities currently a part of the update/draw cycle // active entities are calculated each frame using the loadActiveEntity methods below - public void updateMapEntities(Player player) { + public void updateMapEntities(Player_Old player) { activeEnemies = loadActiveEnemies(); activeProjectiles = loadActiveProjectiles(); activeEnhancedMapTiles = loadActiveEnhancedMapTiles(); diff --git a/src/Level/Enemy.java b/src/Level/Enemy.java index 4ddf6e9..0f31cea 100644 --- a/src/Level/Enemy.java +++ b/src/Level/Enemy.java @@ -44,7 +44,7 @@ public void initialize() { super.initialize(); } - public void update(Player player) { + public void update(Player_Old player) { super.update(); if (intersects(player)) { touchedPlayer(player); @@ -52,7 +52,7 @@ public void update(Player player) { } // A subclass can override this method to specify what it does when it touches the player - public void touchedPlayer(Player player) { + public void touchedPlayer(Player_Old player) { player.hurtPlayer(this); } diff --git a/src/Level/EnhancedMapTile.java b/src/Level/EnhancedMapTile.java index 2819134..41ee6b7 100644 --- a/src/Level/EnhancedMapTile.java +++ b/src/Level/EnhancedMapTile.java @@ -46,7 +46,7 @@ public void initialize() { } - public void update(Player player) { + public void update(Player_Old player) { super.update(); } diff --git a/src/Level/Map.java b/src/Level/Map.java index 69cbfae..d6b853d 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -333,7 +333,7 @@ public void setAdjustCamera(boolean adjustCamera) { this.adjustCamera = adjustCamera; } - public void update(Player player) { + public void update(Player_Old player) { if (adjustCamera) { adjustMovementY(player); adjustMovementX(player); @@ -343,7 +343,7 @@ public void update(Player player) { // based on the player's current X position (which in a level can potentially be updated each frame), // adjust the player's and camera's positions accordingly in order to properly create the map "scrolling" effect - private void adjustMovementX(Player player) { + private void adjustMovementX(Player_Old player) { // if player goes past center screen (on the right side) and there is more map to show on the right side, push player back to center and move camera forward if (player.getCalibratedXLocation() > xMidPoint && camera.getEndBoundX() < endBoundX) { float xMidPointDifference = xMidPoint - player.getCalibratedXLocation(); @@ -370,7 +370,7 @@ else if (player.getCalibratedXLocation() < xMidPoint && camera.getX() > startBou // based on the player's current Y position (which in a level can potentially be updated each frame), // adjust the player's and camera's positions accordingly in order to properly create the map "scrolling" effect - private void adjustMovementY(Player player) { + private void adjustMovementY(Player_Old player) { // if player goes past center screen (below) and there is more map to show below, push player back to center and move camera upward if (player.getCalibratedYLocation() > yMidPoint && camera.getEndBoundY() < endBoundY) { float yMidPointDifference = yMidPoint - player.getCalibratedYLocation(); diff --git a/src/Level/NPC.java b/src/Level/NPC.java index 7ca0240..fb9b03f 100644 --- a/src/Level/NPC.java +++ b/src/Level/NPC.java @@ -65,12 +65,12 @@ protected SpriteFont createMessage() { return null; } - public void update(Player player) { + public void update(Player_Old player) { super.update(); checkTalkedTo(player); } - public void checkTalkedTo(Player player) { + public void checkTalkedTo(Player_Old player) { if (intersects(player) && KeyboardAction.GAME_INTERACT.isDown()) { talkedTo = true; timer.setWaitTime(talkedToTime); diff --git a/src/Level/PlayerAttack.java b/src/Level/PlayerAttack.java index 8f11657..e4ddba7 100644 --- a/src/Level/PlayerAttack.java +++ b/src/Level/PlayerAttack.java @@ -6,13 +6,10 @@ import Engine.ImageLoader; import GameObject.Frame; import GameObject.SpriteSheet; -import Level.Enemy; -import Level.MapEntityStatus; -import Level.Player; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; -import Level.Map; + import java.util.ArrayList; import java.util.HashMap; @@ -38,7 +35,7 @@ public PlayerAttack(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player player) { + public void update(Player_Old player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -74,7 +71,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player player) { + public void touchedPlayer(Player_Old player) { // if fireball touches player, it disappears //super.touchedPlayer(player); //this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Level/Player.java b/src/Level/Player_Old.java similarity index 99% rename from src/Level/Player.java rename to src/Level/Player_Old.java index a54b4da..9ea6615 100644 --- a/src/Level/Player.java +++ b/src/Level/Player_Old.java @@ -13,7 +13,8 @@ import java.util.ArrayList; -public abstract class Player extends GameObject { +@Deprecated +public abstract class Player_Old extends GameObject { // values that affect player movement // these should be set in a subclass protected float walkSpeed = 0; @@ -65,7 +66,7 @@ public abstract class Player extends GameObject { // added 11/19 protected PlayerAttack currentProjectile; - public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { + public Player_Old(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { super(spriteSheet, x, y, startingAnimationName); facingDirection = Direction.RIGHT; airGroundState = AirGroundState.AIR; diff --git a/src/Level/Projectile.java b/src/Level/Projectile.java index d35ea92..5a607c2 100644 --- a/src/Level/Projectile.java +++ b/src/Level/Projectile.java @@ -43,7 +43,7 @@ public void initialize() { super.initialize(); } - public void update(Player player) { + public void update(Player_Old player) { super.update(); if (intersects(player)) { touchedPlayer(player); @@ -51,7 +51,7 @@ public void update(Player player) { } // A subclass can override this method to specify what it does when it touches the player - public void touchedPlayer(Player player) { + public void touchedPlayer(Player_Old player) { player.hurtPlayer(this); } } diff --git a/src/NPCs/Walrus.java b/src/NPCs/Walrus.java index 4803f22..600a28a 100644 --- a/src/NPCs/Walrus.java +++ b/src/NPCs/Walrus.java @@ -8,7 +8,7 @@ import GameObject.SpriteSheet; import Level.Map; import Level.NPC; -import Level.Player; +import Level.Player_Old; import SpriteFont.SpriteFont; import Utils.Point; @@ -27,7 +27,7 @@ protected SpriteFont createMessage() { return new SpriteFont("Good Luck on your quest!", getX(), getY() - 10, "Arial", 12, Color.BLACK); } - public void update(Player player) { + public void update(Player_Old player) { // while npc is being talked to, it raises its tail up (in excitement?) if (talkedTo) { currentAnimationName = "TAIL_UP"; diff --git a/src/Players/Avatar.java b/src/Players/Avatar.java index c39ae30..f7d06a1 100644 --- a/src/Players/Avatar.java +++ b/src/Players/Avatar.java @@ -1,7 +1,7 @@ package Players; -import Level.Player; +import Level.Player_Old; import Utils.Point; //TODO make this the new Cat Options with a factory to create the player @@ -17,11 +17,11 @@ public enum Avatar { this.factory = factory; } - public Player generatePlayer(Point startingPoint) { + public Player_Old generatePlayer(Point startingPoint) { return factory.generatePlayer(startingPoint); } public interface PlayerFactory { - Player generatePlayer(Point startingPoint); + Player_Old generatePlayer(Point startingPoint); } } diff --git a/src/Players/Cat.java b/src/Players/Cat.java index 4225bcd..705fbdb 100644 --- a/src/Players/Cat.java +++ b/src/Players/Cat.java @@ -6,14 +6,14 @@ import GameObject.Frame; import GameObject.ImageEffect; import GameObject.SpriteSheet; -import Level.Player; +import Level.Player_Old; import Utils.Point; import java.util.HashMap; // This is the class for the Cat player character // basically just sets some values for physics and then defines animations -public class Cat extends Player { +public class Cat extends Player_Old { public Cat(String name, Point point) { this(name,point.x,point.y); diff --git a/src/Projectiles/Bone.java b/src/Projectiles/Bone.java index 9a73392..0de9a9c 100644 --- a/src/Projectiles/Bone.java +++ b/src/Projectiles/Bone.java @@ -7,7 +7,7 @@ import GameObject.SpriteSheet; import Level.Enemy; import Level.MapEntityStatus; -import Level.Player; +import Level.Player_Old; import Level.Projectile; import Utils.Direction; import Utils.Point; @@ -35,7 +35,7 @@ public Bone(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player player) { + public void update(Player_Old player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -56,7 +56,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player player) { + public void touchedPlayer(Player_Old player) { // if bone touches player, it disappears super.touchedPlayer(player); this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Projectiles/Fireball.java b/src/Projectiles/Fireball.java index 0d2f98a..c31dcdc 100644 --- a/src/Projectiles/Fireball.java +++ b/src/Projectiles/Fireball.java @@ -4,9 +4,8 @@ import Engine.ImageLoader; import GameObject.Frame; import GameObject.SpriteSheet; -import Level.Enemy; import Level.MapEntityStatus; -import Level.Player; +import Level.Player_Old; import Level.Projectile; import Utils.Direction; import Utils.Point; @@ -35,7 +34,7 @@ public Fireball(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player player) { + public void update(Player_Old player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -56,7 +55,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player player) { + public void touchedPlayer(Player_Old player) { // if fireball touches player, it disappears super.touchedPlayer(player); this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Projectiles/LazerBeam.java b/src/Projectiles/LazerBeam.java index 9780bbe..9c8ed95 100644 --- a/src/Projectiles/LazerBeam.java +++ b/src/Projectiles/LazerBeam.java @@ -6,7 +6,7 @@ import GameObject.SpriteSheet; import Level.Enemy; import Level.MapEntityStatus; -import Level.Player; +import Level.Player_Old; import Level.Projectile; import Utils.Direction; import Utils.Point; @@ -34,7 +34,7 @@ public LazerBeam(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player player) { + public void update(Player_Old player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -55,7 +55,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player player) { + public void touchedPlayer(Player_Old player) { // if lazer beam touches player, it disappears super.touchedPlayer(player); this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Screens/LevelLoseScreen.java b/src/Screens/LevelLoseScreen.java index 413098b..91061ba 100644 --- a/src/Screens/LevelLoseScreen.java +++ b/src/Screens/LevelLoseScreen.java @@ -2,7 +2,7 @@ import Engine.Drawable; import Engine.KeyboardAction; -import Level.Player; +import Level.Player_Old; import Level.PlayerAttack; import Menu.Menu; import SpriteFont.SpriteFont; @@ -26,7 +26,7 @@ public void update() { super.update(); if (KeyboardAction.GAME_RESPAWN.isDown()) { playLevelScreen.resetLevel(); - Player.playerHealth = 3; + Player_Old.playerHealth = 3; PlayerAttack.dogHealth = 8; } } diff --git a/src/Screens/PauseScreen.java b/src/Screens/PauseScreen.java index 288b477..76bc5e6 100644 --- a/src/Screens/PauseScreen.java +++ b/src/Screens/PauseScreen.java @@ -3,7 +3,7 @@ import Engine.*; import Game.GameState; import Level.Map; -import Level.Player; +import Level.Player_Old; import Menu.Menu; import Menu.MenuOption; import SpriteFont.SpriteFont; @@ -24,7 +24,7 @@ public class PauseScreen extends Menu { private final PlayLevelScreen playLevelScreen; private boolean menuEscape; - public PauseScreen(Map map, Player player, PlayLevelScreen playLevelScreen) { + public PauseScreen(Map map, Player_Old player, PlayLevelScreen playLevelScreen) { this.playLevelScreen = playLevelScreen; menuEscape = false; setDrawables(new Drawable[]{ diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 5d397f3..b270fca 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -3,7 +3,7 @@ import Engine.*; import Game.GameState; import Level.Map; -import Level.Player; +import Level.Player_Old; import Level.PlayerListener; import Maps.*; import SpriteFont.SpriteFont; @@ -22,7 +22,7 @@ public class PlayLevelScreen extends Screen implements PlayerListener { private static final Color COLOR_GREY_BACKGROUND; private static Map loadedMap; private static Screen alternateScreen; - private static Player player; + private static Player_Old player; static { screenTimer = new Stopwatch(); From 2a1c453fef38969248aed9827d290dbf5c7a52e6 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 16:53:40 -0500 Subject: [PATCH 011/164] Started working on new Player.java Deprecated LevelState.java --- src/Level/LevelState.java | 1 + src/Level/Player.java | 44 ++++++++++++++++++++++++++++++++++++++ src/Level/PlayerState.java | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/Level/Player.java diff --git a/src/Level/LevelState.java b/src/Level/LevelState.java index ab711b7..3652ef5 100644 --- a/src/Level/LevelState.java +++ b/src/Level/LevelState.java @@ -1,6 +1,7 @@ package Level; // This enum represents the potential states a level can be +@Deprecated public enum LevelState { RUNNING, LEVEL_COMPLETED, PLAYER_DEAD, LEVEL_WIN_MESSAGE, LEVEL_LOSE_MESSAGE } diff --git a/src/Level/Player.java b/src/Level/Player.java new file mode 100644 index 0000000..a4879f6 --- /dev/null +++ b/src/Level/Player.java @@ -0,0 +1,44 @@ +package Level; + +import GameObject.GameObject; +import GameObject.SpriteSheet; +import Utils.Stopwatch; + +public abstract class Player extends GameObject { + + protected float walkSpeed, maxWalkSpeed, minWalkSpeed, walkAcceleration, gravity, jumpHeight, jumpDegrade, terminalVelocityX; + + public static int PLAYER_HEALTH = 3; + + protected Stopwatch attackDelay, jumpDelay; + + protected PlayerState playerState; + + public Player(SpriteSheet spriteSheet, float x,float y, String startingAnimationName) { + super(spriteSheet,x,y,startingAnimationName); + playerState = PlayerState.STANDING; + attackDelay = new Stopwatch(); + jumpDelay = new Stopwatch(); + } + + + public void update() { + switch(playerState) { + case DYING -> updateDying(); + case WINNING -> updateWinning(); + default -> updatePlaying(); + } + } + + public void updatePlaying() { + + } + + public void updateDying() { + + } + + public void updateWinning() { + + } +} diff --git a/src/Level/PlayerState.java b/src/Level/PlayerState.java index 6a6d945..34ef6c9 100644 --- a/src/Level/PlayerState.java +++ b/src/Level/PlayerState.java @@ -2,5 +2,5 @@ // This enum represents different states the Player can be in public enum PlayerState { - STANDING, WALKING, JUMPING, CROUCHING, ATTACKING + STANDING, WALKING, JUMPING, CROUCHING, ATTACKING, DYING, WINNING } From 0146d078e8badc9231049735552c710e08eef5bc Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 16 Nov 2021 17:19:20 -0500 Subject: [PATCH 012/164] Continued work on rebuilding Player.java Added "CollisionType" field to MapEntity to optimize hurtPlayer methods Deprecated AirGroundState.java --- src/Engine/CollisionType.java | 9 ++++++ src/Level/MapEntity.java | 10 ++++++ src/Level/Player.java | 58 ++++++++++++++++++++++++++++++++--- src/Utils/AirGroundState.java | 1 + 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/Engine/CollisionType.java diff --git a/src/Engine/CollisionType.java b/src/Engine/CollisionType.java new file mode 100644 index 0000000..c65fdcb --- /dev/null +++ b/src/Engine/CollisionType.java @@ -0,0 +1,9 @@ +package Engine; + +/** + * Indicates the type of collision that a player should have when it collides with + * a given entity. + */ +public enum CollisionType { + DEFAULT,INSTANT_DEATH,DAMAGE,PREVENT_JUMP +} diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index 0f849ea..8642e95 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -1,5 +1,6 @@ package Level; +import Engine.CollisionType; import GameObject.*; import java.awt.image.BufferedImage; @@ -9,6 +10,7 @@ // it is basically a game object with a few extra features for handling things like respawning public class MapEntity extends GameObject { protected MapEntityStatus mapEntityStatus = MapEntityStatus.ACTIVE; + protected CollisionType collisionType = CollisionType.DEFAULT; // if true, if entity goes out of the camera's update range, and then ends up back in range, the entity will "respawn" back to its starting parameters protected boolean isRespawnable = true; @@ -77,4 +79,12 @@ public boolean isUpdateOffScreen() { public void setIsUpdateOffScreen(boolean isUpdateOffScreen) { this.isUpdateOffScreen = isUpdateOffScreen; } + + public void setCollisionType(CollisionType collisionType) { + this.collisionType = collisionType; + } + + public CollisionType getCollisionType() { + return collisionType; + } } diff --git a/src/Level/Player.java b/src/Level/Player.java index a4879f6..d104b75 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -2,17 +2,42 @@ import GameObject.GameObject; import GameObject.SpriteSheet; +import Utils.AirGroundState; import Utils.Stopwatch; +import java.util.ArrayList; +import java.util.List; + public abstract class Player extends GameObject { - protected float walkSpeed, maxWalkSpeed, minWalkSpeed, walkAcceleration, gravity, jumpHeight, jumpDegrade, terminalVelocityX; +/* +Values set by the cat class + gravity = .5f; -> amount that the velocity moves in the y direction + terminalVelocityY = 6f; + jumpHeight = 14.5f; + jumpDegrade = .5f; + walkSpeed = 2.1f; + minWalkSpeed = 2.1f; + maxWalkSpeed = 3.3f; + walkAcceleration = 1.05f; + momentumYIncrease = .5f; + */ + + /* + Ideas for how to manage movement with minimal modifications: + Point velocity -> current velocity, modified by gravity, etc. + float gravity -> gravity force + + */ public static int PLAYER_HEALTH = 3; protected Stopwatch attackDelay, jumpDelay; protected PlayerState playerState; + protected boolean inAir, invincible; + + private List playerListeners = new ArrayList<>(); public Player(SpriteSheet spriteSheet, float x,float y, String startingAnimationName) { super(spriteSheet,x,y,startingAnimationName); @@ -23,22 +48,47 @@ public Player(SpriteSheet spriteSheet, float x,float y, String startingAnimation public void update() { +// Is the super.update() ordering specific? Unsure? + super.update(); switch(playerState) { case DYING -> updateDying(); case WINNING -> updateWinning(); default -> updatePlaying(); } + } - public void updatePlaying() { + + + private void updatePlaying() { } - public void updateDying() { + private void updateDying() { } - public void updateWinning() { + private void updateWinning() { + + } + + public void hurtPlayer(MapEntity mapEntity) { + if(!invincible) { + switch(mapEntity.getCollisionType()) { + + } + } + } + + public void completeLevel() { + playerState = PlayerState.WINNING; + } + + public boolean isInAir() { + return inAir; + } + public void addListener(PlayerListener listener) { + playerListeners.add(listener); } } diff --git a/src/Utils/AirGroundState.java b/src/Utils/AirGroundState.java index e8b756a..3cba565 100644 --- a/src/Utils/AirGroundState.java +++ b/src/Utils/AirGroundState.java @@ -2,6 +2,7 @@ // Simple enum for keeping track of it something is on the ground or in the air // I don't like the name of this enum, but I couldn't think of a better name... +@Deprecated public enum AirGroundState { GROUND, AIR } From efaf7c23efcf11ec09f32ef51b3c1ba649d9d83f Mon Sep 17 00:00:00 2001 From: Jacob Conrad Date: Tue, 16 Nov 2021 18:49:46 -0500 Subject: [PATCH 013/164] Created test case SCP-55 --- Team A2/Test Cases/Test Case SCP-55.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-55.md diff --git a/Team A2/Test Cases/Test Case SCP-55.md b/Team A2/Test Cases/Test Case SCP-55.md new file mode 100644 index 0000000..a7092c4 --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-55.md @@ -0,0 +1,23 @@ +### Test Case Information +| TEST CASE ID | SCP-55 | +| :--- | :--- | +| Owner of Test | Jacob Conrad | +| Test Name | Character preview not updating properly | +| Date of Last Revision | 11/16/2021 | +| Test Objective | Verify that the character preview shows with the last selected option not the last highlighted option. | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1|Run the game|The main menu displays successfully|| +|2|Press space on "Options"|The options menu should load|| +|3|Click on orange and then hover over blue or green|The orange cat should be displayed|| +|4|Click on blue and then hover over orange or green|The blue cat should be displayed|| +|5|Click on green and then hover over blue or orange|The green cat should be displayed|| + + +### Test Completion +- **Tester**: +- **Date of Test**: +- **Test Result**: \ No newline at end of file From f15d7c485892cfee0cf70e9c5d7c67e244b92527 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 19:10:37 -0500 Subject: [PATCH 014/164] Optimized Stopwatch.java --- src/Utils/Stopwatch.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Utils/Stopwatch.java b/src/Utils/Stopwatch.java index a57f11f..7bae0d1 100644 --- a/src/Utils/Stopwatch.java +++ b/src/Utils/Stopwatch.java @@ -4,16 +4,18 @@ public class Stopwatch { private long beforeTime = System.currentTimeMillis(); private int millisecondsToWait = 0; + private boolean timeUp = true; // tell stopwatch how many milliseconds to "time" public void setWaitTime(int millisecondsToWait) { this.millisecondsToWait = millisecondsToWait; beforeTime = System.currentTimeMillis(); + timeUp = false; } // will return true or false based on if the "time" is up (a specified number of milliseconds have passed) public boolean isTimeUp() { - return System.currentTimeMillis() - beforeTime > millisecondsToWait; + return timeUp || (timeUp = System.currentTimeMillis() - beforeTime > millisecondsToWait); } // reset timer to wait again for specified number of milliseconds From 8ccbdfc45a389556bde0fbf14c5ddd5b6b577cce Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 19:43:46 -0500 Subject: [PATCH 015/164] Continued work on Player.java --- src/Level/LevelState.java | 14 ++++++- src/Level/Player.java | 78 +++++++++++++++++++++++++++++++------- src/Level/PlayerState.java | 28 +++++++++++++- src/Level/Player_Old.java | 33 ++++++++-------- 4 files changed, 120 insertions(+), 33 deletions(-) diff --git a/src/Level/LevelState.java b/src/Level/LevelState.java index 3652ef5..9f36cae 100644 --- a/src/Level/LevelState.java +++ b/src/Level/LevelState.java @@ -1,7 +1,17 @@ package Level; // This enum represents the potential states a level can be -@Deprecated public enum LevelState { - RUNNING, LEVEL_COMPLETED, PLAYER_DEAD, LEVEL_WIN_MESSAGE, LEVEL_LOSE_MESSAGE + @Deprecated + RUNNING, + @Deprecated + LEVEL_COMPLETED, + @Deprecated + PLAYER_DEAD, + @Deprecated + LEVEL_WIN_MESSAGE, + @Deprecated + LEVEL_LOSE_MESSAGE, +// New values + PLAYING,DEAD,WIN } diff --git a/src/Level/Player.java b/src/Level/Player.java index d104b75..ff0ed5d 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -1,8 +1,11 @@ package Level; +import Engine.KeyLocker; +import Engine.KeyboardAction; import GameObject.GameObject; import GameObject.SpriteSheet; -import Utils.AirGroundState; +import Level.PlayerState.Facing; +import Utils.Direction; import Utils.Stopwatch; import java.util.ArrayList; @@ -30,58 +33,99 @@ public abstract class Player extends GameObject { */ + protected float gravity; + public static int PLAYER_HEALTH = 3; protected Stopwatch attackDelay, jumpDelay; + private KeyLocker keyLocker = new KeyLocker(); + protected PlayerState playerState; + protected Facing facing; + protected LevelState levelState; + protected boolean inAir, invincible; - private List playerListeners = new ArrayList<>(); + // Velocities + protected float velocityX, velocityY; + + private final List playerListeners = new ArrayList<>(); public Player(SpriteSheet spriteSheet, float x,float y, String startingAnimationName) { super(spriteSheet,x,y,startingAnimationName); - playerState = PlayerState.STANDING; + + playerState = PlayerState.STAND; + levelState = LevelState.PLAYING; + facing = Facing.RIGHT; + attackDelay = new Stopwatch(); jumpDelay = new Stopwatch(); } public void update() { -// Is the super.update() ordering specific? Unsure? + //Is the super.update() ordering specific? Unsure? super.update(); - switch(playerState) { - case DYING -> updateDying(); - case WINNING -> updateWinning(); - default -> updatePlaying(); + + switch (levelState) { + case PLAYING -> updatePlaying(); + case DEAD -> updateDead(); + case WIN -> updateWin(); } - } + //Update Animation + setCurrentAnimationName(playerState.get(facing)); + //List of keys that require to be tapped + keyLocker.setAction(KeyboardAction.GAME_JUMP); + } private void updatePlaying() { + applyGravity(); } - private void updateDying() { + private void updateDead() { } - private void updateWinning() { + private void updateWin() { + + } + private void applyGravity() { + //Legacy code multiplies velocity by 2 beforehand + velocityY *= 2; + velocityY += gravity; } public void hurtPlayer(MapEntity mapEntity) { +// Do we even still need the invincible value? if(!invincible) { switch(mapEntity.getCollisionType()) { - + case DAMAGE -> PLAYER_HEALTH -= 1; + case INSTANT_DEATH -> PLAYER_HEALTH = 0; + case PREVENT_JUMP -> preventJump(5000); + case DEFAULT -> {} } } } + /** + * @return {@code True} when the player is allowed to jump, and is on the ground + */ + public boolean canJump() { + return jumpDelay.isTimeUp() && !isInAir(); + } + + public void preventJump(int time) { + jumpDelay.setWaitTime(5000); + } + public void completeLevel() { - playerState = PlayerState.WINNING; + levelState = LevelState.WIN; } public boolean isInAir() { @@ -91,4 +135,12 @@ public boolean isInAir() { public void addListener(PlayerListener listener) { playerListeners.add(listener); } + + public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { + if(direction == Direction.DOWN) { + if(hasCollided) { + velocityY = 0; + } + } + } } diff --git a/src/Level/PlayerState.java b/src/Level/PlayerState.java index 34ef6c9..66ea4ca 100644 --- a/src/Level/PlayerState.java +++ b/src/Level/PlayerState.java @@ -2,5 +2,31 @@ // This enum represents different states the Player can be in public enum PlayerState { - STANDING, WALKING, JUMPING, CROUCHING, ATTACKING, DYING, WINNING + STAND, WALK, JUMP, CROUCH, + DEATH, + @Deprecated + ATTACKING; + + private String left,right; + + PlayerState() { + left = this + "_LEFT"; + right = this + "_RIGHT"; + } + + public String getLeft() { + return left; + } + + public String getRight() { + return right; + } + + public String get(Facing facing) { + return facing == Facing.LEFT ? left : right; + } + + public enum Facing { + LEFT,RIGHT + } } diff --git a/src/Level/Player_Old.java b/src/Level/Player_Old.java index 9ea6615..c9d4282 100644 --- a/src/Level/Player_Old.java +++ b/src/Level/Player_Old.java @@ -5,7 +5,6 @@ import GameObject.GameObject; import GameObject.SpriteSheet; import Projectiles.Bone; -import Projectiles.Fireball; import Utils.AirGroundState; import Utils.Direction; import Utils.Point; @@ -71,7 +70,7 @@ public Player_Old(SpriteSheet spriteSheet, float x, float y, String startingAnim facingDirection = Direction.RIGHT; airGroundState = AirGroundState.AIR; previousAirGroundState = airGroundState; - playerState = PlayerState.STANDING; + playerState = PlayerState.STAND; levelState = LevelState.RUNNING; this.x = x; this.y = y; @@ -130,16 +129,16 @@ protected void applyGravity() { // based on player's current state, call appropriate player state handling method protected void handlePlayerState() { switch (playerState) { - case STANDING: + case STAND: playerStanding(); break; - case WALKING: + case WALK: playerWalking(); break; - case CROUCHING: + case CROUCH: playerCrouching(); break; - case JUMPING: + case JUMP: playerJumping(); break; // 11/19 @@ -156,17 +155,17 @@ protected void playerStanding() { // if walk left or walk right key is pressed, player enters WALKING state if (KeyboardAction.GAME_MOVE_LEFT.isDown() || KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - playerState = PlayerState.WALKING; + playerState = PlayerState.WALK; } // if jump key is pressed, player enters JUMPING state else if (KeyboardAction.GAME_JUMP.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_JUMP) && canJump == true) { - playerState = PlayerState.JUMPING; + playerState = PlayerState.JUMP; } // if crouch key is pressed, player enters CROUCHING state else if (KeyboardAction.GAME_CROUCH.isDown()) { - playerState = PlayerState.CROUCHING; + playerState = PlayerState.CROUCH; } // enter the attacking state if the attack key is pressed and the attack cooldown is up @@ -208,18 +207,18 @@ else if (KeyboardAction.GAME_MOVE_RIGHT.isDown()) { moveAmountX += walkSpeed; facingDirection = Direction.RIGHT; } else { - playerState = PlayerState.STANDING; + playerState = PlayerState.STAND; } // if jump key is pressed, player enters JUMPING state if (KeyboardAction.GAME_JUMP.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_JUMP) && canJump == true) { //System.out.println("w"); - playerState = PlayerState.JUMPING; + playerState = PlayerState.JUMP; } // if crouch key is pressed, else if (KeyboardAction.GAME_CROUCH.isDown()) { - playerState = PlayerState.CROUCHING; + playerState = PlayerState.CROUCH; } // enter the attacking state if the attack key is pressed and the attack cooldown is up @@ -236,12 +235,12 @@ protected void playerCrouching() { // if crouch key is released, player enters STANDING state if (!KeyboardAction.GAME_CROUCH.isDown()) { - playerState = PlayerState.STANDING; + playerState = PlayerState.STAND; } // if jump key is pressed, player enters JUMPING state if (KeyboardAction.GAME_JUMP.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_JUMP)) { - playerState = PlayerState.JUMPING; + playerState = PlayerState.JUMP; } } @@ -306,7 +305,7 @@ else if (KeyboardAction.GAME_MOVE_RIGHT.isDown()) { // if player last frame was in air and this frame is now on ground, player enters STANDING state else if (previousAirGroundState == AirGroundState.AIR && airGroundState == AirGroundState.GROUND) { - playerState = PlayerState.STANDING; + playerState = PlayerState.STAND; } } @@ -353,7 +352,7 @@ else if (KeyboardAction.GAME_MOVE_RIGHT.isDown()) { attackCooldown.setWaitTime(1500); // after an attack finished set the player to a standing state - playerState = PlayerState.STANDING; + playerState = PlayerState.STAND; } } @@ -409,7 +408,7 @@ public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { momentumY = 0; airGroundState = AirGroundState.GROUND; } else { - playerState = PlayerState.JUMPING; + playerState = PlayerState.JUMP; airGroundState = AirGroundState.AIR; } } From 9925e552db585f97c7fe97ed8147ba24129a07c7 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 19:44:35 -0500 Subject: [PATCH 016/164] Deprecated Cat.java, created copy to modify. --- src/Players/Avatar.java | 6 +- src/Players/Cat.java | 2 +- src/Players/Cat_Old.java | 179 +++++++++++++++++++++++++++++++++ src/Screens/OptionsScreen.java | 5 - 4 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 src/Players/Cat_Old.java diff --git a/src/Players/Avatar.java b/src/Players/Avatar.java index f7d06a1..a7abec5 100644 --- a/src/Players/Avatar.java +++ b/src/Players/Avatar.java @@ -6,9 +6,9 @@ //TODO make this the new Cat Options with a factory to create the player public enum Avatar { - CAT_ORANGE(p -> new Cat("Cat.png",p)), - CAT_BLUE(p -> new Cat("CatBlue.png",p)), - CAT_GREEN(p -> new Cat("CatGreen.png",p)); + CAT_ORANGE(p -> new Cat_Old("Cat.png", p)), + CAT_BLUE(p -> new Cat_Old("CatBlue.png", p)), + CAT_GREEN(p -> new Cat_Old("CatGreen.png", p)); private PlayerFactory factory; diff --git a/src/Players/Cat.java b/src/Players/Cat.java index 705fbdb..ae74b92 100644 --- a/src/Players/Cat.java +++ b/src/Players/Cat.java @@ -19,7 +19,7 @@ public Cat(String name, Point point) { this(name,point.x,point.y); } - public Cat(String name,float x, float y) { + public Cat(String name, float x, float y) { super(new SpriteSheet(ImageLoader.load(name), 24, 24), x, y, "STAND_RIGHT"); gravity = .5f; diff --git a/src/Players/Cat_Old.java b/src/Players/Cat_Old.java new file mode 100644 index 0000000..8c27bec --- /dev/null +++ b/src/Players/Cat_Old.java @@ -0,0 +1,179 @@ +package Players; + +import Builders.FrameBuilder; +import Engine.GraphicsHandler; +import Engine.ImageLoader; +import GameObject.Frame; +import GameObject.ImageEffect; +import GameObject.SpriteSheet; +import Level.Player_Old; +import Utils.Point; + +import java.util.HashMap; + +// This is the class for the Cat player character +// basically just sets some values for physics and then defines animations +@Deprecated +public class Cat_Old extends Player_Old { + + public Cat_Old(String name, Point point) { + this(name,point.x,point.y); + } + + public Cat_Old(String name, float x, float y) { + super(new SpriteSheet(ImageLoader.load(name), 24, 24), x, y, "STAND_RIGHT"); + + gravity = .5f; + terminalVelocityY = 6f; + jumpHeight = 14.5f; + jumpDegrade = .5f; + walkSpeed = 2.1f; + minWalkSpeed = 2.1f; + maxWalkSpeed = 3.3f; + walkAcceleration = 1.05f; + momentumYIncrease = .5f; + } + + public void update() { + super.update(); + } + + public void draw(GraphicsHandler graphicsHandler) { + super.draw(graphicsHandler); + //drawBounds(graphicsHandler, new Color(255, 0, 0, 170)); + } + + @Override + public HashMap getAnimations(SpriteSheet spriteSheet) { + return new HashMap() {{ + put("STAND_RIGHT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(0, 0), 0) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("STAND_LEFT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(0, 0), 0) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("WALK_RIGHT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(1, 0), 200) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build(), + new FrameBuilder(spriteSheet.getSprite(1, 1), 200) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build(), + new FrameBuilder(spriteSheet.getSprite(1, 2), 200) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build(), + new FrameBuilder(spriteSheet.getSprite(1, 3), 200) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("WALK_LEFT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(1, 0), 200) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build(), + new FrameBuilder(spriteSheet.getSprite(1, 1), 200) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build(), + new FrameBuilder(spriteSheet.getSprite(1, 2), 200) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build(), + new FrameBuilder(spriteSheet.getSprite(1, 3), 200) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("JUMP_RIGHT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(2, 0), 0) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("JUMP_LEFT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(2, 0), 0) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("FALL_RIGHT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(3, 0), 0) + .withScale(3) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("FALL_LEFT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(3, 0), 0) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 9, 8, 9) + .build() + }); + + put("CROUCH_RIGHT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(4, 0), 0) + .withScale(3) + .withBounds(8, 12, 8, 6) + .build() + }); + + put("CROUCH_LEFT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(4, 0), 0) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .withBounds(8, 12, 8, 6) + .build() + }); + + put("DEATH_RIGHT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(5, 0), 100) + .withScale(3) + .build(), + new FrameBuilder(spriteSheet.getSprite(5, 1), 100) + .withScale(3) + .build(), + new FrameBuilder(spriteSheet.getSprite(5, 2), -1) + .withScale(3) + .build() + }); + + put("DEATH_LEFT", new Frame[] { + new FrameBuilder(spriteSheet.getSprite(5, 0), 100) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .build(), + new FrameBuilder(spriteSheet.getSprite(5, 1), 100) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .build(), + new FrameBuilder(spriteSheet.getSprite(5, 2), -1) + .withScale(3) + .withImageEffect(ImageEffect.FLIP_HORIZONTAL) + .build() + }); + }}; + } +} diff --git a/src/Screens/OptionsScreen.java b/src/Screens/OptionsScreen.java index 0c4ffc1..23adeae 100644 --- a/src/Screens/OptionsScreen.java +++ b/src/Screens/OptionsScreen.java @@ -10,14 +10,9 @@ import Menu.Menu; import Menu.MenuOption; import Players.Avatar; -import Players.Cat; import java.awt.*; import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; - -import javax.imageio.ImageIO; public class OptionsScreen extends Menu { private MenuOption[][] items; From 5c447854d1326c95e79f2183b2db63721d7b596a Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 20:10:31 -0500 Subject: [PATCH 017/164] Added KeyLocker.isActionUnlocked method --- src/Engine/KeyLocker.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Engine/KeyLocker.java b/src/Engine/KeyLocker.java index 5077672..95e1b88 100644 --- a/src/Engine/KeyLocker.java +++ b/src/Engine/KeyLocker.java @@ -31,6 +31,10 @@ public boolean isActionLocked(KeyboardAction keyboardAction) { return lockedAdapters.contains(keyboardAction); } + public boolean isActionUnlocked(KeyboardAction keyboardAction) { + return !lockedAdapters.contains(keyboardAction); + } + public void clear() { lockedAdapters.clear(); } From e92b3dfe9f1b653989d16f0d467cfddce6dcc385 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 20:44:13 -0500 Subject: [PATCH 018/164] Proceeded to the testing phase of changes --- src/Enemies/BugEnemy.java | 3 +- src/Enemies/CyborgEnemy.java | 3 +- src/Enemies/DinosaurEnemy.java | 3 +- src/Enemies/Dog.java | 3 +- src/Engine/GamePanel.java | 9 +- src/EnhancedMapTiles/EndLevelBox.java | 3 +- .../HorizontalMovingPlatform.java | 5 +- src/GameObject/GameObject.java | 2 + src/Level/Camera.java | 4 +- src/Level/Enemy.java | 4 +- src/Level/EnhancedMapTile.java | 2 +- src/Level/Map.java | 14 ++- src/Level/NPC.java | 4 +- src/Level/Player.java | 97 +++++++++++++++++-- src/Level/PlayerAttack.java | 4 +- src/Level/PlayerState.java | 2 +- src/Level/Player_Old.java | 2 - src/Level/Projectile.java | 4 +- src/NPCs/Walrus.java | 3 +- src/Players/Avatar.java | 11 ++- src/Players/Cat.java | 19 ++-- src/Projectiles/Bone.java | 9 +- src/Projectiles/Fireball.java | 5 +- src/Projectiles/LazerBeam.java | 9 +- src/Screens/LevelLoseScreen.java | 3 +- src/Screens/PauseScreen.java | 3 +- src/Screens/PlayLevelScreen.java | 3 +- 27 files changed, 167 insertions(+), 66 deletions(-) diff --git a/src/Enemies/BugEnemy.java b/src/Enemies/BugEnemy.java index 9a53e90..a7752cf 100644 --- a/src/Enemies/BugEnemy.java +++ b/src/Enemies/BugEnemy.java @@ -6,6 +6,7 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Enemy; +import Level.Player; import Level.Player_Old; import Utils.AirGroundState; import Utils.Direction; @@ -43,7 +44,7 @@ public void initialize() { } @Override - public void update(Player_Old player) { + public void update(Player player) { float moveAmountX = 0; float moveAmountY = 0; diff --git a/src/Enemies/CyborgEnemy.java b/src/Enemies/CyborgEnemy.java index f7ded18..d7d6843 100644 --- a/src/Enemies/CyborgEnemy.java +++ b/src/Enemies/CyborgEnemy.java @@ -6,6 +6,7 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Enemy; +import Level.Player; import Level.Player_Old; import Projectiles.LazerBeam; import Utils.AirGroundState; @@ -68,7 +69,7 @@ public void initialize() { } @Override - public void update(Player_Old player) { + public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index f0afe11..00a340c 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -6,6 +6,7 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Enemy; +import Level.Player; import Level.Player_Old; import Projectiles.Fireball; import Utils.AirGroundState; @@ -63,7 +64,7 @@ public void initialize() { } @Override - public void update(Player_Old player) { + public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index 62eca58..26f2f98 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -5,6 +5,7 @@ import GameObject.Frame; import GameObject.SpriteSheet; import Level.Enemy; +import Level.Player; import Level.Player_Old; import Projectiles.Bone; import Utils.AirGroundState; @@ -62,7 +63,7 @@ public void initialize() { } @Override - public void update(Player_Old player) { + public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index c9e9228..fadda14 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -1,6 +1,7 @@ package Engine; import GameObject.Rectangle; +import Level.Player; import Level.Player_Old; import Utils.Colors; import Utils.Stopwatch; @@ -172,15 +173,15 @@ public void draw() { // Checks the players health and accordingly changes to the image with the corresponding number of hearts public void changeHealth() { if(coordinator.getGameState() == GameState.LEVEL) { - if(Player_Old.playerHealth == 3) { + if(Player.PLAYER_HEALTH == 3) { health.setIcon(new ImageIcon(ImageLoader.load("3 Hearts.png"))); } - else if(Player_Old.playerHealth == 2) { + else if(Player.PLAYER_HEALTH == 2) { health.setIcon(new ImageIcon(ImageLoader.load("2 Hearts.png"))); } - else if(Player_Old.playerHealth == 1) { + else if(Player.PLAYER_HEALTH == 1) { health.setIcon(new ImageIcon(ImageLoader.load("1 Heart.png"))); } @@ -190,7 +191,7 @@ else if(Player_Old.playerHealth == 1) { } if(coordinator.getGameState() == GameState.MENU) { - Player_Old.playerHealth = 3; + Player.PLAYER_HEALTH = 3; } } diff --git a/src/EnhancedMapTiles/EndLevelBox.java b/src/EnhancedMapTiles/EndLevelBox.java index 9a6ea50..a05c8cd 100644 --- a/src/EnhancedMapTiles/EndLevelBox.java +++ b/src/EnhancedMapTiles/EndLevelBox.java @@ -5,6 +5,7 @@ import GameObject.Frame; import GameObject.SpriteSheet; import Level.EnhancedMapTile; +import Level.Player; import Level.Player_Old; import Level.TileType; import Utils.Point; @@ -19,7 +20,7 @@ public EndLevelBox(Point location) { } @Override - public void update(Player_Old player) { + public void update(Player player) { super.update(player); if (intersects(player)) { player.completeLevel(); diff --git a/src/EnhancedMapTiles/HorizontalMovingPlatform.java b/src/EnhancedMapTiles/HorizontalMovingPlatform.java index 215c171..15d7689 100644 --- a/src/EnhancedMapTiles/HorizontalMovingPlatform.java +++ b/src/EnhancedMapTiles/HorizontalMovingPlatform.java @@ -4,6 +4,7 @@ import GameObject.ImageEffect; import GameObject.Rectangle; import Level.EnhancedMapTile; +import Level.Player; import Level.Player_Old; import Level.TileType; import Utils.AirGroundState; @@ -37,7 +38,7 @@ public void initialize() { } @Override - public void update(Player_Old player) { + public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; @@ -78,7 +79,7 @@ public void update(Player_Old player) { // if player is on standing on top of platform, move player by the amount the platform is moving // this will cause the player to "ride" with the moving platform // without this code, the platform would slide right out from under the player - if (overlaps(player) && player.getScaledBoundsY2() == getScaledBoundsY1() && player.getAirGroundState() == AirGroundState.GROUND) { + if (overlaps(player) && player.getScaledBoundsY2() == getScaledBoundsY1() && !player.isInAir()) { player.moveXHandleCollision(moveAmountX); } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 1cf6e76..d1c8bf8 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -34,6 +34,8 @@ public class GameObject extends AnimatedSprite implements Drawable { // previous location the game object was in from the last frame protected float previousX, previousY; + + // the map instance this game object "belongs" to. protected Map map; diff --git a/src/Level/Camera.java b/src/Level/Camera.java index 351d11f..ffeab9e 100644 --- a/src/Level/Camera.java +++ b/src/Level/Camera.java @@ -49,7 +49,7 @@ public Point getTileIndexByCameraPosition() { } - public void update(Player_Old player) { + public void update(Player player) { updateMapTiles(); updateMapEntities(player); } @@ -69,7 +69,7 @@ private void updateMapTiles() { // update map entities currently a part of the update/draw cycle // active entities are calculated each frame using the loadActiveEntity methods below - public void updateMapEntities(Player_Old player) { + public void updateMapEntities(Player player) { activeEnemies = loadActiveEnemies(); activeProjectiles = loadActiveProjectiles(); activeEnhancedMapTiles = loadActiveEnhancedMapTiles(); diff --git a/src/Level/Enemy.java b/src/Level/Enemy.java index 0f31cea..4ddf6e9 100644 --- a/src/Level/Enemy.java +++ b/src/Level/Enemy.java @@ -44,7 +44,7 @@ public void initialize() { super.initialize(); } - public void update(Player_Old player) { + public void update(Player player) { super.update(); if (intersects(player)) { touchedPlayer(player); @@ -52,7 +52,7 @@ public void update(Player_Old player) { } // A subclass can override this method to specify what it does when it touches the player - public void touchedPlayer(Player_Old player) { + public void touchedPlayer(Player player) { player.hurtPlayer(this); } diff --git a/src/Level/EnhancedMapTile.java b/src/Level/EnhancedMapTile.java index 41ee6b7..2819134 100644 --- a/src/Level/EnhancedMapTile.java +++ b/src/Level/EnhancedMapTile.java @@ -46,7 +46,7 @@ public void initialize() { } - public void update(Player_Old player) { + public void update(Player player) { super.update(); } diff --git a/src/Level/Map.java b/src/Level/Map.java index d6b853d..6b8c670 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -31,6 +31,9 @@ public abstract class Map implements Drawable { protected int width; protected int height; + //right most bound + private int rightBound; + // the tileset this map uses for its map tiles protected Tileset tileset; @@ -72,6 +75,7 @@ public Map(String mapFileName, Tileset tileset, Point playerStartTile) { this.xMidPoint = ScreenManager.getScreenWidth() / 2; this.yMidPoint = (ScreenManager.getScreenHeight() / 2); this.playerStartTile = playerStartTile; + rightBound = getWidthPixels() - getTileset().getScaledSpriteWidth(); } // sets up map by reading in the map file to create the tile map @@ -333,7 +337,7 @@ public void setAdjustCamera(boolean adjustCamera) { this.adjustCamera = adjustCamera; } - public void update(Player_Old player) { + public void update(Player player) { if (adjustCamera) { adjustMovementY(player); adjustMovementX(player); @@ -343,7 +347,7 @@ public void update(Player_Old player) { // based on the player's current X position (which in a level can potentially be updated each frame), // adjust the player's and camera's positions accordingly in order to properly create the map "scrolling" effect - private void adjustMovementX(Player_Old player) { + private void adjustMovementX(Player player) { // if player goes past center screen (on the right side) and there is more map to show on the right side, push player back to center and move camera forward if (player.getCalibratedXLocation() > xMidPoint && camera.getEndBoundX() < endBoundX) { float xMidPointDifference = xMidPoint - player.getCalibratedXLocation(); @@ -370,7 +374,7 @@ else if (player.getCalibratedXLocation() < xMidPoint && camera.getX() > startBou // based on the player's current Y position (which in a level can potentially be updated each frame), // adjust the player's and camera's positions accordingly in order to properly create the map "scrolling" effect - private void adjustMovementY(Player_Old player) { + private void adjustMovementY(Player player) { // if player goes past center screen (below) and there is more map to show below, push player back to center and move camera upward if (player.getCalibratedYLocation() > yMidPoint && camera.getEndBoundY() < endBoundY) { float yMidPointDifference = yMidPoint - player.getCalibratedYLocation(); @@ -402,4 +406,8 @@ public void reset() { public void draw(GraphicsHandler graphicsHandler) { camera.draw(graphicsHandler); } + + public int getRightBound() { + return rightBound; + } } diff --git a/src/Level/NPC.java b/src/Level/NPC.java index fb9b03f..7ca0240 100644 --- a/src/Level/NPC.java +++ b/src/Level/NPC.java @@ -65,12 +65,12 @@ protected SpriteFont createMessage() { return null; } - public void update(Player_Old player) { + public void update(Player player) { super.update(); checkTalkedTo(player); } - public void checkTalkedTo(Player_Old player) { + public void checkTalkedTo(Player player) { if (intersects(player) && KeyboardAction.GAME_INTERACT.isDown()) { talkedTo = true; timer.setWaitTime(talkedToTime); diff --git a/src/Level/Player.java b/src/Level/Player.java index ff0ed5d..0d63cd6 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -6,6 +6,7 @@ import GameObject.SpriteSheet; import Level.PlayerState.Facing; import Utils.Direction; +import Utils.Point; import Utils.Stopwatch; import java.util.ArrayList; @@ -13,6 +14,9 @@ public abstract class Player extends GameObject { + //Static Values + private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; + /* Values set by the cat class gravity = .5f; -> amount that the velocity moves in the y direction @@ -33,7 +37,7 @@ public abstract class Player extends GameObject { */ - protected float gravity; + protected float gravity, jumpHeight; public static int PLAYER_HEALTH = 3; @@ -84,11 +88,72 @@ public void update() { private void updatePlaying() { applyGravity(); + keepInBounds(); + //Update Player Action and Direction + if(KeyboardAction.GAME_MOVE_LEFT.isDown()) { + facing = Facing.LEFT; + playerState = PlayerState.WALK; + } + if(KeyboardAction.GAME_MOVE_RIGHT.isDown()) { + facing = Facing.RIGHT; + playerState = PlayerState.WALK; + } + + //Update Jump + if(KeyboardAction.GAME_JUMP.isDown()) { + jump(); + } else if(velocityY > 0) { //if the player releases while velocity is still up, cut short + velocityY = 0; + } + + //Update Attack + if(KeyboardAction.GAME_ATTACK.isDown() && attackDelay.isTimeUp()) { + attack(); + } + + //If the player is in the air, set its animation based on velocityY + if(inAir) { + playerState = velocityY > 0 ? PlayerState.JUMP : PlayerState.FALL; + } + + //Updates player to death if their health hits 0 + if(PLAYER_HEALTH <= 0) { + levelState = LevelState.DEAD; + } + + applyVelocity(); } - private void updateDead() { + private void attack() { + int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); + int attackY = Math.round(getY()) + 10; + float movementSpeed = facing == Facing.RIGHT ? 1.5f : -1.5f; + + PlayerAttack projectile = new PlayerAttack(new Point(attackX, attackY), movementSpeed, 1000); + + map.addEnemy(projectile); + attackDelay.setWaitTime(ATTACK_DELAY); + } + + private void keepInBounds() { + if(x < 0) { + velocityX = 0; + setX(0); + } else if(levelState != LevelState.WIN && x > map.getRightBound()) { + velocityX = 0; + setX(map.getRightBound()); + } + } + private void jump() { + if(canJump() && keyLocker.isActionUnlocked(KeyboardAction.GAME_JUMP)) { + velocityY = jumpHeight; + } + } + + private void updateDead() { + playerState = PlayerState.DEATH; } private void updateWin() { @@ -101,6 +166,11 @@ private void applyGravity() { velocityY += gravity; } + private void applyVelocity() { + setX(x + velocityX); + setY(y + velocityY); + } + public void hurtPlayer(MapEntity mapEntity) { // Do we even still need the invincible value? if(!invincible) { @@ -121,7 +191,7 @@ public boolean canJump() { } public void preventJump(int time) { - jumpDelay.setWaitTime(5000); + jumpDelay.setWaitTime(JUMP_DELAY); } public void completeLevel() { @@ -138,9 +208,24 @@ public void addListener(PlayerListener listener) { public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { if(direction == Direction.DOWN) { - if(hasCollided) { - velocityY = 0; - } + inAir = !hasCollided; + } + if(hasCollided) { + velocityY = 0; + handleCollision(MapTileCollisionHandler.lastCollidedTileY); + } + } + + public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { + if(hasCollided) { + handleCollision(MapTileCollisionHandler.lastCollidedTileX); } } + + private void handleCollision(MapTile tile) { + if(tile != null && tile.getTileType() == TileType.LETHAL) { + levelState = LevelState.DEAD; + } + } + } diff --git a/src/Level/PlayerAttack.java b/src/Level/PlayerAttack.java index e4ddba7..481c423 100644 --- a/src/Level/PlayerAttack.java +++ b/src/Level/PlayerAttack.java @@ -35,7 +35,7 @@ public PlayerAttack(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player_Old player) { + public void update(Player player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -71,7 +71,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player_Old player) { + public void touchedPlayer(Player player) { // if fireball touches player, it disappears //super.touchedPlayer(player); //this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Level/PlayerState.java b/src/Level/PlayerState.java index 66ea4ca..eaa629a 100644 --- a/src/Level/PlayerState.java +++ b/src/Level/PlayerState.java @@ -2,7 +2,7 @@ // This enum represents different states the Player can be in public enum PlayerState { - STAND, WALK, JUMP, CROUCH, + STAND, WALK, JUMP, CROUCH, FALL, DEATH, @Deprecated ATTACKING; diff --git a/src/Level/Player_Old.java b/src/Level/Player_Old.java index c9d4282..10c347c 100644 --- a/src/Level/Player_Old.java +++ b/src/Level/Player_Old.java @@ -383,11 +383,9 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { if (direction == Direction.LEFT || direction == Direction.RIGHT) { int rightBound = map.getWidthPixels() - map.getTileset().getScaledSpriteWidth(); if (x < 0) { - hasCollided = true; momentumX = 0; setX(0); } else if (levelState != LevelState.LEVEL_COMPLETED && x > rightBound) { - hasCollided = true; momentumX = 0; setX(rightBound); } diff --git a/src/Level/Projectile.java b/src/Level/Projectile.java index 5a607c2..d35ea92 100644 --- a/src/Level/Projectile.java +++ b/src/Level/Projectile.java @@ -43,7 +43,7 @@ public void initialize() { super.initialize(); } - public void update(Player_Old player) { + public void update(Player player) { super.update(); if (intersects(player)) { touchedPlayer(player); @@ -51,7 +51,7 @@ public void update(Player_Old player) { } // A subclass can override this method to specify what it does when it touches the player - public void touchedPlayer(Player_Old player) { + public void touchedPlayer(Player player) { player.hurtPlayer(this); } } diff --git a/src/NPCs/Walrus.java b/src/NPCs/Walrus.java index 600a28a..ca9c4d2 100644 --- a/src/NPCs/Walrus.java +++ b/src/NPCs/Walrus.java @@ -8,6 +8,7 @@ import GameObject.SpriteSheet; import Level.Map; import Level.NPC; +import Level.Player; import Level.Player_Old; import SpriteFont.SpriteFont; import Utils.Point; @@ -27,7 +28,7 @@ protected SpriteFont createMessage() { return new SpriteFont("Good Luck on your quest!", getX(), getY() - 10, "Arial", 12, Color.BLACK); } - public void update(Player_Old player) { + public void update(Player player) { // while npc is being talked to, it raises its tail up (in excitement?) if (talkedTo) { currentAnimationName = "TAIL_UP"; diff --git a/src/Players/Avatar.java b/src/Players/Avatar.java index a7abec5..e938302 100644 --- a/src/Players/Avatar.java +++ b/src/Players/Avatar.java @@ -1,14 +1,15 @@ package Players; +import Level.Player; import Level.Player_Old; import Utils.Point; //TODO make this the new Cat Options with a factory to create the player public enum Avatar { - CAT_ORANGE(p -> new Cat_Old("Cat.png", p)), - CAT_BLUE(p -> new Cat_Old("CatBlue.png", p)), - CAT_GREEN(p -> new Cat_Old("CatGreen.png", p)); + CAT_ORANGE(p -> new Cat("Cat.png", p)), + CAT_BLUE(p -> new Cat("CatBlue.png", p)), + CAT_GREEN(p -> new Cat("CatGreen.png", p)); private PlayerFactory factory; @@ -17,11 +18,11 @@ public enum Avatar { this.factory = factory; } - public Player_Old generatePlayer(Point startingPoint) { + public Player generatePlayer(Point startingPoint) { return factory.generatePlayer(startingPoint); } public interface PlayerFactory { - Player_Old generatePlayer(Point startingPoint); + Player generatePlayer(Point startingPoint); } } diff --git a/src/Players/Cat.java b/src/Players/Cat.java index ae74b92..6f0ec53 100644 --- a/src/Players/Cat.java +++ b/src/Players/Cat.java @@ -6,6 +6,7 @@ import GameObject.Frame; import GameObject.ImageEffect; import GameObject.SpriteSheet; +import Level.Player; import Level.Player_Old; import Utils.Point; @@ -13,7 +14,7 @@ // This is the class for the Cat player character // basically just sets some values for physics and then defines animations -public class Cat extends Player_Old { +public class Cat extends Player { public Cat(String name, Point point) { this(name,point.x,point.y); @@ -23,14 +24,14 @@ public Cat(String name, float x, float y) { super(new SpriteSheet(ImageLoader.load(name), 24, 24), x, y, "STAND_RIGHT"); gravity = .5f; - terminalVelocityY = 6f; - jumpHeight = 14.5f; - jumpDegrade = .5f; - walkSpeed = 2.1f; - minWalkSpeed = 2.1f; - maxWalkSpeed = 3.3f; - walkAcceleration = 1.05f; - momentumYIncrease = .5f; +// terminalVelocityY = 6f; +// jumpHeight = 14.5f; +// jumpDegrade = .5f; +// walkSpeed = 2.1f; +// minWalkSpeed = 2.1f; +// maxWalkSpeed = 3.3f; +// walkAcceleration = 1.05f; +// momentumYIncrease = .5f; } public void update() { diff --git a/src/Projectiles/Bone.java b/src/Projectiles/Bone.java index 0de9a9c..9677033 100644 --- a/src/Projectiles/Bone.java +++ b/src/Projectiles/Bone.java @@ -5,10 +5,7 @@ import GameObject.Frame; import GameObject.ImageEffect; import GameObject.SpriteSheet; -import Level.Enemy; -import Level.MapEntityStatus; -import Level.Player_Old; -import Level.Projectile; +import Level.*; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; @@ -35,7 +32,7 @@ public Bone(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player_Old player) { + public void update(Player player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -56,7 +53,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player_Old player) { + public void touchedPlayer(Player player) { // if bone touches player, it disappears super.touchedPlayer(player); this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Projectiles/Fireball.java b/src/Projectiles/Fireball.java index c31dcdc..1eff9c0 100644 --- a/src/Projectiles/Fireball.java +++ b/src/Projectiles/Fireball.java @@ -5,6 +5,7 @@ import GameObject.Frame; import GameObject.SpriteSheet; import Level.MapEntityStatus; +import Level.Player; import Level.Player_Old; import Level.Projectile; import Utils.Direction; @@ -34,7 +35,7 @@ public Fireball(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player_Old player) { + public void update(Player player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -55,7 +56,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player_Old player) { + public void touchedPlayer(Player player) { // if fireball touches player, it disappears super.touchedPlayer(player); this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Projectiles/LazerBeam.java b/src/Projectiles/LazerBeam.java index 9c8ed95..66e8861 100644 --- a/src/Projectiles/LazerBeam.java +++ b/src/Projectiles/LazerBeam.java @@ -4,10 +4,7 @@ import Engine.ImageLoader; import GameObject.Frame; import GameObject.SpriteSheet; -import Level.Enemy; -import Level.MapEntityStatus; -import Level.Player_Old; -import Level.Projectile; +import Level.*; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; @@ -34,7 +31,7 @@ public LazerBeam(Point location, float movementSpeed, int existenceTime) { } @Override - public void update(Player_Old player) { + public void update(Player player) { // if timer is up, set map entity status to REMOVED // the camera class will see this next frame and remove it permanently from the map if (existenceTimer.isTimeUp()) { @@ -55,7 +52,7 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } @Override - public void touchedPlayer(Player_Old player) { + public void touchedPlayer(Player player) { // if lazer beam touches player, it disappears super.touchedPlayer(player); this.mapEntityStatus = MapEntityStatus.REMOVED; diff --git a/src/Screens/LevelLoseScreen.java b/src/Screens/LevelLoseScreen.java index 91061ba..0913c54 100644 --- a/src/Screens/LevelLoseScreen.java +++ b/src/Screens/LevelLoseScreen.java @@ -2,6 +2,7 @@ import Engine.Drawable; import Engine.KeyboardAction; +import Level.Player; import Level.Player_Old; import Level.PlayerAttack; import Menu.Menu; @@ -26,7 +27,7 @@ public void update() { super.update(); if (KeyboardAction.GAME_RESPAWN.isDown()) { playLevelScreen.resetLevel(); - Player_Old.playerHealth = 3; + Player.PLAYER_HEALTH = 3; PlayerAttack.dogHealth = 8; } } diff --git a/src/Screens/PauseScreen.java b/src/Screens/PauseScreen.java index 76bc5e6..ff4af9f 100644 --- a/src/Screens/PauseScreen.java +++ b/src/Screens/PauseScreen.java @@ -3,6 +3,7 @@ import Engine.*; import Game.GameState; import Level.Map; +import Level.Player; import Level.Player_Old; import Menu.Menu; import Menu.MenuOption; @@ -24,7 +25,7 @@ public class PauseScreen extends Menu { private final PlayLevelScreen playLevelScreen; private boolean menuEscape; - public PauseScreen(Map map, Player_Old player, PlayLevelScreen playLevelScreen) { + public PauseScreen(Map map, Player player, PlayLevelScreen playLevelScreen) { this.playLevelScreen = playLevelScreen; menuEscape = false; setDrawables(new Drawable[]{ diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index b270fca..dfc022e 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -3,6 +3,7 @@ import Engine.*; import Game.GameState; import Level.Map; +import Level.Player; import Level.Player_Old; import Level.PlayerListener; import Maps.*; @@ -22,7 +23,7 @@ public class PlayLevelScreen extends Screen implements PlayerListener { private static final Color COLOR_GREY_BACKGROUND; private static Map loadedMap; private static Screen alternateScreen; - private static Player_Old player; + private static Player player; static { screenTimer = new Stopwatch(); From 416307864e7776eb4f5670a4a94cff7c0d86716c Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:04:32 -0500 Subject: [PATCH 019/164] The Kitty now Jumps --- src/Level/Player.java | 36 +++++++++++++++--------------------- src/Level/PlayerState.java | 7 ++++++- src/Players/Cat.java | 1 + 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 0d63cd6..583958a 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -90,20 +90,22 @@ private void updatePlaying() { applyGravity(); keepInBounds(); + playerState = PlayerState.STAND; + //Update Player Action and Direction - if(KeyboardAction.GAME_MOVE_LEFT.isDown()) { - facing = Facing.LEFT; - playerState = PlayerState.WALK; - } - if(KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - facing = Facing.RIGHT; + boolean move_leftDown = KeyboardAction.GAME_MOVE_LEFT.isDown(); + if(move_leftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown()) { + facing = move_leftDown ? Facing.LEFT : Facing.RIGHT; playerState = PlayerState.WALK; } + //Update Player X Direction + + //Update Jump if(KeyboardAction.GAME_JUMP.isDown()) { jump(); - } else if(velocityY > 0) { //if the player releases while velocity is still up, cut short + } else if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse velocityY = 0; } @@ -122,17 +124,13 @@ private void updatePlaying() { levelState = LevelState.DEAD; } - applyVelocity(); + super.moveYHandleCollision(velocityY); + super.moveXHandleCollision(velocityX); } private void attack() { int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); - int attackY = Math.round(getY()) + 10; - float movementSpeed = facing == Facing.RIGHT ? 1.5f : -1.5f; - - PlayerAttack projectile = new PlayerAttack(new Point(attackX, attackY), movementSpeed, 1000); - - map.addEnemy(projectile); + map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); attackDelay.setWaitTime(ATTACK_DELAY); } @@ -148,7 +146,7 @@ private void keepInBounds() { private void jump() { if(canJump() && keyLocker.isActionUnlocked(KeyboardAction.GAME_JUMP)) { - velocityY = jumpHeight; + velocityY = -jumpHeight; } } @@ -162,15 +160,9 @@ private void updateWin() { private void applyGravity() { //Legacy code multiplies velocity by 2 beforehand - velocityY *= 2; velocityY += gravity; } - private void applyVelocity() { - setX(x + velocityX); - setY(y + velocityY); - } - public void hurtPlayer(MapEntity mapEntity) { // Do we even still need the invincible value? if(!invincible) { @@ -206,6 +198,7 @@ public void addListener(PlayerListener listener) { playerListeners.add(listener); } + @Override public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { if(direction == Direction.DOWN) { inAir = !hasCollided; @@ -216,6 +209,7 @@ public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { } } + @Override public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { if(hasCollided) { handleCollision(MapTileCollisionHandler.lastCollidedTileX); diff --git a/src/Level/PlayerState.java b/src/Level/PlayerState.java index eaa629a..1453302 100644 --- a/src/Level/PlayerState.java +++ b/src/Level/PlayerState.java @@ -27,6 +27,11 @@ public String get(Facing facing) { } public enum Facing { - LEFT,RIGHT + LEFT(-1),RIGHT(1); + + public final int mod; + Facing(int i) { + this.mod = i; + } } } diff --git a/src/Players/Cat.java b/src/Players/Cat.java index 6f0ec53..c0c842a 100644 --- a/src/Players/Cat.java +++ b/src/Players/Cat.java @@ -24,6 +24,7 @@ public Cat(String name, float x, float y) { super(new SpriteSheet(ImageLoader.load(name), 24, 24), x, y, "STAND_RIGHT"); gravity = .5f; + jumpHeight = 14.5f; // terminalVelocityY = 6f; // jumpHeight = 14.5f; // jumpDegrade = .5f; From da32f554b1005f6336c7de61b92e5e390968bf48 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:17:21 -0500 Subject: [PATCH 020/164] Kitty Moves! --- src/Level/Player.java | 32 ++++++++++++++++++++++++-------- src/Players/Cat.java | 3 +++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 583958a..68bd07f 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -16,6 +16,7 @@ public abstract class Player extends GameObject { //Static Values private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; + private static final float MAX_FALL_VELOCITY = 6f; /* Values set by the cat class @@ -37,7 +38,7 @@ public abstract class Player extends GameObject { */ - protected float gravity, jumpHeight; + protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; public static int PLAYER_HEALTH = 3; @@ -52,7 +53,11 @@ public abstract class Player extends GameObject { protected boolean inAir, invincible; // Velocities - protected float velocityX, velocityY; + /** + * VelocityX is absolute, and direction is decided from the facing.mod + */ + private float velocityX, + velocityY; private final List playerListeners = new ArrayList<>(); @@ -97,9 +102,19 @@ private void updatePlaying() { if(move_leftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown()) { facing = move_leftDown ? Facing.LEFT : Facing.RIGHT; playerState = PlayerState.WALK; - } - //Update Player X Direction + if(KeyboardAction.GAME_SPRINT.isDown()) { + if(velocityX < walkSpeed) { + velocityX = walkSpeed; + } else if(velocityX < sprintSpeed) { + velocityX *= sprintAcceleration; + } + } else { + velocityX = walkSpeed; + } + } else { + velocityX = 0; + } //Update Jump @@ -116,7 +131,7 @@ private void updatePlaying() { //If the player is in the air, set its animation based on velocityY if(inAir) { - playerState = velocityY > 0 ? PlayerState.JUMP : PlayerState.FALL; + playerState = velocityY < 0 ? PlayerState.JUMP : PlayerState.FALL; } //Updates player to death if their health hits 0 @@ -125,7 +140,7 @@ private void updatePlaying() { } super.moveYHandleCollision(velocityY); - super.moveXHandleCollision(velocityX); + super.moveXHandleCollision(velocityX * facing.mod); } private void attack() { @@ -159,8 +174,9 @@ private void updateWin() { } private void applyGravity() { - //Legacy code multiplies velocity by 2 beforehand - velocityY += gravity; + if(velocityY < MAX_FALL_VELOCITY) { + velocityY += gravity; + } } public void hurtPlayer(MapEntity mapEntity) { diff --git a/src/Players/Cat.java b/src/Players/Cat.java index c0c842a..f3d28c8 100644 --- a/src/Players/Cat.java +++ b/src/Players/Cat.java @@ -25,6 +25,9 @@ public Cat(String name, float x, float y) { gravity = .5f; jumpHeight = 14.5f; + walkSpeed = 2.1f; + sprintSpeed = 3.3f; + sprintAcceleration = 1.05f; // terminalVelocityY = 6f; // jumpHeight = 14.5f; // jumpDegrade = .5f; From 024afd95ce0768ca9b651214b43bf60070d3e6a9 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:27:33 -0500 Subject: [PATCH 021/164] Cat Jumping is buggy, attempting to find fix --- src/Level/Player.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 68bd07f..de59633 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -86,7 +86,7 @@ public void update() { //Update Animation setCurrentAnimationName(playerState.get(facing)); - //List of keys that require to be tapped + //Lock Binds keyLocker.setAction(KeyboardAction.GAME_JUMP); } @@ -120,8 +120,10 @@ private void updatePlaying() { //Update Jump if(KeyboardAction.GAME_JUMP.isDown()) { jump(); - } else if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse - velocityY = 0; + } else { + if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse + velocityY = 0; + } } //Update Attack @@ -162,6 +164,7 @@ private void keepInBounds() { private void jump() { if(canJump() && keyLocker.isActionUnlocked(KeyboardAction.GAME_JUMP)) { velocityY = -jumpHeight; + keyLocker.setAction(KeyboardAction.GAME_JUMP); } } @@ -229,6 +232,9 @@ public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { if(hasCollided) { handleCollision(MapTileCollisionHandler.lastCollidedTileX); + if(playerState == PlayerState.WALK) { + playerState = PlayerState.STAND; + } } } From f6f89c8ef79957bb33c15a6f7f5002c57ae263ed Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:39:00 -0500 Subject: [PATCH 022/164] Implement Collision Types to Entities --- src/Level/Enemy.java | 2 ++ src/Level/Player.java | 63 +++++++++------------------------------ src/Level/Projectile.java | 2 ++ src/Projectiles/Bone.java | 2 ++ 4 files changed, 20 insertions(+), 49 deletions(-) diff --git a/src/Level/Enemy.java b/src/Level/Enemy.java index 4ddf6e9..c89baa4 100644 --- a/src/Level/Enemy.java +++ b/src/Level/Enemy.java @@ -1,5 +1,6 @@ package Level; +import Engine.CollisionType; import GameObject.Frame; import GameObject.ImageEffect; import GameObject.Rectangle; @@ -42,6 +43,7 @@ public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect ima @Override public void initialize() { super.initialize(); + collisionType = CollisionType.INSTANT_DEATH; } public void update(Player player) { diff --git a/src/Level/Player.java b/src/Level/Player.java index de59633..760a440 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -18,26 +18,6 @@ public abstract class Player extends GameObject { private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; private static final float MAX_FALL_VELOCITY = 6f; -/* -Values set by the cat class - gravity = .5f; -> amount that the velocity moves in the y direction - terminalVelocityY = 6f; - jumpHeight = 14.5f; - jumpDegrade = .5f; - walkSpeed = 2.1f; - minWalkSpeed = 2.1f; - maxWalkSpeed = 3.3f; - walkAcceleration = 1.05f; - momentumYIncrease = .5f; - */ - - /* - Ideas for how to manage movement with minimal modifications: - Point velocity -> current velocity, modified by gravity, etc. - float gravity -> gravity force - - */ - protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; public static int PLAYER_HEALTH = 3; @@ -119,11 +99,12 @@ private void updatePlaying() { //Update Jump if(KeyboardAction.GAME_JUMP.isDown()) { - jump(); - } else { - if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse - velocityY = 0; + if(jumpDelay.isTimeUp() && !isInAir()) { + velocityY = -jumpHeight; + keyLocker.setAction(KeyboardAction.GAME_JUMP); } + } else if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse + velocityY = 0; } //Update Attack @@ -141,6 +122,7 @@ private void updatePlaying() { levelState = LevelState.DEAD; } + inAir = true; super.moveYHandleCollision(velocityY); super.moveXHandleCollision(velocityX * facing.mod); } @@ -161,13 +143,6 @@ private void keepInBounds() { } } - private void jump() { - if(canJump() && keyLocker.isActionUnlocked(KeyboardAction.GAME_JUMP)) { - velocityY = -jumpHeight; - keyLocker.setAction(KeyboardAction.GAME_JUMP); - } - } - private void updateDead() { playerState = PlayerState.DEATH; } @@ -183,24 +158,14 @@ private void applyGravity() { } public void hurtPlayer(MapEntity mapEntity) { -// Do we even still need the invincible value? - if(!invincible) { - switch(mapEntity.getCollisionType()) { - case DAMAGE -> PLAYER_HEALTH -= 1; - case INSTANT_DEATH -> PLAYER_HEALTH = 0; - case PREVENT_JUMP -> preventJump(5000); - case DEFAULT -> {} - } + switch(mapEntity.getCollisionType()) { + case DAMAGE -> PLAYER_HEALTH -= 1; + case INSTANT_DEATH -> PLAYER_HEALTH = 0; + case PREVENT_JUMP -> preventJump(5000); + case DEFAULT -> {} } } - /** - * @return {@code True} when the player is allowed to jump, and is on the ground - */ - public boolean canJump() { - return jumpDelay.isTimeUp() && !isInAir(); - } - public void preventJump(int time) { jumpDelay.setWaitTime(JUMP_DELAY); } @@ -219,10 +184,10 @@ public void addListener(PlayerListener listener) { @Override public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { - if(direction == Direction.DOWN) { - inAir = !hasCollided; - } if(hasCollided) { + if(direction == Direction.DOWN) { + inAir = false; + } velocityY = 0; handleCollision(MapTileCollisionHandler.lastCollidedTileY); } diff --git a/src/Level/Projectile.java b/src/Level/Projectile.java index d35ea92..00c62c9 100644 --- a/src/Level/Projectile.java +++ b/src/Level/Projectile.java @@ -1,5 +1,6 @@ package Level; +import Engine.CollisionType; import GameObject.Frame; import GameObject.ImageEffect; import GameObject.Rectangle; @@ -41,6 +42,7 @@ public Projectile(BufferedImage image, float x, float y, float scale, ImageEffec @Override public void initialize() { super.initialize(); + collisionType = CollisionType.DAMAGE; } public void update(Player player) { diff --git a/src/Projectiles/Bone.java b/src/Projectiles/Bone.java index 9677033..0dbc507 100644 --- a/src/Projectiles/Bone.java +++ b/src/Projectiles/Bone.java @@ -1,6 +1,7 @@ package Projectiles; import Builders.FrameBuilder; +import Engine.CollisionType; import Engine.ImageLoader; import GameObject.Frame; import GameObject.ImageEffect; @@ -29,6 +30,7 @@ public Bone(Point location, float movementSpeed, int existenceTime) { isRespawnable = false; initialize(); + collisionType = CollisionType.PREVENT_JUMP; } @Override From d862542bbf80494600e7d3e774c47a1966ac5369 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:42:47 -0500 Subject: [PATCH 023/164] Added Death Animation (Much faster now too) --- src/Level/Player.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Level/Player.java b/src/Level/Player.java index 760a440..d46e0f9 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -145,6 +145,19 @@ private void keepInBounds() { private void updateDead() { playerState = PlayerState.DEATH; + if(currentFrameIndex == getCurrentAnimation().length - 1) { + if(map.getCamera().containsDraw(this)) { + velocityY += gravity; + } else { + for(PlayerListener listener :playerListeners) { + listener.onDeath(); + } + } + } else { + velocityY = 0; + } + + setY(y + velocityY); } private void updateWin() { From 5df6be7db9668b892326f045e10ecf012309c671 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:43:42 -0500 Subject: [PATCH 024/164] Death Animation now maintains previous velocity --- src/Level/Player.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index d46e0f9..bf021eb 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -153,10 +153,7 @@ private void updateDead() { listener.onDeath(); } } - } else { - velocityY = 0; } - setY(y + velocityY); } From 317750834b44a243a3d80c72869bcfe3fce23866 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 21:50:34 -0500 Subject: [PATCH 025/164] Cat can now complete levels --- src/Level/Player.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index bf021eb..547f6a5 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -99,7 +99,7 @@ private void updatePlaying() { //Update Jump if(KeyboardAction.GAME_JUMP.isDown()) { - if(jumpDelay.isTimeUp() && !isInAir()) { + if(jumpDelay.isTimeUp() && !inAir) { velocityY = -jumpHeight; keyLocker.setAction(KeyboardAction.GAME_JUMP); } @@ -158,7 +158,19 @@ private void updateDead() { } private void updateWin() { - + if(map.getCamera().containsDraw(this)) { + facing = Facing.RIGHT; + if(inAir) { + playerState = PlayerState.FALL; + applyGravity(); + moveYHandleCollision(velocityY); + } else { + playerState = PlayerState.WALK; + moveXHandleCollision(walkSpeed); + } + } else for(PlayerListener listener : playerListeners) { + listener.onLevelCompleted(); + } } private void applyGravity() { From d96365cff40b8afdb0bdd13fec0041a0e2c20ec2 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:02:00 -0500 Subject: [PATCH 026/164] Added parameter for applying gravity with max velocity --- src/Level/Player.java | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 547f6a5..b12dc88 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -14,25 +14,22 @@ public abstract class Player extends GameObject { - //Static Values private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; - private static final float MAX_FALL_VELOCITY = 6f; + private static final float MAX_FALL_VELOCITY = 6f, MAX_DEATH_FALL_VELOCITY = 10f , DEATH_Y_VELOCITY = -2.5f; protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; public static int PLAYER_HEALTH = 3; protected Stopwatch attackDelay, jumpDelay; - private KeyLocker keyLocker = new KeyLocker(); protected PlayerState playerState; protected Facing facing; protected LevelState levelState; - protected boolean inAir, invincible; + protected boolean inAir; - // Velocities /** * VelocityX is absolute, and direction is decided from the facing.mod */ @@ -65,14 +62,11 @@ public void update() { //Update Animation setCurrentAnimationName(playerState.get(facing)); - - //Lock Binds - keyLocker.setAction(KeyboardAction.GAME_JUMP); } private void updatePlaying() { - applyGravity(); + applyGravity(MAX_FALL_VELOCITY); keepInBounds(); playerState = PlayerState.STAND; @@ -96,12 +90,10 @@ private void updatePlaying() { velocityX = 0; } - //Update Jump if(KeyboardAction.GAME_JUMP.isDown()) { if(jumpDelay.isTimeUp() && !inAir) { velocityY = -jumpHeight; - keyLocker.setAction(KeyboardAction.GAME_JUMP); } } else if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse velocityY = 0; @@ -147,12 +139,12 @@ private void updateDead() { playerState = PlayerState.DEATH; if(currentFrameIndex == getCurrentAnimation().length - 1) { if(map.getCamera().containsDraw(this)) { - velocityY += gravity; - } else { - for(PlayerListener listener :playerListeners) { - listener.onDeath(); - } + applyGravity(MAX_DEATH_FALL_VELOCITY); + } else for(PlayerListener listener :playerListeners) { + listener.onDeath(); } + } else { + velocityY = DEATH_Y_VELOCITY; } setY(y + velocityY); } @@ -162,7 +154,7 @@ private void updateWin() { facing = Facing.RIGHT; if(inAir) { playerState = PlayerState.FALL; - applyGravity(); + applyGravity(MAX_FALL_VELOCITY); moveYHandleCollision(velocityY); } else { playerState = PlayerState.WALK; @@ -173,8 +165,8 @@ private void updateWin() { } } - private void applyGravity() { - if(velocityY < MAX_FALL_VELOCITY) { + private void applyGravity(float maxFallVelocity) { + if(velocityY < maxFallVelocity) { velocityY += gravity; } } From 266e6e5473d843447fb01de619326aa42ddeba55 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:14:02 -0500 Subject: [PATCH 027/164] Migrated Boss-Death detection to BossBattle.java --- src/Level/Player.java | 4 ++++ src/Maps/BossBattle.java | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Level/Player.java b/src/Level/Player.java index b12dc88..882dac6 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -196,6 +196,10 @@ public void addListener(PlayerListener listener) { playerListeners.add(listener); } + public void setJumpHeight(int height) { + this.jumpHeight = jumpHeight; + } + @Override public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { if(hasCollided) { diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index 1997d4c..a959170 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -18,6 +18,8 @@ // Represents a test map to be used in a level public class BossBattle extends Map { + private boolean bossKilled = false; + public BossBattle() { super("BossBattle.txt", new CommonTileset(), new Point(1, 17)); } @@ -55,4 +57,13 @@ public ArrayList loadEnhancedMapTiles() { return enhancedMapTiles; } + @Override + public void update(Player player) { + super.update(player); + if(!bossKilled && PlayerAttack.dogHealth <= 0) { + bossKilled = true; + player.setJumpHeight(16); + } + } + } From 0076c3d99db6c82a8375795471e81b07b75db7dd Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:17:50 -0500 Subject: [PATCH 028/164] Add tests to Test Case SCP-57 Added testing of ability to complete all levels with updated physics --- Team A2/Test Cases/Test Case SCP-57.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index bcb63b1..d10970e 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -13,6 +13,7 @@ Functionality of `Player.java` tested: - Collision with enemies - Shooting, including animations while standing still and moving - Collision with map boundaries and map walls + - Ability to complete all levels with physics ### Procedure @@ -42,6 +43,9 @@ Functionality of `Player.java` tested: |21|Navigate and run into a projectile from an enemy|The player's health is now 2 (reduced by 1)|| |22|Navigate and attempt to run off the right-most edge of the map (*without hitting the gold level-complete box*)|The player is stopped and cannot run off of the map|| |23|Hit the complete-level gold box|The level is completed and the player walks off to the right of the screen|| +|24|Hit Escape, go back to main menu|The main menu is displayed|| +|25|Hit "Play Game"|The first level is loaded|| +|26|Play all levels of the game|Each level is completable|| From cedef5b08ed08077975dd314d509652031f34876 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:22:34 -0500 Subject: [PATCH 029/164] Smoothed out player velocity in death animations --- src/Level/Player.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 882dac6..30e8f6f 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -137,7 +137,7 @@ private void keepInBounds() { private void updateDead() { playerState = PlayerState.DEATH; - if(currentFrameIndex == getCurrentAnimation().length - 1) { + if(currentFrameIndex > 0) { if(map.getCamera().containsDraw(this)) { applyGravity(MAX_DEATH_FALL_VELOCITY); } else for(PlayerListener listener :playerListeners) { From e8b031e2f5a5f755a69a076adfa7595de4f93400 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:26:11 -0500 Subject: [PATCH 030/164] Code Cleanup / Bug Fixing --- src/Level/Player.java | 163 +++++++++++++++++++--------------------- src/Players/Cat.java | 169 +++++++++++++----------------------------- 2 files changed, 130 insertions(+), 202 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 30e8f6f..8b96902 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -1,6 +1,5 @@ package Level; -import Engine.KeyLocker; import Engine.KeyboardAction; import GameObject.GameObject; import GameObject.SpriteSheet; @@ -15,31 +14,22 @@ public abstract class Player extends GameObject { private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; - private static final float MAX_FALL_VELOCITY = 6f, MAX_DEATH_FALL_VELOCITY = 10f , DEATH_Y_VELOCITY = -2.5f; - - protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; - + private static final float MAX_FALL_VELOCITY = 6f, MAX_DEATH_FALL_VELOCITY = 10f, DEATH_Y_VELOCITY = -2.5f; public static int PLAYER_HEALTH = 3; - + private final List playerListeners = new ArrayList<>(); + protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; protected Stopwatch attackDelay, jumpDelay; - - protected PlayerState playerState; protected Facing facing; protected LevelState levelState; - protected boolean inAir; - /** * VelocityX is absolute, and direction is decided from the facing.mod */ - private float velocityX, - velocityY; - - private final List playerListeners = new ArrayList<>(); + private float velocityX, velocityY; - public Player(SpriteSheet spriteSheet, float x,float y, String startingAnimationName) { - super(spriteSheet,x,y,startingAnimationName); + public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { + super(spriteSheet, x, y, startingAnimationName); playerState = PlayerState.STAND; levelState = LevelState.PLAYING; @@ -49,7 +39,6 @@ public Player(SpriteSheet spriteSheet, float x,float y, String startingAnimation jumpDelay = new Stopwatch(); } - public void update() { //Is the super.update() ordering specific? Unsure? super.update(); @@ -73,14 +62,14 @@ private void updatePlaying() { //Update Player Action and Direction boolean move_leftDown = KeyboardAction.GAME_MOVE_LEFT.isDown(); - if(move_leftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown()) { + if (move_leftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown()) { facing = move_leftDown ? Facing.LEFT : Facing.RIGHT; playerState = PlayerState.WALK; - if(KeyboardAction.GAME_SPRINT.isDown()) { - if(velocityX < walkSpeed) { + if (KeyboardAction.GAME_SPRINT.isDown()) { + if (velocityX < walkSpeed) { velocityX = walkSpeed; - } else if(velocityX < sprintSpeed) { + } else if (velocityX < sprintSpeed) { velocityX *= sprintAcceleration; } } else { @@ -91,26 +80,26 @@ private void updatePlaying() { } //Update Jump - if(KeyboardAction.GAME_JUMP.isDown()) { - if(jumpDelay.isTimeUp() && !inAir) { + if (KeyboardAction.GAME_JUMP.isDown()) { + if (jumpDelay.isTimeUp() && !inAir) { velocityY = -jumpHeight; } - } else if(velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse + } else if (velocityY < 0) { //if the player releases while velocity is still up, cut short, remember that velocityY is inverse velocityY = 0; } //Update Attack - if(KeyboardAction.GAME_ATTACK.isDown() && attackDelay.isTimeUp()) { + if (KeyboardAction.GAME_ATTACK.isDown() && attackDelay.isTimeUp()) { attack(); } //If the player is in the air, set its animation based on velocityY - if(inAir) { + if (inAir) { playerState = velocityY < 0 ? PlayerState.JUMP : PlayerState.FALL; } //Updates player to death if their health hits 0 - if(PLAYER_HEALTH <= 0) { + if (PLAYER_HEALTH <= 0) { levelState = LevelState.DEAD; } @@ -119,29 +108,15 @@ private void updatePlaying() { super.moveXHandleCollision(velocityX * facing.mod); } - private void attack() { - int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); - map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); - attackDelay.setWaitTime(ATTACK_DELAY); - } - - private void keepInBounds() { - if(x < 0) { - velocityX = 0; - setX(0); - } else if(levelState != LevelState.WIN && x > map.getRightBound()) { - velocityX = 0; - setX(map.getRightBound()); - } - } - private void updateDead() { playerState = PlayerState.DEATH; - if(currentFrameIndex > 0) { - if(map.getCamera().containsDraw(this)) { + if (currentFrameIndex > 0) { + if (map.getCamera().containsDraw(this)) { applyGravity(MAX_DEATH_FALL_VELOCITY); - } else for(PlayerListener listener :playerListeners) { - listener.onDeath(); + } else { + for (PlayerListener listener : playerListeners) { + listener.onDeath(); + } } } else { velocityY = DEATH_Y_VELOCITY; @@ -150,9 +125,9 @@ private void updateDead() { } private void updateWin() { - if(map.getCamera().containsDraw(this)) { + if (map.getCamera().containsDraw(this)) { facing = Facing.RIGHT; - if(inAir) { + if (inAir) { playerState = PlayerState.FALL; applyGravity(MAX_FALL_VELOCITY); moveYHandleCollision(velocityY); @@ -160,27 +135,73 @@ private void updateWin() { playerState = PlayerState.WALK; moveXHandleCollision(walkSpeed); } - } else for(PlayerListener listener : playerListeners) { - listener.onLevelCompleted(); + } else { + for (PlayerListener listener : playerListeners) { + listener.onLevelCompleted(); + } } } private void applyGravity(float maxFallVelocity) { - if(velocityY < maxFallVelocity) { + if (velocityY < maxFallVelocity) { velocityY += gravity; } } + private void keepInBounds() { + if (x < 0) { + velocityX = 0; + setX(0); + } else if (levelState != LevelState.WIN && x > map.getRightBound()) { + velocityX = 0; + setX(map.getRightBound()); + } + } + + private void attack() { + int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); + map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); + attackDelay.setWaitTime(ATTACK_DELAY); + } + + @Override + public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { + if (hasCollided) { + handleCollision(MapTileCollisionHandler.lastCollidedTileX); + if (playerState == PlayerState.WALK) { + playerState = PlayerState.STAND; + } + } + } + + @Override + public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { + if (hasCollided) { + if (direction == Direction.DOWN) { + inAir = false; + } + velocityY = 0; + handleCollision(MapTileCollisionHandler.lastCollidedTileY); + } + } + + private void handleCollision(MapTile tile) { + if (tile != null && tile.getTileType() == TileType.LETHAL) { + levelState = LevelState.DEAD; + } + } + public void hurtPlayer(MapEntity mapEntity) { - switch(mapEntity.getCollisionType()) { + switch (mapEntity.getCollisionType()) { case DAMAGE -> PLAYER_HEALTH -= 1; case INSTANT_DEATH -> PLAYER_HEALTH = 0; - case PREVENT_JUMP -> preventJump(5000); - case DEFAULT -> {} + case PREVENT_JUMP -> preventJump(); + case DEFAULT -> { + } } } - public void preventJump(int time) { + public void preventJump() { jumpDelay.setWaitTime(JUMP_DELAY); } @@ -197,34 +218,6 @@ public void addListener(PlayerListener listener) { } public void setJumpHeight(int height) { - this.jumpHeight = jumpHeight; + this.jumpHeight = height; } - - @Override - public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { - if(hasCollided) { - if(direction == Direction.DOWN) { - inAir = false; - } - velocityY = 0; - handleCollision(MapTileCollisionHandler.lastCollidedTileY); - } - } - - @Override - public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { - if(hasCollided) { - handleCollision(MapTileCollisionHandler.lastCollidedTileX); - if(playerState == PlayerState.WALK) { - playerState = PlayerState.STAND; - } - } - } - - private void handleCollision(MapTile tile) { - if(tile != null && tile.getTileType() == TileType.LETHAL) { - levelState = LevelState.DEAD; - } - } - } diff --git a/src/Players/Cat.java b/src/Players/Cat.java index f3d28c8..a226e67 100644 --- a/src/Players/Cat.java +++ b/src/Players/Cat.java @@ -7,7 +7,6 @@ import GameObject.ImageEffect; import GameObject.SpriteSheet; import Level.Player; -import Level.Player_Old; import Utils.Point; import java.util.HashMap; @@ -17,25 +16,25 @@ public class Cat extends Player { public Cat(String name, Point point) { - this(name,point.x,point.y); + this(name, point.x, point.y); } - public Cat(String name, float x, float y) { + public Cat(String name, float x, float y) { super(new SpriteSheet(ImageLoader.load(name), 24, 24), x, y, "STAND_RIGHT"); - + gravity = .5f; jumpHeight = 14.5f; walkSpeed = 2.1f; sprintSpeed = 3.3f; sprintAcceleration = 1.05f; -// terminalVelocityY = 6f; -// jumpHeight = 14.5f; -// jumpDegrade = .5f; -// walkSpeed = 2.1f; -// minWalkSpeed = 2.1f; -// maxWalkSpeed = 3.3f; -// walkAcceleration = 1.05f; -// momentumYIncrease = .5f; + // terminalVelocityY = 6f; + // jumpHeight = 14.5f; + // jumpDegrade = .5f; + // walkSpeed = 2.1f; + // minWalkSpeed = 2.1f; + // maxWalkSpeed = 3.3f; + // walkAcceleration = 1.05f; + // momentumYIncrease = .5f; } public void update() { @@ -50,133 +49,69 @@ public void draw(GraphicsHandler graphicsHandler) { @Override public HashMap getAnimations(SpriteSheet spriteSheet) { return new HashMap() {{ - put("STAND_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(0, 0), 0) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() + put("STAND_RIGHT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(0, 0), 0).withScale(3).withBounds(8, 9, 8, 9).build() }); - put("STAND_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(0, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() + put("STAND_LEFT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(0, 0), 0).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build() }); - put("WALK_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(1, 0), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 1), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 2), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 3), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() + put("WALK_RIGHT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(1, 0), 200).withScale(3).withBounds(8, 9, 8, 9).build(), new FrameBuilder( + spriteSheet.getSprite(1, 1), 200).withScale(3).withBounds(8, 9, 8, 9).build(), new FrameBuilder(spriteSheet.getSprite(1, 2), 200) + .withScale(3).withBounds(8, 9, 8, 9).build(), new FrameBuilder(spriteSheet.getSprite(1, 3), 200).withScale(3).withBounds( + 8, 9, 8, 9).build() }); - put("WALK_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(1, 0), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 1), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 2), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 3), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() + put("WALK_LEFT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(1, 0), 200).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build(), + new FrameBuilder(spriteSheet.getSprite(1, 1), 200).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build(), + new FrameBuilder(spriteSheet.getSprite(1, 2), 200).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build(), + new FrameBuilder(spriteSheet.getSprite(1, 3), 200).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build() }); - put("JUMP_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(2, 0), 0) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() + put("JUMP_RIGHT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(2, 0), 0).withScale(3).withBounds(8, 9, 8, 9).build() }); - put("JUMP_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(2, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() + put("JUMP_LEFT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(2, 0), 0).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build() }); - put("FALL_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(3, 0), 0) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() + put("FALL_RIGHT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(3, 0), 0).withScale(3).withBounds(8, 9, 8, 9).build() }); - put("FALL_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(3, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() + put("FALL_LEFT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(3, 0), 0).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 9, 8, 9).build() }); - put("CROUCH_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(4, 0), 0) - .withScale(3) - .withBounds(8, 12, 8, 6) - .build() + put("CROUCH_RIGHT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(4, 0), 0).withScale(3).withBounds(8, 12, 8, 6).build() }); - put("CROUCH_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(4, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 12, 8, 6) - .build() + put("CROUCH_LEFT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(4, 0), 0).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).withBounds( + 8, 12, 8, 6).build() }); - put("DEATH_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(5, 0), 100) - .withScale(3) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 1), 100) - .withScale(3) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 2), -1) - .withScale(3) - .build() + put("DEATH_RIGHT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(5, 0), 100).withScale(3).build(), new FrameBuilder( + spriteSheet.getSprite(5, 1), 100).withScale(3).build(), new FrameBuilder(spriteSheet.getSprite(5, 2), -1).withScale(3).build() }); - put("DEATH_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(5, 0), 100) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 1), 100) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 2), -1) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .build() + put("DEATH_LEFT", new Frame[]{ + new FrameBuilder(spriteSheet.getSprite(5, 0), 100).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).build(), + new FrameBuilder(spriteSheet.getSprite(5, 1), 100).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).build(), + new FrameBuilder(spriteSheet.getSprite(5, 2), -1).withScale(3).withImageEffect(ImageEffect.FLIP_HORIZONTAL).build() }); }}; } From 78d1c6ce1d26bc4c2668fb299760478f1d4dcdfe Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:28:53 -0500 Subject: [PATCH 031/164] Optimizing Call-Stack --- src/Level/Player.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 8b96902..cbc66e7 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -23,9 +23,7 @@ public abstract class Player extends GameObject { protected Facing facing; protected LevelState levelState; protected boolean inAir; - /** - * VelocityX is absolute, and direction is decided from the facing.mod - */ + //VelocityX is absolute, and direction is derived from the facing.mod private float velocityX, velocityY; public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { @@ -40,16 +38,13 @@ public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimatio } public void update() { - //Is the super.update() ordering specific? Unsure? super.update(); - switch (levelState) { case PLAYING -> updatePlaying(); case DEAD -> updateDead(); case WIN -> updateWin(); } - //Update Animation setCurrentAnimationName(playerState.get(facing)); } @@ -90,7 +85,9 @@ private void updatePlaying() { //Update Attack if (KeyboardAction.GAME_ATTACK.isDown() && attackDelay.isTimeUp()) { - attack(); + int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); + map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); + attackDelay.setWaitTime(ATTACK_DELAY); } //If the player is in the air, set its animation based on velocityY @@ -103,7 +100,7 @@ private void updatePlaying() { levelState = LevelState.DEAD; } - inAir = true; + inAir = true; //air is decided in the next line super.moveYHandleCollision(velocityY); super.moveXHandleCollision(velocityX * facing.mod); } @@ -158,12 +155,6 @@ private void keepInBounds() { } } - private void attack() { - int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); - map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); - attackDelay.setWaitTime(ATTACK_DELAY); - } - @Override public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { if (hasCollided) { From 1d44f46cd33ed6643a915c4821a62c8891e7fa6f Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:33:40 -0500 Subject: [PATCH 032/164] Removed Deprecated Classes --- src/Enemies/BugEnemy.java | 14 +- src/Enemies/CyborgEnemy.java | 6 +- src/Enemies/DinosaurEnemy.java | 6 +- src/Enemies/Dog.java | 7 +- src/Engine/GamePanel.java | 1 - src/EnhancedMapTiles/EndLevelBox.java | 1 - .../HorizontalMovingPlatform.java | 2 - src/Level/LevelState.java | 11 - src/Level/PlayerState.java | 4 +- src/Level/Player_Old.java | 533 ------------------ src/NPCs/Walrus.java | 1 - src/Players/Avatar.java | 1 - src/Players/Cat_Old.java | 179 ------ src/Projectiles/Fireball.java | 1 - src/Screens/LevelLoseScreen.java | 1 - src/Screens/PauseScreen.java | 1 - src/Screens/PlayLevelScreen.java | 1 - src/Utils/AirGroundState.java | 8 - 18 files changed, 11 insertions(+), 767 deletions(-) delete mode 100644 src/Level/Player_Old.java delete mode 100644 src/Players/Cat_Old.java delete mode 100644 src/Utils/AirGroundState.java diff --git a/src/Enemies/BugEnemy.java b/src/Enemies/BugEnemy.java index a7752cf..b3296a8 100644 --- a/src/Enemies/BugEnemy.java +++ b/src/Enemies/BugEnemy.java @@ -7,8 +7,6 @@ import GameObject.SpriteSheet; import Level.Enemy; import Level.Player; -import Level.Player_Old; -import Utils.AirGroundState; import Utils.Direction; import Utils.Point; @@ -23,7 +21,7 @@ public class BugEnemy extends Enemy { private float movementSpeed = .5f; private Direction startFacingDirection; private Direction facingDirection; - private AirGroundState airGroundState; + private boolean isInAir; public BugEnemy(Point location, Direction facingDirection) { super(location.x, location.y, new SpriteSheet(ImageLoader.load("BugEnemy.png"), 24, 15), "WALK_LEFT"); @@ -40,7 +38,7 @@ public void initialize() { } else if (facingDirection == Direction.LEFT) { currentAnimationName = "WALK_LEFT"; } - airGroundState = AirGroundState.GROUND; + isInAir = false; } @Override @@ -52,7 +50,7 @@ public void update(Player player) { moveAmountY += gravity; // if on ground, walk forward based on facing direction - if (airGroundState == AirGroundState.GROUND) { + if (!isInAir) { if (facingDirection == Direction.RIGHT) { moveAmountX += movementSpeed; } else { @@ -87,11 +85,7 @@ public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { // if bug is colliding with the ground, change its air ground state to GROUND // if it is not colliding with the ground, it means that it's currently in the air, so its air ground state is changed to AIR if (direction == Direction.DOWN) { - if (hasCollided) { - airGroundState = AirGroundState.GROUND; - } else { - airGroundState = AirGroundState.AIR; - } + isInAir = !hasCollided; } } diff --git a/src/Enemies/CyborgEnemy.java b/src/Enemies/CyborgEnemy.java index d7d6843..462e4db 100644 --- a/src/Enemies/CyborgEnemy.java +++ b/src/Enemies/CyborgEnemy.java @@ -7,9 +7,7 @@ import GameObject.SpriteSheet; import Level.Enemy; import Level.Player; -import Level.Player_Old; import Projectiles.LazerBeam; -import Utils.AirGroundState; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; @@ -32,7 +30,7 @@ public class CyborgEnemy extends Enemy { protected float movementSpeed = 0.5f; private Direction startFacingDirection; protected Direction facingDirection; - protected AirGroundState airGroundState; + protected boolean isInAir; // timer is used to determine when a lazer is to be shot out protected Stopwatch shootTimer = new Stopwatch(); @@ -62,7 +60,7 @@ public void initialize() { } else if (facingDirection == Direction.LEFT) { currentAnimationName = "WALK_LEFT"; } - airGroundState = AirGroundState.GROUND; + isInAir = false; // every 2 seconds, the lazer will be shot out shootTimer.setWaitTime(2000); diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index 00a340c..ce79082 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -7,9 +7,7 @@ import GameObject.SpriteSheet; import Level.Enemy; import Level.Player; -import Level.Player_Old; import Projectiles.Fireball; -import Utils.AirGroundState; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; @@ -29,7 +27,7 @@ public class DinosaurEnemy extends Enemy { protected float movementSpeed = 1f; private Direction startFacingDirection; protected Direction facingDirection; - protected AirGroundState airGroundState; + protected boolean isInAir; // timer is used to determine when a fireball is to be shot out protected Stopwatch shootTimer = new Stopwatch(); @@ -57,7 +55,7 @@ public void initialize() { } else if (facingDirection == Direction.LEFT) { currentAnimationName = "WALK_LEFT"; } - airGroundState = AirGroundState.GROUND; + isInAir = false; // every 2 seconds, the fireball will be shot out shootTimer.setWaitTime(2000); diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index 26f2f98..ff945be 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -6,9 +6,7 @@ import GameObject.SpriteSheet; import Level.Enemy; import Level.Player; -import Level.Player_Old; import Projectiles.Bone; -import Utils.AirGroundState; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; @@ -28,7 +26,7 @@ public class Dog extends Enemy { protected float movementSpeed = 1f; private Direction startFacingDirection; protected Direction facingDirection; - protected AirGroundState airGroundState; + protected boolean isInAir; // timer is used to determine when a bone is to be shot out protected Stopwatch shootTimer = new Stopwatch(); @@ -56,8 +54,7 @@ public void initialize() { } else if (facingDirection == Direction.LEFT) { currentAnimationName = "WALK_LEFT"; } - airGroundState = AirGroundState.GROUND; - + isInAir = false; // every 2 seconds, the bone will be shot out shootTimer.setWaitTime(2000); } diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index fadda14..bc6d7fd 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -2,7 +2,6 @@ import GameObject.Rectangle; import Level.Player; -import Level.Player_Old; import Utils.Colors; import Utils.Stopwatch; diff --git a/src/EnhancedMapTiles/EndLevelBox.java b/src/EnhancedMapTiles/EndLevelBox.java index a05c8cd..a6b031d 100644 --- a/src/EnhancedMapTiles/EndLevelBox.java +++ b/src/EnhancedMapTiles/EndLevelBox.java @@ -6,7 +6,6 @@ import GameObject.SpriteSheet; import Level.EnhancedMapTile; import Level.Player; -import Level.Player_Old; import Level.TileType; import Utils.Point; diff --git a/src/EnhancedMapTiles/HorizontalMovingPlatform.java b/src/EnhancedMapTiles/HorizontalMovingPlatform.java index 15d7689..b290500 100644 --- a/src/EnhancedMapTiles/HorizontalMovingPlatform.java +++ b/src/EnhancedMapTiles/HorizontalMovingPlatform.java @@ -5,9 +5,7 @@ import GameObject.Rectangle; import Level.EnhancedMapTile; import Level.Player; -import Level.Player_Old; import Level.TileType; -import Utils.AirGroundState; import Utils.Direction; import Utils.Point; diff --git a/src/Level/LevelState.java b/src/Level/LevelState.java index 9f36cae..775a9ce 100644 --- a/src/Level/LevelState.java +++ b/src/Level/LevelState.java @@ -2,16 +2,5 @@ // This enum represents the potential states a level can be public enum LevelState { - @Deprecated - RUNNING, - @Deprecated - LEVEL_COMPLETED, - @Deprecated - PLAYER_DEAD, - @Deprecated - LEVEL_WIN_MESSAGE, - @Deprecated - LEVEL_LOSE_MESSAGE, -// New values PLAYING,DEAD,WIN } diff --git a/src/Level/PlayerState.java b/src/Level/PlayerState.java index 1453302..479fdfd 100644 --- a/src/Level/PlayerState.java +++ b/src/Level/PlayerState.java @@ -3,9 +3,7 @@ // This enum represents different states the Player can be in public enum PlayerState { STAND, WALK, JUMP, CROUCH, FALL, - DEATH, - @Deprecated - ATTACKING; + DEATH; private String left,right; diff --git a/src/Level/Player_Old.java b/src/Level/Player_Old.java deleted file mode 100644 index 10c347c..0000000 --- a/src/Level/Player_Old.java +++ /dev/null @@ -1,533 +0,0 @@ -package Level; - -import Engine.KeyLocker; -import Engine.KeyboardAction; -import GameObject.GameObject; -import GameObject.SpriteSheet; -import Projectiles.Bone; -import Utils.AirGroundState; -import Utils.Direction; -import Utils.Point; -import Utils.Stopwatch; - -import java.util.ArrayList; - -@Deprecated -public abstract class Player_Old extends GameObject { - // values that affect player movement - // these should be set in a subclass - protected float walkSpeed = 0; - protected float maxWalkSpeed = 0; - protected float minWalkSpeed = 0; - protected float walkAcceleration = 0; - protected float gravity = 0; - protected float jumpHeight = 0; - protected float jumpDegrade = 0; - protected float terminalVelocityX = 0; - - // Number of times a player can be hit by a projectile before dying - public static int playerHealth = 3; - - protected float momentumXIncrease = 0; - - // values used to handle player movement - protected float jumpForce = 0; - protected float momentumX = 0; - protected float terminalVelocityY = 0; - protected float momentumYIncrease = 0; - - - // values used to handle player movement - protected float momentumY = 0; - protected float moveAmountX, moveAmountY; - - protected Stopwatch attackCooldown = new Stopwatch(); - - // Variables used to apply effect to player from the Boss' bone - protected Stopwatch boneEffect = new Stopwatch(); - protected boolean canJump = true; - - // values used to keep track of player's current state - protected PlayerState playerState; - protected Direction facingDirection; - protected AirGroundState airGroundState; - protected AirGroundState previousAirGroundState; - protected LevelState levelState; - - // classes that listen to player events can be added to this list - protected ArrayList listeners = new ArrayList<>(); - - // define keys - protected KeyLocker keyLocker = new KeyLocker(); - - // if true, player cannot be hurt by enemies (good for testing) - protected boolean isInvincible = false; - // added 11/19 - protected PlayerAttack currentProjectile; - - public Player_Old(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { - super(spriteSheet, x, y, startingAnimationName); - facingDirection = Direction.RIGHT; - airGroundState = AirGroundState.AIR; - previousAirGroundState = airGroundState; - playerState = PlayerState.STAND; - levelState = LevelState.RUNNING; - this.x = x; - this.y = y; - - // 11/19 - currentProjectile = null; - } - - public void update() { - moveAmountX = 0; - moveAmountY = 0; - - // if player is currently playing through level (has not won or lost) - if (levelState == LevelState.RUNNING) { - applyGravity(); - - handlePlayerState(); - - previousAirGroundState = airGroundState; - - // update player's animation - super.update(); - - // move player with respect to map collisions based on how much player needs to move this frame - super.moveYHandleCollision(moveAmountY); - super.moveXHandleCollision(moveAmountX); - - updateLockedKeys(); - } - - // if player has beaten level - else if (levelState == LevelState.LEVEL_COMPLETED) { - updateLevelCompleted(); - } - - // if player has lost level - else if (levelState == LevelState.PLAYER_DEAD) { - updatePlayerDead(); - } - - if(boneEffect.isTimeUp()) { - canJump = true; - } - - if(PlayerAttack.dogHealth == 0) { - canJump = true; - jumpHeight = 16; - } - } - - // add gravity to player, which is a downward force - protected void applyGravity() { - moveAmountY += gravity + momentumY; - } - - // based on player's current state, call appropriate player state handling method - protected void handlePlayerState() { - switch (playerState) { - case STAND: - playerStanding(); - break; - case WALK: - playerWalking(); - break; - case CROUCH: - playerCrouching(); - break; - case JUMP: - playerJumping(); - break; - // 11/19 - case ATTACKING: - playerAttacking(); - break; - } - } - - // player STANDING state logic - protected void playerStanding() { - // sets animation to a STAND animation based on which way player is facing - currentAnimationName = facingDirection == Direction.RIGHT ? "STAND_RIGHT" : "STAND_LEFT"; - - // if walk left or walk right key is pressed, player enters WALKING state - if (KeyboardAction.GAME_MOVE_LEFT.isDown() || KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - playerState = PlayerState.WALK; - } - - // if jump key is pressed, player enters JUMPING state - else if (KeyboardAction.GAME_JUMP.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_JUMP) && canJump == true) { - playerState = PlayerState.JUMP; - } - - // if crouch key is pressed, player enters CROUCHING state - else if (KeyboardAction.GAME_CROUCH.isDown()) { - playerState = PlayerState.CROUCH; - } - - // enter the attacking state if the attack key is pressed and the attack cooldown is up - else if(KeyboardAction.GAME_ATTACK.isDown() && attackCooldown.isTimeUp()) { - //keyLocker.lockKey(attackKey); - playerState = PlayerState.ATTACKING; - //System.out.println(previousPlayerState.toString()); - } - } - - // player WALKING state logic - protected void playerWalking() { - // sets animation to a WALK animation based on which way player is facing - currentAnimationName = facingDirection == Direction.RIGHT ? "WALK_RIGHT" : "WALK_LEFT"; - - // if the running key, shift, is held down acceleration the walk speed until the character reaches the max speed - if (KeyboardAction.GAME_SPRINT.isDown()) - { - if (walkSpeed < maxWalkSpeed) - { - walkSpeed = walkSpeed * walkAcceleration; - } - - } - // once the user lets go of the running key reset the walk speed - else { - walkSpeed = minWalkSpeed; - } - - if (KeyboardAction.GAME_MOVE_LEFT.isDown()) { - //System.out.println("s"); - moveAmountX -= walkSpeed; - facingDirection = Direction.LEFT; - } - - // if walk right key is pressed, move player to the right - else if (KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - //System.out.println("d"); - moveAmountX += walkSpeed; - facingDirection = Direction.RIGHT; - } else { - playerState = PlayerState.STAND; - } - - // if jump key is pressed, player enters JUMPING state - if (KeyboardAction.GAME_JUMP.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_JUMP) && canJump == true) { - //System.out.println("w"); - playerState = PlayerState.JUMP; - } - - // if crouch key is pressed, - else if (KeyboardAction.GAME_CROUCH.isDown()) { - playerState = PlayerState.CROUCH; - } - - // enter the attacking state if the attack key is pressed and the attack cooldown is up - else if(KeyboardAction.GAME_ATTACK.isDown() && attackCooldown.isTimeUp()) { - playerState = PlayerState.ATTACKING; - //System.out.println(previousPlayerState.toString()); - } - } - - // player CROUCHING state logic - protected void playerCrouching() { - // sets animation to a CROUCH animation based on which way player is facing - currentAnimationName = facingDirection == Direction.RIGHT ? "CROUCH_RIGHT" : "CROUCH_LEFT"; - - // if crouch key is released, player enters STANDING state - if (!KeyboardAction.GAME_CROUCH.isDown()) { - playerState = PlayerState.STAND; - } - - // if jump key is pressed, player enters JUMPING state - if (KeyboardAction.GAME_JUMP.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_JUMP)) { - playerState = PlayerState.JUMP; - } - } - - // player JUMPING state logic - protected void playerJumping() { - // if last frame player was on ground and this frame player is still on ground, the jump needs to be setup - if (previousAirGroundState == AirGroundState.GROUND && airGroundState == AirGroundState.GROUND && canJump == true) { - // sets animation to a JUMP animation based on which way player is facing - currentAnimationName = facingDirection == Direction.RIGHT ? "JUMP_RIGHT" : "JUMP_LEFT"; - - // player is set to be in air and then player is sent into the air - airGroundState = AirGroundState.AIR; - jumpForce = jumpHeight; - if (jumpForce > 0) { - moveAmountY -= jumpForce; - jumpForce -= jumpDegrade; - if (jumpForce < 0) { - jumpForce = 0; - } - } - } - // if the player is no longer holding any of the jump keys set the jump force to 0 to stop the jump this allows the player to control how high they want to jump - if (!KeyboardAction.GAME_JUMP.isDown()) - { - jumpForce = 0; - } - - - // if player is in air (currently in a jump) and has more jumpForce, continue sending player upwards - if (airGroundState == AirGroundState.AIR) { - if (jumpForce > 0) { - moveAmountY -= jumpForce; - jumpForce -= jumpDegrade; - if (jumpForce < 0) { - jumpForce = 0; - } - } - - // if player is moving upwards, set player's animation to jump. if player moving downwards, set player's animation to fall - if (previousY > Math.round(y)) { - currentAnimationName = facingDirection == Direction.RIGHT ? "JUMP_RIGHT" : "JUMP_LEFT"; - } else { - currentAnimationName = facingDirection == Direction.RIGHT ? "FALL_RIGHT" : "FALL_LEFT"; - } - - // allows you to move left and right while in the air - if (KeyboardAction.GAME_MOVE_LEFT.isDown()) { - moveAmountX -= walkSpeed; - facingDirection = Direction.LEFT; - } - - else if (KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - moveAmountX += walkSpeed; - facingDirection = Direction.RIGHT; - } - - // if player is falling, increases momentum as player falls so it falls faster over time - if (moveAmountY > 0) { - increaseMomentum(); - } - } - - // if player last frame was in air and this frame is now on ground, player enters STANDING state - else if (previousAirGroundState == AirGroundState.AIR && airGroundState == AirGroundState.GROUND) { - playerState = PlayerState.STAND; - - } - } - - // 11/19 - public void playerAttacking() { - if (playerState == PlayerState.ATTACKING) { - - // this allows the player to still move left or right will in the attacking state - if (KeyboardAction.GAME_MOVE_LEFT.isDown()) { - moveAmountX -= walkSpeed; - facingDirection = Direction.LEFT; - } - else if (KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - moveAmountX += walkSpeed; - facingDirection = Direction.RIGHT; - } - - - // define where projectile will spawn on map (x location) relative to cat's - // location - // and define its movement speed - int attackX; - float movementSpeed; - if (facingDirection == Direction.RIGHT) { - attackX = Math.round(getX()) + getScaledWidth() - 20; - movementSpeed = 1.5f; - } else { - attackX = Math.round(getX()); - movementSpeed = -1.5f; - } - - // define where projectile will spawn on the map (y location) relative to - // dinosaur enemy's location - int attackY = Math.round(getY()) + 10; - - // create projectile - PlayerAttack projectile = new PlayerAttack(new Point(attackX, attackY), movementSpeed, 1000); - currentProjectile = projectile; - - // add projectile enemy to the map for it to officially spawn in the level - map.addEnemy(projectile); - - attackCooldown.setWaitTime(1500); - - // after an attack finished set the player to a standing state - playerState = PlayerState.STAND; - - } - } - - // while player is in air, this is called, and will increase momentumY by a set amount until player reaches terminal velocity - protected void increaseMomentum() { - momentumY += momentumYIncrease; - if (momentumY > terminalVelocityY) { - momentumY = terminalVelocityY; - } - } - - protected void increaseMomentumX() { - momentumX += momentumXIncrease; - if (momentumX > terminalVelocityX) { - momentumX = terminalVelocityX; - } - } - - protected void updateLockedKeys() { - keyLocker.setAction(KeyboardAction.GAME_JUMP,KeyboardAction.GAME_ATTACK); - } - - @Override - public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { - // if the player collides with the coordinates specified below, it either stops (beginning of level) or goes back to the start (end of level) - - if (direction == Direction.LEFT || direction == Direction.RIGHT) { - int rightBound = map.getWidthPixels() - map.getTileset().getScaledSpriteWidth(); - if (x < 0) { - momentumX = 0; - setX(0); - } else if (levelState != LevelState.LEVEL_COMPLETED && x > rightBound) { - momentumX = 0; - setX(rightBound); - } - } - if (hasCollided && MapTileCollisionHandler.lastCollidedTileX != null) { - if (MapTileCollisionHandler.lastCollidedTileX.getTileType() == TileType.LETHAL) { - levelState = LevelState.PLAYER_DEAD; - } - } - } - - @Override - public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { - // if player collides with a map tile below it, it is now on the ground - // if player does not collide with a map tile below, it is in air - if (direction == Direction.DOWN) { - if (hasCollided) { - momentumY = 0; - airGroundState = AirGroundState.GROUND; - } else { - playerState = PlayerState.JUMP; - airGroundState = AirGroundState.AIR; - } - } - - // if player collides with map tile upwards, it means it was jumping and then hit into a ceiling -- immediately stop upwards jump velocity - else if (direction == Direction.UP) { - if (hasCollided) { - jumpForce = 0; - } - } - if (hasCollided && MapTileCollisionHandler.lastCollidedTileY != null) { - if (MapTileCollisionHandler.lastCollidedTileY.getTileType() == TileType.LETHAL) { - levelState = LevelState.PLAYER_DEAD; - } - } - } - - // other entities can call this method to hurt the player - public void hurtPlayer(MapEntity mapEntity) { - if (!isInvincible) { - // if map entity is an enemy, kill player on touch - if (mapEntity instanceof Enemy) { - playerHealth = 0; - } - if (mapEntity instanceof Projectile) { - playerHealth -= 1; - } - if(mapEntity instanceof Bone) { - canJump = false; - boneEffect.setWaitTime(5000); - } - if (playerHealth <= 0) { - levelState = LevelState.PLAYER_DEAD; - } - } - } - - // other entities can call this to tell the player they beat a level - public void completeLevel() { - levelState = LevelState.LEVEL_COMPLETED; - - } - - // if player has beaten level, this will be the update cycle - public void updateLevelCompleted() { - // if player is not on ground, player should fall until it touches the ground - if (airGroundState != AirGroundState.GROUND && map.getCamera().containsDraw(this)) { - currentAnimationName = "FALL_RIGHT"; - applyGravity(); - increaseMomentum(); - super.update(); - moveYHandleCollision(moveAmountY); - } - // move player to the right until it walks off screen - else if (map.getCamera().containsDraw(this)) { - currentAnimationName = "WALK_RIGHT"; - super.update(); - moveXHandleCollision(walkSpeed); - } else { - // tell all player listeners that the player has finished the level - for (PlayerListener listener : listeners) { - listener.onLevelCompleted(); - } - } - } - - // if player has died, this will be the update cycle - public void updatePlayerDead() { - // change player animation to DEATH - if (!currentAnimationName.startsWith("DEATH")) { - if (facingDirection == Direction.RIGHT) { - currentAnimationName = "DEATH_RIGHT"; - } else { - currentAnimationName = "DEATH_LEFT"; - } - super.update(); - } - // if death animation not on last frame yet, continue to play out death animation - else if (currentFrameIndex != getCurrentAnimation().length - 1) { - super.update(); - } - // if death animation on last frame (it is set up not to loop back to start), player should continually fall until it goes off screen - else if (currentFrameIndex == getCurrentAnimation().length - 1) { - if (map.getCamera().containsDraw(this)) { - moveY(3); - } else { - // tell all player listeners that the player has died in the level - for (PlayerListener listener : listeners) { - listener.onDeath(); - } - } - } - } - - public PlayerState getPlayerState() { - return playerState; - } - - public void setPlayerState(PlayerState playerState) { - this.playerState = playerState; - } - - public AirGroundState getAirGroundState() { - return airGroundState; - } - - public Direction getFacingDirection() { - return facingDirection; - } - - public void setFacingDirection(Direction facingDirection) { - this.facingDirection = facingDirection; - } - - public void setLevelState(LevelState levelState) { - this.levelState = levelState; - } - - public void addListener(PlayerListener listener) { - listeners.add(listener); - } -} - - diff --git a/src/NPCs/Walrus.java b/src/NPCs/Walrus.java index ca9c4d2..4803f22 100644 --- a/src/NPCs/Walrus.java +++ b/src/NPCs/Walrus.java @@ -9,7 +9,6 @@ import Level.Map; import Level.NPC; import Level.Player; -import Level.Player_Old; import SpriteFont.SpriteFont; import Utils.Point; diff --git a/src/Players/Avatar.java b/src/Players/Avatar.java index e938302..91b730a 100644 --- a/src/Players/Avatar.java +++ b/src/Players/Avatar.java @@ -2,7 +2,6 @@ import Level.Player; -import Level.Player_Old; import Utils.Point; //TODO make this the new Cat Options with a factory to create the player diff --git a/src/Players/Cat_Old.java b/src/Players/Cat_Old.java deleted file mode 100644 index 8c27bec..0000000 --- a/src/Players/Cat_Old.java +++ /dev/null @@ -1,179 +0,0 @@ -package Players; - -import Builders.FrameBuilder; -import Engine.GraphicsHandler; -import Engine.ImageLoader; -import GameObject.Frame; -import GameObject.ImageEffect; -import GameObject.SpriteSheet; -import Level.Player_Old; -import Utils.Point; - -import java.util.HashMap; - -// This is the class for the Cat player character -// basically just sets some values for physics and then defines animations -@Deprecated -public class Cat_Old extends Player_Old { - - public Cat_Old(String name, Point point) { - this(name,point.x,point.y); - } - - public Cat_Old(String name, float x, float y) { - super(new SpriteSheet(ImageLoader.load(name), 24, 24), x, y, "STAND_RIGHT"); - - gravity = .5f; - terminalVelocityY = 6f; - jumpHeight = 14.5f; - jumpDegrade = .5f; - walkSpeed = 2.1f; - minWalkSpeed = 2.1f; - maxWalkSpeed = 3.3f; - walkAcceleration = 1.05f; - momentumYIncrease = .5f; - } - - public void update() { - super.update(); - } - - public void draw(GraphicsHandler graphicsHandler) { - super.draw(graphicsHandler); - //drawBounds(graphicsHandler, new Color(255, 0, 0, 170)); - } - - @Override - public HashMap getAnimations(SpriteSheet spriteSheet) { - return new HashMap() {{ - put("STAND_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(0, 0), 0) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("STAND_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(0, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("WALK_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(1, 0), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 1), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 2), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 3), 200) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("WALK_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(1, 0), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 1), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 2), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build(), - new FrameBuilder(spriteSheet.getSprite(1, 3), 200) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("JUMP_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(2, 0), 0) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("JUMP_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(2, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("FALL_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(3, 0), 0) - .withScale(3) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("FALL_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(3, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 9, 8, 9) - .build() - }); - - put("CROUCH_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(4, 0), 0) - .withScale(3) - .withBounds(8, 12, 8, 6) - .build() - }); - - put("CROUCH_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(4, 0), 0) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .withBounds(8, 12, 8, 6) - .build() - }); - - put("DEATH_RIGHT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(5, 0), 100) - .withScale(3) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 1), 100) - .withScale(3) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 2), -1) - .withScale(3) - .build() - }); - - put("DEATH_LEFT", new Frame[] { - new FrameBuilder(spriteSheet.getSprite(5, 0), 100) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 1), 100) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .build(), - new FrameBuilder(spriteSheet.getSprite(5, 2), -1) - .withScale(3) - .withImageEffect(ImageEffect.FLIP_HORIZONTAL) - .build() - }); - }}; - } -} diff --git a/src/Projectiles/Fireball.java b/src/Projectiles/Fireball.java index 1eff9c0..c73ae76 100644 --- a/src/Projectiles/Fireball.java +++ b/src/Projectiles/Fireball.java @@ -6,7 +6,6 @@ import GameObject.SpriteSheet; import Level.MapEntityStatus; import Level.Player; -import Level.Player_Old; import Level.Projectile; import Utils.Direction; import Utils.Point; diff --git a/src/Screens/LevelLoseScreen.java b/src/Screens/LevelLoseScreen.java index 0913c54..59a3a2d 100644 --- a/src/Screens/LevelLoseScreen.java +++ b/src/Screens/LevelLoseScreen.java @@ -3,7 +3,6 @@ import Engine.Drawable; import Engine.KeyboardAction; import Level.Player; -import Level.Player_Old; import Level.PlayerAttack; import Menu.Menu; import SpriteFont.SpriteFont; diff --git a/src/Screens/PauseScreen.java b/src/Screens/PauseScreen.java index ff4af9f..288b477 100644 --- a/src/Screens/PauseScreen.java +++ b/src/Screens/PauseScreen.java @@ -4,7 +4,6 @@ import Game.GameState; import Level.Map; import Level.Player; -import Level.Player_Old; import Menu.Menu; import Menu.MenuOption; import SpriteFont.SpriteFont; diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index dfc022e..5d397f3 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -4,7 +4,6 @@ import Game.GameState; import Level.Map; import Level.Player; -import Level.Player_Old; import Level.PlayerListener; import Maps.*; import SpriteFont.SpriteFont; diff --git a/src/Utils/AirGroundState.java b/src/Utils/AirGroundState.java deleted file mode 100644 index 3cba565..0000000 --- a/src/Utils/AirGroundState.java +++ /dev/null @@ -1,8 +0,0 @@ -package Utils; - -// Simple enum for keeping track of it something is on the ground or in the air -// I don't like the name of this enum, but I couldn't think of a better name... -@Deprecated -public enum AirGroundState { - GROUND, AIR -} From 0281c81ae96053377a625a9b43ca6955568bad31 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:42:59 -0500 Subject: [PATCH 033/164] renamed velocityX to absVelocityX --- src/Level/Player.java | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index cbc66e7..c5247a4 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -23,8 +23,7 @@ public abstract class Player extends GameObject { protected Facing facing; protected LevelState levelState; protected boolean inAir; - //VelocityX is absolute, and direction is derived from the facing.mod - private float velocityX, velocityY; + private float absVelocityX, velocityY; public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { super(spriteSheet, x, y, startingAnimationName); @@ -62,16 +61,16 @@ private void updatePlaying() { playerState = PlayerState.WALK; if (KeyboardAction.GAME_SPRINT.isDown()) { - if (velocityX < walkSpeed) { - velocityX = walkSpeed; - } else if (velocityX < sprintSpeed) { - velocityX *= sprintAcceleration; + if (absVelocityX < walkSpeed) { + absVelocityX = walkSpeed; + } else if (absVelocityX < sprintSpeed) { + absVelocityX *= sprintAcceleration; } } else { - velocityX = walkSpeed; + absVelocityX = walkSpeed; } } else { - velocityX = 0; + absVelocityX = 0; } //Update Jump @@ -102,7 +101,7 @@ private void updatePlaying() { inAir = true; //air is decided in the next line super.moveYHandleCollision(velocityY); - super.moveXHandleCollision(velocityX * facing.mod); + super.moveXHandleCollision(absVelocityX * facing.mod); } private void updateDead() { @@ -147,10 +146,10 @@ private void applyGravity(float maxFallVelocity) { private void keepInBounds() { if (x < 0) { - velocityX = 0; + absVelocityX = 0; setX(0); } else if (levelState != LevelState.WIN && x > map.getRightBound()) { - velocityX = 0; + absVelocityX = 0; setX(map.getRightBound()); } } From 0523ffa05005f3ef4d40ec0af4957e13c5f7783d Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 22:58:01 -0500 Subject: [PATCH 034/164] Removed Unnecessary Case --- src/Level/Player.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index c5247a4..329237d 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -186,8 +186,6 @@ public void hurtPlayer(MapEntity mapEntity) { case DAMAGE -> PLAYER_HEALTH -= 1; case INSTANT_DEATH -> PLAYER_HEALTH = 0; case PREVENT_JUMP -> preventJump(); - case DEFAULT -> { - } } } From a28cc4a2c9e38d24d92689954a77416187f9ffc8 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 16 Nov 2021 23:00:33 -0500 Subject: [PATCH 035/164] Removed Bounds method --- src/Level/Player.java | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 329237d..de9cf6e 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -50,7 +50,15 @@ public void update() { private void updatePlaying() { applyGravity(MAX_FALL_VELOCITY); - keepInBounds(); + +// Keep player in bounds + if (x < 0) { + absVelocityX = 0; + setX(0); + } else if (levelState != LevelState.WIN && x > map.getRightBound()) { + absVelocityX = 0; + setX(map.getRightBound()); + } playerState = PlayerState.STAND; @@ -144,16 +152,6 @@ private void applyGravity(float maxFallVelocity) { } } - private void keepInBounds() { - if (x < 0) { - absVelocityX = 0; - setX(0); - } else if (levelState != LevelState.WIN && x > map.getRightBound()) { - absVelocityX = 0; - setX(map.getRightBound()); - } - } - @Override public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { if (hasCollided) { From 315693a5b50350918cd61e1dbe68caf4c872630e Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 10:14:12 -0500 Subject: [PATCH 036/164] Updated layout of LevelSelectScreen.java Now levels are evenly split between two columns Also movement with keyboard is more intuitive Renamed back button to "Back to main menu" --- src/Screens/LevelSelectScreen.java | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Screens/LevelSelectScreen.java b/src/Screens/LevelSelectScreen.java index 0eb2ae5..a29e56e 100644 --- a/src/Screens/LevelSelectScreen.java +++ b/src/Screens/LevelSelectScreen.java @@ -5,6 +5,7 @@ import Game.ScreenCoordinator; import Maps.TitleScreenMap; import Menu.Menu; +import Menu.Direction; import Menu.MenuOption; public class LevelSelectScreen extends Menu { @@ -12,31 +13,30 @@ public class LevelSelectScreen extends Menu { private final ScreenCoordinator coordinator; public LevelSelectScreen() { + final int x_left_column = 150, x_right_column = 350; coordinator = GamePanel.getScreenCoordinator(); MenuOption[][] menu = new MenuOption[][]{ { - new MenuOption("Tutorial", 200, 100, () -> coordinator.loadLevel(0)) + new MenuOption("Tutorial", x_left_column, 100, () -> coordinator.loadLevel(0)) }, { - new MenuOption("Level One", 200, 150, () -> coordinator.loadLevel(1)) + new MenuOption("Level One", x_left_column, 150, () -> coordinator.loadLevel(1)), + new MenuOption("Level Five", x_right_column, 150, () -> coordinator.loadLevel(5)) }, { - new MenuOption("Level Two", 200, 200, () -> coordinator.loadLevel(2)) + new MenuOption("Level Two", x_left_column, 200, () -> coordinator.loadLevel(2)), + new MenuOption("Level Six", x_right_column, 200, () -> coordinator.loadLevel(6)) }, { - new MenuOption("Level Three", 200, 250, () -> coordinator.loadLevel(3)) + new MenuOption("Level Three", x_left_column, 250, () -> coordinator.loadLevel(3)), + new MenuOption("Level Seven", x_right_column, 250, () -> coordinator.loadLevel(7)) }, { - new MenuOption("Level Four", 200, 300, () -> coordinator.loadLevel(4)) - }, { - new MenuOption("Level Five", 200, 350, () -> coordinator.loadLevel(5)) - }, { - new MenuOption("Level Six", 200, 400, () -> coordinator.loadLevel(6)) - }, { - new MenuOption("Level Seven", 200, 450, () -> coordinator.loadLevel(7)) - }, { - new MenuOption("Boss Battle", 400, 100, () -> coordinator.loadLevel(8)) + new MenuOption("Level Four", x_left_column, 300, () -> coordinator.loadLevel(4)), + new MenuOption("Boss Battle", x_right_column, 300, () -> coordinator.loadLevel(8)) }, { new MenuOption( - "Hit [Escape] to go back to main menu", 100, 550, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) + "Back to Main Menu", x_left_column, 375, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) } }; + menu[4][1].setNeighborItem(menu[5][0], Direction.DOWN); + menu[1][1].setNeighborItem(menu[0][0],Direction.UP); setBackground(new TitleScreenMap()); setMenuItemsAsGrid(menu); } From bda498900b1b1a44385221d36377946a2a713880 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 10:45:32 -0500 Subject: [PATCH 037/164] Optimized map-edge collision and animation Cat will not show walking animation when trying to walk off the edge of the map This is complicated, maybe I should comment... --- src/Level/Player.java | 46 +++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index de9cf6e..6799205 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -16,13 +16,13 @@ public abstract class Player extends GameObject { private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; private static final float MAX_FALL_VELOCITY = 6f, MAX_DEATH_FALL_VELOCITY = 10f, DEATH_Y_VELOCITY = -2.5f; public static int PLAYER_HEALTH = 3; - private final List playerListeners = new ArrayList<>(); protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; - protected Stopwatch attackDelay, jumpDelay; - protected PlayerState playerState; - protected Facing facing; - protected LevelState levelState; - protected boolean inAir; + private final List playerListeners = new ArrayList<>(); + private final Stopwatch attackDelay, jumpDelay; + private PlayerState playerState; + private Facing facing; + private LevelState levelState; + private boolean inAir; private float absVelocityX, velocityY; public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { @@ -47,31 +47,18 @@ public void update() { setCurrentAnimationName(playerState.get(facing)); } - private void updatePlaying() { applyGravity(MAX_FALL_VELOCITY); -// Keep player in bounds - if (x < 0) { - absVelocityX = 0; - setX(0); - } else if (levelState != LevelState.WIN && x > map.getRightBound()) { - absVelocityX = 0; - setX(map.getRightBound()); - } - - playerState = PlayerState.STAND; - //Update Player Action and Direction - boolean move_leftDown = KeyboardAction.GAME_MOVE_LEFT.isDown(); - if (move_leftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown()) { - facing = move_leftDown ? Facing.LEFT : Facing.RIGHT; + boolean moveLeftDown = KeyboardAction.GAME_MOVE_LEFT.isDown(); + boolean playerMove = moveLeftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown(); + facing = playerMove ? moveLeftDown ? Facing.LEFT : Facing.RIGHT : facing; //Update facing if the player moved + //Only move if the player moved and is not going out of bounds + if (playerMove && ((facing == Facing.LEFT && x > 0) ^ (facing == Facing.RIGHT && x < map.getRightBound()))) { playerState = PlayerState.WALK; - - if (KeyboardAction.GAME_SPRINT.isDown()) { - if (absVelocityX < walkSpeed) { - absVelocityX = walkSpeed; - } else if (absVelocityX < sprintSpeed) { + if (KeyboardAction.GAME_SPRINT.isDown() && absVelocityX >= walkSpeed) { + if (absVelocityX < sprintSpeed) { absVelocityX *= sprintAcceleration; } } else { @@ -79,6 +66,7 @@ private void updatePlaying() { } } else { absVelocityX = 0; + playerState = PlayerState.STAND; } //Update Jump @@ -117,10 +105,8 @@ private void updateDead() { if (currentFrameIndex > 0) { if (map.getCamera().containsDraw(this)) { applyGravity(MAX_DEATH_FALL_VELOCITY); - } else { - for (PlayerListener listener : playerListeners) { - listener.onDeath(); - } + } else for (PlayerListener listener : playerListeners) { + listener.onDeath(); } } else { velocityY = DEATH_Y_VELOCITY; From e5897d27013f4a322e6cd2eec6e3da142efe3631 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 10:51:29 -0500 Subject: [PATCH 038/164] Removed Wrapper Method --- src/Level/Player.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 6799205..b82b218 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -95,7 +95,7 @@ private void updatePlaying() { levelState = LevelState.DEAD; } - inAir = true; //air is decided in the next line + inAir = true; //air is decided in moveYHandleCollision() super.moveYHandleCollision(velocityY); super.moveXHandleCollision(absVelocityX * facing.mod); } @@ -169,14 +169,10 @@ public void hurtPlayer(MapEntity mapEntity) { switch (mapEntity.getCollisionType()) { case DAMAGE -> PLAYER_HEALTH -= 1; case INSTANT_DEATH -> PLAYER_HEALTH = 0; - case PREVENT_JUMP -> preventJump(); + case PREVENT_JUMP -> jumpDelay.setWaitTime(JUMP_DELAY); } } - public void preventJump() { - jumpDelay.setWaitTime(JUMP_DELAY); - } - public void completeLevel() { levelState = LevelState.WIN; } From 710b241d99b3f3fbc53159fa738afbd65d27232b Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 10:58:32 -0500 Subject: [PATCH 039/164] Added Author --- src/Level/Player.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index b82b218..d6d14a5 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -11,6 +11,9 @@ import java.util.ArrayList; import java.util.List; +/** + * @author Thomas Kwashnak + */ public abstract class Player extends GameObject { private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; @@ -125,10 +128,8 @@ private void updateWin() { playerState = PlayerState.WALK; moveXHandleCollision(walkSpeed); } - } else { - for (PlayerListener listener : playerListeners) { - listener.onLevelCompleted(); - } + } else for (PlayerListener listener : playerListeners) { + listener.onLevelCompleted(); } } From a5af7eef59e598414fe733f7e73913845c7f82e8 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 14:25:25 -0500 Subject: [PATCH 040/164] Added additional comments --- src/Level/Player.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index d6d14a5..8f1f068 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -21,7 +21,7 @@ public abstract class Player extends GameObject { public static int PLAYER_HEALTH = 3; protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; private final List playerListeners = new ArrayList<>(); - private final Stopwatch attackDelay, jumpDelay; + private final Stopwatch attackDelay = new Stopwatch(), jumpDelay = new Stopwatch(); private PlayerState playerState; private Facing facing; private LevelState levelState; @@ -34,9 +34,6 @@ public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimatio playerState = PlayerState.STAND; levelState = LevelState.PLAYING; facing = Facing.RIGHT; - - attackDelay = new Stopwatch(); - jumpDelay = new Stopwatch(); } public void update() { @@ -55,7 +52,7 @@ private void updatePlaying() { //Update Player Action and Direction boolean moveLeftDown = KeyboardAction.GAME_MOVE_LEFT.isDown(); - boolean playerMove = moveLeftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown(); + boolean playerMove = moveLeftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown(); //Only true if the player is moving in a direction facing = playerMove ? moveLeftDown ? Facing.LEFT : Facing.RIGHT : facing; //Update facing if the player moved //Only move if the player moved and is not going out of bounds if (playerMove && ((facing == Facing.LEFT && x > 0) ^ (facing == Facing.RIGHT && x < map.getRightBound()))) { @@ -64,10 +61,10 @@ private void updatePlaying() { if (absVelocityX < sprintSpeed) { absVelocityX *= sprintAcceleration; } - } else { + } else { //If player is not sprinting, or if the player started off sprinting from rest (where velocityX is 0) absVelocityX = walkSpeed; } - } else { + } else { //Player is not moving absVelocityX = 0; playerState = PlayerState.STAND; } From d5ddd07cf44395707829e954a4577faf6bda62b2 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 14:51:10 -0500 Subject: [PATCH 041/164] Restructured how Test Case SCP-56 is executed --- Team A2/Test Cases/Test Case SCP-56.md | 36 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 9d053b2..cb4d323 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -5,22 +5,38 @@ | Test Name | Test Game Speed | | Date of Last Revision | 11/16/2021 | | Test Objective | Ensure that the game runs consistently through multiple distributions | -| Test Notes| Due to the nature of this test, multiple tests must be made before the test can be considered complete. Testing must be performed on multiple devices with varied operating system and configuration| +| Test Notes| Due to the nature of this test case, multiple runs of the test must be conducted on various machines of different make and models. Measurements will be taken using a recording software, and should not be expected to be perfect| +|Software Required|Screen recording software: Needs to be able to record the screen such that the tester can go back and accurately measure the time between events| + ### Procedure -|Step | Action | Expected Result | -|:---:| :--- | :---- | -|1| Run the game| The game successfully opens | +|Step | Action | Expected Result | Measurement Field | +|:---:| :--- | :---- | :----:| +|1|Run the game|The game successfully opens|| +|2|Begin recording|A screen recorder is started that records the game|| +|3|Click *Play Game*|The tutorial level is successfully opened|| +|4|Walk to the left-most edge of the level|The cat is at the left most bound of the tutorial level|| +|5|Hold `D/Right Arrow` until the cat is blocked from moving by the tree|The cat moves from the edge of the map into the tree|**Measurement 1:** The time it takes starting when the cat begins moving to when the cat finishes moving| +|6|Move the cat out from under the tree|The cat has a clear sky above it such that the cat is able to jump|| +|7|Hold `Space/W/Up Arrow` until the cat reaches the ground again|The cat jumps and lands back on the ground|**Measurement 2:** The time it takes starting when the cat begins jumping to when the cat hits the ground again| +|8|Hold `e` until the player shoots a reasonable amount of fireballs|The cat shoots multiple fireballs|**Measurement 3:** The time between two consecutive fireballs spawning (multiple attempts can be averaged if needed)|\ +|9|Complete the tutorial level|When the tutorial level is completed, the `level complete` is shown, and after a few seconds the player is loaded into the next level|**Measurement 4:** The time that the `level complete` screen is shown + +### Test Execution +Instances of tests are listed in table below (template provided). Measurements listed in instructions above are listed below for test completer to evaluate. -### Test Completion -Instances of the test execution are listed below with results. On failed tests, steps that have failed are listed in the `Test Result` column -|Tester Name| Computer Type / Operating System | Date of Test | Test Result -|:---|:---:|:---:|:---:| -|[NAME]|[TYPE], [OPERATING SYSTEM] | [DATE] | [RESULT] | +|Date of Test|Tester Name|Computer Configuration | Measurement 1|Measurement 2|Measurement 3|Measurement 4| +|:---:|:---|:---|:---:|:---:|:---:|:---:| +|[DATE]|[TESTER]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]| -**Marking Test as Complete** +[comment]: <> (Add test rows to end here ^^) + +### Completion Criteria + - There are no outliers on all measurements + +### Test Completion - **Tester**: [TEST REVIEWER NAME] - **Date of Test**: [TEST COMPLETION DATE] - **Test Result**: [TEST RESULT] \ No newline at end of file From 8820dabeae65c9e62e65a2be9af98ab6d8261e67 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 14:54:24 -0500 Subject: [PATCH 042/164] Added Pass/Fail to individual tests --- Team A2/Test Cases/Test Case SCP-56.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index cb4d323..c3ddbd7 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -26,10 +26,12 @@ ### Test Execution Instances of tests are listed in table below (template provided). Measurements listed in instructions above are listed below for test completer to evaluate. +**Overall Test Completion** indicates whether all steps were completed and no errors / inability to follow instructions occurred. -|Date of Test|Tester Name|Computer Configuration | Measurement 1|Measurement 2|Measurement 3|Measurement 4| -|:---:|:---|:---|:---:|:---:|:---:|:---:| -|[DATE]|[TESTER]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]| + +|Date of Test|Tester Name|Computer Configuration | Measurement 1|Measurement 2|Measurement 3|Measurement 4| Overall Test Completion| +|:---:|:---|:---|:---:|:---:|:---:|:---:|:---:| +|[DATE]|[TESTER]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[PASS/FAIL]| [comment]: <> (Add test rows to end here ^^) From 147a0d7b4f6d80ad5928726e02eace2fa3dfc04e Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 14:56:25 -0500 Subject: [PATCH 043/164] Modified headings of tests table to better format once data was inputted --- Team A2/Test Cases/Test Case SCP-56.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index c3ddbd7..990b6c3 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -29,9 +29,9 @@ Instances of tests are listed in table below (template provided). Measurements l **Overall Test Completion** indicates whether all steps were completed and no errors / inability to follow instructions occurred. -|Date of Test|Tester Name|Computer Configuration | Measurement 1|Measurement 2|Measurement 3|Measurement 4| Overall Test Completion| +|Date|Name|Device Information | Measure 1|Measure 2|Measure 3|Measure 4|Pass/Fail| |:---:|:---|:---|:---:|:---:|:---:|:---:|:---:| -|[DATE]|[TESTER]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[PASS/FAIL]| +|[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[PASS/FAIL]| [comment]: <> (Add test rows to end here ^^) From abab67826df186723918f350e3b699b9a602a5e2 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:03:13 -0500 Subject: [PATCH 044/164] Updated Test Case SCP-56 Modified Software Requirements --- Team A2/Test Cases/Test Case SCP-56.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 990b6c3..8807d27 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -6,7 +6,7 @@ | Date of Last Revision | 11/16/2021 | | Test Objective | Ensure that the game runs consistently through multiple distributions | | Test Notes| Due to the nature of this test case, multiple runs of the test must be conducted on various machines of different make and models. Measurements will be taken using a recording software, and should not be expected to be perfect| -|Software Required|Screen recording software: Needs to be able to record the screen such that the tester can go back and accurately measure the time between events| +|Software Requirement|**Screen recording software:** Needs to be able to record the screen such that the tester can go back and accurately measure the time between events. *Suggested:* OBS| ### Procedure From 216203b3a3976511fbecd74103ea5555e94b0b17 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:10:47 -0500 Subject: [PATCH 045/164] Added debug that displays the time (in ms) between frames --- src/Engine/GamePanel.java | 6 ++++-- src/Engine/GameWindow.java | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 313e7a1..1c4b9b5 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -47,6 +47,7 @@ public class GamePanel extends JPanel { public static Clip clip; private Point previousMousePoint = new Point(0,0); private JLabel health; + private long lastFrame; /* @@ -71,7 +72,6 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { - timer = new Timer(1000 / Config.FPS, new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -84,6 +84,8 @@ public void actionPerformed(ActionEvent e) { health.hide(); } repaint(); + System.out.println((System.currentTimeMillis() - lastFrame)); + lastFrame = System.currentTimeMillis(); } }); timer.setRepeats(true); @@ -99,8 +101,8 @@ public void setupGame() { setBackground(Colors.CORNFLOWER_BLUE); screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); doPaint = true; - } + public static GameWindow getGameWindow() { return gameWindow; } diff --git a/src/Engine/GameWindow.java b/src/Engine/GameWindow.java index 0f12d10..afd206e 100644 --- a/src/Engine/GameWindow.java +++ b/src/Engine/GameWindow.java @@ -26,7 +26,6 @@ public void mouseClicked(MouseEvent e) { GamePanel.mouseClicked(e); } }); - gamePanel = new GamePanel(c1,this); gamePanel.setFocusable(true); gamePanel.requestFocusInWindow(); From 50e16647e3253d6535922e6585f8278a7b91cb69 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:14:52 -0500 Subject: [PATCH 046/164] Player can now crouch --- src/Level/Player.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Level/Player.java b/src/Level/Player.java index 8f1f068..fd277d0 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -88,6 +88,9 @@ private void updatePlaying() { //If the player is in the air, set its animation based on velocityY if (inAir) { playerState = velocityY < 0 ? PlayerState.JUMP : PlayerState.FALL; + } else if(KeyboardAction.GAME_CROUCH.isDown()) { + absVelocityX = 0; + playerState = PlayerState.CROUCH; } //Updates player to death if their health hits 0 From 10f17bc73317db7ee9885cc477f90123d0bfd0df Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:17:28 -0500 Subject: [PATCH 047/164] Added Measurement for Cat Sprinting --- Team A2/Test Cases/Test Case SCP-56.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 8807d27..dbe980b 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -18,10 +18,10 @@ |3|Click *Play Game*|The tutorial level is successfully opened|| |4|Walk to the left-most edge of the level|The cat is at the left most bound of the tutorial level|| |5|Hold `D/Right Arrow` until the cat is blocked from moving by the tree|The cat moves from the edge of the map into the tree|**Measurement 1:** The time it takes starting when the cat begins moving to when the cat finishes moving| -|6|Move the cat out from under the tree|The cat has a clear sky above it such that the cat is able to jump|| -|7|Hold `Space/W/Up Arrow` until the cat reaches the ground again|The cat jumps and lands back on the ground|**Measurement 2:** The time it takes starting when the cat begins jumping to when the cat hits the ground again| -|8|Hold `e` until the player shoots a reasonable amount of fireballs|The cat shoots multiple fireballs|**Measurement 3:** The time between two consecutive fireballs spawning (multiple attempts can be averaged if needed)|\ -|9|Complete the tutorial level|When the tutorial level is completed, the `level complete` is shown, and after a few seconds the player is loaded into the next level|**Measurement 4:** The time that the `level complete` screen is shown +|6|Hold `Shift`, then hold `A/Left Arrow` until the cat stops moving at the left edge of the map|The player sprints to the left-most edge of the map|**Measurement 2:** The time it takes for the cat to move starting when the cat begins moving to when the cat is stopped by the map edge| +|7|Hold `Space/W/Up Arrow` until the cat reaches the ground again|The cat jumps and lands back on the ground|**Measurement 3:** The time it takes starting when the cat begins jumping to when the cat hits the ground again| +|8|Hold `e` until the player shoots a reasonable amount of fireballs|The cat shoots multiple fireballs|**Measurement 4:** The time between two consecutive fireballs spawning (multiple attempts can be averaged if needed)|\ +|9|Complete the tutorial level|When the tutorial level is completed, the `level complete` is shown, and after a few seconds the player is loaded into the next level|**Measurement 5:** The time that the `level complete` screen is shown ### Test Execution Instances of tests are listed in table below (template provided). Measurements listed in instructions above are listed below for test completer to evaluate. @@ -29,9 +29,9 @@ Instances of tests are listed in table below (template provided). Measurements l **Overall Test Completion** indicates whether all steps were completed and no errors / inability to follow instructions occurred. -|Date|Name|Device Information | Measure 1|Measure 2|Measure 3|Measure 4|Pass/Fail| -|:---:|:---|:---|:---:|:---:|:---:|:---:|:---:| -|[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[PASS/FAIL]| +|Date|Name|Device Information | Measure 1|Measure 2|Measure 3|Measure 5|Measure 4|Pass/Fail| +|:---:|:---|:---|:---:|:---:|:---:|:---:|:---:|:---:| +|[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[MEASURE 5]|[PASS/FAIL]| [comment]: <> (Add test rows to end here ^^) From b6fecf20205dd31cc29273f05b7a6ee74f24b705 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:28:18 -0500 Subject: [PATCH 048/164] Added code to detect highest refresh rate --- src/Game/Game.java | 1 + src/Game/GameTick.java | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/Game/GameTick.java diff --git a/src/Game/Game.java b/src/Game/Game.java index ca2a96f..9729cdc 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -23,6 +23,7 @@ public Game() { gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); + new GameTick(); // DEBUG USE ONLY // screenManager.setCurrentScreen(new DebugScreen()); } diff --git a/src/Game/GameTick.java b/src/Game/GameTick.java new file mode 100644 index 0000000..46c8386 --- /dev/null +++ b/src/Game/GameTick.java @@ -0,0 +1,30 @@ +package Game; + +import java.awt.*; + +/** + * Responsible for the looping of the class and containing values such as time since last tick, etc. + * @author Thomas Kwashnak + */ +public class GameTick { + + private static final int SCREEN_REFRESH_RATE; + + static { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); +// Sets the highest refresh rate to be the highest display rate + int highestRefreshRate = 0; + for(GraphicsDevice device : ge.getScreenDevices()) { + int refreshRate = device.getDisplayMode().getRefreshRate(); + System.out.println(refreshRate); + if(refreshRate > highestRefreshRate) { + highestRefreshRate = refreshRate; + } + } + SCREEN_REFRESH_RATE = highestRefreshRate; + } + + /* + http://www.java2s.com/Code/Java/2D-Graphics-GUI/GettingtheCurrentScreenRefreshRateandNumberofColors.htm + */ +} From d09e93434e048baded6bcf787bbbf84396112dad Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:29:00 -0500 Subject: [PATCH 049/164] Removed code meant for different branch --- src/Game/GameTick.java | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 src/Game/GameTick.java diff --git a/src/Game/GameTick.java b/src/Game/GameTick.java deleted file mode 100644 index 46c8386..0000000 --- a/src/Game/GameTick.java +++ /dev/null @@ -1,30 +0,0 @@ -package Game; - -import java.awt.*; - -/** - * Responsible for the looping of the class and containing values such as time since last tick, etc. - * @author Thomas Kwashnak - */ -public class GameTick { - - private static final int SCREEN_REFRESH_RATE; - - static { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); -// Sets the highest refresh rate to be the highest display rate - int highestRefreshRate = 0; - for(GraphicsDevice device : ge.getScreenDevices()) { - int refreshRate = device.getDisplayMode().getRefreshRate(); - System.out.println(refreshRate); - if(refreshRate > highestRefreshRate) { - highestRefreshRate = refreshRate; - } - } - SCREEN_REFRESH_RATE = highestRefreshRate; - } - - /* - http://www.java2s.com/Code/Java/2D-Graphics-GUI/GettingtheCurrentScreenRefreshRateandNumberofColors.htm - */ -} From 2d8689031636aef263c562df3b25dd2b608144b2 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:29:14 -0500 Subject: [PATCH 050/164] Removed code meant for different branch --- src/Game/Game.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Game/Game.java b/src/Game/Game.java index 9729cdc..ca2a96f 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -23,7 +23,6 @@ public Game() { gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); - new GameTick(); // DEBUG USE ONLY // screenManager.setCurrentScreen(new DebugScreen()); } From ad37857e1d49f2721f635b4a2a68b1737f23053e Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:29:43 -0500 Subject: [PATCH 051/164] Added code to fetch the highest refresh rate --- src/Game/Game.java | 3 ++- src/Game/GameTick.java | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/Game/GameTick.java diff --git a/src/Game/Game.java b/src/Game/Game.java index ca2a96f..0bd63e3 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -19,7 +19,8 @@ public static void main(String[] args) { public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); - + + new GameTick(); gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); diff --git a/src/Game/GameTick.java b/src/Game/GameTick.java new file mode 100644 index 0000000..7acfddb --- /dev/null +++ b/src/Game/GameTick.java @@ -0,0 +1,30 @@ +package Game; + +import java.awt.*; + +/** + * Responsible for the looping of the class and containing values such as time since last tick, etc. + * @author Thomas Kwashnak + */ +public class GameTick { + + private static final int SCREEN_REFRESH_RATE; + + static { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // Sets the highest refresh rate to be the highest display rate + int highestRefreshRate = 0; + for(GraphicsDevice device : ge.getScreenDevices()) { + int refreshRate = device.getDisplayMode().getRefreshRate(); + System.out.println(refreshRate); + if(refreshRate > highestRefreshRate) { + highestRefreshRate = refreshRate; + } + } + SCREEN_REFRESH_RATE = highestRefreshRate; + } + + /* + http://www.java2s.com/Code/Java/2D-Graphics-GUI/GettingtheCurrentScreenRefreshRateandNumberofColors.htm + */ +} From 4a4503b4f5e8672a5ba4d11f93176393622569f5 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:41:45 -0500 Subject: [PATCH 052/164] Created GameTick.java, which uses Threads to send updates rather than Timers --- src/Game/Game.java | 2 +- src/Game/GameTick.java | 44 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/Game/Game.java b/src/Game/Game.java index 0bd63e3..81c760c 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -20,7 +20,7 @@ public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); - new GameTick(); + new GameTick(null); gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); diff --git a/src/Game/GameTick.java b/src/Game/GameTick.java index 7acfddb..5382362 100644 --- a/src/Game/GameTick.java +++ b/src/Game/GameTick.java @@ -6,9 +6,13 @@ * Responsible for the looping of the class and containing values such as time since last tick, etc. * @author Thomas Kwashnak */ -public class GameTick { +public class GameTick implements Runnable { + /** + * May not need refresh rate and only refresh time ms + */ private static final int SCREEN_REFRESH_RATE; + private static final long REFRESH_TIME_MS; static { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); @@ -22,9 +26,47 @@ public class GameTick { } } SCREEN_REFRESH_RATE = highestRefreshRate; + REFRESH_TIME_MS = 1000 / SCREEN_REFRESH_RATE; } /* http://www.java2s.com/Code/Java/2D-Graphics-GUI/GettingtheCurrentScreenRefreshRateandNumberofColors.htm */ + + private Thread thread; + private Runnable runnable; + private boolean runCode = true; + private long lastTime; + private long timeSincePing; + + public GameTick(Runnable runnable) { + thread = new Thread(this); + } + + public void start() { + lastTime = System.currentTimeMillis(); + timeSincePing = 0; + thread.start(); + } + + public void end() { + runCode = false; + } + + public void run() { + while(runCode) { + + if(timeSincePing > REFRESH_TIME_MS) { + runnable.run(); + timeSincePing = 0; + } + + long currentTime = System.currentTimeMillis(); + timeSincePing += currentTime - lastTime; + lastTime = currentTime; + } + runCode = true; + } + + } From 2cd86540372520d2d36c5f72702bc1379f914a4e Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Wed, 17 Nov 2021 15:42:49 -0500 Subject: [PATCH 053/164] Assigned runnable variable --- src/Game/GameTick.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Game/GameTick.java b/src/Game/GameTick.java index 5382362..fca400d 100644 --- a/src/Game/GameTick.java +++ b/src/Game/GameTick.java @@ -41,6 +41,7 @@ public class GameTick implements Runnable { public GameTick(Runnable runnable) { thread = new Thread(this); + this.runnable = runnable; } public void start() { From f2a7e0a864401eef34ed30e9ccedf4ddc30020d6 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Thu, 18 Nov 2021 15:10:52 -0500 Subject: [PATCH 054/164] Passed Test Case SCP-59 --- Team A2/Test Cases/Test Case SCP-59.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-59.md b/Team A2/Test Cases/Test Case SCP-59.md index d05844d..b284fc0 100644 --- a/Team A2/Test Cases/Test Case SCP-59.md +++ b/Team A2/Test Cases/Test Case SCP-59.md @@ -10,11 +10,11 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens || -|2|Select "Level Select"|The level select screen is opened. Levels are listed in a grid formation|| -|3|Use `w/up arrow`,`a/left arrow`,`s/down arrow`,`d/right arrow` to navigate from and to each level listed|Navigating by a direction selects the first option visually in that direction. If the option is at the edge, the selection does not change.|| +|1| Run the game| The game successfully opens |Pass| +|2|Select "Level Select"|The level select screen is opened. Levels are listed in a grid formation|Pass| +|3|Use `w/up arrow`,`a/left arrow`,`s/down arrow`,`d/right arrow` to navigate from and to each level listed|Navigating by a direction selects the first option visually in that direction. If the option is at the edge, the selection does not change.|Pass| ### Test Completion -- **Tester**: [TESTER NAME] -- **Date of Test**: DATE OF TEST -- **Test Result**: TEST RESULT \ No newline at end of file +- **Tester**: Nicholas Tourony +- **Date of Test**: 11/18/2021 +- **Test Result**: Passed \ No newline at end of file From 633f62fa93986390b09ff9bdf27413cd8cd442af Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 18 Nov 2021 19:12:58 -0500 Subject: [PATCH 055/164] Game indeed runs different on different computers It actually runs 50% slower than what it's meant to run at on windows computers --- src/Engine/GamePanel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 1c4b9b5..744f4ea 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -84,7 +84,6 @@ public void actionPerformed(ActionEvent e) { health.hide(); } repaint(); - System.out.println((System.currentTimeMillis() - lastFrame)); lastFrame = System.currentTimeMillis(); } }); From 8174efcc527ea1c89c9ca29b8a705d5ef54846a3 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 18 Nov 2021 19:38:32 -0500 Subject: [PATCH 056/164] It was at this moment, he knew he broke the game this is gonna be fun --- src/Engine/GamePanel.java | 80 ++++++++++++++++---------------- src/Game/Game.java | 3 +- src/Game/GameThread.java | 8 ++++ src/Game/GameTick.java | 73 ----------------------------- src/Game/RenderThread.java | 33 +++++++++++++ src/Game/ThreadManager.java | 42 +++++++++++++++++ src/Screens/PlayLevelScreen.java | 3 +- 7 files changed, 126 insertions(+), 116 deletions(-) create mode 100644 src/Game/GameThread.java delete mode 100644 src/Game/GameTick.java create mode 100644 src/Game/RenderThread.java create mode 100644 src/Game/ThreadManager.java diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 744f4ea..6846637 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -1,27 +1,16 @@ package Engine; +import Game.*; import GameObject.Rectangle; import Level.Player; -import Players.Avatar; -import Players.Cat; -import Screens.OptionsScreen; -import SpriteFont.SpriteFont; import Utils.Colors; -import Utils.Stopwatch; -import javax.imageio.ImageIO; import javax.sound.sampled.*; //import sun.audio.AudioData; import javax.swing.*; -import Game.GameState; -import Game.ScreenCoordinator; - import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -30,24 +19,17 @@ * The JPanel uses a timer to continually call cycles of update and draw */ public class GamePanel extends JPanel { - // loads Screens on to the JPanel - // each screen has its own update and draw methods defined to handle a "section" - // of the game. - protected KeyLocker keyLocker = new KeyLocker(); - private ScreenManager screenManager; + private final ScreenManager screenManager; // used to create the game loop and cycle between update and draw calls private Timer timer; // used to draw graphics to the panel - private GraphicsHandler graphicsHandler; + private final GraphicsHandler graphicsHandler; private boolean doPaint = false; - protected int pointerLocationX, pointerLocationY; - protected Stopwatch keyTimer = new Stopwatch(); protected static GameWindow gameWindow; private static ScreenCoordinator coordinator; public static Clip clip; - private Point previousMousePoint = new Point(0,0); - private JLabel health; - private long lastFrame; + private final JLabel health; + private ThreadManager gameThread, renderThread; /* @@ -71,23 +53,40 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { coordinator = c1; - - timer = new Timer(1000 / Config.FPS, new ActionListener() { - public void actionPerformed(ActionEvent e) { - update(); - changeHealth(); - if(coordinator.getGameState() == GameState.LEVEL) { - health.show(); - } - else { - health.hide(); - } - repaint(); - lastFrame = System.currentTimeMillis(); - } + gameThread = new GameThread(() -> { + update(); }); - timer.setRepeats(true); + renderThread = new RenderThread(() -> { + repaint(); + }); + +// timer = new Timer(1000 / Config.FPS, new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// update(); +// changeHealth(); +// if(coordinator.getGameState() == GameState.LEVEL) { +// health.show(); +// } +// else { +// health.hide(); +// } +// repaint(); +// } +// }); +// timer.setRepeats(true); +// tickGame = new GameTick(new Runnable() { +// @Override +// public void run() { +// update(); +// } +// }); +// tickRender = new GameTick(new Runnable() { +// @Override +// public void run() { +// repaint(); +// } +// }); } public static ScreenCoordinator getScreenCoordinator() { @@ -149,7 +148,9 @@ public static void setVolumeHigh() { // this starts the timer (the game loop is started here public void startGame() { - timer.start(); +// timer.start(); + gameThread.start(); + renderThread.start(); try { music("Resources/Music/music.wav",.05); @@ -168,6 +169,7 @@ public ScreenManager getScreenManager() { public void update() { screenManager.update(); + changeHealth(); } public void draw() { diff --git a/src/Game/Game.java b/src/Game/Game.java index 81c760c..8e3a17e 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -3,7 +3,6 @@ import Engine.GameWindow; import Engine.ScreenManager; -import Menu.DebugScreen; /* * The game starts here @@ -20,7 +19,7 @@ public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); - new GameTick(null); + new RenderThread(null); gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java new file mode 100644 index 0000000..a9eb5a1 --- /dev/null +++ b/src/Game/GameThread.java @@ -0,0 +1,8 @@ +package Game; + +public class GameThread extends ThreadManager { + + public GameThread(Runnable runnable) { + super(runnable,0); + } +} diff --git a/src/Game/GameTick.java b/src/Game/GameTick.java deleted file mode 100644 index fca400d..0000000 --- a/src/Game/GameTick.java +++ /dev/null @@ -1,73 +0,0 @@ -package Game; - -import java.awt.*; - -/** - * Responsible for the looping of the class and containing values such as time since last tick, etc. - * @author Thomas Kwashnak - */ -public class GameTick implements Runnable { - - /** - * May not need refresh rate and only refresh time ms - */ - private static final int SCREEN_REFRESH_RATE; - private static final long REFRESH_TIME_MS; - - static { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - // Sets the highest refresh rate to be the highest display rate - int highestRefreshRate = 0; - for(GraphicsDevice device : ge.getScreenDevices()) { - int refreshRate = device.getDisplayMode().getRefreshRate(); - System.out.println(refreshRate); - if(refreshRate > highestRefreshRate) { - highestRefreshRate = refreshRate; - } - } - SCREEN_REFRESH_RATE = highestRefreshRate; - REFRESH_TIME_MS = 1000 / SCREEN_REFRESH_RATE; - } - - /* - http://www.java2s.com/Code/Java/2D-Graphics-GUI/GettingtheCurrentScreenRefreshRateandNumberofColors.htm - */ - - private Thread thread; - private Runnable runnable; - private boolean runCode = true; - private long lastTime; - private long timeSincePing; - - public GameTick(Runnable runnable) { - thread = new Thread(this); - this.runnable = runnable; - } - - public void start() { - lastTime = System.currentTimeMillis(); - timeSincePing = 0; - thread.start(); - } - - public void end() { - runCode = false; - } - - public void run() { - while(runCode) { - - if(timeSincePing > REFRESH_TIME_MS) { - runnable.run(); - timeSincePing = 0; - } - - long currentTime = System.currentTimeMillis(); - timeSincePing += currentTime - lastTime; - lastTime = currentTime; - } - runCode = true; - } - - -} diff --git a/src/Game/RenderThread.java b/src/Game/RenderThread.java new file mode 100644 index 0000000..bdce73f --- /dev/null +++ b/src/Game/RenderThread.java @@ -0,0 +1,33 @@ +package Game; + +import java.awt.*; + +/** + * Responsible for the looping of the class and containing values such as time since last tick, etc. + * @author Thomas Kwashnak + */ +public class RenderThread extends ThreadManager { + + /** + * May not need refresh rate and only refresh time ms + */ + private static final long REFRESH_TIME_MS; + + static { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // Sets the highest refresh rate to be the highest display rate + int highestRefreshRate = 0; + for(GraphicsDevice device : ge.getScreenDevices()) { + int refreshRate = device.getDisplayMode().getRefreshRate(); + System.out.println(refreshRate); + if(refreshRate > highestRefreshRate) { + highestRefreshRate = refreshRate; + } + } + REFRESH_TIME_MS = 1000 / highestRefreshRate; + } + + public RenderThread(Runnable runnable) { + super(runnable, REFRESH_TIME_MS); + } +} diff --git a/src/Game/ThreadManager.java b/src/Game/ThreadManager.java new file mode 100644 index 0000000..5d4495d --- /dev/null +++ b/src/Game/ThreadManager.java @@ -0,0 +1,42 @@ +package Game; + +/** + * @author Thomas Kwashnak + */ +public class ThreadManager implements Runnable { + + private Thread thread; + private long tickDelay, lastTick, elapsedTick; + private boolean running = true; + private Runnable runnable; + + public ThreadManager(Runnable runnable, long tickDelay) { + thread = new Thread(this); + this.tickDelay = tickDelay; + this.runnable = runnable; + } + + public void start() { + thread.start(); + } + + public void stop() { + running = false; + } + + @Override + public void run() { + lastTick = System.currentTimeMillis(); + while(running) { + if(elapsedTick > tickDelay) { + elapsedTick = 0; + runnable.run(); + } + + long currentTick = System.currentTimeMillis(); + elapsedTick += currentTick - lastTick; + lastTick = currentTick; + } + running = true; + } +} diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 5d397f3..f9a9e9b 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -64,7 +64,7 @@ public class PlayLevelScreen extends Screen implements PlayerListener { COLOR_GREY_BACKGROUND = new Color(0, 0, 0, 100); } - private State screenState; + private State screenState = State.RUNNING; private int currentMap; public PlayLevelScreen() { @@ -80,7 +80,6 @@ public PlayLevelScreen(int initialMap) { @Override public void initialize() { loadMap(currentMap); - screenState = State.RUNNING; } @Override From 3af25e5513160896511938fe70f0ec40ea6624f3 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 18 Nov 2021 19:41:55 -0500 Subject: [PATCH 057/164] Added Scaler to GameThread.java --- src/Game/GameThread.java | 8 ++++++++ src/Game/ThreadManager.java | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index a9eb5a1..28abf9d 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -5,4 +5,12 @@ public class GameThread extends ThreadManager { public GameThread(Runnable runnable) { super(runnable,0); } + + public void run() { + super.run(); + } + + public float getScaledMovement() { + return (float) elapsedTick / 1000; + } } diff --git a/src/Game/ThreadManager.java b/src/Game/ThreadManager.java index 5d4495d..4f6af6a 100644 --- a/src/Game/ThreadManager.java +++ b/src/Game/ThreadManager.java @@ -6,7 +6,8 @@ public class ThreadManager implements Runnable { private Thread thread; - private long tickDelay, lastTick, elapsedTick; + protected long lastTick, elapsedTick; + private final long tickDelay; private boolean running = true; private Runnable runnable; @@ -29,8 +30,8 @@ public void run() { lastTick = System.currentTimeMillis(); while(running) { if(elapsedTick > tickDelay) { - elapsedTick = 0; runnable.run(); + elapsedTick = 0; } long currentTick = System.currentTimeMillis(); From 2677d4d2b44cbb4643ce528dd5b4e33ffb446929 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 18 Nov 2021 19:59:42 -0500 Subject: [PATCH 058/164] Player moves? --- src/Game/GameThread.java | 11 ++++++----- src/Level/Player.java | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 28abf9d..072143a 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -2,15 +2,16 @@ public class GameThread extends ThreadManager { + + private static GameThread instance; + public GameThread(Runnable runnable) { super(runnable,0); + instance = this; } - public void run() { - super.run(); + public static float getScale() { + return ((float) instance.elapsedTick) / 15; } - public float getScaledMovement() { - return (float) elapsedTick / 1000; - } } diff --git a/src/Level/Player.java b/src/Level/Player.java index fd277d0..10b7f24 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -1,6 +1,7 @@ package Level; import Engine.KeyboardAction; +import Game.GameThread; import GameObject.GameObject; import GameObject.SpriteSheet; import Level.PlayerState.Facing; @@ -99,8 +100,8 @@ private void updatePlaying() { } inAir = true; //air is decided in moveYHandleCollision() - super.moveYHandleCollision(velocityY); - super.moveXHandleCollision(absVelocityX * facing.mod); + super.moveYHandleCollision(velocityY * GameThread.getScale()); + super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); } private void updateDead() { @@ -114,7 +115,7 @@ private void updateDead() { } else { velocityY = DEATH_Y_VELOCITY; } - setY(y + velocityY); + setY(y + velocityY * GameThread.getScale()); } private void updateWin() { @@ -135,7 +136,7 @@ private void updateWin() { private void applyGravity(float maxFallVelocity) { if (velocityY < maxFallVelocity) { - velocityY += gravity; + velocityY += gravity * GameThread.getScale(); } } From 266ce4b841293bd792aed47e304f359498962516 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 18 Nov 2021 20:05:40 -0500 Subject: [PATCH 059/164] Player finishing the level now correctly works --- src/Level/Player.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 10b7f24..06c45e7 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -124,10 +124,10 @@ private void updateWin() { if (inAir) { playerState = PlayerState.FALL; applyGravity(MAX_FALL_VELOCITY); - moveYHandleCollision(velocityY); + moveYHandleCollision(velocityY * GameThread.getScale()); } else { playerState = PlayerState.WALK; - moveXHandleCollision(walkSpeed); + moveXHandleCollision(walkSpeed * GameThread.getScale()); } } else for (PlayerListener listener : playerListeners) { listener.onLevelCompleted(); From 731623c8c115043dccf2e86a234a6ee33099d280 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:05:34 -0500 Subject: [PATCH 060/164] Player successfully moves at the same speed on different computers --- src/Engine/GamePanel.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index c63fcbc..ec2a6fc 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -60,6 +60,12 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { renderThread = new RenderThread(() -> { repaint(); }); + //WORKS + /* + However, current plan should be as follows: + - First get the system to work on a single thread (with the dynamic speed and such) + - THEN get the system to work on multiple threads for painting / etc + */ // timer = new Timer(1000 / Config.FPS, new ActionListener() { // public void actionPerformed(ActionEvent e) { From 24a800817293ad44d1be6ce347a83b2ad0209b74 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:19:36 -0500 Subject: [PATCH 061/164] Changed to Single Thread --- src/Engine/GamePanel.java | 5 +++-- src/Game/Game.java | 8 ++++++-- src/Game/GameThread.java | 18 ++++++++++++++++++ src/Game/ThreadManager.java | 4 ++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index ec2a6fc..1ca04d6 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -56,9 +56,10 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { gameThread = new GameThread(() -> { update(); + repaint(); }); renderThread = new RenderThread(() -> { - repaint(); + }); //WORKS /* @@ -156,7 +157,7 @@ public static void setVolumeHigh() { public void startGame() { // timer.start(); gameThread.start(); - renderThread.start(); +// renderThread.start(); try { music("Resources/Music/music.wav",.05); diff --git a/src/Game/Game.java b/src/Game/Game.java index 8e3a17e..0b93350 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -11,6 +11,10 @@ */ public class Game { + public static ThreadManager thread; + + + public static void main(String[] args) { new Game(); } @@ -18,12 +22,12 @@ public static void main(String[] args) { public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); - - new RenderThread(null); gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); // DEBUG USE ONLY // screenManager.setCurrentScreen(new DebugScreen()); } + + } diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 072143a..5539178 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -1,10 +1,28 @@ package Game; +import java.awt.*; + public class GameThread extends ThreadManager { private static GameThread instance; + private static final long RENDER_DELAY_MS; + + static { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // Sets the highest refresh rate to be the highest display rate + int highestRefreshRate = 0; + for(GraphicsDevice device : ge.getScreenDevices()) { + int refreshRate = device.getDisplayMode().getRefreshRate(); + System.out.println(refreshRate); + if(refreshRate > highestRefreshRate) { + highestRefreshRate = refreshRate; + } + } + RENDER_DELAY_MS = 1000 / highestRefreshRate; + } + public GameThread(Runnable runnable) { super(runnable,0); instance = this; diff --git a/src/Game/ThreadManager.java b/src/Game/ThreadManager.java index 4f6af6a..eb8ae0e 100644 --- a/src/Game/ThreadManager.java +++ b/src/Game/ThreadManager.java @@ -40,4 +40,8 @@ public void run() { } running = true; } + + public static float getTimeScale() { + return 0f; + } } From b6e281e2e91924393ff69dbfcb94a63fe666bfeb Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:28:10 -0500 Subject: [PATCH 062/164] Game breaks when tick delay is set to 5 --- src/Game/GameThread.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 5539178..e4f6200 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -24,7 +24,8 @@ public class GameThread extends ThreadManager { } public GameThread(Runnable runnable) { - super(runnable,0); + super(runnable,5); + //Somehow setting tickDelay to 0 causes the game to break in some way? instance = this; } From fb2c48d810b946859ca1fc04c389c38eaa546c26 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:29:57 -0500 Subject: [PATCH 063/164] Deprecated RenderThread for now --- src/Engine/GamePanel.java | 9 +++++---- src/Engine/GameWindow.java | 2 -- src/Game/RenderThread.java | 1 + 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 1ca04d6..cf7842a 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -29,7 +29,8 @@ public class GamePanel extends JPanel { private static ScreenCoordinator coordinator; public static Clip clip; private final JLabel health; - private ThreadManager gameThread, renderThread; + private ThreadManager gameThread; +// private ThreadManager renderThread; /* @@ -58,9 +59,9 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { update(); repaint(); }); - renderThread = new RenderThread(() -> { - - }); +// renderThread = new RenderThread(() -> { +// +// }); //WORKS /* However, current plan should be as follows: diff --git a/src/Engine/GameWindow.java b/src/Engine/GameWindow.java index afd206e..32d4032 100644 --- a/src/Engine/GameWindow.java +++ b/src/Engine/GameWindow.java @@ -16,8 +16,6 @@ public class GameWindow { private JFrame gameWindow; private GamePanel gamePanel; - - public GameWindow(ScreenCoordinator c1) { gameWindow = new JFrame("Game"); diff --git a/src/Game/RenderThread.java b/src/Game/RenderThread.java index bdce73f..10821a9 100644 --- a/src/Game/RenderThread.java +++ b/src/Game/RenderThread.java @@ -6,6 +6,7 @@ * Responsible for the looping of the class and containing values such as time since last tick, etc. * @author Thomas Kwashnak */ +@Deprecated public class RenderThread extends ThreadManager { /** From 69bd9d98fbfd35e5dd87c48a51d2402568d22061 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:31:26 -0500 Subject: [PATCH 064/164] Changed Tick Delay to 1 --- src/Game/GameThread.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index e4f6200..c059570 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -24,7 +24,7 @@ public class GameThread extends ThreadManager { } public GameThread(Runnable runnable) { - super(runnable,5); + super(runnable,1); //Somehow setting tickDelay to 0 causes the game to break in some way? instance = this; } From 5f2989d2b8d9cc391bdecf9a28e23e41bdc2c716 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:42:32 -0500 Subject: [PATCH 065/164] Located code responsible for causing animation errors --- src/Game/GameThread.java | 2 +- src/Level/Player.java | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index c059570..7efe024 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -30,7 +30,7 @@ public GameThread(Runnable runnable) { } public static float getScale() { - return ((float) instance.elapsedTick) / 15; + return ((float) instance.elapsedTick) / 10; } } diff --git a/src/Level/Player.java b/src/Level/Player.java index 06c45e7..7750d75 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -44,7 +44,6 @@ public void update() { case DEAD -> updateDead(); case WIN -> updateWin(); } - setCurrentAnimationName(playerState.get(facing)); } @@ -100,7 +99,16 @@ private void updatePlaying() { } inAir = true; //air is decided in moveYHandleCollision() + /* + So what's happening here is that the player never actually "hits" the block until the velocity gets enough to actually + change the player's Y position (since it rounds movement to an int) + Thus, as the gravity increases the veloctyY, it still thinks its in the air as the player doesn't actually "hit" anything + (movement is set to 0). Something that might fix would be to make internal movements stored in floats, and then have + the rendering be "truncated" to ints? or maybe it also does floats? + Basically we're going away from int locations? Would need to keep some things as ints to allow for + */ super.moveYHandleCollision(velocityY * GameThread.getScale()); + System.out.println(velocityY * GameThread.getScale() + " " + inAir); super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); } From 54d943159a31e22055a1ca8037f3f82a5486ed67 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 10:53:27 -0500 Subject: [PATCH 066/164] I've decided I may rewrite a few classes Particularly reworking how the whole system stores locations (probably going to rebuild those classes particularly, make it a lot cleaner to!) --- src/GameObject/GameObject.java | 8 ++++++-- src/Level/Player.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index d1c8bf8..a2fe061 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -162,10 +162,14 @@ public void moveYHandleCollision(float dy) { } } + private int magnitudeToInt(float magnitude) { + return (int) magnitude; + } + // performs collision check logic for moving along the x axis against the map's tiles public float handleCollisionX(float moveAmountX) { // determines amount to move (whole number) - int amountToMove = (int)Math.abs(moveAmountX); + int amountToMove = magnitudeToInt(moveAmountX); // gets decimal remainder from amount to move float moveAmountXRemainder = MathUtils.getRemainder(moveAmountX); @@ -212,7 +216,7 @@ public float handleCollisionX(float moveAmountX) { // performs collision check logic for moving along the y axis against the map's tiles public float handleCollisionY(float moveAmountY) { // determines amount to move (whole number) - int amountToMove = (int)Math.abs(moveAmountY); + int amountToMove = magnitudeToInt(moveAmountY); // gets decimal remainder from amount to move float moveAmountYRemainder = MathUtils.getRemainder(moveAmountY); diff --git a/src/Level/Player.java b/src/Level/Player.java index 7750d75..7bca596 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -108,7 +108,7 @@ private void updatePlaying() { Basically we're going away from int locations? Would need to keep some things as ints to allow for */ super.moveYHandleCollision(velocityY * GameThread.getScale()); - System.out.println(velocityY * GameThread.getScale() + " " + inAir); +// System.out.println(velocityY * GameThread.getScale() + " " + inAir); super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); } From b603a4f18934a8c2c6f9cc4387e18a5e8f6a6822 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 11:01:45 -0500 Subject: [PATCH 067/164] Added list of ideas needed for task --- src/GameObject/GameObject.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index a2fe061..f25f23e 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -12,7 +12,7 @@ import java.awt.image.BufferedImage; import java.util.HashMap; -/* +/** The all important GameObject class is what every "entity" used in this game should be based off of It encapsulates all the other class logic in the GameObject package to be a "one stop shop" for all entity needs This includes: @@ -21,6 +21,12 @@ 3. collision detection with a map 4. performing proper draw logic based on camera movement */ + +/* + * GOALS with a potential rewrite + * - Enable float-based locations -> more accurate positioning + * - Add "move velocity" to move a specific velocity, scale it with the current time difference, and check collisions + */ public class GameObject extends AnimatedSprite implements Drawable { // stores game object's start position From c605f87dc542b1d16481128bfb1a5dfe65a32522 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Fri, 19 Nov 2021 12:03:14 -0500 Subject: [PATCH 068/164] Removed Thread Variable --- src/Game/Game.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Game/Game.java b/src/Game/Game.java index 0b93350..e1f57d4 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -11,10 +11,6 @@ */ public class Game { - public static ThreadManager thread; - - - public static void main(String[] args) { new Game(); } From 2aab7bd284204cd3013239edd2845e372e61ed68 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Fri, 19 Nov 2021 14:30:17 -0500 Subject: [PATCH 069/164] Commenting / Parsing out Collision Detection --- src/Game/GameThread.java | 7 +++- src/GameObject/GameObject.java | 57 +++++++++++++++----------- src/Level/MapTileCollisionHandler.java | 44 ++++++++++++++++---- src/Screens/PlayLevelScreen.java | 2 +- 4 files changed, 78 insertions(+), 32 deletions(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 7efe024..2fb1b8a 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -24,8 +24,13 @@ public class GameThread extends ThreadManager { } public GameThread(Runnable runnable) { - super(runnable,1); + super(runnable,5); //Somehow setting tickDelay to 0 causes the game to break in some way? + //somehow even 1 is bad.... SOMETHING.. is going on here + /* + That something is probably due to the fact that rendering (painting) is done on a run-later class, so the updates is still technically + multithreaded in a way, so something's going wonky here.. + */ instance = this; } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index f25f23e..d4ce9a2 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -233,37 +233,48 @@ public float handleCollisionY(float moveAmountY) { // moves game object one pixel at a time until total move amount is reached // if at any point a map tile collision is determined to have occurred from the move, // move player back to right in front of the "solid" map tile's position, and stop attempting to move further - float amountMoved = 0; +// float amountMoved = 0; +// boolean hasCollided = false; +// for (int i = 0; i < amountToMove; i++) { +// moveY(direction.getVelocity()); +// float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); +// if (newLocation != 0) { +// hasCollided = true; +// setY(newLocation); +// break; +// } +// amountMoved = (i + 1) * direction.getVelocity(); +// } +// +// // if no collision occurred in the above steps, this deals with the decimal remainder from the original move amount (stored in moveAmountYRemainder) +// // it starts by moving the game object by that decimal amount +// // it then does one more check for a collision in the case that this added decimal amount was enough to change the rounding and move the game object to the next pixel over +// // if a collision occurs from this move, the player is moved back to right in front of the "solid" map tile's position +// if (!hasCollided) { +// moveY(moveAmountYRemainder * direction.getVelocity()); +// float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); +// if (newLocation != 0) { +// hasCollided = true; +// setY(newLocation); +// } +// } boolean hasCollided = false; - for (int i = 0; i < amountToMove; i++) { - moveY(direction.getVelocity()); - float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); - if (newLocation != 0) { - hasCollided = true; - setY(newLocation); - break; - } - amountMoved = (i + 1) * direction.getVelocity(); - } - // if no collision occurred in the above steps, this deals with the decimal remainder from the original move amount (stored in moveAmountYRemainder) - // it starts by moving the game object by that decimal amount - // it then does one more check for a collision in the case that this added decimal amount was enough to change the rounding and move the game object to the next pixel over - // if a collision occurs from this move, the player is moved back to right in front of the "solid" map tile's position - if (!hasCollided) { - moveY(moveAmountYRemainder * direction.getVelocity()); - float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); - if (newLocation != 0) { - hasCollided = true; - setY(newLocation); - } + + setY(moveAmountY + y); + float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this,map,direction); + if(newLocation != 0) { + setY(newLocation); +// System.out.println(newLocation); + hasCollided = true; } + // call this method which a game object subclass can override to listen for collision events and react accordingly onEndCollisionCheckY(hasCollided, direction); // returns the amount actually moved -- this isn't really used by the game, but I have it here for debug purposes - return amountMoved + (moveAmountYRemainder * direction.getVelocity()); + return (moveAmountYRemainder * direction.getVelocity()); } // game object subclass can override this method to listen for x axis collision events and react accordingly after calling "moveXHandleCollision" diff --git a/src/Level/MapTileCollisionHandler.java b/src/Level/MapTileCollisionHandler.java index bc99ba4..d926a6a 100644 --- a/src/Level/MapTileCollisionHandler.java +++ b/src/Level/MapTileCollisionHandler.java @@ -4,8 +4,16 @@ import Utils.Direction; import Utils.Point; -// This class has methods to check if a game object has collided with a map tile -// it is used by the game object class to determine if a collision occurred + + +/* + * Why is this a static class + */ + +/** + * This class has methods to check if a game object has collided with a map tile + * it is used by the game object class to determine if a collision occurred + */ public class MapTileCollisionHandler { public static MapTile lastCollidedTileX, lastCollidedTileY; @@ -41,14 +49,36 @@ public static float getAdjustedPositionAfterCollisionCheckX(GameObject gameObjec return 0; } + /** + * Firstly, totally going to be changing this in velocities + * + * Checks collisions between a list of tiles and enhanced tile-sets, returns 0 if no collision, or the new Y value if a collision does occur. + * @param gameObject Object to check collision + * @param map Map the object is on + * @param direction Direction the object is moving in + * @return + */ public static float getAdjustedPositionAfterCollisionCheckY(GameObject gameObject, Map map, Direction direction) { + //Tiles to check? getting a list of tiles int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(), 1); float edgeBoundY = direction == Direction.UP ? gameObject.getScaledBounds().getY() : gameObject.getScaledBounds().getY2(); - Point tileIndex = map.getTileIndexByPosition(gameObject.getScaledBounds().getX1(), edgeBoundY); - for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { - MapTile mapTile = map.getMapTile(Math.round(tileIndex.x) + j, Math.round(tileIndex.y)); - if (mapTile != null && hasCollidedWithMapTile(gameObject, mapTile, direction)) { - lastCollidedTileY = mapTile; + /*Get the edge bounds... ok?*/ + Point tileIndex = map.getTileIndexByPosition(gameObject.getScaledBounds().getX1(), edgeBoundY); /*Gets the uh, bottom left item? */ + for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { /*Get only immediately surrounding map tiles. AHA */ + /* + So the bottom message rounds to a whole number to check the tile at that location + */ + MapTile mapTile = map.getMapTile(/*converts / grabs based on array*/Math.round(tileIndex.x) + j, Math.round(tileIndex.y)); /*Grab the map + tile relative to the gameObject position*/ + + if (mapTile != null && hasCollidedWithMapTile(gameObject, mapTile, direction)) { /* Checks if there's a tile there, and if it's collided*/ + lastCollidedTileY = mapTile; /*Update tile*/ + + /* + Normalizes the distance based on the direction + bounds of the block + + hmm.. I wonder how this could be made simpler + */ if (direction == Direction.DOWN) { float boundsDifference = gameObject.getScaledY2() - gameObject.getScaledBoundsY2(); return mapTile.getScaledBoundsY1() - gameObject.getScaledHeight() + boundsDifference; diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index f9a9e9b..1b9bc53 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -100,7 +100,7 @@ public void update() { screenState = State.RUNNING; } } - case PAUSE,LEVEL_LOSE_MESSAGE -> alternateScreen.update(); + case PAUSE,LEVEL_LOSE_MESSAGE -> alternateScreen.update(); //TODO for some reason this breaks.. case PLAYER_DEAD -> screenState = State.LEVEL_LOSE_MESSAGE; case LEVEL_COMPLETED -> { alternateScreen = new LevelClearedScreen(); From fe090ee9c638689a8cd3d4cd546251fa3db2414b Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Fri, 19 Nov 2021 14:45:49 -0500 Subject: [PATCH 070/164] Created Vector.java to hold vectors --- src/Engine/Vector.java | 49 ++++++++++++++++++++++++++ src/GameObject/GameObject.java | 5 +++ src/Level/MapTileCollisionHandler.java | 7 +--- 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/Engine/Vector.java diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java new file mode 100644 index 0000000..26a0297 --- /dev/null +++ b/src/Engine/Vector.java @@ -0,0 +1,49 @@ +package Engine; + +public class Vector { + private double x,y; + + + public Vector() { + this(0,0); + } + + public Vector(double x, double y) { + this.x = x; + this.y = y; + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } + + public void addX(double x) { + this.x += x; + } + + public void addY(double y) { + this.y += y; + } + + public void setY(double y) { + this.y = y; + } + + public void setX(double x) { + this.x = x; + } + + public void applyVelocity(Vector vector) { + x += vector.x; + y += vector.y; + } + + public double getMagnitude() { + return Math.sqrt(x * x + y * y); + } + +} diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index d4ce9a2..a2dd876 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -3,6 +3,7 @@ import Builders.FrameBuilder; import Engine.Drawable; import Engine.GraphicsHandler; +import Engine.Vector; import Level.Map; import Level.MapTileCollisionHandler; import Utils.Direction; @@ -33,6 +34,8 @@ public class GameObject extends AnimatedSprite implements Drawable { // important to keep track of this as it's what allows the special draw logic to work protected float startPositionX, startPositionY; + protected Vector startPosition, amountMoved, previousPosition; + // how much game object's position has changed from start position over time // also important to keep track of for the special draw logic protected float amountMovedX, amountMovedY; @@ -47,8 +50,10 @@ public class GameObject extends AnimatedSprite implements Drawable { public GameObject(SpriteSheet spriteSheet, float x, float y, String startingAnimation) { super(spriteSheet, x, y, startingAnimation); + startPosition = new Vector(x, y); this.startPositionX = x; this.startPositionY = y; + previousPosition = new Vector(x, y); this.previousX = x; this.previousY = y; } diff --git a/src/Level/MapTileCollisionHandler.java b/src/Level/MapTileCollisionHandler.java index d926a6a..6e96da9 100644 --- a/src/Level/MapTileCollisionHandler.java +++ b/src/Level/MapTileCollisionHandler.java @@ -73,12 +73,7 @@ public static float getAdjustedPositionAfterCollisionCheckY(GameObject gameObjec if (mapTile != null && hasCollidedWithMapTile(gameObject, mapTile, direction)) { /* Checks if there's a tile there, and if it's collided*/ lastCollidedTileY = mapTile; /*Update tile*/ - - /* - Normalizes the distance based on the direction + bounds of the block - - hmm.. I wonder how this could be made simpler - */ + /*Normalizes the distance based on the direction + bounds of the block*/ if (direction == Direction.DOWN) { float boundsDifference = gameObject.getScaledY2() - gameObject.getScaledBoundsY2(); return mapTile.getScaledBoundsY1() - gameObject.getScaledHeight() + boundsDifference; From 6a605c5f88b80e5522314ee702535764291af90c Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sat, 20 Nov 2021 10:54:10 -0500 Subject: [PATCH 071/164] Implemented Vectors, started work on Collision Handling --- src/Engine/Vector.java | 93 ++++++++++++++++++++++---- src/GameObject/AnimatedSprite.java | 51 ++++++++------ src/GameObject/GameObject.java | 70 ++++++++----------- src/GameObject/Rectangle.java | 2 + src/Level/Camera.java | 8 +-- src/Level/CollisionHandler.java | 83 +++++++++++++++++++++++ src/Level/Map.java | 11 +-- src/Level/MapEntity.java | 18 +++-- src/Level/MapTileCollisionHandler.java | 3 +- src/Level/Player.java | 4 +- src/Level/PlayerAttack.java | 2 +- src/Projectiles/Bone.java | 2 +- src/Projectiles/Fireball.java | 2 +- src/Projectiles/LazerBeam.java | 2 +- 14 files changed, 250 insertions(+), 101 deletions(-) create mode 100644 src/Level/CollisionHandler.java diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index 26a0297..e576ed9 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -1,49 +1,114 @@ package Engine; public class Vector { - private double x,y; + private float x,y; public Vector() { - this(0,0); + this(0.0f,0.0f); } - public Vector(double x, double y) { + public Vector(float x, float y) { this.x = x; this.y = y; } - public double getX() { + public float getX() { return x; } - public double getY() { + public float getY() { return y; } - public void addX(double x) { + public void addX(float x) { this.x += x; } - public void addY(double y) { + public void addY(float y) { this.y += y; } - public void setY(double y) { + public void setY(float y) { this.y = y; } - public void setX(double x) { + public void setX(float x) { this.x = x; } - public void applyVelocity(Vector vector) { - x += vector.x; - y += vector.y; + public float getMagnitude() { + return (float) Math.sqrt(x * x + y * y); } - public double getMagnitude() { - return Math.sqrt(x * x + y * y); + public void set(float x, float y) { + this.x = x; + this.y = y; + } + + public Vector set(Vector location) { + this.x = location.x; + this.y = location.y; + return this; + } + + public Vector getDivided(float divisor) { + return new Vector(x / divisor, y / divisor); + } + + public Vector getMultiplied(float factor) { + return new Vector(x * factor, y * factor); + } + + public Vector getUnit() { + return getDivided(Math.abs(getMagnitude())); + } + + public void add(Vector vector) { + this.x += vector.x; + this.y += vector.y; + } + + public Vector multiply(float factor) { + this.x *= factor; + this.y *= factor; + return this; } + public Vector divide(float divisor) { + this.x /= divisor; + this.y /= divisor; + return this; + } + + public Vector subtract(float magnitude) { + return add(-magnitude); + } + + public Vector add(float magnitude) { + add(getUnit().multiply(magnitude)); + return this; + } + + public Vector clone() { + return new Vector(x,y); + } + + public Vector getGreatestDirection() { + if(x > y) { + return new Vector(x,0); + } else if(y > x) { + return new Vector(0,y); + } else { + return clone(); + } + } + + public Vector getAbsolute() { + return new Vector(Math.abs(x), Math.abs(y)); + } + + public Vector getNegative() { + return clone().multiply(-1); + } } diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index 10ff80a..10ec54b 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -1,6 +1,7 @@ package GameObject; import Engine.GraphicsHandler; +import Engine.Vector; import Utils.Stopwatch; import java.awt.*; @@ -16,7 +17,11 @@ While this calls does not extend from Sprite, it is set up in a way where it is */ public class AnimatedSprite implements IntersectableRectangle { // location of entity - protected float x, y; +// protected float x, y; + /** + * Position of the Animated Sprite + */ + protected Vector pos; // maps animation name to an array of Frames representing one animation protected HashMap animations; @@ -39,24 +44,21 @@ public class AnimatedSprite implements IntersectableRectangle { private Stopwatch frameTimer = new Stopwatch(); public AnimatedSprite(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { - this.x = x; - this.y = y; + pos = new Vector(x, y); this.animations = getAnimations(spriteSheet); this.currentAnimationName = startingAnimationName; updateCurrentFrame(); } public AnimatedSprite(float x, float y, HashMap animations, String startingAnimationName) { - this.x = x; - this.y = y; + pos = new Vector(x, y); this.animations = animations; this.currentAnimationName = startingAnimationName; updateCurrentFrame(); } public AnimatedSprite(BufferedImage image, float x, float y, String startingAnimationName) { - this.x = x; - this.y = y; + pos = new Vector(x, y); SpriteSheet spriteSheet = new SpriteSheet(image, image.getWidth(), image.getHeight()); this.animations = getAnimations(spriteSheet); this.currentAnimationName = startingAnimationName; @@ -64,8 +66,7 @@ public AnimatedSprite(BufferedImage image, float x, float y, String startingAnim } public AnimatedSprite(float x, float y) { - this.x = x; - this.y = y; + pos = new Vector(x, y); this.animations = new HashMap<>(); this.currentAnimationName = ""; } @@ -113,8 +114,8 @@ public void setAnimations(HashMap animations) { // and location updated to match any changes to the animated sprite class protected void updateCurrentFrame() { currentFrame = getCurrentFrame(); - currentFrame.setX(x); - currentFrame.setY(y); + currentFrame.setX(pos.getX()); + currentFrame.setY(pos.getY()); } // gets the frame from current animation that the animated sprite class is currently using @@ -143,11 +144,11 @@ public void drawBounds(GraphicsHandler graphicsHandler, Color color) { public float getScaledY2() { return currentFrame.getScaledY2(); } public void setX(float x) { - this.x = x; + pos.setX(x); currentFrame.setX(x); } public void setY(float y) { - this.y = y; + pos.setY(y); currentFrame.setY(y); } @@ -157,32 +158,32 @@ public void setLocation(float x, float y) { } public void moveX(float dx) { - this.x += dx; + this.pos.addX(dx); currentFrame.moveX(dx); } public void moveRight(float dx) { - this.x += dx; + this.pos.addX(dx); currentFrame.moveRight(dx); } public void moveLeft(float dx) { - this.x -= dx; + this.pos.addX(-dx); currentFrame.moveLeft(dx); } public void moveY(float dy) { - this.y += dy; + this.pos.addY(dy); currentFrame.moveY(dy); } public void moveDown(float dy) { - this.y += dy; + this.pos.addY(dy); currentFrame.moveDown(dy); } public void moveUp(float dy) { - this.y -= dy; + this.pos.addY(-dy); currentFrame.moveUp(dy); } @@ -270,12 +271,20 @@ public boolean intersects(IntersectableRectangle other) { @Override public String toString() { - return String.format("Current Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", x, y, getScaledWidth(), getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); + return String.format("Current Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", pos.getX(), pos.getY(), getScaledWidth(), + getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); } public void setCurrentAnimationName(String name) { this.currentAnimationName = name; } - + + public Vector getPos() { + return pos; + } + + public void move(Vector vector) { + pos.add(vector); + } } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index a2dd876..015df93 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -32,16 +32,16 @@ public class GameObject extends AnimatedSprite implements Drawable { // stores game object's start position // important to keep track of this as it's what allows the special draw logic to work - protected float startPositionX, startPositionY; +// protected float startPositionX, startPositionY; protected Vector startPosition, amountMoved, previousPosition; - - // how much game object's position has changed from start position over time - // also important to keep track of for the special draw logic - protected float amountMovedX, amountMovedY; - - // previous location the game object was in from the last frame - protected float previousX, previousY; +// +// // how much game object's position has changed from start position over time +// // also important to keep track of for the special draw logic +// protected float amountMovedX, amountMovedY; +// +// // previous location the game object was in from the last frame +// protected float previousX, previousY; @@ -51,27 +51,19 @@ public class GameObject extends AnimatedSprite implements Drawable { public GameObject(SpriteSheet spriteSheet, float x, float y, String startingAnimation) { super(spriteSheet, x, y, startingAnimation); startPosition = new Vector(x, y); - this.startPositionX = x; - this.startPositionY = y; previousPosition = new Vector(x, y); - this.previousX = x; - this.previousY = y; } public GameObject(float x, float y, HashMap animations, String startingAnimation) { super(x, y, animations, startingAnimation); - this.startPositionX = x; - this.startPositionY = y; - this.previousX = x; - this.previousY = y; + startPosition = new Vector(x, y); + previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, String startingAnimation) { super(image, x, y, startingAnimation); - this.startPositionX = x; - this.startPositionY = y; - this.previousX = x; - this.previousY = y; + startPosition = new Vector(x, y); + previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y) { @@ -83,10 +75,8 @@ public GameObject(BufferedImage image, float x, float y) { }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - this.startPositionX = x; - this.startPositionY = y; - this.previousX = x; - this.previousY = y; + startPosition = new Vector(x, y); + previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, float scale) { @@ -100,10 +90,8 @@ public GameObject(BufferedImage image, float x, float y, float scale) { }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - this.startPositionX = x; - this.startPositionY = y; - this.previousX = x; - this.previousY = y; + startPosition = new Vector(x, y); + previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { @@ -118,10 +106,8 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - this.startPositionX = x; - this.startPositionY = y; - this.previousX = x; - this.previousY = y; + startPosition = new Vector(x, y); + previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { @@ -137,10 +123,8 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - this.startPositionX = x; - this.startPositionY = y; - this.previousX = x; - this.previousY = y; + startPosition = new Vector(x, y); + previousPosition = new Vector(x, y); } @Override @@ -149,8 +133,7 @@ public void update() { super.update(); // update previous position to be the current position - previousX = x; - previousY = y; + previousPosition.set(pos); } // move game object along the x axis @@ -266,7 +249,7 @@ public float handleCollisionY(float moveAmountY) { boolean hasCollided = false; - setY(moveAmountY + y); + setY(moveAmountY + pos.getY()); float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this,map,direction); if(newLocation != 0) { setY(newLocation); @@ -291,7 +274,7 @@ public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { } // gets x location taking into account map camera position public float getCalibratedXLocation() { if (map != null) { - return x - map.getCamera().getX(); + return pos.getX() - map.getCamera().getX(); } else { return getX(); } @@ -300,7 +283,7 @@ public float getCalibratedXLocation() { // gets y location taking into account map camera position public float getCalibratedYLocation() { if (map != null) { - return y - map.getCamera().getY(); + return pos.getY() - map.getCamera().getY(); } else { return getY(); } @@ -351,4 +334,9 @@ public void drawBounds(GraphicsHandler graphicsHandler, Color color) { super.drawBounds(graphicsHandler, color); } } + + public Map getMap() { + return map; + } + } diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index bf9dc34..f1cad11 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -1,6 +1,7 @@ package GameObject; import Engine.GraphicsHandler; +import Engine.Vector; import java.awt.*; @@ -8,6 +9,7 @@ // it has some properties, rectangle math methods, and draw logic // the methods here are pretty self explanatory public class Rectangle implements IntersectableRectangle { + protected Vector location, dimensions; protected float x; protected float y; protected int width; diff --git a/src/Level/Camera.java b/src/Level/Camera.java index ffeab9e..07a63de 100644 --- a/src/Level/Camera.java +++ b/src/Level/Camera.java @@ -111,7 +111,7 @@ private ArrayList loadActiveEnemies() { } } else if (enemy.getMapEntityStatus() == MapEntityStatus.ACTIVE) { enemy.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (enemy.isRespawnable()) { + if (enemy.isRespawnEnabled()) { enemy.initialize(); } } else if (enemy.getMapEntityStatus() == MapEntityStatus.REMOVED) { @@ -133,7 +133,7 @@ private ArrayList loadActiveProjectiles() { } } else if (projectile.getMapEntityStatus() == MapEntityStatus.ACTIVE) { projectile.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (projectile.isRespawnable()) { + if (projectile.isRespawnEnabled()) { projectile.initialize(); } } else if (projectile.getMapEntityStatus() == MapEntityStatus.REMOVED) { @@ -162,7 +162,7 @@ private ArrayList loadActiveEnhancedMapTiles() { } } else if (enhancedMapTile.getMapEntityStatus() == MapEntityStatus.ACTIVE) { enhancedMapTile.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (enhancedMapTile.isRespawnable()) { + if (enhancedMapTile.isRespawnEnabled()) { enhancedMapTile.initialize(); } } else if (enhancedMapTile.getMapEntityStatus() == MapEntityStatus.REMOVED) { @@ -191,7 +191,7 @@ private ArrayList loadActiveNPCs() { } } else if (npc.getMapEntityStatus() == MapEntityStatus.ACTIVE) { npc.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (npc.isRespawnable()) { + if (npc.isRespawnEnabled()) { npc.initialize(); } } else if (npc.getMapEntityStatus() == MapEntityStatus.REMOVED) { diff --git a/src/Level/CollisionHandler.java b/src/Level/CollisionHandler.java new file mode 100644 index 0000000..6770d1a --- /dev/null +++ b/src/Level/CollisionHandler.java @@ -0,0 +1,83 @@ +package Level; + +import Engine.Vector; +import GameObject.GameObject; +import Utils.Point; + +/** + * + */ +public class CollisionHandler { + + private GameObject gameObject; + private Map map; + private MapTile lastCollidedTile; + + public CollisionHandler(GameObject gameObject) { + this.gameObject = gameObject; + this.map = gameObject.getMap(); + } + + + public Vector getAdjustedMovement(Vector velocity) { + Vector unit = velocity.getUnit(), cloned = velocity.clone(); + Vector originalPos = gameObject.getPos().clone(); + + while(cloned.getMagnitude() > 1) { + gameObject.move(unit); + cloned.subtract(1); + MapTile collision = getCollision(cloned); + if(collision != null) { + gameObject.move(unit.getNegative()); + cloned.add(1); + lastCollidedTile = collision; + return modifiedVelocity(collision,cloned); + } + } + + return velocity; + } + + public Vector modifiedVelocity(MapTile collided, Vector velocity) { + + return null; + } + + /** + * Checks if the game object has collided with any map tiles, and returns the collided map-tile if it has. Otherwise, returns null + * @param velocity + * @return + */ + private MapTile getCollision(Vector velocity) { + int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(),1); + Point tileIndex = map.getTileIndexByPosition(gameObject.getPos()); + for(int i = -1;i < numberOfTilesToCheck + 1; i++) { + for(int j = -1;j < numberOfTilesToCheck + 1; j++) { + MapTile mapTile = map.getTileByPosition((int) tileIndex.x + i, (int) tileIndex.y + j); + if(checkCollision(mapTile, velocity)) { + return mapTile; + } + } + } + + return null; + } + + public boolean checkCollision(MapTile mapTile, Vector velocity) { + return mapTile != null && hasCollidedWithMapTile(gameObject,mapTile,velocity); + } + + public static boolean hasCollidedWithMapTile(GameObject gameObject, MapTile mapTile, Vector velocity) { + return switch (mapTile.getTileType()) { + case NOT_PASSABLE, LETHAL -> gameObject.intersects(mapTile); + case JUMP_THROUGH_PLATFORM -> velocity.getY() < 0 && gameObject.intersects(mapTile) && Math.round(gameObject.getScaledBoundsY2() -1) == Math.round( + mapTile.getScaledBoundsY1()); + default -> false; + }; + } + + public MapTile getLastCollidedTile() { + return lastCollidedTile; + } + +} diff --git a/src/Level/Map.java b/src/Level/Map.java index 6b8c670..f75db98 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -1,9 +1,6 @@ package Level; -import Engine.Config; -import Engine.Drawable; -import Engine.GraphicsHandler; -import Engine.ScreenManager; +import Engine.*; import Utils.Point; import java.io.File; @@ -235,6 +232,12 @@ public MapTile getTileByPosition(int xPosition, int yPosition) { } } + public Point getTileIndexByPosition(Vector vector) { + int xIndex = Math.round(vector.getX() / tileset.getScaledSpriteWidth()); + int yIndex = Math.round(vector.getY()) / tileset.getScaledSpriteHeight(); + return new Point(xIndex,yIndex); + } + // returns the index of a tile (x index and y index) based on a position in the map public Point getTileIndexByPosition(float xPosition, float yPosition) { int xIndex = Math.round(xPosition) / tileset.getScaledSpriteWidth(); diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index 8642e95..40e537d 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -1,6 +1,7 @@ package Level; import Engine.CollisionType; +import Engine.Vector; import GameObject.*; import java.awt.image.BufferedImage; @@ -13,7 +14,7 @@ public class MapEntity extends GameObject { protected CollisionType collisionType = CollisionType.DEFAULT; // if true, if entity goes out of the camera's update range, and then ends up back in range, the entity will "respawn" back to its starting parameters - protected boolean isRespawnable = true; + protected boolean respawnEnabled = true; // if true, enemy cannot go out of camera's update range protected boolean isUpdateOffScreen = false; @@ -47,12 +48,9 @@ public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect } public void initialize() { - this.x = startPositionX; - this.y = startPositionY; - this.amountMovedX = 0; - this.amountMovedY = 0; - this.previousX = startPositionX; - this.previousY = startPositionY; + pos.set(startPosition); + amountMoved = new Vector(0, 0); + previousPosition.set(pos); updateCurrentFrame(); } @@ -64,12 +62,12 @@ public void setMapEntityStatus(MapEntityStatus mapEntityStatus) { this.mapEntityStatus = mapEntityStatus; } - public boolean isRespawnable() { - return isRespawnable; + public boolean isRespawnEnabled() { + return respawnEnabled; } public void setIsRespawnable(boolean isRespawnable) { - this.isRespawnable = isRespawnable; + this.respawnEnabled = isRespawnable; } public boolean isUpdateOffScreen() { diff --git a/src/Level/MapTileCollisionHandler.java b/src/Level/MapTileCollisionHandler.java index 6e96da9..c4c2b34 100644 --- a/src/Level/MapTileCollisionHandler.java +++ b/src/Level/MapTileCollisionHandler.java @@ -14,10 +14,11 @@ * This class has methods to check if a game object has collided with a map tile * it is used by the game object class to determine if a collision occurred */ +@Deprecated public class MapTileCollisionHandler { public static MapTile lastCollidedTileX, lastCollidedTileY; - + public static float getAdjustedPositionAfterCollisionCheckX(GameObject gameObject, Map map, Direction direction) { int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight(), 1); float edgeBoundX = direction == Direction.LEFT ? gameObject.getScaledBounds().getX1() : gameObject.getScaledBounds().getX2(); diff --git a/src/Level/Player.java b/src/Level/Player.java index 7bca596..85c6df3 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -55,7 +55,7 @@ private void updatePlaying() { boolean playerMove = moveLeftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown(); //Only true if the player is moving in a direction facing = playerMove ? moveLeftDown ? Facing.LEFT : Facing.RIGHT : facing; //Update facing if the player moved //Only move if the player moved and is not going out of bounds - if (playerMove && ((facing == Facing.LEFT && x > 0) ^ (facing == Facing.RIGHT && x < map.getRightBound()))) { + if (playerMove && ((facing == Facing.LEFT && pos.getX() > 0) ^ (facing == Facing.RIGHT && pos.getY() < map.getRightBound()))) { playerState = PlayerState.WALK; if (KeyboardAction.GAME_SPRINT.isDown() && absVelocityX >= walkSpeed) { if (absVelocityX < sprintSpeed) { @@ -123,7 +123,7 @@ private void updateDead() { } else { velocityY = DEATH_Y_VELOCITY; } - setY(y + velocityY * GameThread.getScale()); + setY(getY() + velocityY * GameThread.getScale()); } private void updateWin() { diff --git a/src/Level/PlayerAttack.java b/src/Level/PlayerAttack.java index 481c423..1996326 100644 --- a/src/Level/PlayerAttack.java +++ b/src/Level/PlayerAttack.java @@ -29,7 +29,7 @@ public PlayerAttack(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this enemy will not respawn after it has been removed - isRespawnable = false; + respawnEnabled = false; initialize(); } diff --git a/src/Projectiles/Bone.java b/src/Projectiles/Bone.java index 0dbc507..73486d7 100644 --- a/src/Projectiles/Bone.java +++ b/src/Projectiles/Bone.java @@ -27,7 +27,7 @@ public Bone(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this will not respawn after it has been removed - isRespawnable = false; + respawnEnabled = false; initialize(); collisionType = CollisionType.PREVENT_JUMP; diff --git a/src/Projectiles/Fireball.java b/src/Projectiles/Fireball.java index c73ae76..bf6ec3b 100644 --- a/src/Projectiles/Fireball.java +++ b/src/Projectiles/Fireball.java @@ -28,7 +28,7 @@ public Fireball(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this will not respawn after it has been removed - isRespawnable = false; + respawnEnabled = false; initialize(); } diff --git a/src/Projectiles/LazerBeam.java b/src/Projectiles/LazerBeam.java index 66e8861..7cdd8e5 100644 --- a/src/Projectiles/LazerBeam.java +++ b/src/Projectiles/LazerBeam.java @@ -25,7 +25,7 @@ public LazerBeam(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this will not respawn after it has been removed - isRespawnable = false; + respawnEnabled = false; initialize(); } From b175ff8cdd20cbed79313a3e097e0817c9a5d833 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sun, 21 Nov 2021 15:43:55 -0500 Subject: [PATCH 072/164] Collision Handling will be handled in GameObject.java --- src/Engine/Vector.java | 4 ++++ src/GameObject/GameObject.java | 10 ++++++++++ src/Level/CollisionHandler.java | 18 ++++++++++-------- src/Level/Player.java | 10 ++++++++-- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index e576ed9..ace799c 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -111,4 +111,8 @@ public Vector getAbsolute() { public Vector getNegative() { return clone().multiply(-1); } + + public String toString() { + return "(" + x + ", " + y + ")"; + } } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 015df93..d5622d5 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -138,6 +138,7 @@ public void update() { // move game object along the x axis // will stop object from moving based on map collision logic (such as if it hits a solid tile) + @Deprecated public void moveXHandleCollision(float dx) { if (map != null) { handleCollisionX(dx); @@ -148,6 +149,7 @@ public void moveXHandleCollision(float dx) { // move game object along the y axis // will stop object from moving based on map collision logic (such as if it hits a solid tile) + @Deprecated public void moveYHandleCollision(float dy) { if (map != null) { handleCollisionY(dy); @@ -156,11 +158,13 @@ public void moveYHandleCollision(float dy) { } } + @Deprecated private int magnitudeToInt(float magnitude) { return (int) magnitude; } // performs collision check logic for moving along the x axis against the map's tiles + @Deprecated public float handleCollisionX(float moveAmountX) { // determines amount to move (whole number) int amountToMove = magnitudeToInt(moveAmountX); @@ -208,6 +212,7 @@ public float handleCollisionX(float moveAmountX) { } // performs collision check logic for moving along the y axis against the map's tiles + @Deprecated public float handleCollisionY(float moveAmountY) { // determines amount to move (whole number) int amountToMove = magnitudeToInt(moveAmountY); @@ -266,12 +271,16 @@ public float handleCollisionY(float moveAmountY) { } // game object subclass can override this method to listen for x axis collision events and react accordingly after calling "moveXHandleCollision" + @Deprecated public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } // game object subclass can override this method to listen for y axis collision events and react accordingly after calling "moveYHandleCollision" + @Deprecated public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { } // gets x location taking into account map camera position + @Deprecated + //TODO change to vector public float getCalibratedXLocation() { if (map != null) { return pos.getX() - map.getCamera().getX(); @@ -281,6 +290,7 @@ public float getCalibratedXLocation() { } // gets y location taking into account map camera position + @Deprecated public float getCalibratedYLocation() { if (map != null) { return pos.getY() - map.getCamera().getY(); diff --git a/src/Level/CollisionHandler.java b/src/Level/CollisionHandler.java index 6770d1a..e54d159 100644 --- a/src/Level/CollisionHandler.java +++ b/src/Level/CollisionHandler.java @@ -1,6 +1,7 @@ package Level; import Engine.Vector; +import Game.GameThread; import GameObject.GameObject; import Utils.Point; @@ -10,16 +11,18 @@ public class CollisionHandler { private GameObject gameObject; - private Map map; private MapTile lastCollidedTile; public CollisionHandler(GameObject gameObject) { this.gameObject = gameObject; - this.map = gameObject.getMap(); } + public Map getMap() { + return gameObject.getMap(); + } public Vector getAdjustedMovement(Vector velocity) { + velocity.multiply(GameThread.getScale()); Vector unit = velocity.getUnit(), cloned = velocity.clone(); Vector originalPos = gameObject.getPos().clone(); @@ -34,12 +37,11 @@ public Vector getAdjustedMovement(Vector velocity) { return modifiedVelocity(collision,cloned); } } - return velocity; } - public Vector modifiedVelocity(MapTile collided, Vector velocity) { - + private Vector modifiedVelocity(MapTile collided, Vector velocity) { + System.out.println(velocity); return null; } @@ -49,11 +51,11 @@ public Vector modifiedVelocity(MapTile collided, Vector velocity) { * @return */ private MapTile getCollision(Vector velocity) { - int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(),1); - Point tileIndex = map.getTileIndexByPosition(gameObject.getPos()); + int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth(),1); + Point tileIndex = getMap().getTileIndexByPosition(gameObject.getPos()); for(int i = -1;i < numberOfTilesToCheck + 1; i++) { for(int j = -1;j < numberOfTilesToCheck + 1; j++) { - MapTile mapTile = map.getTileByPosition((int) tileIndex.x + i, (int) tileIndex.y + j); + MapTile mapTile = getMap().getTileByPosition((int) tileIndex.x + i, (int) tileIndex.y + j); if(checkCollision(mapTile, velocity)) { return mapTile; } diff --git a/src/Level/Player.java b/src/Level/Player.java index 85c6df3..3f2654a 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -1,6 +1,7 @@ package Level; import Engine.KeyboardAction; +import Engine.Vector; import Game.GameThread; import GameObject.GameObject; import GameObject.SpriteSheet; @@ -28,6 +29,7 @@ public abstract class Player extends GameObject { private LevelState levelState; private boolean inAir; private float absVelocityX, velocityY; + private CollisionHandler collisionHandler; public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { super(spriteSheet, x, y, startingAnimationName); @@ -35,6 +37,7 @@ public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimatio playerState = PlayerState.STAND; levelState = LevelState.PLAYING; facing = Facing.RIGHT; + collisionHandler = new CollisionHandler(this); } public void update() { @@ -107,9 +110,12 @@ private void updatePlaying() { the rendering be "truncated" to ints? or maybe it also does floats? Basically we're going away from int locations? Would need to keep some things as ints to allow for */ - super.moveYHandleCollision(velocityY * GameThread.getScale()); + + +// super.moveYHandleCollision(velocityY * GameThread.getScale()); // System.out.println(velocityY * GameThread.getScale() + " " + inAir); - super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); +// super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); + collisionHandler.getAdjustedMovement(new Vector(absVelocityX * facing.mod, velocityY)); } private void updateDead() { From f3b4af39d397d5ad02fac03fc5e0957eb7ee02a8 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sun, 21 Nov 2021 16:53:15 -0500 Subject: [PATCH 073/164] New Collisions actually detect if a collision occurred. --- src/Engine/Vector.java | 17 +++- src/GameObject/GameObject.java | 152 ++++++++++++++++++++++++++------- src/GameObject/Rectangle.java | 9 ++ src/Level/Map.java | 29 ++++++- src/Level/MapEntity.java | 1 - src/Level/Player.java | 3 +- src/Utils/Point.java | 4 + 7 files changed, 175 insertions(+), 40 deletions(-) diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index ace799c..ae0b122 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -1,5 +1,7 @@ package Engine; +import Utils.Point; + public class Vector { private float x,y; @@ -64,9 +66,10 @@ public Vector getUnit() { return getDivided(Math.abs(getMagnitude())); } - public void add(Vector vector) { + public Vector add(Vector vector) { this.x += vector.x; this.y += vector.y; + return this; } public Vector multiply(float factor) { @@ -85,6 +88,14 @@ public Vector subtract(float magnitude) { return add(-magnitude); } + public Vector subtract(Vector vector) { + return add(vector.getNegative()); + } + + public Vector getSubtracted(Vector vector) { + return clone().subtract(vector); + } + public Vector add(float magnitude) { add(getUnit().multiply(magnitude)); return this; @@ -112,6 +123,10 @@ public Vector getNegative() { return clone().multiply(-1); } + public Point toPoint() { + return new Point(x, y); + } + public String toString() { return "(" + x + ", " + y + ")"; } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index d5622d5..cc88973 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -4,23 +4,29 @@ import Engine.Drawable; import Engine.GraphicsHandler; import Engine.Vector; +import Game.GameThread; import Level.Map; +import Level.MapTile; import Level.MapTileCollisionHandler; import Utils.Direction; import Utils.MathUtils; +import Utils.Point; import java.awt.*; import java.awt.image.BufferedImage; import java.util.HashMap; /** - The all important GameObject class is what every "entity" used in this game should be based off of - It encapsulates all the other class logic in the GameObject package to be a "one stop shop" for all entity needs - This includes: - 1. displaying an image (as a sprite) to represent the entity - 2. animation logic for the sprite - 3. collision detection with a map - 4. performing proper draw logic based on camera movement + * The all important GameObject class is what every "entity" used in this game should be based off of + * It encapsulates all the other class logic in the GameObject package to be a "one stop shop" for all entity needs + * This includes: + * 1. displaying an image (as a sprite) to represent the entity + * 2. animation logic for the sprite + * 3. collision detection with a map + * 4. performing proper draw logic based on camera movement + * + * @author Thomas Kwashnak + * @author Alex Thimineur + Others */ /* @@ -30,20 +36,9 @@ */ public class GameObject extends AnimatedSprite implements Drawable { - // stores game object's start position - // important to keep track of this as it's what allows the special draw logic to work -// protected float startPositionX, startPositionY; - - protected Vector startPosition, amountMoved, previousPosition; -// -// // how much game object's position has changed from start position over time -// // also important to keep track of for the special draw logic -// protected float amountMovedX, amountMovedY; -// -// // previous location the game object was in from the last frame -// protected float previousX, previousY; - + protected Vector startPosition, amountMoved; + protected MapTile lastCollided; // the map instance this game object "belongs" to. protected Map map; @@ -51,19 +46,16 @@ public class GameObject extends AnimatedSprite implements Drawable { public GameObject(SpriteSheet spriteSheet, float x, float y, String startingAnimation) { super(spriteSheet, x, y, startingAnimation); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } public GameObject(float x, float y, HashMap animations, String startingAnimation) { super(x, y, animations, startingAnimation); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, String startingAnimation) { super(image, x, y, startingAnimation); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y) { @@ -76,7 +68,6 @@ public GameObject(BufferedImage image, float x, float y) { this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, float scale) { @@ -91,7 +82,6 @@ public GameObject(BufferedImage image, float x, float y, float scale) { this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { @@ -107,7 +97,6 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { @@ -124,16 +113,113 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); startPosition = new Vector(x, y); - previousPosition = new Vector(x, y); } - @Override - public void update() { - // call to animation logic - super.update(); +// @Override +// public void update() { +// // call to animation logic +// super.update(); +// +// // update previous position to be the current position +// +// } + + /** + * Moves the game object by a given velocity, barring impacts from collisions (within the map instance) + * @param providedVelocity Amount to move. Will not be modified during movement. Will scale down to the current scale from + * {@link GameThread#getScale()} + * @author Thomas Kwashnak + */ + public void moveHandleCollision(Vector providedVelocity) { + + + //Copies the velocity scaled with current frame time + Vector velocity = providedVelocity.getMultiplied(GameThread.getScale()); + //Gets the unit vector, which is basically the unit-circle direction that the velocity is pointing towards + final Vector unit = providedVelocity.getUnit(); + final Vector negativeUnit = unit.getNegative(); + + + //Inch the object by integer increments to get closer to the position + int intIterations = (int) velocity.getMagnitude(); + for(int i = 0; i < intIterations; i++) { + //Moves a unit closer and reduces the "velocity left" by 1 + move(unit); + velocity.add(negativeUnit); + MapTile collision = getCollision(unit); + if(collision != null) { + //Move back and then break out of the loop + velocity.add(unit); + move(negativeUnit); + break; + } + } + + + } + + /** + * Checks if the game object has collided with any map tiles, and returns the collided map-tile if it has. Otherwise, returns null + * + * Copied from CollisionHandler + * @param velocity + * @return + */ + private MapTile getCollision(Vector velocity) { + //TODO modify / recreate this code to iterate through all neighbor blocks only in the half direction of the velocity +// int numberOfTilesToCheck = Math.max(getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth() + 2, 3); + + Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getPos1()); + + int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; + int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; + + MapTile[] tiles = map.getTilesInBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); + + for(MapTile tile : tiles) { + if(checkCollision(tile,velocity)) { + return tile; + } + } + +// MapTile[] tiles = map.getRange((int) tileIndex.x - 1, (int) tileIndex.y - 1, +// getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 2, ) + +// for(int i = -1; i < numberOfTilesToCheck + 1; i++) { +// for(int j = -1;j < numberOfTilesToCheck + 1; j++) { +// MapTile mapTile = getMap().getTileByPosition((int) tileIndex.x + i, (int) tileIndex.y + j); +// System.out.println((tileIndex.x + i) + " " + (tileIndex.y + j) + " " + mapTile.getTileIndex()); +// if(checkCollision(mapTile, velocity)) { +// return mapTile; +// } +// } +// } + return null; + } - // update previous position to be the current position - previousPosition.set(pos); +// /** +// * Copied from CollisionHandler +// * @param mapTile +// * @param velocity +// * @return +// */ +// private boolean checkCollision(MapTile mapTile, Vector velocity) { +// return mapTile != null && hasCollidedWithMapTile(mapTile,velocity); +// } + + /** + * Copied from CollisionHandler + * @param mapTile + * @param velocity + * @return + */ + private boolean checkCollision(MapTile mapTile, Vector velocity) { + return mapTile != null && switch (mapTile.getTileType()) { + case NOT_PASSABLE, LETHAL -> intersects(mapTile); + case JUMP_THROUGH_PLATFORM -> velocity.getY() > 0 && intersects(mapTile) && Math.round(getScaledBoundsY2() -1) == Math.round( + mapTile.getScaledBoundsY1()); + case PASSABLE -> false; + }; } // move game object along the x axis diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index f1cad11..62e3434 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -190,4 +190,13 @@ public boolean overlaps(IntersectableRectangle other) { return Math.round(intersectRectangle.getX1()) <= Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) >= Math.round(otherIntersectRectangle.getX1()) && Math.round(intersectRectangle.getY1()) <= Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) >= Math.round(otherIntersectRectangle.getY1()); } + + //TODO reduce calls + public Vector getPos1() { + return new Vector(getX1(), getY1()); + } + + public Vector getPos2() { + return new Vector(getX2(), getY2()); + } } diff --git a/src/Level/Map.java b/src/Level/Map.java index f75db98..2a4bc7f 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -223,25 +223,46 @@ public void setMapTile(int x, int y, MapTile tile) { } // returns a tile based on a position in the map + @Deprecated + /** + * uhh.. doesn't work? + */ public MapTile getTileByPosition(int xPosition, int yPosition) { + System.out.println(xPosition + " " + yPosition); Point tileIndex = getTileIndexByPosition(xPosition, yPosition); - if (isInBounds(Math.round(tileIndex.x), Math.round(tileIndex.y))) { + if (isInBounds(Math.round(tileIndex.x), Math.round(tileIndex.y))) { //useless as it already checks within getMapTile? return getMapTile(Math.round(tileIndex.x), Math.round(tileIndex.y)); } else { return null; } } + /** + * Returns a list of Tiles within the bounds listed starting at x,y and going height,width + * @param x + * @param y + * @param width + * @param height + * @return + */ + public MapTile[] getTilesInBounds(int x, int y, int width, int height) { + MapTile[] ret = new MapTile[width * height]; + for(int i = 0; i < ret.length; i++) { + ret[i] = getMapTile(x + i / width, y + i % width); + } + return ret; + } + public Point getTileIndexByPosition(Vector vector) { int xIndex = Math.round(vector.getX() / tileset.getScaledSpriteWidth()); - int yIndex = Math.round(vector.getY()) / tileset.getScaledSpriteHeight(); + int yIndex = Math.round(vector.getY() / tileset.getScaledSpriteHeight()); return new Point(xIndex,yIndex); } // returns the index of a tile (x index and y index) based on a position in the map public Point getTileIndexByPosition(float xPosition, float yPosition) { - int xIndex = Math.round(xPosition) / tileset.getScaledSpriteWidth(); - int yIndex = Math.round(yPosition) / tileset.getScaledSpriteHeight(); + int xIndex = Math.round(xPosition / tileset.getScaledSpriteWidth()); + int yIndex = Math.round(yPosition / tileset.getScaledSpriteHeight()); return new Point(xIndex, yIndex); } diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index 40e537d..b41c034 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -50,7 +50,6 @@ public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect public void initialize() { pos.set(startPosition); amountMoved = new Vector(0, 0); - previousPosition.set(pos); updateCurrentFrame(); } diff --git a/src/Level/Player.java b/src/Level/Player.java index 3f2654a..1fd88da 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -115,7 +115,8 @@ private void updatePlaying() { // super.moveYHandleCollision(velocityY * GameThread.getScale()); // System.out.println(velocityY * GameThread.getScale() + " " + inAir); // super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); - collisionHandler.getAdjustedMovement(new Vector(absVelocityX * facing.mod, velocityY)); +// collisionHandler.getAdjustedMovement(new Vector(absVelocityX * facing.mod, velocityY)); + moveHandleCollision(new Vector(absVelocityX * facing.mod, velocityY)); } private void updateDead() { diff --git a/src/Utils/Point.java b/src/Utils/Point.java index cc9b6a3..5b60c0d 100644 --- a/src/Utils/Point.java +++ b/src/Utils/Point.java @@ -33,4 +33,8 @@ public Point subtractX(int x) { public Point subtractY(int y) { return new Point(this.x, this.y - y); } + + public String toString() { + return "Point: " + x + ", " + y; + } } From b14be3c30c0ad324ef49f66ca99edaaf1fab3001 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sun, 21 Nov 2021 16:57:44 -0500 Subject: [PATCH 074/164] Added EnhancedMapTiles to the collision check --- src/GameObject/GameObject.java | 18 ++++++------------ src/Level/Player.java | 1 - 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index cc88973..09bdeb9 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -39,6 +39,7 @@ public class GameObject extends AnimatedSprite implements Drawable { protected Vector startPosition, amountMoved; protected MapTile lastCollided; + protected boolean inAir; // the map instance this game object "belongs" to. protected Map map; @@ -155,7 +156,6 @@ public void moveHandleCollision(Vector providedVelocity) { } } - } /** @@ -182,18 +182,12 @@ private MapTile getCollision(Vector velocity) { } } -// MapTile[] tiles = map.getRange((int) tileIndex.x - 1, (int) tileIndex.y - 1, -// getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 2, ) + for(MapTile enhancedTile : map.getEnhancedMapTiles()) { + if(checkCollision(enhancedTile,velocity)) { + return enhancedTile; + } + } -// for(int i = -1; i < numberOfTilesToCheck + 1; i++) { -// for(int j = -1;j < numberOfTilesToCheck + 1; j++) { -// MapTile mapTile = getMap().getTileByPosition((int) tileIndex.x + i, (int) tileIndex.y + j); -// System.out.println((tileIndex.x + i) + " " + (tileIndex.y + j) + " " + mapTile.getTileIndex()); -// if(checkCollision(mapTile, velocity)) { -// return mapTile; -// } -// } -// } return null; } diff --git a/src/Level/Player.java b/src/Level/Player.java index 1fd88da..8172423 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -27,7 +27,6 @@ public abstract class Player extends GameObject { private PlayerState playerState; private Facing facing; private LevelState levelState; - private boolean inAir; private float absVelocityX, velocityY; private CollisionHandler collisionHandler; From 487e0392be0678ee51849d5478b7253d2dcf124f Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sun, 21 Nov 2021 18:09:29 -0500 Subject: [PATCH 075/164] Collisions work... not! --- src/GameObject/GameObject.java | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 09bdeb9..2b04580 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -132,10 +132,8 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec * @author Thomas Kwashnak */ public void moveHandleCollision(Vector providedVelocity) { - - //Copies the velocity scaled with current frame time - Vector velocity = providedVelocity.getMultiplied(GameThread.getScale()); + final Vector velocity = providedVelocity.getMultiplied(GameThread.getScale()); //Gets the unit vector, which is basically the unit-circle direction that the velocity is pointing towards final Vector unit = providedVelocity.getUnit(); final Vector negativeUnit = unit.getNegative(); @@ -150,12 +148,32 @@ public void moveHandleCollision(Vector providedVelocity) { MapTile collision = getCollision(unit); if(collision != null) { //Move back and then break out of the loop - velocity.add(unit); +// velocity.add(unit); + velocity.set(unit); move(negativeUnit); + break; } } + move(velocity); + //TODO find out why this doesn't work + if((lastCollided = getCollision(unit)) != null) { + float xScale = 0, yScale = 0; + + if(velocity.getX() != 0) { //Preventing div by 0 + float xCol = velocity.getX() > 0 ? lastCollided.getBounds().getX1() : -lastCollided.getBounds().getX2(); + float xObj = velocity.getX() > 0 ? getBounds().getX2() : -getBounds().getX1(); + xScale = (xObj - xCol) / unit.getX(); + } + if(velocity.getY() != 0) { + float yCol = velocity.getY() > 0 ? lastCollided.getBounds().getY1() : -lastCollided.getBounds().getY2(); + float yObj = velocity.getY() > 0 ? getBounds().getY2() : -getBounds().getY1(); + yScale = (yObj - yCol) / unit.getY(); + } +// System.out.println(yScale + " " + velocity.getMagnitude()); + move(negativeUnit.getMultiplied(Math.max(xScale,yScale))); + } } /** From 1e668ba6db6b8f666e1c3863b2a37ed4cf5dbe4e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 11:14:49 -0500 Subject: [PATCH 076/164] Player now skips first 2 move updates Causing some bug where the tick scale was bumping above 10. Will rebuild the threads to try and clear things up. --- src/Game/GameThread.java | 3 ++- src/GameObject/GameObject.java | 5 +++++ src/Level/Player.java | 10 +++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 2fb1b8a..552b664 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -30,12 +30,13 @@ public GameThread(Runnable runnable) { /* That something is probably due to the fact that rendering (painting) is done on a run-later class, so the updates is still technically multithreaded in a way, so something's going wonky here.. + AND SOMEHOW THIS IS LAGGING ON LEVEL LOAD */ instance = this; } public static float getScale() { - return ((float) instance.elapsedTick) / 10; + return ((float) instance.elapsedTick) / 1000; } } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 2b04580..c921fbc 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -138,9 +138,13 @@ public void moveHandleCollision(Vector providedVelocity) { final Vector unit = providedVelocity.getUnit(); final Vector negativeUnit = unit.getNegative(); + System.out.println("Start Movement:\nVelocity = " + providedVelocity + ", Scaled = " + velocity); + System.out.println("Scale: " + GameThread.getScale()); + //Inch the object by integer increments to get closer to the position int intIterations = (int) velocity.getMagnitude(); + System.out.println(intIterations + " iterations"); for(int i = 0; i < intIterations; i++) { //Moves a unit closer and reduces the "velocity left" by 1 move(unit); @@ -155,6 +159,7 @@ public void moveHandleCollision(Vector providedVelocity) { break; } } + System.out.println("Configure Velocity: " + velocity); move(velocity); //TODO find out why this doesn't work if((lastCollided = getCollision(unit)) != null) { diff --git a/src/Level/Player.java b/src/Level/Player.java index 8172423..fe19b66 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -28,7 +28,8 @@ public abstract class Player extends GameObject { private Facing facing; private LevelState levelState; private float absVelocityX, velocityY; - private CollisionHandler collisionHandler; + private int moveDelay = 2; + public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { super(spriteSheet, x, y, startingAnimationName); @@ -36,7 +37,6 @@ public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimatio playerState = PlayerState.STAND; levelState = LevelState.PLAYING; facing = Facing.RIGHT; - collisionHandler = new CollisionHandler(this); } public void update() { @@ -115,7 +115,11 @@ private void updatePlaying() { // System.out.println(velocityY * GameThread.getScale() + " " + inAir); // super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); // collisionHandler.getAdjustedMovement(new Vector(absVelocityX * facing.mod, velocityY)); - moveHandleCollision(new Vector(absVelocityX * facing.mod, velocityY)); + if(moveDelay > 0) { + moveDelay--; + } else { + moveHandleCollision(new Vector(absVelocityX * facing.mod, velocityY)); + } } private void updateDead() { From 95cd0a5849a198c1fb1cb6ebbd7f86dbd4611adb Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 11:54:18 -0500 Subject: [PATCH 077/164] Re-built Game Thread --- src/Engine/GamePanel.java | 405 ++++++++++++++--------------- src/Game/Game.java | 3 +- src/Game/GameThread.java | 75 ++++-- src/Game/GameThreadDeprecated.java | 43 +++ src/Game/ThreadManager.java | 1 + src/GameObject/GameObject.java | 6 +- src/Level/CollisionHandler.java | 3 +- src/Level/Player.java | 9 +- 8 files changed, 302 insertions(+), 243 deletions(-) create mode 100644 src/Game/GameThreadDeprecated.java diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index cf7842a..6b8825a 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -1,14 +1,14 @@ package Engine; -import Game.*; +import Game.GameState; +import Game.GameThread; +import Game.ScreenCoordinator; import GameObject.Rectangle; import Level.Player; import Utils.Colors; import javax.sound.sampled.*; -//import sun.audio.AudioData; import javax.swing.*; - import java.awt.*; import java.awt.event.MouseEvent; import java.io.File; @@ -19,213 +19,206 @@ * The JPanel uses a timer to continually call cycles of update and draw */ public class GamePanel extends JPanel { - private final ScreenManager screenManager; - // used to create the game loop and cycle between update and draw calls - private Timer timer; - // used to draw graphics to the panel - private final GraphicsHandler graphicsHandler; - private boolean doPaint = false; - protected static GameWindow gameWindow; - private static ScreenCoordinator coordinator; - public static Clip clip; - private final JLabel health; - private ThreadManager gameThread; -// private ThreadManager renderThread; - - - /* - * The JPanel and various important class instances are setup here - */ - public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { - super(); - this.gameWindow = gameWindow; - this.setDoubleBuffered(true); - - health = new JLabel(); - add(health); - - this.setSize(Config.WIDTH, Config.HEIGHT); - // attaches Keyboard class's keyListener to this JPanel - this.addKeyListener(Keyboard.getKeyListener()); - - graphicsHandler = new GraphicsHandler(); - - screenManager = new ScreenManager(); - coordinator = c1; - - - - gameThread = new GameThread(() -> { - update(); - repaint(); - }); -// renderThread = new RenderThread(() -> { -// -// }); - //WORKS + + public static Clip clip; + protected static GameWindow gameWindow; + private static ScreenCoordinator coordinator; + private final ScreenManager screenManager; + // used to draw graphics to the panel + private final GraphicsHandler graphicsHandler; + private final JLabel health; + // used to create the game loop and cycle between update and draw calls + private Timer timer; + private boolean doPaint = false; + private GameThread gameThread; + // private ThreadManager gameThread; + // private ThreadManager renderThread; + + + /* + * The JPanel and various important class instances are setup here + */ + public GamePanel(ScreenCoordinator c1, GameWindow gameWindow) { + super(); + GamePanel.gameWindow = gameWindow; + this.setDoubleBuffered(true); + + health = new JLabel(); + add(health); + + this.setSize(Config.WIDTH, Config.HEIGHT); + // attaches Keyboard class's keyListener to this JPanel + this.addKeyListener(Keyboard.getKeyListener()); + + graphicsHandler = new GraphicsHandler(); + + screenManager = new ScreenManager(); + coordinator = c1; + + gameThread = new GameThread(this::repaint, this::update); + + // gameThread = new GameThreadDeprecated(() -> { + // update(); + // repaint(); + // }); + // renderThread = new RenderThread(() -> { + // + // }); + //WORKS /* However, current plan should be as follows: - First get the system to work on a single thread (with the dynamic speed and such) - THEN get the system to work on multiple threads for painting / etc */ -// timer = new Timer(1000 / Config.FPS, new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// update(); -// changeHealth(); -// if(coordinator.getGameState() == GameState.LEVEL) { -// health.show(); -// } -// else { -// health.hide(); -// } -// repaint(); -// } -// }); -// timer.setRepeats(true); -// tickGame = new GameTick(new Runnable() { -// @Override -// public void run() { -// update(); -// } -// }); -// tickRender = new GameTick(new Runnable() { -// @Override -// public void run() { -// repaint(); -// } -// }); - } - - public static ScreenCoordinator getScreenCoordinator() { - return coordinator; - } - // this is called later after instantiation, and will initialize screenManager - // this had to be done outside of the constructor because it needed to know the - // JPanel's width and height, which aren't available in the constructor - public void setupGame() { - setBackground(Colors.CORNFLOWER_BLUE); - screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); - doPaint = true; - } - - public static GameWindow getGameWindow() { - return gameWindow; - } - - public static void music(String filepath, double gain) throws LineUnavailableException, UnsupportedAudioFileException, IOException { - - AudioInputStream audioInput = AudioSystem.getAudioInputStream(new File(filepath)); - clip = AudioSystem.getClip(); - clip.open(audioInput); - setVolume(gain); - clip.start(); - - clip.loop(Clip.LOOP_CONTINUOUSLY); - - } - public static void setVolume(double gain) { - try { - FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); - float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); - gainControl.setValue(dB); - } catch(Exception e) { - e.printStackTrace(); - } - - } - - public static void setVolumeOff() { - - setVolume(0); - } - public static void setVolumeLow() { - - setVolume(.05); - } - - public static void setVolumeMed() { - setVolume(.1); - - } - - public static void setVolumeHigh() { - setVolume(.3); - - } - - // this starts the timer (the game loop is started here - public void startGame() { -// timer.start(); - gameThread.start(); -// renderThread.start(); - - try { - music("Resources/Music/music.wav",.05); - } catch(Exception e) { - try { - music("Resources/Music/music.mp3",.05); - } catch(Exception f) { - - } - } - } - - public ScreenManager getScreenManager() { - return screenManager; - } - - public void update() { - screenManager.update(); - changeHealth(); - } - - public void draw() { - screenManager.draw(graphicsHandler); - - - } - - // Checks the players health and accordingly changes to the image with the corresponding number of hearts - public void changeHealth() { - if(coordinator.getGameState() == GameState.LEVEL) { - if(Player.PLAYER_HEALTH == 3) { - health.setIcon(new ImageIcon(ImageLoader.load("3 Hearts.png"))); - } - - else if(Player.PLAYER_HEALTH == 2) { - health.setIcon(new ImageIcon(ImageLoader.load("2 Hearts.png"))); - } - - else if(Player.PLAYER_HEALTH == 1) { - health.setIcon(new ImageIcon(ImageLoader.load("1 Heart.png"))); - } - - else { - health.setIcon(new ImageIcon(ImageLoader.load("0 Hearts.png"))); - } - } - - if(coordinator.getGameState() == GameState.MENU) { - Player.PLAYER_HEALTH = 3; - } - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - // every repaint call will schedule this method to be called - // when called, it will setup the graphics handler and then call this class's - // draw method - graphicsHandler.setGraphics((Graphics2D) g); - if (doPaint) { - draw(); - } - } - - public static void mouseClicked(MouseEvent e) { -// System.out.println("Click: " + e.getPoint()); - coordinator.mouseClicked(e); - } - + // timer = new Timer(1000 / Config.FPS, new ActionListener() { + // public void actionPerformed(ActionEvent e) { + // update(); + // changeHealth(); + // if(coordinator.getGameState() == GameState.LEVEL) { + // health.show(); + // } + // else { + // health.hide(); + // } + // repaint(); + // } + // }); + // timer.setRepeats(true); + // tickGame = new GameTick(new Runnable() { + // @Override + // public void run() { + // update(); + // } + // }); + // tickRender = new GameTick(new Runnable() { + // @Override + // public void run() { + // repaint(); + // } + // }); + } + + public void update() { + + screenManager.update(); + changeHealth(); + } + + // Checks the players health and accordingly changes to the image with the corresponding number of hearts + public void changeHealth() { + if (coordinator.getGameState() == GameState.LEVEL) { + if (Player.PLAYER_HEALTH == 3) { + health.setIcon(new ImageIcon(ImageLoader.load("3 Hearts.png"))); + } else if (Player.PLAYER_HEALTH == 2) { + health.setIcon(new ImageIcon(ImageLoader.load("2 Hearts.png"))); + } else if (Player.PLAYER_HEALTH == 1) { + health.setIcon(new ImageIcon(ImageLoader.load("1 Heart.png"))); + } else { + health.setIcon(new ImageIcon(ImageLoader.load("0 Hearts.png"))); + } + } + + if (coordinator.getGameState() == GameState.MENU) { + Player.PLAYER_HEALTH = 3; + } + } + + public static ScreenCoordinator getScreenCoordinator() { + return coordinator; + } + + public static GameWindow getGameWindow() { + return gameWindow; + } + + public static void setVolumeOff() { + + setVolume(0); + } + + public static void setVolume(double gain) { + try { + FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); + gainControl.setValue(dB); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void setVolumeLow() { + + setVolume(.05); + } + + public static void setVolumeMed() { + setVolume(.1); + } + + public static void setVolumeHigh() { + setVolume(.3); + } + + public static void mouseClicked(MouseEvent e) { + // System.out.println("Click: " + e.getPoint()); + coordinator.mouseClicked(e); + } + + // this is called later after instantiation, and will initialize screenManager + // this had to be done outside of the constructor because it needed to know the + // JPanel's width and height, which aren't available in the constructor + public void setupGame() { + setBackground(Colors.CORNFLOWER_BLUE); + screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); + doPaint = true; + } + + // this starts the timer (the game loop is started here + public void startGame() { + // timer.start(); + gameThread.start(); + // renderThread.start(); + + try { + music("Resources/Music/music.wav", .05); + } catch (Exception e) { + try { + music("Resources/Music/music.mp3", .05); + } catch (Exception f) { + + } + } + } + + public static void music(String filepath, double gain) throws LineUnavailableException, UnsupportedAudioFileException, IOException { + + AudioInputStream audioInput = AudioSystem.getAudioInputStream(new File(filepath)); + clip = AudioSystem.getClip(); + clip.open(audioInput); + setVolume(gain); + clip.start(); + + clip.loop(Clip.LOOP_CONTINUOUSLY); + } + + public ScreenManager getScreenManager() { + return screenManager; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + // every repaint call will schedule this method to be called + // when called, it will setup the graphics handler and then call this class's + // draw method + graphicsHandler.setGraphics((Graphics2D) g); + if (doPaint) { + draw(); + } + } + + public void draw() { + screenManager.draw(graphicsHandler); + } } diff --git a/src/Game/Game.java b/src/Game/Game.java index e1f57d4..bea8f84 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -18,9 +18,10 @@ public static void main(String[] args) { public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); - gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); + gameWindow.startGame(); + // DEBUG USE ONLY // screenManager.setCurrentScreen(new DebugScreen()); } diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 552b664..c2bbc1a 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -1,42 +1,61 @@ package Game; -import java.awt.*; +public class GameThread implements Runnable { -public class GameThread extends ThreadManager { + private static double delta_time; + private static final long UPDATE_FIXED_MS; - private static GameThread instance; - - private static final long RENDER_DELAY_MS; + public static final float UPDATE_FACTOR; static { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - // Sets the highest refresh rate to be the highest display rate - int highestRefreshRate = 0; - for(GraphicsDevice device : ge.getScreenDevices()) { - int refreshRate = device.getDisplayMode().getRefreshRate(); - System.out.println(refreshRate); - if(refreshRate > highestRefreshRate) { - highestRefreshRate = refreshRate; - } - } - RENDER_DELAY_MS = 1000 / highestRefreshRate; + UPDATE_FIXED_MS = 5; + UPDATE_FACTOR = UPDATE_FIXED_MS / 15.0f; + } + + private final Thread thread; + private final Runnable render, update; + private boolean running = true; + + + public GameThread(Runnable render, Runnable update) { + thread = new Thread(this); + this.render = render; + this.update = update; } - public GameThread(Runnable runnable) { - super(runnable,5); - //Somehow setting tickDelay to 0 causes the game to break in some way? - //somehow even 1 is bad.... SOMETHING.. is going on here - /* - That something is probably due to the fact that rendering (painting) is done on a run-later class, so the updates is still technically - multithreaded in a way, so something's going wonky here.. - AND SOMEHOW THIS IS LAGGING ON LEVEL LOAD - */ - instance = this; + public void start() { + thread.start(); } - public static float getScale() { - return ((float) instance.elapsedTick) / 1000; + public void stop() { + running = false; } + @Override + public void run() { +// lastTime = System.currentTimeMillis(); + long nextUpdateTime = System.currentTimeMillis(); + long currentTime; + while(running) { + currentTime = System.currentTimeMillis(); + while(currentTime > nextUpdateTime) { + update.run(); + nextUpdateTime += UPDATE_FIXED_MS; + } + render.run(); + +// delta_time = ((double) timePassed) / 1000; +// while(timePassed >= UPDATE_FIXED_MS) { +// timePassed -= UPDATE_FIXED_MS; +// update.run(); +// } +// +// render.run(); +// currentTime = System.currentTimeMillis(); +// timePassed += currentTime - lastTime; +// lastTime = currentTime; + } + running = true; + } } diff --git a/src/Game/GameThreadDeprecated.java b/src/Game/GameThreadDeprecated.java new file mode 100644 index 0000000..6d22188 --- /dev/null +++ b/src/Game/GameThreadDeprecated.java @@ -0,0 +1,43 @@ +package Game; + +import java.awt.*; + +@Deprecated +public class GameThreadDeprecated extends ThreadManager { + + + private static GameThreadDeprecated instance; + + private static final long RENDER_DELAY_MS; + + static { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // Sets the highest refresh rate to be the highest display rate + int highestRefreshRate = 0; + for(GraphicsDevice device : ge.getScreenDevices()) { + int refreshRate = device.getDisplayMode().getRefreshRate(); + System.out.println(refreshRate); + if(refreshRate > highestRefreshRate) { + highestRefreshRate = refreshRate; + } + } + RENDER_DELAY_MS = 1000 / highestRefreshRate; + } + + public GameThreadDeprecated(Runnable runnable) { + super(runnable,5); + //Somehow setting tickDelay to 0 causes the game to break in some way? + //somehow even 1 is bad.... SOMETHING.. is going on here + /* + That something is probably due to the fact that rendering (painting) is done on a run-later class, so the updates is still technically + multithreaded in a way, so something's going wonky here.. + AND SOMEHOW THIS IS LAGGING ON LEVEL LOAD + */ + instance = this; + } + + public static float getScale() { + return ((float) instance.elapsedTick) / 1000; + } + +} diff --git a/src/Game/ThreadManager.java b/src/Game/ThreadManager.java index eb8ae0e..ff14695 100644 --- a/src/Game/ThreadManager.java +++ b/src/Game/ThreadManager.java @@ -3,6 +3,7 @@ /** * @author Thomas Kwashnak */ +@Deprecated public class ThreadManager implements Runnable { private Thread thread; diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index c921fbc..dbe29d4 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -5,6 +5,7 @@ import Engine.GraphicsHandler; import Engine.Vector; import Game.GameThread; +import Game.GameThreadDeprecated; import Level.Map; import Level.MapTile; import Level.MapTileCollisionHandler; @@ -128,18 +129,17 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec /** * Moves the game object by a given velocity, barring impacts from collisions (within the map instance) * @param providedVelocity Amount to move. Will not be modified during movement. Will scale down to the current scale from - * {@link GameThread#getScale()} + * {@link GameThreadDeprecated#getScale()} * @author Thomas Kwashnak */ public void moveHandleCollision(Vector providedVelocity) { //Copies the velocity scaled with current frame time - final Vector velocity = providedVelocity.getMultiplied(GameThread.getScale()); + final Vector velocity = providedVelocity.getMultiplied(GameThread.UPDATE_FACTOR); //Gets the unit vector, which is basically the unit-circle direction that the velocity is pointing towards final Vector unit = providedVelocity.getUnit(); final Vector negativeUnit = unit.getNegative(); System.out.println("Start Movement:\nVelocity = " + providedVelocity + ", Scaled = " + velocity); - System.out.println("Scale: " + GameThread.getScale()); //Inch the object by integer increments to get closer to the position diff --git a/src/Level/CollisionHandler.java b/src/Level/CollisionHandler.java index e54d159..8a60bca 100644 --- a/src/Level/CollisionHandler.java +++ b/src/Level/CollisionHandler.java @@ -2,6 +2,7 @@ import Engine.Vector; import Game.GameThread; +import Game.GameThreadDeprecated; import GameObject.GameObject; import Utils.Point; @@ -22,7 +23,7 @@ public Map getMap() { } public Vector getAdjustedMovement(Vector velocity) { - velocity.multiply(GameThread.getScale()); + velocity.multiply(GameThread.UPDATE_FACTOR); Vector unit = velocity.getUnit(), cloned = velocity.clone(); Vector originalPos = gameObject.getPos().clone(); diff --git a/src/Level/Player.java b/src/Level/Player.java index fe19b66..3283e90 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -3,6 +3,7 @@ import Engine.KeyboardAction; import Engine.Vector; import Game.GameThread; +import Game.GameThreadDeprecated; import GameObject.GameObject; import GameObject.SpriteSheet; import Level.PlayerState.Facing; @@ -133,7 +134,7 @@ private void updateDead() { } else { velocityY = DEATH_Y_VELOCITY; } - setY(getY() + velocityY * GameThread.getScale()); + setY(getY() + velocityY * GameThread.UPDATE_FACTOR); } private void updateWin() { @@ -142,10 +143,10 @@ private void updateWin() { if (inAir) { playerState = PlayerState.FALL; applyGravity(MAX_FALL_VELOCITY); - moveYHandleCollision(velocityY * GameThread.getScale()); + moveYHandleCollision(velocityY * GameThread.UPDATE_FACTOR); } else { playerState = PlayerState.WALK; - moveXHandleCollision(walkSpeed * GameThread.getScale()); + moveXHandleCollision(walkSpeed * GameThread.UPDATE_FACTOR); } } else for (PlayerListener listener : playerListeners) { listener.onLevelCompleted(); @@ -154,7 +155,7 @@ private void updateWin() { private void applyGravity(float maxFallVelocity) { if (velocityY < maxFallVelocity) { - velocityY += gravity * GameThread.getScale(); + velocityY += gravity * GameThread.UPDATE_FACTOR; } } From 05f7b56f334b302a0dd82b370a8a8e5bcdbe78de Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 12:19:52 -0500 Subject: [PATCH 078/164] Cat hits the ground! Kindof --- src/GameObject/GameObject.java | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index dbe29d4..48afb4b 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -166,17 +166,39 @@ public void moveHandleCollision(Vector providedVelocity) { float xScale = 0, yScale = 0; if(velocity.getX() != 0) { //Preventing div by 0 - float xCol = velocity.getX() > 0 ? lastCollided.getBounds().getX1() : -lastCollided.getBounds().getX2(); - float xObj = velocity.getX() > 0 ? getBounds().getX2() : -getBounds().getX1(); - xScale = (xObj - xCol) / unit.getX(); +// float xCol = velocity.getX() > 0 ? lastCollided.getBounds().getX1() : -lastCollided.getBounds().getX2(); +// float xObj = velocity.getX() > 0 ? getBounds().getX2() : -getBounds().getX1(); +// xScale = (xObj - xCol) / unit.getX(); + float xCol, xObj; + if(velocity.getX() > 0) { + xCol = lastCollided.getPos().getX(); + xObj = pos.getX() + getBounds().getWidth(); + } else { + xCol = lastCollided.getPos().getX() + lastCollided.getBounds().getWidth(); + xObj = pos.getX(); + } + if(xObj > xCol) { + xScale = (xObj - xCol) / unit.getX(); + } } if(velocity.getY() != 0) { - float yCol = velocity.getY() > 0 ? lastCollided.getBounds().getY1() : -lastCollided.getBounds().getY2(); - float yObj = velocity.getY() > 0 ? getBounds().getY2() : -getBounds().getY1(); - yScale = (yObj - yCol) / unit.getY(); +// float yCol = velocity.getY() > 0 ? lastCollided.getBounds().getY1() : -lastCollided.getBounds().getY2(); +// float yObj = velocity.getY() > 0 ? getBounds().getY2() : -getBounds().getY1(); + float yCol, yObj; + if(velocity.getY() > 0) { + yCol = lastCollided.getPos().getY(); + yObj = pos.getY() + getBounds().getHeight(); + } else { + yCol = lastCollided.getPos().getY() + lastCollided.getBounds().getHeight(); + yObj = pos.getY(); + } + if(yObj > yCol) { + yScale = (yObj - yCol) / unit.getY(); + } } // System.out.println(yScale + " " + velocity.getMagnitude()); +// System.out.println(negativeUnit.getMultiplied(Math.max(xScale,yScale))); move(negativeUnit.getMultiplied(Math.max(xScale,yScale))); } } From a59c96e097ab027dc8dad9110ddade000d5efe1f Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 12:31:20 -0500 Subject: [PATCH 079/164] Back to the drawing board --- src/GameObject/GameObject.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 48afb4b..0f403be 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -161,14 +161,10 @@ public void moveHandleCollision(Vector providedVelocity) { } System.out.println("Configure Velocity: " + velocity); move(velocity); - //TODO find out why this doesn't work if((lastCollided = getCollision(unit)) != null) { float xScale = 0, yScale = 0; if(velocity.getX() != 0) { //Preventing div by 0 -// float xCol = velocity.getX() > 0 ? lastCollided.getBounds().getX1() : -lastCollided.getBounds().getX2(); -// float xObj = velocity.getX() > 0 ? getBounds().getX2() : -getBounds().getX1(); -// xScale = (xObj - xCol) / unit.getX(); float xCol, xObj; if(velocity.getX() > 0) { xCol = lastCollided.getPos().getX(); @@ -183,8 +179,6 @@ public void moveHandleCollision(Vector providedVelocity) { } if(velocity.getY() != 0) { -// float yCol = velocity.getY() > 0 ? lastCollided.getBounds().getY1() : -lastCollided.getBounds().getY2(); -// float yObj = velocity.getY() > 0 ? getBounds().getY2() : -getBounds().getY1(); float yCol, yObj; if(velocity.getY() > 0) { yCol = lastCollided.getPos().getY(); @@ -196,9 +190,10 @@ public void moveHandleCollision(Vector providedVelocity) { if(yObj > yCol) { yScale = (yObj - yCol) / unit.getY(); } + System.out.println(yCol + " " + yObj); } -// System.out.println(yScale + " " + velocity.getMagnitude()); -// System.out.println(negativeUnit.getMultiplied(Math.max(xScale,yScale))); + inAir = xScale > yScale; + move(negativeUnit.getMultiplied(Math.max(xScale,yScale))); } } From 1b6c450be8b364b99394f1a3a3fbd4a71240cb9c Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 14:20:01 -0500 Subject: [PATCH 080/164] Vector Physics should work However I bet the tiles it's trying to get isn't working --- src/Engine/Vector.java | 25 +++++++ src/GameObject/GameObject.java | 116 +++++++++++++++++++++++++++++++-- src/Level/Player.java | 1 - src/Maps/TestTutorial.java | 2 +- 4 files changed, 135 insertions(+), 9 deletions(-) diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index ae0b122..748d5a4 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -15,6 +15,11 @@ public Vector(float x, float y) { this.y = y; } + public Vector(Point point) { + this.x = point.x; + this.y = point.y; + } + public float getX() { return x; } @@ -101,6 +106,10 @@ public Vector add(float magnitude) { return this; } + public Vector getAdd(Vector vector) { + return new Vector(x + vector.x, y + vector.y); + } + public Vector clone() { return new Vector(x,y); } @@ -130,4 +139,20 @@ public Point toPoint() { public String toString() { return "(" + x + ", " + y + ")"; } + + public Vector getFlipped() { + return new Vector(y,x); + } + + public boolean equals(Object other) { + return other instanceof Vector && ((Vector) other).x == this.x && ((Vector) other).y == this.y; + } + + public void multiplyX(float magnitude) { + x *= magnitude; + } + + public void multiplyY(float magnitude) { + y *= magnitude; + } } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 0f403be..fe4bae7 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -9,6 +9,7 @@ import Level.Map; import Level.MapTile; import Level.MapTileCollisionHandler; +import Level.TileType; import Utils.Direction; import Utils.MathUtils; import Utils.Point; @@ -126,13 +127,112 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec // // } + public void moveHandleCollision(Vector providedVelocity) { + Vector velocity = providedVelocity.getMultiplied(GameThread.UPDATE_FACTOR); + Vector originalVelocity = velocity.clone(); + Vector unit = velocity.getUnit(); + + Vector[] startingPoints = new Vector[] { + pos, pos.getAdd(new Vector(getBounds().getWidth(),0)), pos.getAdd(new Vector(0,getBounds().getHeight())), + pos.getAdd(new Vector(getBounds().getWidth(),getBounds().getHeight())) + }; + + + Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getPos1()); + + int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; + int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; + + MapTile[] tiles = map.getTilesInBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); + + //this doesn't seem to work + + System.out.println("Velocity: " + velocity); + + for(MapTile mapTile : tiles) { + checkMapTile(startingPoints,velocity,mapTile); + } + + for(MapTile mapTile : map.getEnhancedMapTiles()) { + checkMapTile(startingPoints,velocity,mapTile); + } + + System.out.println("Update Velocity: " + velocity); + move(velocity); + } +// +// /** +// * +// * @param startPosition +// * @param velocity +// * @param mapTile +// * @return +// */ +// private boolean rayIntersects(Vector startPosition, Vector velocity, MapTile mapTile) { + +// float ySlope = velocity.getY() / velocity.getX(), xSlope = velocity.getX() / velocity.getY(); +// +// //Check left bound +// float y = ySlope * (x1 - startPosition.getX()) + startPosition.getY(); +// boolean intersectsLeft = y <= y2 && y >= y1; +// y = ySlope * (x2 - startPosition.getX()) + startPosition.getY(); +// boolean intersectsRight = y <= y2 && y >= y1; +// +// return false; +// } + + private void checkMapTile(Vector[] startingPoints, Vector velocity, MapTile mapTile) { + if(mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0)) { + updateVelocity(startingPoints,velocity,mapTile); + } + } + + private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile mapTile) { + float x1 = mapTile.getPos().getX(), x2 = mapTile.getPos().getX() + mapTile.getBounds().getWidth(); + float y1 = mapTile.getPos().getY(), y2 = mapTile.getPos().getY() + mapTile.getBounds().getHeight(); + + for(Vector start : startingPoints) { + System.out.println(velocity + " " + start + " " + x1 + " " + x2 + " " + y1 + " " + y2); + float xLambda = Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2)); + float yLambda = Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), + findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2)); + + if(xLambda > yLambda) { + velocity.multiplyY(yLambda); + velocity.multiplyX( Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2))); + } else { + velocity.multiplyX(xLambda); + velocity.multiplyY(Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), + findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2))); + } + +// if(Math.abs(start.getX() - mapTile.getX()) > Math.abs(start.getY() - mapTile.getY())) { +// +// +// velocity.multiplyY(); +// } else { +// velocity.multiplyY(Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), +// findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2))); +// velocity.multiplyX(Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2))); +// } + } + } + + private float findCoefficient(Vector startPosition, Vector velocity, float v, float lowerBound, float upperBound) { + float lambda = (v - startPosition.getX()) / velocity.getX(); + float y = velocity.getY() * lambda + startPosition.getY(); + //return lambda only if it is less than 1 and the y position is within the bounds + return (lambda >= 0 && lambda < 1 && (y <= upperBound && y >= lowerBound)) ? lambda : 1; + } + /** * Moves the game object by a given velocity, barring impacts from collisions (within the map instance) * @param providedVelocity Amount to move. Will not be modified during movement. Will scale down to the current scale from * {@link GameThreadDeprecated#getScale()} * @author Thomas Kwashnak */ - public void moveHandleCollision(Vector providedVelocity) { + @Deprecated + public void moveHandleCollisionIterative(Vector providedVelocity) { //Copies the velocity scaled with current frame time final Vector velocity = providedVelocity.getMultiplied(GameThread.UPDATE_FACTOR); //Gets the unit vector, which is basically the unit-circle direction that the velocity is pointing towards @@ -149,7 +249,7 @@ public void moveHandleCollision(Vector providedVelocity) { //Moves a unit closer and reduces the "velocity left" by 1 move(unit); velocity.add(negativeUnit); - MapTile collision = getCollision(unit); + MapTile collision = getCollisionBounds(unit); if(collision != null) { //Move back and then break out of the loop // velocity.add(unit); @@ -161,7 +261,7 @@ public void moveHandleCollision(Vector providedVelocity) { } System.out.println("Configure Velocity: " + velocity); move(velocity); - if((lastCollided = getCollision(unit)) != null) { + if((lastCollided = getCollisionBounds(unit)) != null) { float xScale = 0, yScale = 0; if(velocity.getX() != 0) { //Preventing div by 0 @@ -205,7 +305,8 @@ public void moveHandleCollision(Vector providedVelocity) { * @param velocity * @return */ - private MapTile getCollision(Vector velocity) { + @Deprecated + private MapTile getCollisionBounds(Vector velocity) { //TODO modify / recreate this code to iterate through all neighbor blocks only in the half direction of the velocity // int numberOfTilesToCheck = Math.max(getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth() + 2, 3); @@ -217,13 +318,13 @@ private MapTile getCollision(Vector velocity) { MapTile[] tiles = map.getTilesInBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); for(MapTile tile : tiles) { - if(checkCollision(tile,velocity)) { + if(checkCollisionBounds(tile, velocity)) { return tile; } } for(MapTile enhancedTile : map.getEnhancedMapTiles()) { - if(checkCollision(enhancedTile,velocity)) { + if(checkCollisionBounds(enhancedTile, velocity)) { return enhancedTile; } } @@ -247,7 +348,8 @@ private MapTile getCollision(Vector velocity) { * @param velocity * @return */ - private boolean checkCollision(MapTile mapTile, Vector velocity) { + @Deprecated + private boolean checkCollisionBounds(MapTile mapTile, Vector velocity) { return mapTile != null && switch (mapTile.getTileType()) { case NOT_PASSABLE, LETHAL -> intersects(mapTile); case JUMP_THROUGH_PLATFORM -> velocity.getY() > 0 && intersects(mapTile) && Math.round(getScaledBoundsY2() -1) == Math.round( diff --git a/src/Level/Player.java b/src/Level/Player.java index 3283e90..172ac68 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -3,7 +3,6 @@ import Engine.KeyboardAction; import Engine.Vector; import Game.GameThread; -import Game.GameThreadDeprecated; import GameObject.GameObject; import GameObject.SpriteSheet; import Level.PlayerState.Facing; diff --git a/src/Maps/TestTutorial.java b/src/Maps/TestTutorial.java index 69bb925..2f83c3f 100644 --- a/src/Maps/TestTutorial.java +++ b/src/Maps/TestTutorial.java @@ -20,7 +20,7 @@ public class TestTutorial extends Map { public TestTutorial() { - super("test_tutorial.txt", new CommonTileset(), new Point(1, 11)); + super("test_tutorial.txt", new CommonTileset(), new Point(1, 8)); } @Override From 3031dc2a3ee391be1f21ffe241b2d1349fece078 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 14:57:46 -0500 Subject: [PATCH 081/164] Added method in Map to get mapTiles Uses l1 distance (or is it l-infinity distance) to prune to a list --- src/GameObject/GameObject.java | 37 +++++++++++++++++++------- src/Level/CollisionHandler.java | 3 +-- src/Level/Map.java | 46 ++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index fe4bae7..97deddb 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -17,6 +17,7 @@ import java.awt.*; import java.awt.image.BufferedImage; import java.util.HashMap; +import java.util.List; /** * The all important GameObject class is what every "entity" used in this game should be based off of @@ -140,10 +141,15 @@ public void moveHandleCollision(Vector providedVelocity) { Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getPos1()); - int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; - int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; +// int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; +// int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; + + float boundingVelocity = (float) Math.max(velocity.getMagnitude(),getBounds().getWidth() * 1.5); + +// int rangeHeight = (int) ( (boundingVelocity + getBounds().getHeight()) / map.getTileset().getScaledSpriteHeight()) * 2; +// int rangeWidth = (int) ( (boundingVelocity + getBounds().getWidth()) / map.getTileset().getScaledSpriteWidth()) * 2; - MapTile[] tiles = map.getTilesInBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); + List tiles = map.getMapTilesInRange(getCenter(), boundingVelocity); //this doesn't seem to work @@ -152,10 +158,10 @@ public void moveHandleCollision(Vector providedVelocity) { for(MapTile mapTile : tiles) { checkMapTile(startingPoints,velocity,mapTile); } - - for(MapTile mapTile : map.getEnhancedMapTiles()) { - checkMapTile(startingPoints,velocity,mapTile); - } +// +// for(MapTile mapTile : map.getEnhancedMapTiles()) { +// checkMapTile(startingPoints,velocity,mapTile); +// } System.out.println("Update Velocity: " + velocity); move(velocity); @@ -182,7 +188,7 @@ public void moveHandleCollision(Vector providedVelocity) { // } private void checkMapTile(Vector[] startingPoints, Vector velocity, MapTile mapTile) { - if(mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0)) { + if(mapTile != null && (mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0))) { updateVelocity(startingPoints,velocity,mapTile); } } @@ -192,7 +198,7 @@ private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile ma float y1 = mapTile.getPos().getY(), y2 = mapTile.getPos().getY() + mapTile.getBounds().getHeight(); for(Vector start : startingPoints) { - System.out.println(velocity + " " + start + " " + x1 + " " + x2 + " " + y1 + " " + y2); + System.out.print(velocity + " " + start + " " + x1 + " " + x2 + " " + y1 + " " + y2); float xLambda = Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2)); float yLambda = Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2)); @@ -206,6 +212,8 @@ private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile ma findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2))); } + System.out.println(" " + xLambda + " " + yLambda); + // if(Math.abs(start.getX() - mapTile.getX()) > Math.abs(start.getY() - mapTile.getY())) { // // @@ -219,6 +227,11 @@ private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile ma } private float findCoefficient(Vector startPosition, Vector velocity, float v, float lowerBound, float upperBound) { + + if(velocity.getX() == 0) { + return 1; + } + float lambda = (v - startPosition.getX()) / velocity.getX(); float y = velocity.getY() * lambda + startPosition.getY(); //return lambda only if it is less than 1 and the y position is within the bounds @@ -315,7 +328,7 @@ private MapTile getCollisionBounds(Vector velocity) { int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; - MapTile[] tiles = map.getTilesInBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); + MapTile[] tiles = map.getTilesInIndexBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); for(MapTile tile : tiles) { if(checkCollisionBounds(tile, velocity)) { @@ -571,4 +584,8 @@ public Map getMap() { return map; } + public Vector getCenter() { + return pos.getAdd(new Vector(getBounds().getWidth() / 2f, getBounds().getHeight() / 2f)); + } + } diff --git a/src/Level/CollisionHandler.java b/src/Level/CollisionHandler.java index 8a60bca..bf047f5 100644 --- a/src/Level/CollisionHandler.java +++ b/src/Level/CollisionHandler.java @@ -2,7 +2,6 @@ import Engine.Vector; import Game.GameThread; -import Game.GameThreadDeprecated; import GameObject.GameObject; import Utils.Point; @@ -56,7 +55,7 @@ private MapTile getCollision(Vector velocity) { Point tileIndex = getMap().getTileIndexByPosition(gameObject.getPos()); for(int i = -1;i < numberOfTilesToCheck + 1; i++) { for(int j = -1;j < numberOfTilesToCheck + 1; j++) { - MapTile mapTile = getMap().getTileByPosition((int) tileIndex.x + i, (int) tileIndex.y + j); + MapTile mapTile = getMap().getTileByIntPosition((int) tileIndex.x + i, (int) tileIndex.y + j); if(checkCollision(mapTile, velocity)) { return mapTile; } diff --git a/src/Level/Map.java b/src/Level/Map.java index 2a4bc7f..fff4124 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -8,6 +8,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; +import java.util.List; import java.util.Scanner; /* @@ -223,12 +224,11 @@ public void setMapTile(int x, int y, MapTile tile) { } // returns a tile based on a position in the map - @Deprecated /** * uhh.. doesn't work? */ - public MapTile getTileByPosition(int xPosition, int yPosition) { - System.out.println(xPosition + " " + yPosition); + @Deprecated + public MapTile getTileByIntPosition(int xPosition, int yPosition) { Point tileIndex = getTileIndexByPosition(xPosition, yPosition); if (isInBounds(Math.round(tileIndex.x), Math.round(tileIndex.y))) { //useless as it already checks within getMapTile? return getMapTile(Math.round(tileIndex.x), Math.round(tileIndex.y)); @@ -245,7 +245,8 @@ public MapTile getTileByPosition(int xPosition, int yPosition) { * @param height * @return */ - public MapTile[] getTilesInBounds(int x, int y, int width, int height) { + @Deprecated + public MapTile[] getTilesInIndexBounds(int x, int y, int width, int height) { MapTile[] ret = new MapTile[width * height]; for(int i = 0; i < ret.length; i++) { ret[i] = getMapTile(x + i / width, y + i % width); @@ -253,6 +254,43 @@ public MapTile[] getTilesInBounds(int x, int y, int width, int height) { return ret; } + public MapTile[] getTilesInBounds(Vector start, int width, int height) { + MapTile[] ret = new MapTile[width * height]; + Point s = getTileIndexByPosition(start); + int x = (int) s.x, y = (int) s.y; + for(int i = 0; i < ret.length; i++) { + ret[i] = getMapTile(x + i / width, y + i % width); + } + return ret; + } + + /** + * Cuts down the list of mapTiles to only ones that are at most 2 * length distance away. Also includes enhancedMapTiles + * @param origin + * @param length + * @return + */ + public List getMapTilesInRange(Vector origin, float length) { + List tiles = new ArrayList<>((int) (4 * length * length / tileset.getScaledSpriteHeight() / tileset.getScaledSpriteWidth())); + for(MapTile tile : mapTiles) { + if(Math.min(Math.abs(tile.getCenter().getX() - origin.getX()), Math.abs(tile.getCenter().getY() - origin.getY())) < length) { + tiles.add(tile); + } + } + for(MapTile tile : enhancedMapTiles) { + if(Math.min(Math.abs(tile.getCenter().getX() - origin.getX()), Math.abs(tile.getCenter().getY() - origin.getY())) < length) { + tiles.add(tile); + } + } + return tiles; + } + + public MapTile getTileByPosition(Vector position) { + int xIndex = (int) (position.getX() / tileset.getScaledSpriteWidth()); + int yIndex = (int) (position.getY() / tileset.getScaledSpriteHeight()); + return getMapTile(xIndex,yIndex); + } + public Point getTileIndexByPosition(Vector vector) { int xIndex = Math.round(vector.getX() / tileset.getScaledSpriteWidth()); int yIndex = Math.round(vector.getY() / tileset.getScaledSpriteHeight()); From a9da4567b1aa0811eb5278567c08692160f012ae Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 22 Nov 2021 15:31:11 -0500 Subject: [PATCH 082/164] Add in inAir calculations --- src/GameObject/GameObject.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 97deddb..8c7996b 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -165,6 +165,7 @@ public void moveHandleCollision(Vector providedVelocity) { System.out.println("Update Velocity: " + velocity); move(velocity); + inAir = velocity.getY() != 0; } // // /** @@ -235,7 +236,7 @@ private float findCoefficient(Vector startPosition, Vector velocity, float v, fl float lambda = (v - startPosition.getX()) / velocity.getX(); float y = velocity.getY() * lambda + startPosition.getY(); //return lambda only if it is less than 1 and the y position is within the bounds - return (lambda >= 0 && lambda < 1 && (y <= upperBound && y >= lowerBound)) ? lambda : 1; + return (lambda >= 0 && lambda < 1 && (y < upperBound && y > lowerBound)) ? lambda : 1; } /** From d4f6c8df50c1e6b4b81108f8f7b327709440c098 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 12:33:34 -0500 Subject: [PATCH 083/164] Deprecated RectangleOld.java, created new Rectangle.java --- src/Builders/FrameBuilder.java | 8 +- src/Engine/GamePanel.java | 4 +- src/Engine/ScreenManager.java | 10 +- src/Engine/Vector.java | 2 +- .../HorizontalMovingPlatform.java | 4 +- src/GameObject/AnimatedSprite.java | 14 +- src/GameObject/Frame.java | 2 +- src/GameObject/GameObject.java | 63 ++-- src/GameObject/Hitbox.java | 8 + src/GameObject/Intersectable.java | 7 + ...le.java => IntersectableRectangleOld.java} | 5 +- src/GameObject/Overlappable.java | 5 + src/GameObject/Rectangle.java | 300 +++++++----------- src/GameObject/RectangleOld.java | 203 ++++++++++++ src/GameObject/Sprite.java | 26 +- src/Level/Camera.java | 4 +- src/Level/Enemy.java | 4 +- src/Level/EnhancedMapTile.java | 4 +- src/Level/MapEntity.java | 2 +- src/Level/MapTile.java | 4 +- src/Level/NPC.java | 4 +- src/Level/Projectile.java | 4 +- src/Maps/BossBattle.java | 6 +- src/Maps/TestMap.java | 4 +- src/Maps/TestMap2.java | 4 - src/Maps/TestMap3.java | 5 +- src/Maps/TestMap4.java | 6 +- src/Maps/TestMap5.java | 5 +- src/Maps/TestMap6.java | 9 +- src/Maps/TestMap7.java | 7 +- src/Maps/TestTutorial.java | 5 +- 31 files changed, 454 insertions(+), 284 deletions(-) create mode 100644 src/GameObject/Hitbox.java create mode 100644 src/GameObject/Intersectable.java rename src/GameObject/{IntersectableRectangle.java => IntersectableRectangleOld.java} (74%) create mode 100644 src/GameObject/Overlappable.java create mode 100644 src/GameObject/RectangleOld.java diff --git a/src/Builders/FrameBuilder.java b/src/Builders/FrameBuilder.java index 35903b6..f3d1f90 100644 --- a/src/Builders/FrameBuilder.java +++ b/src/Builders/FrameBuilder.java @@ -2,7 +2,7 @@ import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import java.awt.image.BufferedImage; @@ -10,7 +10,7 @@ public class FrameBuilder { private BufferedImage image; private int delay; - private Rectangle bounds; + private RectangleOld bounds; private float scale; private ImageEffect imageEffect; @@ -24,13 +24,13 @@ public FrameBuilder(BufferedImage image, int delay) { this.imageEffect = ImageEffect.NONE; } - public FrameBuilder withBounds(Rectangle bounds) { + public FrameBuilder withBounds(RectangleOld bounds) { this.bounds = bounds; return this; } public FrameBuilder withBounds(float x, float y, int width, int height) { - this.bounds = new Rectangle(Math.round(x), Math.round(y), width, height); + this.bounds = new RectangleOld(Math.round(x), Math.round(y), width, height); return this; } diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 6b8825a..ed08713 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -3,7 +3,7 @@ import Game.GameState; import Game.GameThread; import Game.ScreenCoordinator; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.Player; import Utils.Colors; @@ -170,7 +170,7 @@ public static void mouseClicked(MouseEvent e) { // JPanel's width and height, which aren't available in the constructor public void setupGame() { setBackground(Colors.CORNFLOWER_BLUE); - screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); + screenManager.initialize(new RectangleOld(getX(), getY(), getWidth(), getHeight())); doPaint = true; } diff --git a/src/Engine/ScreenManager.java b/src/Engine/ScreenManager.java index ee6ea2a..774a925 100644 --- a/src/Engine/ScreenManager.java +++ b/src/Engine/ScreenManager.java @@ -1,9 +1,7 @@ package Engine; -import Game.GameState; - -import GameObject.Rectangle; +import GameObject.RectangleOld; /* * The game engine uses this class to start off the cascading Screen updating/drawing @@ -13,9 +11,9 @@ public class ScreenManager { private Screen currentScreen; - private static Rectangle screenBounds = new Rectangle(0, 0, 0, 0); + private static RectangleOld screenBounds = new RectangleOld(0, 0, 0, 0); - public void initialize(Rectangle screenBounds) { + public void initialize(RectangleOld screenBounds) { ScreenManager.screenBounds = screenBounds; setCurrentScreen(new DefaultScreen()); } @@ -46,7 +44,7 @@ public static int getScreenHeight() { } // gets bounds of currentScreen -- can be called from anywhere in an application - public static Rectangle getScreenBounds() { + public static RectangleOld getScreenBounds() { return screenBounds; } } diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index 748d5a4..3f2db86 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -137,7 +137,7 @@ public Point toPoint() { } public String toString() { - return "(" + x + ", " + y + ")"; + return String.format("(%s,%s)",x,y); } public Vector getFlipped() { diff --git a/src/EnhancedMapTiles/HorizontalMovingPlatform.java b/src/EnhancedMapTiles/HorizontalMovingPlatform.java index b290500..6d221d1 100644 --- a/src/EnhancedMapTiles/HorizontalMovingPlatform.java +++ b/src/EnhancedMapTiles/HorizontalMovingPlatform.java @@ -2,7 +2,7 @@ import Engine.GraphicsHandler; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.EnhancedMapTile; import Level.Player; import Level.TileType; @@ -21,7 +21,7 @@ public class HorizontalMovingPlatform extends EnhancedMapTile { private Direction startDirection; private Direction direction; - public HorizontalMovingPlatform(BufferedImage image, Point startLocation, Point endLocation, TileType tileType, float scale, Rectangle bounds, Direction startDirection) { + public HorizontalMovingPlatform(BufferedImage image, Point startLocation, Point endLocation, TileType tileType, float scale, RectangleOld bounds, Direction startDirection) { super(image, startLocation.x, startLocation.y, tileType, scale, ImageEffect.NONE, bounds); this.startLocation = startLocation; this.endLocation = endLocation; diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index 10ec54b..3011a8d 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -15,7 +15,7 @@ Subclasses need to call down to this class's update method in order for animation logic to be performed While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite (based on value of currentFrame) */ -public class AnimatedSprite implements IntersectableRectangle { +public class AnimatedSprite implements IntersectableRectangleOld { // location of entity // protected float x, y; /** @@ -214,11 +214,11 @@ public int getScaledHeight() { return currentFrame.getScaledHeight(); } - public Rectangle getBounds() { + public RectangleOld getBounds() { return currentFrame.getBounds(); } - public Rectangle getScaledBounds() { + public RectangleOld getScaledBounds() { return currentFrame.getScaledBounds(); } @@ -254,20 +254,20 @@ public float getScaledBoundsY2() { return currentFrame.getScaledBoundsY2(); } - public void setBounds(Rectangle bounds) { + public void setBounds(RectangleOld bounds) { currentFrame.setBounds(bounds); } @Override - public Rectangle getIntersectRectangle() { + public RectangleOld getIntersectRectangle() { return currentFrame.getIntersectRectangle(); } - public boolean intersects(IntersectableRectangle other) { + public boolean intersects(IntersectableRectangleOld other) { return currentFrame.intersects(other); } - public boolean overlaps(IntersectableRectangle other) { return currentFrame.overlaps(other); } + public boolean overlaps(IntersectableRectangleOld other) { return currentFrame.overlaps(other); } @Override public String toString() { diff --git a/src/GameObject/Frame.java b/src/GameObject/Frame.java index e620d8b..575cbbf 100644 --- a/src/GameObject/Frame.java +++ b/src/GameObject/Frame.java @@ -7,7 +7,7 @@ public class Frame extends Sprite { private int delay; - public Frame(BufferedImage image, float scale, ImageEffect imageEffect, Rectangle bounds, int delay) { + public Frame(BufferedImage image, float scale, ImageEffect imageEffect, RectangleOld bounds, int delay) { super(image, scale, imageEffect); if (bounds != null) { this.bounds = bounds; diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 8c7996b..e4f1c87 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -103,7 +103,7 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec startPosition = new Vector(x, y); } - public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { + public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { super(x, y); this.animations = new HashMap() {{ put("DEFAULT", new Frame[]{ @@ -190,43 +190,62 @@ public void moveHandleCollision(Vector providedVelocity) { private void checkMapTile(Vector[] startingPoints, Vector velocity, MapTile mapTile) { if(mapTile != null && (mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0))) { - updateVelocity(startingPoints,velocity,mapTile); + updateVelocityOld(startingPoints, velocity, mapTile); } } private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile mapTile) { + +// //x1 x2 y1 y2 are ordered values where x1 < x2 and y1 < y2. These indicate the x and y values of the edges of the bounding box +// float x1 = mapTile.getPos().getX(), x2 = mapTile.getPos().getX() + mapTile.getBounds().getWidth(); +// float y1 = mapTile.getPos().getY(), y2 = mapTile.getPos().getY() + mapTile.getBounds().getHeight(); +// /* +// xTest and yTest are the two faces that we will test intersections with (aka: the two faces that the velocity will hit first) +// xTestObj and yTestObj are the same thing except for this GameObject +// */ +// float xTest = x2, yTest = y2, xTestObj = pos.getX(), yTestObj = pos.getY(); +// if(velocity.getX() > 0) { +// xTest = x1; +// xTestObj += getBounds().getWidth(); +// } +// if(velocity.getY() > 0) { +// yTest = y1; +// yTestObj += getBounds().getHeight(); +// } + + + + + } + + @Deprecated + private void updateVelocityOld(Vector[] startingPoints, Vector velocity, MapTile mapTile) { float x1 = mapTile.getPos().getX(), x2 = mapTile.getPos().getX() + mapTile.getBounds().getWidth(); float y1 = mapTile.getPos().getY(), y2 = mapTile.getPos().getY() + mapTile.getBounds().getHeight(); for(Vector start : startingPoints) { System.out.print(velocity + " " + start + " " + x1 + " " + x2 + " " + y1 + " " + y2); - float xLambda = Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2)); - float yLambda = Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), - findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2)); + float xLambda = Math.min(findCoefficient(start, velocity, x1, y1, y2), findCoefficient(start, velocity, x2, y1, y2)); + float yLambda = Math.min( + findCoefficient(start.getFlipped(), velocity.getFlipped(), y1, x1, x2), + findCoefficient(start.getFlipped(), velocity.getFlipped(), y2, x1, x2)); if(xLambda > yLambda) { velocity.multiplyY(yLambda); - velocity.multiplyX( Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2))); + velocity.multiplyX( Math.min(findCoefficient(start, velocity, x1, y1, y2), findCoefficient(start, velocity, x2, y1, y2))); } else { velocity.multiplyX(xLambda); - velocity.multiplyY(Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), - findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2))); + velocity.multiplyY(Math.min( + findCoefficient(start.getFlipped(), velocity.getFlipped(), y1, x1, x2), + findCoefficient(start.getFlipped(), velocity.getFlipped(), y2, x1, x2))); } System.out.println(" " + xLambda + " " + yLambda); - -// if(Math.abs(start.getX() - mapTile.getX()) > Math.abs(start.getY() - mapTile.getY())) { -// -// -// velocity.multiplyY(); -// } else { -// velocity.multiplyY(Math.min(findCoefficient(start.getFlipped(),velocity.getFlipped(),y1,x1,x2), -// findCoefficient(start.getFlipped(),velocity.getFlipped(),y2,x1,x2))); -// velocity.multiplyX(Math.min(findCoefficient(start,velocity,x1,y1,y2),findCoefficient(start,velocity,x2,y1,y2))); -// } } } + + private float findCoefficient(Vector startPosition, Vector velocity, float v, float lowerBound, float upperBound) { if(velocity.getX() == 0) { @@ -536,10 +555,10 @@ public float getCalibratedYLocation() { } // gets scaled bounds taking into account map camera position - public Rectangle getCalibratedScaledBounds() { + public RectangleOld getCalibratedScaledBounds() { if (map != null) { - Rectangle scaledBounds = getScaledBounds(); - return new Rectangle( + RectangleOld scaledBounds = getScaledBounds(); + return new RectangleOld( scaledBounds.getX1() - map.getCamera().getX(), scaledBounds.getY1() - map.getCamera().getY(), scaledBounds.getScaledWidth(), @@ -573,7 +592,7 @@ public void draw(GraphicsHandler graphicsHandler) { @Override public void drawBounds(GraphicsHandler graphicsHandler, Color color) { if (map != null) { - Rectangle scaledCalibratedBounds = getCalibratedScaledBounds(); + RectangleOld scaledCalibratedBounds = getCalibratedScaledBounds(); scaledCalibratedBounds.setColor(color); scaledCalibratedBounds.draw(graphicsHandler); } else { diff --git a/src/GameObject/Hitbox.java b/src/GameObject/Hitbox.java new file mode 100644 index 0000000..45375a9 --- /dev/null +++ b/src/GameObject/Hitbox.java @@ -0,0 +1,8 @@ +package GameObject; + +import Engine.Vector; + +public interface Hitbox { + Vector getMinLocation(); + Vector getMaxLocation(); +} diff --git a/src/GameObject/Intersectable.java b/src/GameObject/Intersectable.java new file mode 100644 index 0000000..9e00192 --- /dev/null +++ b/src/GameObject/Intersectable.java @@ -0,0 +1,7 @@ +package GameObject; + +import Engine.Vector; + +public interface Intersectable extends Hitbox { + boolean intersects(Intersectable other); +} diff --git a/src/GameObject/IntersectableRectangle.java b/src/GameObject/IntersectableRectangleOld.java similarity index 74% rename from src/GameObject/IntersectableRectangle.java rename to src/GameObject/IntersectableRectangleOld.java index 3a45d37..1944688 100644 --- a/src/GameObject/IntersectableRectangle.java +++ b/src/GameObject/IntersectableRectangleOld.java @@ -2,6 +2,7 @@ // This interface allows for specifying a rectangle that can be used in intersection logic by the Rectangle class // it really only exists so an AnimatedSprite can be checked for intersection directly against by a Sprite or Rectangle (and all other combinations of that) -public interface IntersectableRectangle { - Rectangle getIntersectRectangle(); +@Deprecated +public interface IntersectableRectangleOld { + RectangleOld getIntersectRectangle(); } diff --git a/src/GameObject/Overlappable.java b/src/GameObject/Overlappable.java new file mode 100644 index 0000000..9fb606c --- /dev/null +++ b/src/GameObject/Overlappable.java @@ -0,0 +1,5 @@ +package GameObject; + +public interface Overlappable extends Hitbox { + boolean overlaps(Overlappable other); +} diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index 62e3434..92cfb54 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -1,202 +1,144 @@ package GameObject; +import Engine.Drawable; import Engine.GraphicsHandler; import Engine.Vector; import java.awt.*; -// This class represents a rectangle, which at its core is (x, y, width, height) -// it has some properties, rectangle math methods, and draw logic -// the methods here are pretty self explanatory -public class Rectangle implements IntersectableRectangle { - protected Vector location, dimensions; - protected float x; - protected float y; - protected int width; - protected int height; - protected float scale; - protected Color color; - protected Color borderColor; - protected int borderThickness; - - public Rectangle(float x, float y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.scale = 1; - this.color = Color.white; - this.borderColor = null; - this.borderThickness = 0; - } - - public Rectangle(float x, float y, int width, int height, float scale) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.scale = scale; - this.color = Color.white; - this.borderColor = null; - this.borderThickness = 0; - } - - public float getX() { - return x; +/** + * @author Thomas Kwashnak + */ +public class Rectangle implements Drawable, Intersectable, Overlappable { + + private static final int BORDER_THICKNESS = 0; + + private Vector location, dimension; + private float scale; + private Color color, borderColor; + + public Rectangle(float x, float y, float width, float height) { + this(new Vector(x,y), new Vector(width,height)); + } + + public Rectangle(Vector location, Vector dimension) { + this(location,dimension,1); + } + + public Rectangle(float x, float y, float width, float height, float scale) { + this(new Vector(x,y), new Vector(width,height), scale); + } + + public Rectangle(Vector location, Vector dimension, float scale) { + this.location = location; + this.dimension = dimension; + this.scale = scale; } public float getX1() { - return x; + return location.getX(); } public float getX2() { - return x + width; + return location.getX() + dimension.getX(); } public float getScaledX2() { - return x + getScaledWidth(); - } - - public void setX(float x) { - this.x = x; - } - - public void moveX(float dx) { - this.x += dx; - } - - public void moveRight(float dx) { - this.x += dx; - } - - public void moveLeft(float dx) { - this.x -= dx; - } - - public float getY() { - return y; + return location.getX() + (dimension.getX() * scale); } public float getY1() { - return y; + return location.getY(); } public float getY2() { - return y + height; - } - - public float getScaledY2() { - return y + getScaledHeight(); - } - - public void setY(float y) { - this.y = y; - } - - public void moveY(float dy) { - this.y += dy; - } - - public void moveDown(float dy) { - this.y += dy; - } - - public void moveUp(float dy) { - this.y -= dy; - } - - public void setLocation(float x, float y) { - this.x = x; - this.y = y; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getScaledWidth() { - return Math.round(width * scale); - } - - public int getScaledHeight() { - return Math.round(height * scale); - } - - public float getScale() { return scale; } - - public void setScale(float scale) { - this.scale = scale; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - public void setBorderThickness(int borderThickness) { - this.borderThickness = borderThickness; - } - - @Override - public String toString() { - return String.format("Rectangle: x=%s y=%s width=%s height=%s", getX(), getY(), getScaledWidth(), getScaledHeight()); - } - - public void update() { } - - public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawFilledRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), color); - if (borderColor != null && !borderColor.equals(color)) { - graphicsHandler.drawRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), borderColor, borderThickness); - } - } - - @Override - public Rectangle getIntersectRectangle() { - return new Rectangle(x, y, getScaledWidth(), getScaledHeight()); - } - - // check if this intersects with another rectangle - public boolean intersects(IntersectableRectangle other) { - Rectangle intersectRectangle = getIntersectRectangle(); - Rectangle otherIntersectRectangle = other.getIntersectRectangle(); - return Math.round(intersectRectangle.getX1()) < Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) > Math.round(otherIntersectRectangle.getX1()) && - Math.round(intersectRectangle.getY1()) < Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) > Math.round(otherIntersectRectangle.getY1()); - } - - // check if this overlaps with another rectangle - public boolean overlaps(IntersectableRectangle other) { - Rectangle intersectRectangle = getIntersectRectangle(); - Rectangle otherIntersectRectangle = other.getIntersectRectangle(); - return Math.round(intersectRectangle.getX1()) <= Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) >= Math.round(otherIntersectRectangle.getX1()) && - Math.round(intersectRectangle.getY1()) <= Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) >= Math.round(otherIntersectRectangle.getY1()); - } - - //TODO reduce calls - public Vector getPos1() { - return new Vector(getX1(), getY1()); - } - - public Vector getPos2() { - return new Vector(getX2(), getY2()); - } + return location.getY() + dimension.getY(); + } + + public float getScaledY2() { + return location.getY() + (dimension.getY() * scale); + } + + public void setLocation(Vector location) { + this.location = location; + } + + public void move(Vector displacement) { + location.add(displacement); + } + + public Vector getDimension() { + return dimension; + } + + public Vector getScaledDimension() { + return dimension.getMultiplied(scale); + } + + public Vector getLocation() { + return location; + } + + public float getScaledWidth() { + return dimension.getX() * scale; + } + + public float getScaledHeight() { + return dimension.getY() * scale; + } + + public Vector getMinLocation() { + return location; + } + + public Vector getMaxLocation() { + return location.getAdd(dimension); + } + + public void update() {} + + public boolean intersects(Intersectable other) { + Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); + return (min.getX() < maxOther.getX()) && (max.getX() > minOther.getX()) && (min.getY() < maxOther.getY()) && (max.getY() > minOther.getY()); + } + + public boolean overlaps(Overlappable other) { + Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); + return (min.getX() <= maxOther.getX()) && (max.getX() >= minOther.getX()) && (min.getY() <= maxOther.getY()) && (max.getY() >= minOther.getY()); + } + + public void draw(GraphicsHandler graphicsHandler) { + graphicsHandler.drawFilledRectangle(Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), color); + if (borderColor != null && !borderColor.equals(color)) { + graphicsHandler.drawRectangle(Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), borderColor, BORDER_THICKNESS); + } + } + + public String toString() { + return String.format("Rectangle: location = %s, dimensions = %s",location.toString(),dimension.toString()); + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public float getScale() { + return scale; + } + + public void setScale(float scale) { + this.scale = scale; + } + + public Color getBorderColor() { + return borderColor; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } } diff --git a/src/GameObject/RectangleOld.java b/src/GameObject/RectangleOld.java new file mode 100644 index 0000000..9f14b53 --- /dev/null +++ b/src/GameObject/RectangleOld.java @@ -0,0 +1,203 @@ +package GameObject; + +import Engine.GraphicsHandler; +import Engine.Vector; + +import java.awt.*; + +// This class represents a rectangle, which at its core is (x, y, width, height) +// it has some properties, rectangle math methods, and draw logic +// the methods here are pretty self explanatory +@Deprecated +public class RectangleOld implements IntersectableRectangleOld { + protected Vector location, dimensions; + protected float x; + protected float y; + protected int width; + protected int height; + protected float scale; + protected Color color; + protected Color borderColor; + protected int borderThickness; + + public RectangleOld(float x, float y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.scale = 1; + this.color = Color.white; + this.borderColor = null; + this.borderThickness = 0; + } + + public RectangleOld(float x, float y, int width, int height, float scale) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.scale = scale; + this.color = Color.white; + this.borderColor = null; + this.borderThickness = 0; + } + + public float getX() { + return x; + } + + public float getX1() { + return x; + } + + public float getX2() { + return x + width; + } + + public float getScaledX2() { + return x + getScaledWidth(); + } + + public void setX(float x) { + this.x = x; + } + + public void moveX(float dx) { + this.x += dx; + } + + public void moveRight(float dx) { + this.x += dx; + } + + public void moveLeft(float dx) { + this.x -= dx; + } + + public float getY() { + return y; + } + + public float getY1() { + return y; + } + + public float getY2() { + return y + height; + } + + public float getScaledY2() { + return y + getScaledHeight(); + } + + public void setY(float y) { + this.y = y; + } + + public void moveY(float dy) { + this.y += dy; + } + + public void moveDown(float dy) { + this.y += dy; + } + + public void moveUp(float dy) { + this.y -= dy; + } + + public void setLocation(float x, float y) { + this.x = x; + this.y = y; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getScaledWidth() { + return Math.round(width * scale); + } + + public int getScaledHeight() { + return Math.round(height * scale); + } + + public float getScale() { return scale; } + + public void setScale(float scale) { + this.scale = scale; + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + public void setBorderThickness(int borderThickness) { + this.borderThickness = borderThickness; + } + + @Override + public String toString() { + return String.format("Rectangle: x=%s y=%s width=%s height=%s", getX(), getY(), getScaledWidth(), getScaledHeight()); + } + + public void update() { } + + public void draw(GraphicsHandler graphicsHandler) { + graphicsHandler.drawFilledRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), color); + if (borderColor != null && !borderColor.equals(color)) { + graphicsHandler.drawRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), borderColor, borderThickness); + } + } + + @Override + public RectangleOld getIntersectRectangle() { + return new RectangleOld(x, y, getScaledWidth(), getScaledHeight()); + } + + // check if this intersects with another rectangle + public boolean intersects(IntersectableRectangleOld other) { + RectangleOld intersectRectangle = getIntersectRectangle(); + RectangleOld otherIntersectRectangle = other.getIntersectRectangle(); + return Math.round(intersectRectangle.getX1()) < Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) > Math.round(otherIntersectRectangle.getX1()) && + Math.round(intersectRectangle.getY1()) < Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) > Math.round(otherIntersectRectangle.getY1()); + } + + // check if this overlaps with another rectangle + public boolean overlaps(IntersectableRectangleOld other) { + RectangleOld intersectRectangle = getIntersectRectangle(); + RectangleOld otherIntersectRectangle = other.getIntersectRectangle(); + return Math.round(intersectRectangle.getX1()) <= Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) >= Math.round(otherIntersectRectangle.getX1()) && + Math.round(intersectRectangle.getY1()) <= Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) >= Math.round(otherIntersectRectangle.getY1()); + } + + //TODO reduce calls + public Vector getPos1() { + return new Vector(getX1(), getY1()); + } + + public Vector getPos2() { + return new Vector(getX2(), getY2()); + } +} diff --git a/src/GameObject/Sprite.java b/src/GameObject/Sprite.java index 1a52c77..6b2b857 100644 --- a/src/GameObject/Sprite.java +++ b/src/GameObject/Sprite.java @@ -8,22 +8,22 @@ // This class is for representing a Sprite, which is essentially a Rectangle with an image attached // it also includes an attribute for "bounds", which can be thought of a sub rectangle on the image where it can be interacted with (like for collisions) -public class Sprite extends Rectangle implements IntersectableRectangle { +public class Sprite extends RectangleOld implements IntersectableRectangleOld { protected BufferedImage image; - protected Rectangle bounds; + protected RectangleOld bounds; protected ImageEffect imageEffect; public Sprite (BufferedImage image, float scale, ImageEffect imageEffect) { super(0, 0, image.getWidth(), image.getHeight(), scale); this.image = image; - this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); + this.bounds = new RectangleOld(0, 0, image.getWidth(), image.getHeight(), scale); this.imageEffect = imageEffect; } public Sprite(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { super(x, y, image.getWidth(), image.getHeight(), scale); this.image = image; - this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); + this.bounds = new RectangleOld(0, 0, image.getWidth(), image.getHeight(), scale); this.imageEffect = imageEffect; } @@ -45,8 +45,8 @@ public void setImageEffect(ImageEffect imageEffect) { this.imageEffect = imageEffect; } - public Rectangle getBounds() { - return new Rectangle(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); + public RectangleOld getBounds() { + return new RectangleOld(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); } public float getBoundsX1() { @@ -81,19 +81,19 @@ public float getScaledBoundsY2() { return getScaledBoundsY1() + bounds.getScaledHeight(); } - public Rectangle getScaledBounds() { - return new Rectangle(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); + public RectangleOld getScaledBounds() { + return new RectangleOld(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); } - public void setBounds(Rectangle bounds) { - this.bounds = new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), scale); + public void setBounds(RectangleOld bounds) { + this.bounds = new RectangleOld(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), scale); } public void setBounds(float x, float y, int width, int height) { - this.bounds = new Rectangle(x, y, width, height, scale); + this.bounds = new RectangleOld(x, y, width, height, scale); } - public Rectangle getIntersectRectangle() { + public RectangleOld getIntersectRectangle() { return getScaledBounds(); } @@ -108,7 +108,7 @@ public void draw(GraphicsHandler graphicsHandler) { } public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - Rectangle scaledBounds = getScaledBounds(); + RectangleOld scaledBounds = getScaledBounds(); scaledBounds.setColor(color); scaledBounds.draw(graphicsHandler); } diff --git a/src/Level/Camera.java b/src/Level/Camera.java index 07a63de..56c9c6e 100644 --- a/src/Level/Camera.java +++ b/src/Level/Camera.java @@ -3,14 +3,14 @@ import Engine.GraphicsHandler; import Engine.ScreenManager; import GameObject.GameObject; -import GameObject.Rectangle; +import GameObject.RectangleOld; import java.awt.*; import java.util.ArrayList; // This class represents a Map's "Camera", aka a piece of the map that is currently included in a level's update/draw logic based on what should be shown on screen. // A majority of its job is just determining which map tiles, enemies, npcs, and enhanced map tiles are "active" each frame (active = included in update/draw cycle) -public class Camera extends Rectangle { +public class Camera extends RectangleOld { // the current map this camera is attached to private Map map; diff --git a/src/Level/Enemy.java b/src/Level/Enemy.java index c89baa4..67fabea 100644 --- a/src/Level/Enemy.java +++ b/src/Level/Enemy.java @@ -3,7 +3,7 @@ import Engine.CollisionType; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; @@ -36,7 +36,7 @@ public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect ima super(image, x, y, scale, imageEffect); } - public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { + public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { super(image, x, y, scale, imageEffect, bounds); } diff --git a/src/Level/EnhancedMapTile.java b/src/Level/EnhancedMapTile.java index 2819134..96c27b7 100644 --- a/src/Level/EnhancedMapTile.java +++ b/src/Level/EnhancedMapTile.java @@ -3,7 +3,7 @@ import Engine.GraphicsHandler; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; @@ -36,7 +36,7 @@ public EnhancedMapTile(BufferedImage image, float x, float y, TileType tileType, super(image, x, y, scale, imageEffect, tileType); } - public EnhancedMapTile(BufferedImage image, float x, float y, TileType tileType, float scale, ImageEffect imageEffect, Rectangle bounds) { + public EnhancedMapTile(BufferedImage image, float x, float y, TileType tileType, float scale, ImageEffect imageEffect, RectangleOld bounds) { super(image, x, y, scale, imageEffect, bounds, tileType); } diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index b41c034..71182bb 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -43,7 +43,7 @@ public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect super(image, x, y, scale, imageEffect); } - public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { + public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { super(image, x, y, scale, imageEffect, bounds); } diff --git a/src/Level/MapTile.java b/src/Level/MapTile.java index cd87374..0fd4af0 100644 --- a/src/Level/MapTile.java +++ b/src/Level/MapTile.java @@ -3,7 +3,7 @@ import Engine.GraphicsHandler; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; @@ -52,7 +52,7 @@ public MapTile(BufferedImage image, float x, float y, float scale, ImageEffect i this.tileType = tileType; } - public MapTile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds, TileType tileType) { + public MapTile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds, TileType tileType) { super(image, x, y, scale, imageEffect, bounds); this.tileType = tileType; } diff --git a/src/Level/NPC.java b/src/Level/NPC.java index 7ca0240..ddc52e0 100644 --- a/src/Level/NPC.java +++ b/src/Level/NPC.java @@ -4,7 +4,7 @@ import Engine.KeyboardAction; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import GameObject.SpriteSheet; import SpriteFont.SpriteFont; import Utils.Stopwatch; @@ -55,7 +55,7 @@ public NPC(BufferedImage image, float x, float y, int talkedToTime, float scale, this.talkedToTime = talkedToTime; } - public NPC(BufferedImage image, float x, float y, int talkedToTime, float scale, ImageEffect imageEffect, Rectangle bounds) { + public NPC(BufferedImage image, float x, float y, int talkedToTime, float scale, ImageEffect imageEffect, RectangleOld bounds) { super(image, x, y, scale, imageEffect, bounds); this.message = createMessage(); this.talkedToTime = talkedToTime; diff --git a/src/Level/Projectile.java b/src/Level/Projectile.java index 00c62c9..98c3db8 100644 --- a/src/Level/Projectile.java +++ b/src/Level/Projectile.java @@ -3,7 +3,7 @@ import Engine.CollisionType; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.Rectangle; +import GameObject.RectangleOld; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; import java.util.HashMap; @@ -35,7 +35,7 @@ public Projectile(BufferedImage image, float x, float y, float scale, ImageEffec super(image, x, y, scale, imageEffect); } - public Projectile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { + public Projectile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { super(image, x, y, scale, imageEffect, bounds); } diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index a959170..813f10c 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -1,15 +1,13 @@ package Maps; -import Enemies.BugEnemy; import Enemies.DinosaurEnemy; import Enemies.Dog; import Enemies.CyborgEnemy; import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -46,7 +44,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(42, 13), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap.java b/src/Maps/TestMap.java index 831cd12..473aee2 100644 --- a/src/Maps/TestMap.java +++ b/src/Maps/TestMap.java @@ -5,7 +5,7 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; import NPCs.Walrus; import Tilesets.CommonTileset; @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap2.java b/src/Maps/TestMap2.java index 23e5cd3..52793f6 100644 --- a/src/Maps/TestMap2.java +++ b/src/Maps/TestMap2.java @@ -2,12 +2,8 @@ import Enemies.BugEnemy; import Enemies.DinosaurEnemy; -import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; -import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; diff --git a/src/Maps/TestMap3.java b/src/Maps/TestMap3.java index 3fe66b7..d7c1408 100644 --- a/src/Maps/TestMap3.java +++ b/src/Maps/TestMap3.java @@ -5,9 +5,8 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -39,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(17, 10), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap4.java b/src/Maps/TestMap4.java index 1c913e1..3eaf147 100644 --- a/src/Maps/TestMap4.java +++ b/src/Maps/TestMap4.java @@ -2,13 +2,11 @@ import Enemies.BugEnemy; import Enemies.CyborgEnemy; -import Enemies.DinosaurEnemy; import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -41,7 +39,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap5.java b/src/Maps/TestMap5.java index c00d753..c5f8fbe 100644 --- a/src/Maps/TestMap5.java +++ b/src/Maps/TestMap5.java @@ -5,9 +5,8 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -39,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap6.java b/src/Maps/TestMap6.java index 1e321d8..23c0ee4 100644 --- a/src/Maps/TestMap6.java +++ b/src/Maps/TestMap6.java @@ -6,9 +6,8 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -43,7 +42,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(11, 8), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); @@ -53,7 +52,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(14, 5), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.LEFT )); @@ -63,7 +62,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(38, 5), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.LEFT )); diff --git a/src/Maps/TestMap7.java b/src/Maps/TestMap7.java index a753c22..fc9cdee 100644 --- a/src/Maps/TestMap7.java +++ b/src/Maps/TestMap7.java @@ -6,9 +6,8 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -48,7 +47,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(7, 9), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); @@ -58,7 +57,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(26, 9), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestTutorial.java b/src/Maps/TestTutorial.java index 2f83c3f..6b2cb99 100644 --- a/src/Maps/TestTutorial.java +++ b/src/Maps/TestTutorial.java @@ -5,9 +5,8 @@ import Engine.*; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.Rectangle; +import GameObject.RectangleOld; import Level.*; -import NPCs.Walrus; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -41,7 +40,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6,16,4), + new RectangleOld(0, 6, 16, 4), Direction.RIGHT )); From 58e78eb8d553b5d5dd6c07ee94106557aea477c9 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 13:00:02 -0500 Subject: [PATCH 084/164] Converted use to new Rectangle.java This did break deprecated methods --- src/Builders/FrameBuilder.java | 8 +-- src/Enemies/DinosaurEnemy.java | 2 +- src/Enemies/Dog.java | 2 +- .../HorizontalMovingPlatform.java | 4 +- src/GameObject/AnimatedSprite.java | 67 +++++++++---------- src/GameObject/Frame.java | 2 +- src/GameObject/GameObject.java | 33 ++++----- src/GameObject/Rectangle.java | 22 +++++- src/GameObject/Sprite.java | 43 ++++++------ src/Level/CollisionHandler.java | 3 +- src/Level/Enemy.java | 4 +- src/Level/EnhancedMapTile.java | 4 +- src/Level/MapEntity.java | 2 +- src/Level/MapTile.java | 4 +- src/Level/MapTileCollisionHandler.java | 6 +- src/Level/NPC.java | 4 +- src/Level/Player.java | 2 +- src/Level/Projectile.java | 5 +- src/MapEditor/TileBuilder.java | 4 +- src/MapEditor/TilePicker.java | 4 +- src/Maps/BossBattle.java | 7 +- src/Maps/TestMap.java | 4 +- src/Maps/TestMap3.java | 4 +- src/Maps/TestMap4.java | 4 +- src/Maps/TestMap5.java | 4 +- src/Maps/TestMap6.java | 15 +++-- src/Maps/TestMap7.java | 13 ++-- src/Maps/TestTutorial.java | 9 +-- 28 files changed, 152 insertions(+), 133 deletions(-) diff --git a/src/Builders/FrameBuilder.java b/src/Builders/FrameBuilder.java index f3d1f90..35903b6 100644 --- a/src/Builders/FrameBuilder.java +++ b/src/Builders/FrameBuilder.java @@ -2,7 +2,7 @@ import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import java.awt.image.BufferedImage; @@ -10,7 +10,7 @@ public class FrameBuilder { private BufferedImage image; private int delay; - private RectangleOld bounds; + private Rectangle bounds; private float scale; private ImageEffect imageEffect; @@ -24,13 +24,13 @@ public FrameBuilder(BufferedImage image, int delay) { this.imageEffect = ImageEffect.NONE; } - public FrameBuilder withBounds(RectangleOld bounds) { + public FrameBuilder withBounds(Rectangle bounds) { this.bounds = bounds; return this; } public FrameBuilder withBounds(float x, float y, int width, int height) { - this.bounds = new RectangleOld(Math.round(x), Math.round(y), width, height); + this.bounds = new Rectangle(Math.round(x), Math.round(y), width, height); return this; } diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index ce79082..e3c93f0 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -109,7 +109,7 @@ public void update(Player player) { int fireballX; float movementSpeed; if (facingDirection == Direction.RIGHT) { - fireballX = Math.round(getX()) + getScaledWidth(); + fireballX = Math.round(getX() + getScaledWidth()); movementSpeed = 1.5f; } else { fireballX = Math.round(getX()); diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index ff945be..5c0b091 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -107,7 +107,7 @@ public void update(Player player) { int boneX; float movementSpeed; if (facingDirection == Direction.RIGHT) { - boneX = Math.round(getX()) + getScaledWidth(); + boneX = Math.round(getX() + getScaledWidth()); movementSpeed = 1.5f; } else { boneX = Math.round(getX()); diff --git a/src/EnhancedMapTiles/HorizontalMovingPlatform.java b/src/EnhancedMapTiles/HorizontalMovingPlatform.java index 6d221d1..b290500 100644 --- a/src/EnhancedMapTiles/HorizontalMovingPlatform.java +++ b/src/EnhancedMapTiles/HorizontalMovingPlatform.java @@ -2,7 +2,7 @@ import Engine.GraphicsHandler; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.EnhancedMapTile; import Level.Player; import Level.TileType; @@ -21,7 +21,7 @@ public class HorizontalMovingPlatform extends EnhancedMapTile { private Direction startDirection; private Direction direction; - public HorizontalMovingPlatform(BufferedImage image, Point startLocation, Point endLocation, TileType tileType, float scale, RectangleOld bounds, Direction startDirection) { + public HorizontalMovingPlatform(BufferedImage image, Point startLocation, Point endLocation, TileType tileType, float scale, Rectangle bounds, Direction startDirection) { super(image, startLocation.x, startLocation.y, tileType, scale, ImageEffect.NONE, bounds); this.startLocation = startLocation; this.endLocation = endLocation; diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index 3011a8d..ec6d2d4 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -15,7 +15,7 @@ Subclasses need to call down to this class's update method in order for animation logic to be performed While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite (based on value of currentFrame) */ -public class AnimatedSprite implements IntersectableRectangleOld { +public class AnimatedSprite implements Intersectable, Overlappable { // location of entity // protected float x, y; /** @@ -114,8 +114,7 @@ public void setAnimations(HashMap animations) { // and location updated to match any changes to the animated sprite class protected void updateCurrentFrame() { currentFrame = getCurrentFrame(); - currentFrame.setX(pos.getX()); - currentFrame.setY(pos.getY()); + currentFrame.setLocation(pos.clone()); } // gets the frame from current animation that the animated sprite class is currently using @@ -134,8 +133,8 @@ public void drawBounds(GraphicsHandler graphicsHandler, Color color) { currentFrame.drawBounds(graphicsHandler, color); } - public float getX() { return currentFrame.getX(); } - public float getY() { return currentFrame.getY(); } + public float getX() { return currentFrame.getX1(); } + public float getY() { return currentFrame.getY1(); } public float getX1() { return currentFrame.getX1(); } public float getY1() { return currentFrame.getY1(); } public float getX2() { return currentFrame.getX2(); } @@ -145,11 +144,11 @@ public void drawBounds(GraphicsHandler graphicsHandler, Color color) { public void setX(float x) { pos.setX(x); - currentFrame.setX(x); + currentFrame.getLocation().setX(x); } public void setY(float y) { pos.setY(y); - currentFrame.setY(y); + currentFrame.getLocation().setY(y); } public void setLocation(float x, float y) { @@ -159,32 +158,28 @@ public void setLocation(float x, float y) { public void moveX(float dx) { this.pos.addX(dx); - currentFrame.moveX(dx); + currentFrame.move(new Vector(dx,0)); } public void moveRight(float dx) { - this.pos.addX(dx); - currentFrame.moveRight(dx); + moveX(dx); } public void moveLeft(float dx) { - this.pos.addX(-dx); - currentFrame.moveLeft(dx); + moveX(-dx); } public void moveY(float dy) { this.pos.addY(dy); - currentFrame.moveY(dy); + currentFrame.move(new Vector(0,dy)); } public void moveDown(float dy) { - this.pos.addY(dy); - currentFrame.moveDown(dy); + moveY(dy); } public void moveUp(float dy) { - this.pos.addY(-dy); - currentFrame.moveUp(dy); + moveY(-dy); } public float getScale() { @@ -195,30 +190,30 @@ public void setScale(float scale) { currentFrame.setScale(scale); } - public int getWidth() { + public float getWidth() { return currentFrame.getWidth(); } - public int getHeight() { + public float getHeight() { return currentFrame.getHeight(); } - public void setWidth(int width) { + public void setWidth(float width) { currentFrame.setWidth(width); } - public void setHeight(int height) { + public void setHeight(float height) { currentFrame.setHeight(height); } - public int getScaledWidth() { + public float getScaledWidth() { return currentFrame.getScaledWidth(); } - public int getScaledHeight() { + public float getScaledHeight() { return currentFrame.getScaledHeight(); } - public RectangleOld getBounds() { + public Rectangle getBounds() { return currentFrame.getBounds(); } - public RectangleOld getScaledBounds() { + public Rectangle getScaledBounds() { return currentFrame.getScaledBounds(); } @@ -254,20 +249,15 @@ public float getScaledBoundsY2() { return currentFrame.getScaledBoundsY2(); } - public void setBounds(RectangleOld bounds) { + public void setBounds(Rectangle bounds) { currentFrame.setBounds(bounds); } - @Override - public RectangleOld getIntersectRectangle() { - return currentFrame.getIntersectRectangle(); - } - - public boolean intersects(IntersectableRectangleOld other) { + public boolean intersects(Intersectable other) { return currentFrame.intersects(other); } - public boolean overlaps(IntersectableRectangleOld other) { return currentFrame.overlaps(other); } + public boolean overlaps(Overlappable other) { return currentFrame.overlaps(other); } @Override public String toString() { @@ -286,5 +276,14 @@ public Vector getPos() { public void move(Vector vector) { pos.add(vector); } - + + @Override + public Vector getMinLocation() { + return currentFrame.getMinLocation(); + } + + @Override + public Vector getMaxLocation() { + return currentFrame.getMaxLocation(); + } } diff --git a/src/GameObject/Frame.java b/src/GameObject/Frame.java index 575cbbf..e620d8b 100644 --- a/src/GameObject/Frame.java +++ b/src/GameObject/Frame.java @@ -7,7 +7,7 @@ public class Frame extends Sprite { private int delay; - public Frame(BufferedImage image, float scale, ImageEffect imageEffect, RectangleOld bounds, int delay) { + public Frame(BufferedImage image, float scale, ImageEffect imageEffect, Rectangle bounds, int delay) { super(image, scale, imageEffect); if (bounds != null) { this.bounds = bounds; diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index e4f1c87..253595e 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -103,7 +103,7 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec startPosition = new Vector(x, y); } - public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { + public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { super(x, y); this.animations = new HashMap() {{ put("DEFAULT", new Frame[]{ @@ -139,7 +139,7 @@ public void moveHandleCollision(Vector providedVelocity) { }; - Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getPos1()); + Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getLocation()); // int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; // int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; @@ -335,6 +335,8 @@ public void moveHandleCollisionIterative(Vector providedVelocity) { * Checks if the game object has collided with any map tiles, and returns the collided map-tile if it has. Otherwise, returns null * * Copied from CollisionHandler + * + * Deprecated, no longer works with changes to {@link Rectangle} * @param velocity * @return */ @@ -343,10 +345,10 @@ private MapTile getCollisionBounds(Vector velocity) { //TODO modify / recreate this code to iterate through all neighbor blocks only in the half direction of the velocity // int numberOfTilesToCheck = Math.max(getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth() + 2, 3); - Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getPos1()); + Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getLocation()); - int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; - int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; + int rangeWidth = (int) getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; + int rangeHeight = (int) getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; MapTile[] tiles = map.getTilesInIndexBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); @@ -365,15 +367,6 @@ private MapTile getCollisionBounds(Vector velocity) { return null; } -// /** -// * Copied from CollisionHandler -// * @param mapTile -// * @param velocity -// * @return -// */ -// private boolean checkCollision(MapTile mapTile, Vector velocity) { -// return mapTile != null && hasCollidedWithMapTile(mapTile,velocity); -// } /** * Copied from CollisionHandler @@ -555,10 +548,10 @@ public float getCalibratedYLocation() { } // gets scaled bounds taking into account map camera position - public RectangleOld getCalibratedScaledBounds() { + public Rectangle getCalibratedScaledBounds() { if (map != null) { - RectangleOld scaledBounds = getScaledBounds(); - return new RectangleOld( + Rectangle scaledBounds = getScaledBounds(); + return new Rectangle( scaledBounds.getX1() - map.getCamera().getX(), scaledBounds.getY1() - map.getCamera().getY(), scaledBounds.getScaledWidth(), @@ -581,8 +574,8 @@ public void draw(GraphicsHandler graphicsHandler) { currentFrame.getImage(), Math.round(getCalibratedXLocation()), Math.round(getCalibratedYLocation()), - currentFrame.getScaledWidth(), - currentFrame.getScaledHeight(), + Math.round(currentFrame.getScaledWidth()), + Math.round(currentFrame.getScaledHeight()), currentFrame.getImageEffect()); } else { super.draw(graphicsHandler); @@ -592,7 +585,7 @@ public void draw(GraphicsHandler graphicsHandler) { @Override public void drawBounds(GraphicsHandler graphicsHandler, Color color) { if (map != null) { - RectangleOld scaledCalibratedBounds = getCalibratedScaledBounds(); + Rectangle scaledCalibratedBounds = getCalibratedScaledBounds(); scaledCalibratedBounds.setColor(color); scaledCalibratedBounds.draw(graphicsHandler); } else { diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index 92cfb54..c8b06a9 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -13,9 +13,9 @@ public class Rectangle implements Drawable, Intersectable, Overlappable { private static final int BORDER_THICKNESS = 0; - private Vector location, dimension; - private float scale; - private Color color, borderColor; + protected Vector location, dimension; + protected float scale; + protected Color color, borderColor; public Rectangle(float x, float y, float width, float height) { this(new Vector(x,y), new Vector(width,height)); @@ -141,4 +141,20 @@ public Color getBorderColor() { public void setBorderColor(Color borderColor) { this.borderColor = borderColor; } + + public float getWidth() { + return dimension.getX(); + } + + public float getHeight() { + return dimension.getY(); + } + + public void setWidth(float width) { + dimension.setX(width); + } + + public void setHeight(float height) { + dimension.setY(height); + } } diff --git a/src/GameObject/Sprite.java b/src/GameObject/Sprite.java index 6b2b857..1062e3f 100644 --- a/src/GameObject/Sprite.java +++ b/src/GameObject/Sprite.java @@ -8,22 +8,22 @@ // This class is for representing a Sprite, which is essentially a Rectangle with an image attached // it also includes an attribute for "bounds", which can be thought of a sub rectangle on the image where it can be interacted with (like for collisions) -public class Sprite extends RectangleOld implements IntersectableRectangleOld { +public class Sprite extends Rectangle { protected BufferedImage image; - protected RectangleOld bounds; + protected Rectangle bounds; protected ImageEffect imageEffect; public Sprite (BufferedImage image, float scale, ImageEffect imageEffect) { super(0, 0, image.getWidth(), image.getHeight(), scale); this.image = image; - this.bounds = new RectangleOld(0, 0, image.getWidth(), image.getHeight(), scale); + this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); this.imageEffect = imageEffect; } public Sprite(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { super(x, y, image.getWidth(), image.getHeight(), scale); this.image = image; - this.bounds = new RectangleOld(0, 0, image.getWidth(), image.getHeight(), scale); + this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); this.imageEffect = imageEffect; } @@ -45,28 +45,28 @@ public void setImageEffect(ImageEffect imageEffect) { this.imageEffect = imageEffect; } - public RectangleOld getBounds() { - return new RectangleOld(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); + public Rectangle getBounds() { + return new Rectangle(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); } public float getBoundsX1() { - return x + bounds.getX1(); + return getX1() + bounds.getX1(); } public float getBoundsX2() { - return x + bounds.getX2(); + return getX1() + bounds.getX2(); } public float getBoundsY1() { - return y + bounds.getY1(); + return getY1() + bounds.getY1(); } public float getBoundsY2() { - return y + bounds.getY2(); + return getY1() + bounds.getY2(); } public float getScaledBoundsX1() { - return getX() + (bounds.getX1() * scale); + return getX1() + (bounds.getX1() * scale); } public float getScaledBoundsX2() { @@ -74,26 +74,26 @@ public float getScaledBoundsX2() { } public float getScaledBoundsY1() { - return getY() + (bounds.getY1() * scale); + return getY1() + (bounds.getY1() * scale); } public float getScaledBoundsY2() { return getScaledBoundsY1() + bounds.getScaledHeight(); } - public RectangleOld getScaledBounds() { - return new RectangleOld(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); + public Rectangle getScaledBounds() { + return new Rectangle(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); } - public void setBounds(RectangleOld bounds) { - this.bounds = new RectangleOld(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), scale); + public void setBounds(Rectangle bounds) { + this.bounds = new Rectangle(bounds.getX1(), bounds.getY1(), bounds.getWidth(), bounds.getHeight(), scale); } public void setBounds(float x, float y, int width, int height) { - this.bounds = new RectangleOld(x, y, width, height, scale); + this.bounds = new Rectangle(x, y, width, height, scale); } - public RectangleOld getIntersectRectangle() { + public Rectangle getIntersectRectangle() { return getScaledBounds(); } @@ -104,17 +104,18 @@ public void update() { @Override public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawImage(image, Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), imageEffect); + graphicsHandler.drawImage(image, Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), imageEffect); } public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - RectangleOld scaledBounds = getScaledBounds(); + Rectangle scaledBounds = getScaledBounds(); scaledBounds.setColor(color); scaledBounds.draw(graphicsHandler); } @Override public String toString() { - return String.format("Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", getX(), getY(), getScaledWidth(), getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); + return String.format("Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", getX1(), getY1(), getScaledWidth(), getScaledHeight(), + getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); } } diff --git a/src/Level/CollisionHandler.java b/src/Level/CollisionHandler.java index bf047f5..18fcc9a 100644 --- a/src/Level/CollisionHandler.java +++ b/src/Level/CollisionHandler.java @@ -8,6 +8,7 @@ /** * */ +@Deprecated public class CollisionHandler { private GameObject gameObject; @@ -51,7 +52,7 @@ private Vector modifiedVelocity(MapTile collided, Vector velocity) { * @return */ private MapTile getCollision(Vector velocity) { - int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth(),1); + int numberOfTilesToCheck = Math.max((int) gameObject.getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth(),1); Point tileIndex = getMap().getTileIndexByPosition(gameObject.getPos()); for(int i = -1;i < numberOfTilesToCheck + 1; i++) { for(int j = -1;j < numberOfTilesToCheck + 1; j++) { diff --git a/src/Level/Enemy.java b/src/Level/Enemy.java index 67fabea..c89baa4 100644 --- a/src/Level/Enemy.java +++ b/src/Level/Enemy.java @@ -3,7 +3,7 @@ import Engine.CollisionType; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; @@ -36,7 +36,7 @@ public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect ima super(image, x, y, scale, imageEffect); } - public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { + public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { super(image, x, y, scale, imageEffect, bounds); } diff --git a/src/Level/EnhancedMapTile.java b/src/Level/EnhancedMapTile.java index 96c27b7..2819134 100644 --- a/src/Level/EnhancedMapTile.java +++ b/src/Level/EnhancedMapTile.java @@ -3,7 +3,7 @@ import Engine.GraphicsHandler; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; @@ -36,7 +36,7 @@ public EnhancedMapTile(BufferedImage image, float x, float y, TileType tileType, super(image, x, y, scale, imageEffect, tileType); } - public EnhancedMapTile(BufferedImage image, float x, float y, TileType tileType, float scale, ImageEffect imageEffect, RectangleOld bounds) { + public EnhancedMapTile(BufferedImage image, float x, float y, TileType tileType, float scale, ImageEffect imageEffect, Rectangle bounds) { super(image, x, y, scale, imageEffect, bounds, tileType); } diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index 71182bb..b41c034 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -43,7 +43,7 @@ public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect super(image, x, y, scale, imageEffect); } - public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { + public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { super(image, x, y, scale, imageEffect, bounds); } diff --git a/src/Level/MapTile.java b/src/Level/MapTile.java index 0fd4af0..cd87374 100644 --- a/src/Level/MapTile.java +++ b/src/Level/MapTile.java @@ -3,7 +3,7 @@ import Engine.GraphicsHandler; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import GameObject.SpriteSheet; import java.awt.image.BufferedImage; @@ -52,7 +52,7 @@ public MapTile(BufferedImage image, float x, float y, float scale, ImageEffect i this.tileType = tileType; } - public MapTile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds, TileType tileType) { + public MapTile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds, TileType tileType) { super(image, x, y, scale, imageEffect, bounds); this.tileType = tileType; } diff --git a/src/Level/MapTileCollisionHandler.java b/src/Level/MapTileCollisionHandler.java index c4c2b34..8d1263d 100644 --- a/src/Level/MapTileCollisionHandler.java +++ b/src/Level/MapTileCollisionHandler.java @@ -20,7 +20,7 @@ public class MapTileCollisionHandler { public static MapTile lastCollidedTileX, lastCollidedTileY; public static float getAdjustedPositionAfterCollisionCheckX(GameObject gameObject, Map map, Direction direction) { - int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight(), 1); + int numberOfTilesToCheck = (int) Math.max(gameObject.getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight(), 1); float edgeBoundX = direction == Direction.LEFT ? gameObject.getScaledBounds().getX1() : gameObject.getScaledBounds().getX2(); Point tileIndex = map.getTileIndexByPosition(edgeBoundX, gameObject.getScaledBounds().getY1()); for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { @@ -61,8 +61,8 @@ public static float getAdjustedPositionAfterCollisionCheckX(GameObject gameObjec */ public static float getAdjustedPositionAfterCollisionCheckY(GameObject gameObject, Map map, Direction direction) { //Tiles to check? getting a list of tiles - int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(), 1); - float edgeBoundY = direction == Direction.UP ? gameObject.getScaledBounds().getY() : gameObject.getScaledBounds().getY2(); + int numberOfTilesToCheck = (int) Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(), 1); + float edgeBoundY = direction == Direction.UP ? gameObject.getScaledBounds().getY1() : gameObject.getScaledBounds().getY2(); /*Get the edge bounds... ok?*/ Point tileIndex = map.getTileIndexByPosition(gameObject.getScaledBounds().getX1(), edgeBoundY); /*Gets the uh, bottom left item? */ for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { /*Get only immediately surrounding map tiles. AHA */ diff --git a/src/Level/NPC.java b/src/Level/NPC.java index ddc52e0..7ca0240 100644 --- a/src/Level/NPC.java +++ b/src/Level/NPC.java @@ -4,7 +4,7 @@ import Engine.KeyboardAction; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import GameObject.SpriteSheet; import SpriteFont.SpriteFont; import Utils.Stopwatch; @@ -55,7 +55,7 @@ public NPC(BufferedImage image, float x, float y, int talkedToTime, float scale, this.talkedToTime = talkedToTime; } - public NPC(BufferedImage image, float x, float y, int talkedToTime, float scale, ImageEffect imageEffect, RectangleOld bounds) { + public NPC(BufferedImage image, float x, float y, int talkedToTime, float scale, ImageEffect imageEffect, Rectangle bounds) { super(image, x, y, scale, imageEffect, bounds); this.message = createMessage(); this.talkedToTime = talkedToTime; diff --git a/src/Level/Player.java b/src/Level/Player.java index 172ac68..c43016a 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -82,7 +82,7 @@ private void updatePlaying() { //Update Attack if (KeyboardAction.GAME_ATTACK.isDown() && attackDelay.isTimeUp()) { - int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); + int attackX = facing == Facing.RIGHT ? Math.round(getX() + getScaledWidth() - 20) : Math.round(getX()); map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); attackDelay.setWaitTime(ATTACK_DELAY); } diff --git a/src/Level/Projectile.java b/src/Level/Projectile.java index 98c3db8..c836077 100644 --- a/src/Level/Projectile.java +++ b/src/Level/Projectile.java @@ -3,8 +3,9 @@ import Engine.CollisionType; import GameObject.Frame; import GameObject.ImageEffect; -import GameObject.RectangleOld; +import GameObject.Rectangle; import GameObject.SpriteSheet; + import java.awt.image.BufferedImage; import java.util.HashMap; @@ -35,7 +36,7 @@ public Projectile(BufferedImage image, float x, float y, float scale, ImageEffec super(image, x, y, scale, imageEffect); } - public Projectile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, RectangleOld bounds) { + public Projectile(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { super(image, x, y, scale, imageEffect, bounds); } diff --git a/src/MapEditor/TileBuilder.java b/src/MapEditor/TileBuilder.java index 8a55179..f464783 100644 --- a/src/MapEditor/TileBuilder.java +++ b/src/MapEditor/TileBuilder.java @@ -76,8 +76,8 @@ public void draw() { graphicsHandler.drawRectangle( Math.round(hoveredMapTile.getX()) + 2, Math.round(hoveredMapTile.getY()) + 2, - hoveredMapTile.getScaledWidth() - 5, - hoveredMapTile.getScaledHeight() - 5, + Math.round(hoveredMapTile.getScaledWidth() - 5), + Math.round(hoveredMapTile.getScaledHeight() - 5), Color.YELLOW, 5 ); diff --git a/src/MapEditor/TilePicker.java b/src/MapEditor/TilePicker.java index 5c09e8b..036c304 100644 --- a/src/MapEditor/TilePicker.java +++ b/src/MapEditor/TilePicker.java @@ -89,8 +89,8 @@ public void draw() { graphicsHandler.drawRectangle( Math.round(selectedTile.getX()) - 2, Math.round(selectedTile.getY()) - 2, - selectedTile.getScaledWidth() + 4, - selectedTile.getScaledHeight() + 4, + Math.round(selectedTile.getScaledWidth() + 4), + Math.round(selectedTile.getScaledHeight() + 4), Color.YELLOW, 4 ); diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index 813f10c..7d5756f 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -1,16 +1,17 @@ package Maps; +import Enemies.CyborgEnemy; import Enemies.DinosaurEnemy; import Enemies.Dog; -import Enemies.CyborgEnemy; import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.*; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; + import java.util.ArrayList; // Represents a test map to be used in a level @@ -44,7 +45,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(42, 13), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap.java b/src/Maps/TestMap.java index 473aee2..d60b833 100644 --- a/src/Maps/TestMap.java +++ b/src/Maps/TestMap.java @@ -5,7 +5,7 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.*; import NPCs.Walrus; import Tilesets.CommonTileset; @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap3.java b/src/Maps/TestMap3.java index d7c1408..d7cd747 100644 --- a/src/Maps/TestMap3.java +++ b/src/Maps/TestMap3.java @@ -5,7 +5,7 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.*; import Tilesets.CommonTileset; import Utils.Direction; @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(17, 10), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap4.java b/src/Maps/TestMap4.java index 3eaf147..7c0720c 100644 --- a/src/Maps/TestMap4.java +++ b/src/Maps/TestMap4.java @@ -5,7 +5,7 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.*; import Tilesets.CommonTileset; import Utils.Direction; @@ -39,7 +39,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap5.java b/src/Maps/TestMap5.java index c5f8fbe..02903cf 100644 --- a/src/Maps/TestMap5.java +++ b/src/Maps/TestMap5.java @@ -5,7 +5,7 @@ import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.*; import Tilesets.CommonTileset; import Utils.Direction; @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestMap6.java b/src/Maps/TestMap6.java index 23c0ee4..03dd6e4 100644 --- a/src/Maps/TestMap6.java +++ b/src/Maps/TestMap6.java @@ -1,13 +1,16 @@ package Maps; import Enemies.BugEnemy; -import Enemies.DinosaurEnemy; import Enemies.CyborgEnemy; +import Enemies.DinosaurEnemy; import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; -import Level.*; +import GameObject.Rectangle; +import Level.Enemy; +import Level.EnhancedMapTile; +import Level.Map; +import Level.TileType; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -42,7 +45,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(11, 8), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); @@ -52,7 +55,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(14, 5), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.LEFT )); @@ -62,7 +65,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(38, 5), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.LEFT )); diff --git a/src/Maps/TestMap7.java b/src/Maps/TestMap7.java index fc9cdee..3b753d8 100644 --- a/src/Maps/TestMap7.java +++ b/src/Maps/TestMap7.java @@ -1,13 +1,16 @@ package Maps; import Enemies.BugEnemy; -import Enemies.DinosaurEnemy; import Enemies.CyborgEnemy; +import Enemies.DinosaurEnemy; import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; -import Level.*; +import GameObject.Rectangle; +import Level.Enemy; +import Level.EnhancedMapTile; +import Level.Map; +import Level.TileType; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; @@ -47,7 +50,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(7, 9), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); @@ -57,7 +60,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(26, 9), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); diff --git a/src/Maps/TestTutorial.java b/src/Maps/TestTutorial.java index 6b2cb99..9ecf6e5 100644 --- a/src/Maps/TestTutorial.java +++ b/src/Maps/TestTutorial.java @@ -2,15 +2,16 @@ import Enemies.BugEnemy; import Enemies.DinosaurEnemy; -import Engine.*; +import Engine.GraphicsHandler; +import Engine.ImageLoader; import EnhancedMapTiles.EndLevelBox; import EnhancedMapTiles.HorizontalMovingPlatform; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.*; +import SpriteFont.SpriteFont; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; -import SpriteFont.*; import java.awt.*; import java.util.ArrayList; @@ -40,7 +41,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new RectangleOld(0, 6, 16, 4), + new Rectangle(0, 6, 16, 4), Direction.RIGHT )); From 5ba8964feb1aad8ba3fbbc96f7d12ba5ff51a049 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 14:25:31 -0500 Subject: [PATCH 085/164] Switched back to iterative algorithm --- src/Engine/Vector.java | 3 +- src/GameObject/GameObject.java | 75 +++++++++++++++++++------------ src/GameObject/Hitbox.java | 24 ++++++++++ src/GameObject/Intersectable.java | 12 ++++- src/GameObject/Overlappable.java | 9 ++++ src/Level/Map.java | 7 ++- 6 files changed, 95 insertions(+), 35 deletions(-) diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index 3f2db86..dea033a 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -53,10 +53,9 @@ public void set(float x, float y) { this.y = y; } - public Vector set(Vector location) { + public void set(Vector location) { this.x = location.x; this.y = location.y; - return this; } public Vector getDivided(float divisor) { diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 253595e..15bfbc2 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -28,8 +28,8 @@ * 3. collision detection with a map * 4. performing proper draw logic based on camera movement * - * @author Thomas Kwashnak - * @author Alex Thimineur + Others + * @author Thomas Kwashnak (Modified) + * @author Alex Thimineur (plus extra) */ /* @@ -130,42 +130,58 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec public void moveHandleCollision(Vector providedVelocity) { Vector velocity = providedVelocity.getMultiplied(GameThread.UPDATE_FACTOR); - Vector originalVelocity = velocity.clone(); + Vector oVelocity = velocity.clone(); + Vector oPosition = pos.clone(); Vector unit = velocity.getUnit(); - Vector[] startingPoints = new Vector[] { - pos, pos.getAdd(new Vector(getBounds().getWidth(),0)), pos.getAdd(new Vector(0,getBounds().getHeight())), - pos.getAdd(new Vector(getBounds().getWidth(),getBounds().getHeight())) - }; - - - Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getLocation()); +// Vector[] startingPoints = new Vector[] { +// pos, pos.getAdd(new Vector(getBounds().getWidth(),0)), pos.getAdd(new Vector(0,getBounds().getHeight())), +// pos.getAdd(new Vector(getBounds().getWidth(),getBounds().getHeight())) +// }; -// int rangeWidth = getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; -// int rangeHeight = getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; + float boundingVelocity = Math.max(velocity.getMagnitude(),getBounds().getScaledWidth() * 7); - float boundingVelocity = (float) Math.max(velocity.getMagnitude(),getBounds().getWidth() * 1.5); + List tiles = map.getMapTilesInRange(getCenter(), boundingVelocity); -// int rangeHeight = (int) ( (boundingVelocity + getBounds().getHeight()) / map.getTileset().getScaledSpriteHeight()) * 2; -// int rangeWidth = (int) ( (boundingVelocity + getBounds().getWidth()) / map.getTileset().getScaledSpriteWidth()) * 2; + while(velocity.getMagnitude() > 1) { + move(unit); //Move 1 unit ahead + velocity.subtract(1); + //If it collides, moves one back, sets lastCollided to that, set magnitude to 1 + if(getCollidedTile(tiles,velocity) != null) { + move(unit.getNegative()); + velocity.set(unit); + break; + } + } - List tiles = map.getMapTilesInRange(getCenter(), boundingVelocity); +// see if it collides + move(velocity); + if ((lastCollided = getCollidedTile(tiles,velocity)) != null) { + handleCollision(lastCollided,velocity); + System.out.println("Player = " + getPos() + ", Block = " + lastCollided.getPos()); + move(velocity.getNegative()); + } - //this doesn't seem to work - System.out.println("Velocity: " + velocity); + } - for(MapTile mapTile : tiles) { - checkMapTile(startingPoints,velocity,mapTile); + private MapTile getCollidedTile(List mapTiles, Vector velocity) { + System.out.println("Player: " + pos); + for(MapTile mapTile : mapTiles) { + if((mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0))) { +// return mapTile; + System.out.println(mapTile.pos); + if(intersects(mapTile)) { + System.out.println("Intersects"); + return mapTile; + } + } } -// -// for(MapTile mapTile : map.getEnhancedMapTiles()) { -// checkMapTile(startingPoints,velocity,mapTile); -// } + return null; + } + + private void handleCollision(MapTile mapTile, Vector velocity) { - System.out.println("Update Velocity: " + velocity); - move(velocity); - inAir = velocity.getY() != 0; } // // /** @@ -188,12 +204,14 @@ public void moveHandleCollision(Vector providedVelocity) { // return false; // } - private void checkMapTile(Vector[] startingPoints, Vector velocity, MapTile mapTile) { + @Deprecated + private void checkMapTileOld(Vector[] startingPoints, Vector velocity, MapTile mapTile) { if(mapTile != null && (mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0))) { updateVelocityOld(startingPoints, velocity, mapTile); } } + @Deprecated private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile mapTile) { // //x1 x2 y1 y2 are ordered values where x1 < x2 and y1 < y2. These indicate the x and y values of the edges of the bounding box @@ -215,7 +233,6 @@ private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile ma - } @Deprecated diff --git a/src/GameObject/Hitbox.java b/src/GameObject/Hitbox.java index 45375a9..2b3599b 100644 --- a/src/GameObject/Hitbox.java +++ b/src/GameObject/Hitbox.java @@ -2,7 +2,31 @@ import Engine.Vector; +/** + * Indicates that a class contains a HitBox. The hitbox is split up into two locations, the min value and the max value. + * + *

+ * Given a rectangle with 4 locations, as listed: {@code (x1, y1), (x1, y2), (x2, y1), (x2, y2)}, the min and max locations would be as follows + *

  • Min Location: {@code (x1, y1)}
  • + *
  • Max Location: {@code (x2, y2)}
+ * Where {@code x1 < x2} and {@code y1 < y2} + *

+ * @author Thomas Kwashnak + */ public interface Hitbox { + + /** + * Returns the upper left point of a hitbox. (Assuming that the top left corner is {@code (0,0)}). In short, given a hitbox with the + * points {@code (x1, y1), (x1, y2), (x2, y1), (x2, y2)}, returns {@code (x1, y1)} where {@code x1 < x2} and {@code y1 < y2} + * @return A vector representing {@code (x1, y1)} + * @see Hitbox + */ Vector getMinLocation(); + /** + * Returns the bottom right point of a hitbox. (Assuming that the top left corner is {@code (0,0)}). In short, given a hitbox with the + * points {@code (x1, y1), (x1, y2), (x2, y1), (x2, y2)}, returns {@code (x2, y2)} where {@code x2 > x1} and {@code y2 > y1} + * @return A vector representing {@code (x2, y2)} + * @see Hitbox + */ Vector getMaxLocation(); } diff --git a/src/GameObject/Intersectable.java b/src/GameObject/Intersectable.java index 9e00192..a19d47e 100644 --- a/src/GameObject/Intersectable.java +++ b/src/GameObject/Intersectable.java @@ -1,7 +1,15 @@ package GameObject; -import Engine.Vector; - +/** + * Indicates that an object can be checked for intersection with another intersectable + * @author Thomas Kwashnak + */ public interface Intersectable extends Hitbox { + + /** + * Checks the intersection with another intersectable + * @param other Intersectable to check intersection with + * @return {@code true} if this intersectable and the provided intersectable intersect + */ boolean intersects(Intersectable other); } diff --git a/src/GameObject/Overlappable.java b/src/GameObject/Overlappable.java index 9fb606c..d4b8c98 100644 --- a/src/GameObject/Overlappable.java +++ b/src/GameObject/Overlappable.java @@ -1,5 +1,14 @@ package GameObject; +/** + * Indicates that an object can be checked if it overlaps with another overlappable + * @author Thomas Kwashnak + */ public interface Overlappable extends Hitbox { + /** + * Checks the overlapping with another Overlappable + * @param other Overlappable to check overlapping with + * @return {@code true} if this intersectable and the provided intersectable intersect + */ boolean overlaps(Overlappable other); } diff --git a/src/Level/Map.java b/src/Level/Map.java index fff4124..5a91deb 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -272,13 +272,16 @@ public MapTile[] getTilesInBounds(Vector start, int width, int height) { */ public List getMapTilesInRange(Vector origin, float length) { List tiles = new ArrayList<>((int) (4 * length * length / tileset.getScaledSpriteHeight() / tileset.getScaledSpriteWidth())); + float lSquared = length * length; for(MapTile tile : mapTiles) { - if(Math.min(Math.abs(tile.getCenter().getX() - origin.getX()), Math.abs(tile.getCenter().getY() - origin.getY())) < length) { + float dx = tile.getX() - origin.getX(), dy = tile.getY() - origin.getY(); + if(dx * dx + dy * dy < lSquared) { tiles.add(tile); } } for(MapTile tile : enhancedMapTiles) { - if(Math.min(Math.abs(tile.getCenter().getX() - origin.getX()), Math.abs(tile.getCenter().getY() - origin.getY())) < length) { + float dx = tile.getX() - origin.getX(), dy = tile.getY() - origin.getY(); + if(dx * dx + dy * dy < lSquared) { tiles.add(tile); } } From cf55e973c4ae84c8404e5ebf83fc55414ba3553a Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 14:55:03 -0500 Subject: [PATCH 086/164] So collision detection works... --- src/GameObject/AnimatedSprite.java | 11 ++-- src/GameObject/GameObject.java | 17 ++---- src/GameObject/Rectangle.java | 97 +++++++++++++++++++----------- 3 files changed, 74 insertions(+), 51 deletions(-) diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index ec6d2d4..51525db 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -114,7 +114,7 @@ public void setAnimations(HashMap animations) { // and location updated to match any changes to the animated sprite class protected void updateCurrentFrame() { currentFrame = getCurrentFrame(); - currentFrame.setLocation(pos.clone()); + currentFrame.setLocationReference(pos); } // gets the frame from current animation that the animated sprite class is currently using @@ -144,11 +144,13 @@ public void drawBounds(GraphicsHandler graphicsHandler, Color color) { public void setX(float x) { pos.setX(x); - currentFrame.getLocation().setX(x); } public void setY(float y) { pos.setY(y); - currentFrame.getLocation().setY(y); + } + + public void setLocation(Vector location) { + pos.set(location); } public void setLocation(float x, float y) { @@ -157,8 +159,7 @@ public void setLocation(float x, float y) { } public void moveX(float dx) { - this.pos.addX(dx); - currentFrame.move(new Vector(dx,0)); + move(new Vector(dx,0)); } public void moveRight(float dx) { diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 15bfbc2..deb928c 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -139,7 +139,7 @@ public void moveHandleCollision(Vector providedVelocity) { // pos.getAdd(new Vector(getBounds().getWidth(),getBounds().getHeight())) // }; - float boundingVelocity = Math.max(velocity.getMagnitude(),getBounds().getScaledWidth() * 7); + float boundingVelocity = Math.max(velocity.getMagnitude(),getMap().getTileset().getScaledSpriteWidth() * 3); List tiles = map.getMapTilesInRange(getCenter(), boundingVelocity); @@ -159,22 +159,17 @@ public void moveHandleCollision(Vector providedVelocity) { if ((lastCollided = getCollidedTile(tiles,velocity)) != null) { handleCollision(lastCollided,velocity); System.out.println("Player = " + getPos() + ", Block = " + lastCollided.getPos()); - move(velocity.getNegative()); +// move(unit.getNegative()); } - + inAir = lastCollided == null; } private MapTile getCollidedTile(List mapTiles, Vector velocity) { - System.out.println("Player: " + pos); + System.out.println("\nPlayer: " + pos); for(MapTile mapTile : mapTiles) { - if((mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0))) { -// return mapTile; - System.out.println(mapTile.pos); - if(intersects(mapTile)) { - System.out.println("Intersects"); - return mapTile; - } + if((mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0)) && intersects(mapTile)) { + return mapTile; } } return null; diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index c8b06a9..ef4e6fc 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -18,15 +18,11 @@ public class Rectangle implements Drawable, Intersectable, Overlappable { protected Color color, borderColor; public Rectangle(float x, float y, float width, float height) { - this(new Vector(x,y), new Vector(width,height)); + this(new Vector(x, y), new Vector(width, height)); } public Rectangle(Vector location, Vector dimension) { - this(location,dimension,1); - } - - public Rectangle(float x, float y, float width, float height, float scale) { - this(new Vector(x,y), new Vector(width,height), scale); + this(location, dimension, 1); } public Rectangle(Vector location, Vector dimension, float scale) { @@ -35,8 +31,8 @@ public Rectangle(Vector location, Vector dimension, float scale) { this.scale = scale; } - public float getX1() { - return location.getX(); + public Rectangle(float x, float y, float width, float height, float scale) { + this(new Vector(x, y), new Vector(width, height), scale); } public float getX2() { @@ -47,10 +43,6 @@ public float getScaledX2() { return location.getX() + (dimension.getX() * scale); } - public float getY1() { - return location.getY(); - } - public float getY2() { return location.getY() + dimension.getY(); } @@ -59,10 +51,6 @@ public float getScaledY2() { return location.getY() + (dimension.getY() * scale); } - public void setLocation(Vector location) { - this.location = location; - } - public void move(Vector displacement) { location.add(displacement); } @@ -79,12 +67,29 @@ public Vector getLocation() { return location; } - public float getScaledWidth() { - return dimension.getX() * scale; + public void setLocation(Vector vector) { + this.location.set(vector); } - public float getScaledHeight() { - return dimension.getY() * scale; + public void setLocationReference(Vector location) { + this.location = location; + } + + public void update() { + } + + public boolean intersects(Intersectable other) { + Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); + boolean xIntersects = min.getX() > minOther.getX() && min.getX() < maxOther.getX(); + xIntersects |= max.getX() > minOther.getX() && max.getX() < maxOther.getX(); + xIntersects |= minOther.getX() > min.getX() && minOther.getX() < max.getX(); + xIntersects |= maxOther.getX() > min.getX() && maxOther.getX() < max.getX(); + boolean yIntersects = min.getY() > minOther.getY() && min.getY() < maxOther.getY(); + yIntersects |= max.getY() > minOther.getY() && max.getY() < maxOther.getY(); + yIntersects |= minOther.getY() > min.getY() && minOther.getY() < max.getY(); + yIntersects |= maxOther.getY() > min.getY() && maxOther.getY() < max.getY(); +// System.out.println(xIntersects + " " + yIntersects + " " + min + " " + max + " " + minOther + " " + maxOther); + return xIntersects && yIntersects; } public Vector getMinLocation() { @@ -95,27 +100,49 @@ public Vector getMaxLocation() { return location.getAdd(dimension); } - public void update() {} - - public boolean intersects(Intersectable other) { - Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); - return (min.getX() < maxOther.getX()) && (max.getX() > minOther.getX()) && (min.getY() < maxOther.getY()) && (max.getY() > minOther.getY()); - } - public boolean overlaps(Overlappable other) { Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); - return (min.getX() <= maxOther.getX()) && (max.getX() >= minOther.getX()) && (min.getY() <= maxOther.getY()) && (max.getY() >= minOther.getY()); + boolean xIntersects = min.getX() >= minOther.getX() && min.getX() <= maxOther.getX(); + xIntersects |= max.getX() > minOther.getX() && max.getX() <= maxOther.getX(); + xIntersects |= minOther.getX() >= min.getX() && minOther.getX() <= max.getX(); + xIntersects |= maxOther.getX() >= min.getX() && maxOther.getX() <= max.getX(); + boolean yIntersects = min.getY() >= minOther.getY() && min.getY() <= maxOther.getY(); + yIntersects |= max.getY() >= minOther.getY() && max.getY() <= maxOther.getY(); + yIntersects |= minOther.getY() >= min.getY() && minOther.getY() <= max.getY(); + yIntersects |= maxOther.getY() >= min.getY() && maxOther.getY() <= max.getY(); + // System.out.println(xIntersects + " " + yIntersects + " " + min + " " + max + " " + minOther + " " + maxOther); + return xIntersects && yIntersects; } public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawFilledRectangle(Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), color); + graphicsHandler.drawFilledRectangle( + Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), color); if (borderColor != null && !borderColor.equals(color)) { - graphicsHandler.drawRectangle(Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), borderColor, BORDER_THICKNESS); + graphicsHandler.drawRectangle( + Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), borderColor, + BORDER_THICKNESS + ); } } + public float getX1() { + return location.getX(); + } + + public float getY1() { + return location.getY(); + } + + public float getScaledWidth() { + return dimension.getX() * scale; + } + + public float getScaledHeight() { + return dimension.getY() * scale; + } + public String toString() { - return String.format("Rectangle: location = %s, dimensions = %s",location.toString(),dimension.toString()); + return String.format("Rectangle: location = %s, dimensions = %s", location.toString(), dimension.toString()); } public Color getColor() { @@ -146,14 +173,14 @@ public float getWidth() { return dimension.getX(); } - public float getHeight() { - return dimension.getY(); - } - public void setWidth(float width) { dimension.setX(width); } + public float getHeight() { + return dimension.getY(); + } + public void setHeight(float height) { dimension.setY(height); } From cc9d1804f13cb7a019223a7cd82f79e9629dd1a5 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 16:17:18 -0500 Subject: [PATCH 087/164] Cleaning up Entity Bounds --- src/Engine/GamePanel.java | 4 +- src/Engine/ScreenManager.java | 12 +- src/Engine/Vector.java | 6 + src/GameObject/AnimatedSprite.java | 523 ++++++++++++++++------------- src/GameObject/GameObject.java | 41 ++- src/GameObject/Rectangle.java | 6 +- src/GameObject/Sprite.java | 129 +++---- src/GameObject/SpriteOld.java | 122 +++++++ 8 files changed, 519 insertions(+), 324 deletions(-) create mode 100644 src/GameObject/SpriteOld.java diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index ed08713..6b8825a 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -3,7 +3,7 @@ import Game.GameState; import Game.GameThread; import Game.ScreenCoordinator; -import GameObject.RectangleOld; +import GameObject.Rectangle; import Level.Player; import Utils.Colors; @@ -170,7 +170,7 @@ public static void mouseClicked(MouseEvent e) { // JPanel's width and height, which aren't available in the constructor public void setupGame() { setBackground(Colors.CORNFLOWER_BLUE); - screenManager.initialize(new RectangleOld(getX(), getY(), getWidth(), getHeight())); + screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); doPaint = true; } diff --git a/src/Engine/ScreenManager.java b/src/Engine/ScreenManager.java index 774a925..22489a3 100644 --- a/src/Engine/ScreenManager.java +++ b/src/Engine/ScreenManager.java @@ -1,7 +1,7 @@ package Engine; -import GameObject.RectangleOld; +import GameObject.Rectangle; /* * The game engine uses this class to start off the cascading Screen updating/drawing @@ -11,9 +11,9 @@ public class ScreenManager { private Screen currentScreen; - private static RectangleOld screenBounds = new RectangleOld(0, 0, 0, 0); + private static Rectangle screenBounds = new Rectangle(0, 0, 0, 0); - public void initialize(RectangleOld screenBounds) { + public void initialize(Rectangle screenBounds) { ScreenManager.screenBounds = screenBounds; setCurrentScreen(new DefaultScreen()); } @@ -35,16 +35,16 @@ public void draw(GraphicsHandler graphicsHandler) { // gets width of currentScreen -- can be called from anywhere in an application public static int getScreenWidth() { - return screenBounds.getWidth(); + return Math.round(screenBounds.getWidth()); } // gets height of currentScreen -- can be called from anywhere in an application public static int getScreenHeight() { - return screenBounds.getHeight(); + return Math.round(screenBounds.getHeight()); } // gets bounds of currentScreen -- can be called from anywhere in an application - public static RectangleOld getScreenBounds() { + public static Rectangle getScreenBounds() { return screenBounds; } } diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java index dea033a..5b9c338 100644 --- a/src/Engine/Vector.java +++ b/src/Engine/Vector.java @@ -2,6 +2,8 @@ import Utils.Point; +import java.awt.image.BufferedImage; + public class Vector { private float x,y; @@ -154,4 +156,8 @@ public void multiplyX(float magnitude) { public void multiplyY(float magnitude) { y *= magnitude; } + + public static Vector convertImageDimensions(BufferedImage bufferedImage) { + return new Vector(bufferedImage.getWidth(), bufferedImage.getHeight()); + } } diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index 51525db..34bc60e 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -8,283 +8,350 @@ import java.awt.image.BufferedImage; import java.util.HashMap; -/* - Represents an animated sprite - Animations can either be passed in directly or loaded automatically in a subclass by overriding the getAnimations method - This class contains logic for transitioning animations as well as playing out the frames in an animation in a loop - Subclasses need to call down to this class's update method in order for animation logic to be performed - While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite (based on value of currentFrame) -*/ +/** + * Represents an animated sprite
+ * Animations can either be passed in directly or loaded automatically in a subclass by overriding the getAnimations method
+ * This class contains logic for transitioning animations as well as playing out the frames in an animation in a loop
+ * Subclasses need to call down to this class's update method in order for animation logic to be performed
+ * While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite + * (based on value of currentFrame)
+ */ public class AnimatedSprite implements Intersectable, Overlappable { - // location of entity -// protected float x, y; - /** - * Position of the Animated Sprite - */ - protected Vector pos; - // maps animation name to an array of Frames representing one animation - protected HashMap animations; - - // keeps track of current animation the sprite is using - protected String currentAnimationName = ""; - protected String previousAnimationName = ""; - - // keeps track of current frame number in an animation the sprite is using - protected int currentFrameIndex; - - // if an animation has looped, this is set to true - protected boolean hasAnimationLooped; + /** + * Position of the Animated Sprite + */ + protected Vector pos; + + /** + * maps animation name to an array of Frames representing one animation + */ + protected HashMap animations; + + /** + * keeps track of current animation the sprite is using + */ + protected String currentAnimationName = ""; + protected String previousAnimationName = ""; + + /** + * keeps track of current frame number in an animation the sprite is using + */ + protected int currentFrameIndex; + + /** + * if an animation has looped, this is set to true + */ + protected boolean hasAnimationLooped; + + /** + * current Frame object the animation is using based on currentAnimationName and currentFrameIndex + * this is essential for the class, as it uses this to be treated as "one sprite" + */ + protected Frame currentFrame; + + /** + * times frame delay before transitioning into the next frame of an animation + */ + private Stopwatch frameTimer = new Stopwatch(); + + public AnimatedSprite(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { + pos = new Vector(x, y); + this.animations = getAnimations(spriteSheet); + this.currentAnimationName = startingAnimationName; + updateCurrentFrame(); + } - // current Frame object the animation is using based on currentAnimationName and currentFrameIndex - // this is essential for the class, as it uses this to be treated as "one sprite" - protected Frame currentFrame; + /** + * Subclasses can override this method in order to add their own animations, which will be loaded in at initialization time + * + * @param spriteSheet + * + * @return + */ + public HashMap getAnimations(SpriteSheet spriteSheet) { + return null; + } - // times frame delay before transitioning into the next frame of an animation - private Stopwatch frameTimer = new Stopwatch(); + /** + * currentFrame is essentially a sprite, so each game loop cycle
+ * the sprite needs to have its current state updated based on animation logic,
+ * and location updated to match any changes to the animated sprite class + */ + protected void updateCurrentFrame() { + currentFrame = getCurrentFrame(); + currentFrame.setLocationReference(pos); + } - public AnimatedSprite(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { - pos = new Vector(x, y); - this.animations = getAnimations(spriteSheet); - this.currentAnimationName = startingAnimationName; - updateCurrentFrame(); - } + /** + * gets the frame from current animation that the animated sprite class is currently using + * + * @return + */ + protected Frame getCurrentFrame() { + return animations.get(currentAnimationName)[currentFrameIndex]; + } public AnimatedSprite(float x, float y, HashMap animations, String startingAnimationName) { - pos = new Vector(x, y); + pos = new Vector(x, y); this.animations = animations; this.currentAnimationName = startingAnimationName; updateCurrentFrame(); } - public AnimatedSprite(BufferedImage image, float x, float y, String startingAnimationName) { - pos = new Vector(x, y); - SpriteSheet spriteSheet = new SpriteSheet(image, image.getWidth(), image.getHeight()); + public AnimatedSprite(BufferedImage image, float x, float y, String startingAnimationName) { + pos = new Vector(x, y); + SpriteSheet spriteSheet = new SpriteSheet(image, image.getWidth(), image.getHeight()); this.animations = getAnimations(spriteSheet); this.currentAnimationName = startingAnimationName; - updateCurrentFrame(); - } + updateCurrentFrame(); + } public AnimatedSprite(float x, float y) { - pos = new Vector(x, y); + pos = new Vector(x, y); this.animations = new HashMap<>(); this.currentAnimationName = ""; } - public void update() { - // if animation name has been changed (previous no longer equals current), setup for the new animation and start using it - if (!previousAnimationName.equals(currentAnimationName)) { - currentFrameIndex = 0; - updateCurrentFrame(); - frameTimer.setWaitTime(getCurrentFrame().getDelay()); - hasAnimationLooped = false; - } else { - // if animation has more than one frame, check if it's time to transition to a new frame based on that frame's delay - if (getCurrentAnimation().length > 1 && currentFrame.getDelay() > 0) { - - // if enough time has passed based on current frame's delay and it's time to transition to a new frame, - // update frame index to the next frame - // It will also wrap around back to the first frame index if it was already on the last frame index (the animation will loop) - if (frameTimer.isTimeUp()) { - currentFrameIndex++; - if (currentFrameIndex >= animations.get(currentAnimationName).length) { - currentFrameIndex = 0; - hasAnimationLooped = true; - } - frameTimer.setWaitTime(getCurrentFrame().getDelay()); - updateCurrentFrame(); - } - } - } - previousAnimationName = currentAnimationName; - } - - // Subclasses can override this method in order to add their own animations, which will be loaded in at initialization time - public HashMap getAnimations(SpriteSheet spriteSheet) { - return null; - } - - public void setAnimations(HashMap animations) { - this.animations = animations; - - } - - // currentFrame is essentially a sprite, so each game loop cycle - // the sprite needs to have its current state updated based on animation logic, - // and location updated to match any changes to the animated sprite class - protected void updateCurrentFrame() { - currentFrame = getCurrentFrame(); - currentFrame.setLocationReference(pos); - } - - // gets the frame from current animation that the animated sprite class is currently using - protected Frame getCurrentFrame() { - return animations.get(currentAnimationName)[currentFrameIndex]; - } - - // gets the animation that the animated sprite class is currently using - protected Frame[] getCurrentAnimation() { return animations.get(currentAnimationName); } - - public void draw(GraphicsHandler graphicsHandler) { - currentFrame.draw(graphicsHandler); - } + public void update() { + // if animation name has been changed (previous no longer equals current), setup for the new animation and start using it + if (!previousAnimationName.equals(currentAnimationName)) { + currentFrameIndex = 0; + updateCurrentFrame(); + frameTimer.setWaitTime(getCurrentFrame().getDelay()); + hasAnimationLooped = false; + } else { + // if animation has more than one frame, check if it's time to transition to a new frame based on that frame's delay + if (getCurrentAnimation().length > 1 && currentFrame.getDelay() > 0) { + + // if enough time has passed based on current frame's delay and it's time to transition to a new frame, + // update frame index to the next frame + // It will also wrap around back to the first frame index if it was already on the last frame index (the animation will loop) + if (frameTimer.isTimeUp()) { + currentFrameIndex++; + if (currentFrameIndex >= animations.get(currentAnimationName).length) { + currentFrameIndex = 0; + hasAnimationLooped = true; + } + frameTimer.setWaitTime(getCurrentFrame().getDelay()); + updateCurrentFrame(); + } + } + } + previousAnimationName = currentAnimationName; + } + + /** + * gets the animation that the animated sprite class is currently using + * + * @return + */ + protected Frame[] getCurrentAnimation() { + return animations.get(currentAnimationName); + } + + public void setAnimations(HashMap animations) { + this.animations = animations; + } + + public void draw(GraphicsHandler graphicsHandler) { + currentFrame.draw(graphicsHandler); + } public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - currentFrame.drawBounds(graphicsHandler, color); - } - - public float getX() { return currentFrame.getX1(); } - public float getY() { return currentFrame.getY1(); } - public float getX1() { return currentFrame.getX1(); } - public float getY1() { return currentFrame.getY1(); } - public float getX2() { return currentFrame.getX2(); } - public float getScaledX2() { return currentFrame.getScaledX2(); } - public float getY2() { return currentFrame.getY2(); } - public float getScaledY2() { return currentFrame.getScaledY2(); } - - public void setX(float x) { - pos.setX(x); - } - public void setY(float y) { - pos.setY(y); - } - - public void setLocation(Vector location) { - pos.set(location); - } - - public void setLocation(float x, float y) { - this.setX(x); - this.setY(y); - } - - public void moveX(float dx) { - move(new Vector(dx,0)); - } - - public void moveRight(float dx) { - moveX(dx); - } - - public void moveLeft(float dx) { - moveX(-dx); - } - - public void moveY(float dy) { - this.pos.addY(dy); - currentFrame.move(new Vector(0,dy)); - } - - public void moveDown(float dy) { - moveY(dy); - } - - public void moveUp(float dy) { - moveY(-dy); - } - - public float getScale() { - return currentFrame.getScale(); - } - - public void setScale(float scale) { - currentFrame.setScale(scale); - } - - public float getWidth() { - return currentFrame.getWidth(); - } - public float getHeight() { - return currentFrame.getHeight(); - } - public void setWidth(float width) { - currentFrame.setWidth(width); - } - public void setHeight(float height) { - currentFrame.setHeight(height); - } - public float getScaledWidth() { - return currentFrame.getScaledWidth(); - } - public float getScaledHeight() { - return currentFrame.getScaledHeight(); - } - - public Rectangle getBounds() { - return currentFrame.getBounds(); - } - - public Rectangle getScaledBounds() { - return currentFrame.getScaledBounds(); - } + currentFrame.drawBounds(graphicsHandler, color); + } - public float getBoundsX1() { - return currentFrame.getBoundsX1(); + public float getX() { + return currentFrame.getBounds().getX1(); } - public float getScaledBoundsX1() { - return currentFrame.getScaledBoundsX1(); + public void setX(float x) { + pos.setX(x); + } + + public float getY() { + return currentFrame.getBounds().getY1(); + } + + public void setY(float y) { + pos.setY(y); + } + + public float getX1() { + return currentFrame.getBounds().getX1(); + } + + public float getY1() { + return currentFrame.getBounds().getY1(); + } + + public float getX2() { + return currentFrame.getBounds().getX2(); + } + + public float getScaledX2() { + return currentFrame.getScaledBounds().getX2(); + } + + public float getY2() { + return currentFrame.getBounds().getY2(); + } + + public float getScaledY2() { + return currentFrame.getScaledBounds().getY2(); + } + + public void setLocation(Vector location) { + pos.set(location); + } + + public void setLocation(float x, float y) { + this.setX(x); + this.setY(y); + } + + public void moveRight(float dx) { + moveX(dx); + } + + public void moveX(float dx) { + move(new Vector(dx, 0)); + } + + public void move(Vector vector) { + pos.add(vector); + } + + public void moveLeft(float dx) { + moveX(-dx); + } + + public void moveDown(float dy) { + moveY(dy); + } + + public void moveY(float dy) { + this.pos.addY(dy); + currentFrame.move(new Vector(0, dy)); + } + + public void moveUp(float dy) { + moveY(-dy); + } + + public float getScale() { + return currentFrame.getScale(); + } + + public void setScale(float scale) { + currentFrame.setScale(scale); + } + + @Deprecated + public float getWidth() { + return currentFrame.getWidth(); + } + + @Deprecated + public void setWidth(float width) { + currentFrame.setWidth(width); + } + + @Deprecated + public float getHeight() { + return currentFrame.getHeight(); + } + + @Deprecated + public void setHeight(float height) { + currentFrame.setHeight(height); + } + + public Rectangle getBounds() { + return currentFrame.getBounds(); + } + + public void setBounds(Rectangle bounds) { + currentFrame.setBounds(bounds); + } + + public float getBoundsX1() { + return currentFrame.getBounds().getX1(); } public float getBoundsX2() { - return currentFrame.getBoundsX2(); + return currentFrame.getBounds().getX2(); } public float getScaledBoundsX2() { - return currentFrame.getScaledBoundsX2(); + return currentFrame.getBounds().getScaledX2(); } public float getBoundsY1() { - return currentFrame.getBoundsY1(); - } - - public float getScaledBoundsY1() { - return currentFrame.getScaledBoundsY1(); + return currentFrame.getBounds().getY1(); } public float getBoundsY2() { - return currentFrame.getBoundsY2(); + return currentFrame.getBounds().getY2(); } public float getScaledBoundsY2() { - return currentFrame.getScaledBoundsY2(); + return currentFrame.getBounds().getScaledY2(); } - public void setBounds(Rectangle bounds) { - currentFrame.setBounds(bounds); - } - + @Override public boolean intersects(Intersectable other) { return currentFrame.intersects(other); } - public boolean overlaps(Overlappable other) { return currentFrame.overlaps(other); } + @Override + public boolean overlaps(Overlappable other) { + return currentFrame.overlaps(other); + } + + @Override + public String toString() { + return String.format("Current Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", pos.getX(), pos.getY(), getScaledWidth(), + getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight() + ); + } + + public float getScaledWidth() { + return currentFrame.getScaledBounds().getWidth(); + } + + public float getScaledHeight() { + return currentFrame.getScaledBounds().getWidth(); + } + + public float getScaledBoundsX1() { + return currentFrame.getScaledBounds().getX1(); + } + + public float getScaledBoundsY1() { + return currentFrame.getScaledBounds().getY1(); + } - @Override - public String toString() { - return String.format("Current Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", pos.getX(), pos.getY(), getScaledWidth(), - getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); - } - - public void setCurrentAnimationName(String name) { - this.currentAnimationName = name; - } + public Rectangle getScaledBounds() { + return currentFrame.getScaledBounds(); + } - public Vector getPos() { - return pos; - } + public void setCurrentAnimationName(String name) { + this.currentAnimationName = name; + } - public void move(Vector vector) { - pos.add(vector); - } + public Vector getPos() { + return pos; + } - @Override - public Vector getMinLocation() { - return currentFrame.getMinLocation(); - } + @Override + public Vector getMinLocation() { + return currentFrame.getMinLocation(); + } - @Override - public Vector getMaxLocation() { - return currentFrame.getMaxLocation(); - } + @Override + public Vector getMaxLocation() { + return currentFrame.getMaxLocation(); + } } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index deb928c..18b6a54 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -16,6 +16,7 @@ import java.awt.*; import java.awt.image.BufferedImage; +import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -156,17 +157,16 @@ public void moveHandleCollision(Vector providedVelocity) { // see if it collides move(velocity); + inAir = true; if ((lastCollided = getCollidedTile(tiles,velocity)) != null) { handleCollision(lastCollided,velocity); System.out.println("Player = " + getPos() + ", Block = " + lastCollided.getPos()); // move(unit.getNegative()); } - - inAir = lastCollided == null; } private MapTile getCollidedTile(List mapTiles, Vector velocity) { - System.out.println("\nPlayer: " + pos); + System.out.println("\nPlayer: " + pos + " " + velocity); for(MapTile mapTile : mapTiles) { if((mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0)) && intersects(mapTile)) { return mapTile; @@ -176,7 +176,42 @@ private MapTile getCollidedTile(List mapTiles, Vector velocity) { } private void handleCollision(MapTile mapTile, Vector velocity) { + //initializing x1 x2 y1 y2 ox1 ox2 oy1 oy2 + float x1 = getScaledBoundsX1(), x2 = getScaledBoundsX2(), y1 = getScaledBoundsY1(), y2 = getScaledBoundsY2(); + float ox1 = mapTile.getScaledBoundsX1(), ox2 = mapTile.getScaledBoundsX2(), oy1 = mapTile.getScaledBoundsY1(), oy2 = + mapTile.getScaledBoundsY2(); + System.out.println(x1 + " " + x2 + " " + y1 + " " + y2 + " | " + ox1 + " " + ox2 + " " + oy1 + " " + oy2); + System.out.println(getBounds() + " " + mapTile.getBounds()); + if(getIntersected(x1,x2,ox1,ox2) > getIntersected(y1,y2,oy1,oy2)) { + //Vertical impact + if(y1 < oy1) { + //downwards + inAir = false; + move(new Vector(0,oy1 - y2)); + } else { + move(new Vector(0,oy2 - y1)); + } + + } else { + //Horizontal impact + if(x1 < ox1) { + move(new Vector(ox1 - x2,0)); + } else { + move(new Vector(ox2 - x1,0)); + } + + } + } + /** + * Given 2 ranges that intersect, returns the amount of range intersected + *

Given that {@code x1 < x2} and {@code ox1 < ox2}

+ * @param values + * @return Amount of range intersected + */ + private static float getIntersected(float... values) { + Arrays.sort(values); + return values[2] - values[1]; } // // /** diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index ef4e6fc..8ea4b8e 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -88,7 +88,6 @@ public boolean intersects(Intersectable other) { yIntersects |= max.getY() > minOther.getY() && max.getY() < maxOther.getY(); yIntersects |= minOther.getY() > min.getY() && minOther.getY() < max.getY(); yIntersects |= maxOther.getY() > min.getY() && maxOther.getY() < max.getY(); -// System.out.println(xIntersects + " " + yIntersects + " " + min + " " + max + " " + minOther + " " + maxOther); return xIntersects && yIntersects; } @@ -110,7 +109,6 @@ public boolean overlaps(Overlappable other) { yIntersects |= max.getY() >= minOther.getY() && max.getY() <= maxOther.getY(); yIntersects |= minOther.getY() >= min.getY() && minOther.getY() <= max.getY(); yIntersects |= maxOther.getY() >= min.getY() && maxOther.getY() <= max.getY(); - // System.out.println(xIntersects + " " + yIntersects + " " + min + " " + max + " " + minOther + " " + maxOther); return xIntersects && yIntersects; } @@ -184,4 +182,8 @@ public float getHeight() { public void setHeight(float height) { dimension.setY(height); } + + public Rectangle getScaled() { + return new Rectangle(location,dimension.getMultiplied(scale)); + } } diff --git a/src/GameObject/Sprite.java b/src/GameObject/Sprite.java index 1062e3f..b60f635 100644 --- a/src/GameObject/Sprite.java +++ b/src/GameObject/Sprite.java @@ -1,121 +1,84 @@ package GameObject; import Engine.GraphicsHandler; -import Engine.ImageLoader; +import Engine.Vector; import java.awt.*; import java.awt.image.BufferedImage; -// This class is for representing a Sprite, which is essentially a Rectangle with an image attached -// it also includes an attribute for "bounds", which can be thought of a sub rectangle on the image where it can be interacted with (like for collisions) +/** + * @author Thomas Kwashnak (re-wrote) + * @author Alex Thimineur (original) + */ public class Sprite extends Rectangle { - protected BufferedImage image; - protected Rectangle bounds; - protected ImageEffect imageEffect; - public Sprite (BufferedImage image, float scale, ImageEffect imageEffect) { - super(0, 0, image.getWidth(), image.getHeight(), scale); - this.image = image; - this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); - this.imageEffect = imageEffect; - } + protected BufferedImage image; + protected ImageEffect imageEffect; + protected Rectangle bounds; - public Sprite(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { - super(x, y, image.getWidth(), image.getHeight(), scale); - this.image = image; - this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); - this.imageEffect = imageEffect; - } - - public BufferedImage getImage() { - return image; - } - - public void setImage(String imageFileName) { - image = ImageLoader.load(imageFileName); - } - - public void setImage(BufferedImage image) { - this.image = image; + public Sprite(BufferedImage image, float scale) { + this(image, scale, ImageEffect.NONE); } - public ImageEffect getImageEffect() { return imageEffect; } - - public void setImageEffect(ImageEffect imageEffect) { - this.imageEffect = imageEffect; + public Sprite(BufferedImage image, float scale, ImageEffect imageEffect) { + this(image, 0, 0, scale, imageEffect); } - public Rectangle getBounds() { - return new Rectangle(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); + public Sprite(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { + this(image, new Vector(x, y), scale, imageEffect); } - public float getBoundsX1() { - return getX1() + bounds.getX1(); + public Sprite(BufferedImage image, Vector location, float scale, ImageEffect imageEffect) { + super(location, Vector.convertImageDimensions(image), scale); + this.image = image; + this.imageEffect = imageEffect; + bounds = new Rectangle(new Vector(0,0),dimension.clone()); } - public float getBoundsX2() { - return getX1() + bounds.getX2(); + public BufferedImage getImage() { + return image; } - public float getBoundsY1() { - return getY1() + bounds.getY1(); + public ImageEffect getImageEffect() { + return imageEffect; } - public float getBoundsY2() { - return getY1() + bounds.getY2(); + /* + Overrides the Rectangle to use bounds if a custom bounds was specified + */ + @Override + public Vector getMinLocation() { + return bounds.location; } - public float getScaledBoundsX1() { - return getX1() + (bounds.getX1() * scale); + /* + Overrides the Rectangle to use bounds if a custom bounds was specified + */ + @Override + public Vector getMaxLocation() { + return bounds.location.getAdd(dimension); } - public float getScaledBoundsX2() { - return getScaledBoundsX1() + bounds.getScaledWidth(); + public void draw(GraphicsHandler graphicsHandler) { + graphicsHandler.drawImage( + image, Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), imageEffect); } - public float getScaledBoundsY1() { - return getY1() + (bounds.getY1() * scale); + public void drawBounds(GraphicsHandler graphicsHandler, Color color) { + Rectangle scaledBounds = getBounds().getScaled(); + scaledBounds.setColor(color); + scaledBounds.draw(graphicsHandler); } - public float getScaledBoundsY2() { - return getScaledBoundsY1() + bounds.getScaledHeight(); + public Rectangle getBounds() { + return new Rectangle(location.getAdd(bounds.location),bounds.dimension,bounds.scale); } public Rectangle getScaledBounds() { - return new Rectangle(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); + return new Rectangle(location.getAdd(bounds.location.getMultiplied(bounds.scale)),bounds.dimension.getMultiplied(bounds.scale)); } public void setBounds(Rectangle bounds) { - this.bounds = new Rectangle(bounds.getX1(), bounds.getY1(), bounds.getWidth(), bounds.getHeight(), scale); - } - - public void setBounds(float x, float y, int width, int height) { - this.bounds = new Rectangle(x, y, width, height, scale); - } - - public Rectangle getIntersectRectangle() { - return getScaledBounds(); - } - - @Override - public void update() { - super.update(); - } - - @Override - public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawImage(image, Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), imageEffect); - } - - public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - Rectangle scaledBounds = getScaledBounds(); - scaledBounds.setColor(color); - scaledBounds.draw(graphicsHandler); - } - - @Override - public String toString() { - return String.format("Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", getX1(), getY1(), getScaledWidth(), getScaledHeight(), - getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); + this.bounds = bounds; } } diff --git a/src/GameObject/SpriteOld.java b/src/GameObject/SpriteOld.java new file mode 100644 index 0000000..b03e55c --- /dev/null +++ b/src/GameObject/SpriteOld.java @@ -0,0 +1,122 @@ +package GameObject; + +import Engine.GraphicsHandler; +import Engine.ImageLoader; + +import java.awt.*; +import java.awt.image.BufferedImage; + +// This class is for representing a Sprite, which is essentially a Rectangle with an image attached +// it also includes an attribute for "bounds", which can be thought of a sub rectangle on the image where it can be interacted with (like for collisions) +@Deprecated +public class SpriteOld extends Rectangle { + protected BufferedImage image; + protected Rectangle bounds; + protected ImageEffect imageEffect; + + public SpriteOld (BufferedImage image, float scale, ImageEffect imageEffect) { + super(0, 0, image.getWidth(), image.getHeight(), scale); + this.image = image; + this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); + this.imageEffect = imageEffect; + } + + public SpriteOld(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { + super(x, y, image.getWidth(), image.getHeight(), scale); + this.image = image; + this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); + this.imageEffect = imageEffect; + } + + public BufferedImage getImage() { + return image; + } + + public void setImage(String imageFileName) { + image = ImageLoader.load(imageFileName); + } + + public void setImage(BufferedImage image) { + this.image = image; + } + + public ImageEffect getImageEffect() { return imageEffect; } + + public void setImageEffect(ImageEffect imageEffect) { + this.imageEffect = imageEffect; + } + + public Rectangle getBounds() { + return new Rectangle(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); + } + + public float getBoundsX1() { + return getX1() + bounds.getX1(); + } + + public float getBoundsX2() { + return getX1() + bounds.getX2(); + } + + public float getBoundsY1() { + return getY1() + bounds.getY1(); + } + + public float getBoundsY2() { + return getY1() + bounds.getY2(); + } + + public float getScaledBoundsX1() { + return getX1() + (bounds.getX1() * scale); + } + + public float getScaledBoundsX2() { + return getScaledBoundsX1() + bounds.getScaledWidth(); + } + + public float getScaledBoundsY1() { + return getY1() + (bounds.getY1() * scale); + } + + public float getScaledBoundsY2() { + return getScaledBoundsY1() + bounds.getScaledHeight(); + } + + public Rectangle getScaledBounds() { + return new Rectangle(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); + } + + public void setBounds(Rectangle bounds) { + this.bounds = new Rectangle(bounds.getX1(), bounds.getY1(), bounds.getWidth(), bounds.getHeight(), scale); + } + + public void setBounds(float x, float y, int width, int height) { + this.bounds = new Rectangle(x, y, width, height, scale); + } + + public Rectangle getIntersectRectangle() { + return getScaledBounds(); + } + + @Override + public void update() { + super.update(); + } + + @Override + public void draw(GraphicsHandler graphicsHandler) { + graphicsHandler.drawImage(image, Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), imageEffect); + } + + public void drawBounds(GraphicsHandler graphicsHandler, Color color) { + Rectangle scaledBounds = getScaledBounds(); + scaledBounds.setColor(color); + scaledBounds.draw(graphicsHandler); + } + + @Override + public String toString() { + return String.format("Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", getX1(), getY1(), getScaledWidth(), getScaledHeight(), + getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); + } +} From 68867f5697df36801fdccd4f228e228991f4d102 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 16:26:09 -0500 Subject: [PATCH 088/164] Fixed scaled bounds originating at (0,0) --- src/GameObject/AnimatedSprite.java | 3 ++- src/GameObject/Sprite.java | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index 34bc60e..c62e20b 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -1,5 +1,6 @@ package GameObject; +import Engine.Drawable; import Engine.GraphicsHandler; import Engine.Vector; import Utils.Stopwatch; @@ -16,7 +17,7 @@ * While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite * (based on value of currentFrame)
*/ -public class AnimatedSprite implements Intersectable, Overlappable { +public class AnimatedSprite implements Intersectable, Overlappable, Drawable { /** * Position of the Animated Sprite diff --git a/src/GameObject/Sprite.java b/src/GameObject/Sprite.java index b60f635..b79f4b4 100644 --- a/src/GameObject/Sprite.java +++ b/src/GameObject/Sprite.java @@ -14,7 +14,7 @@ public class Sprite extends Rectangle { protected BufferedImage image; protected ImageEffect imageEffect; - protected Rectangle bounds; + protected Rectangle bounds, scaledBounds; public Sprite(BufferedImage image, float scale) { this(image, scale, ImageEffect.NONE); @@ -33,6 +33,7 @@ public Sprite(BufferedImage image, Vector location, float scale, ImageEffect ima this.image = image; this.imageEffect = imageEffect; bounds = new Rectangle(new Vector(0,0),dimension.clone()); + scaledBounds = scaleBounds(bounds); } public BufferedImage getImage() { @@ -65,7 +66,7 @@ public void draw(GraphicsHandler graphicsHandler) { } public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - Rectangle scaledBounds = getBounds().getScaled(); + Rectangle scaledBounds = getScaledBounds(); scaledBounds.setColor(color); scaledBounds.draw(graphicsHandler); } @@ -75,10 +76,25 @@ public Rectangle getBounds() { } public Rectangle getScaledBounds() { - return new Rectangle(location.getAdd(bounds.location.getMultiplied(bounds.scale)),bounds.dimension.getMultiplied(bounds.scale)); + return new Rectangle(location.getAdd(scaledBounds.location),scaledBounds.dimension); } public void setBounds(Rectangle bounds) { this.bounds = bounds; + scaledBounds = scaleBounds(bounds); } + + public boolean intersects(Intersectable other) { + return getScaledBounds().intersects(other); + } + + /** + * Returns the scaled bounds of the given bounds + * @param bounds Bounds to scale to scale = 1 + * @return Scaled bounds where both the location and dimension are scaled + */ + private Rectangle scaleBounds(Rectangle bounds) { + return new Rectangle(bounds.location.getMultiplied(bounds.scale), bounds.dimension.getMultiplied(bounds.scale)); + } + } From 6f8b7411cce17ef5a355bbcbaab724a3ac60f736 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 16:40:21 -0500 Subject: [PATCH 089/164] Revert back / implement fix for task --- src/Enemies/DinosaurEnemy.java | 2 +- src/Enemies/Dog.java | 2 +- src/Engine/GamePanel.java | 395 +++++++------ src/Engine/GameWindow.java | 9 +- src/Engine/ScreenManager.java | 4 +- src/Engine/Vector.java | 163 ------ src/Game/Game.java | 8 +- src/Game/GameThread.java | 25 +- src/Game/GameThreadDeprecated.java | 43 -- src/Game/RenderThread.java | 1 - src/Game/ThreadManager.java | 5 - src/GameObject/AnimatedSprite.java | 533 ++++++++---------- src/GameObject/GameObject.java | 487 +++------------- src/GameObject/Hitbox.java | 32 -- src/GameObject/Intersectable.java | 15 - ...leOld.java => IntersectableRectangle.java} | 5 +- src/GameObject/Overlappable.java | 14 - src/GameObject/Rectangle.java | 340 +++++------ src/GameObject/RectangleOld.java | 203 ------- src/GameObject/Sprite.java | 136 +++-- src/GameObject/SpriteOld.java | 122 ---- src/Level/Camera.java | 12 +- src/Level/CollisionHandler.java | 86 --- src/Level/Map.java | 81 +-- src/Level/MapEntity.java | 17 +- src/Level/MapTileCollisionHandler.java | 48 +- src/Level/Player.java | 39 +- src/Level/PlayerAttack.java | 2 +- src/MapEditor/TileBuilder.java | 4 +- src/MapEditor/TilePicker.java | 4 +- src/Maps/BossBattle.java | 2 +- src/Maps/TestMap.java | 2 +- src/Maps/TestMap2.java | 5 +- src/Maps/TestMap3.java | 2 +- src/Maps/TestMap4.java | 2 +- src/Maps/TestMap5.java | 2 +- src/Maps/TestMap6.java | 6 +- src/Maps/TestMap7.java | 4 +- src/Maps/TestTutorial.java | 4 +- src/Projectiles/Bone.java | 8 +- src/Projectiles/Fireball.java | 2 +- src/Projectiles/LazerBeam.java | 8 +- src/Screens/PlayLevelScreen.java | 2 +- src/Utils/Point.java | 4 - 44 files changed, 860 insertions(+), 2030 deletions(-) delete mode 100644 src/Engine/Vector.java delete mode 100644 src/Game/GameThreadDeprecated.java delete mode 100644 src/GameObject/Hitbox.java delete mode 100644 src/GameObject/Intersectable.java rename src/GameObject/{IntersectableRectangleOld.java => IntersectableRectangle.java} (74%) delete mode 100644 src/GameObject/Overlappable.java delete mode 100644 src/GameObject/RectangleOld.java delete mode 100644 src/GameObject/SpriteOld.java delete mode 100644 src/Level/CollisionHandler.java diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index e3c93f0..ce79082 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -109,7 +109,7 @@ public void update(Player player) { int fireballX; float movementSpeed; if (facingDirection == Direction.RIGHT) { - fireballX = Math.round(getX() + getScaledWidth()); + fireballX = Math.round(getX()) + getScaledWidth(); movementSpeed = 1.5f; } else { fireballX = Math.round(getX()); diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index 5c0b091..ff945be 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -107,7 +107,7 @@ public void update(Player player) { int boneX; float movementSpeed; if (facingDirection == Direction.RIGHT) { - boneX = Math.round(getX() + getScaledWidth()); + boneX = Math.round(getX()) + getScaledWidth(); movementSpeed = 1.5f; } else { boneX = Math.round(getX()); diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 6b8825a..4155314 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -19,206 +19,199 @@ * The JPanel uses a timer to continually call cycles of update and draw */ public class GamePanel extends JPanel { + private final ScreenManager screenManager; + // used to create the game loop and cycle between update and draw calls + private Timer timer; + // used to draw graphics to the panel + private final GraphicsHandler graphicsHandler; + private boolean doPaint = false; + protected static GameWindow gameWindow; + private static ScreenCoordinator coordinator; + public static Clip clip; + private final JLabel health; + private GameThread gameThread; + + + /* + * The JPanel and various important class instances are setup here + */ + public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { + super(); + this.gameWindow = gameWindow; + this.setDoubleBuffered(true); + + health = new JLabel(); + add(health); + + this.setSize(Config.WIDTH, Config.HEIGHT); + // attaches Keyboard class's keyListener to this JPanel + this.addKeyListener(Keyboard.getKeyListener()); + + graphicsHandler = new GraphicsHandler(); + + screenManager = new ScreenManager(); + coordinator = c1; + + + + gameThread = new GameThread(this::repaint, this::update); + +// timer = new Timer(1000 / Config.FPS, new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// update(); +// changeHealth(); +// if(coordinator.getGameState() == GameState.LEVEL) { +// health.show(); +// } +// else { +// health.hide(); +// } +// repaint(); +// } +// }); +// timer.setRepeats(true); +// tickGame = new GameTick(new Runnable() { +// @Override +// public void run() { +// update(); +// } +// }); +// tickRender = new GameTick(new Runnable() { +// @Override +// public void run() { +// repaint(); +// } +// }); + } + + public static ScreenCoordinator getScreenCoordinator() { + return coordinator; + } + // this is called later after instantiation, and will initialize screenManager + // this had to be done outside of the constructor because it needed to know the + // JPanel's width and height, which aren't available in the constructor + public void setupGame() { + setBackground(Colors.CORNFLOWER_BLUE); + screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); + doPaint = true; + } + + public static GameWindow getGameWindow() { + return gameWindow; + } + + public static void music(String filepath, double gain) throws LineUnavailableException, UnsupportedAudioFileException, IOException { + + AudioInputStream audioInput = AudioSystem.getAudioInputStream(new File(filepath)); + clip = AudioSystem.getClip(); + clip.open(audioInput); + setVolume(gain); + clip.start(); + + clip.loop(Clip.LOOP_CONTINUOUSLY); + + } + public static void setVolume(double gain) { + try { + FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); + gainControl.setValue(dB); + } catch(Exception e) { + e.printStackTrace(); + } + + } + + public static void setVolumeOff() { + + setVolume(0); + } + public static void setVolumeLow() { + + setVolume(.05); + } + + public static void setVolumeMed() { + setVolume(.1); + + } + + public static void setVolumeHigh() { + setVolume(.3); + + } + + // this starts the timer (the game loop is started here + public void startGame() { +// timer.start(); + gameThread.start(); + + try { + music("Resources/Music/music.wav",.05); + } catch(Exception e) { + try { + music("Resources/Music/music.mp3",.05); + } catch(Exception f) { + + } + } + } + + public ScreenManager getScreenManager() { + return screenManager; + } + + public void update() { + screenManager.update(); + changeHealth(); + } + + public void draw() { + screenManager.draw(graphicsHandler); + + + } + + // Checks the players health and accordingly changes to the image with the corresponding number of hearts + public void changeHealth() { + if(coordinator.getGameState() == GameState.LEVEL) { + if(Player.PLAYER_HEALTH == 3) { + health.setIcon(new ImageIcon(ImageLoader.load("3 Hearts.png"))); + } + + else if(Player.PLAYER_HEALTH == 2) { + health.setIcon(new ImageIcon(ImageLoader.load("2 Hearts.png"))); + } + + else if(Player.PLAYER_HEALTH == 1) { + health.setIcon(new ImageIcon(ImageLoader.load("1 Heart.png"))); + } + + else { + health.setIcon(new ImageIcon(ImageLoader.load("0 Hearts.png"))); + } + } + + if(coordinator.getGameState() == GameState.MENU) { + Player.PLAYER_HEALTH = 3; + } + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + // every repaint call will schedule this method to be called + // when called, it will setup the graphics handler and then call this class's + // draw method + graphicsHandler.setGraphics((Graphics2D) g); + if (doPaint) { + draw(); + } + } + + public static void mouseClicked(MouseEvent e) { +// System.out.println("Click: " + e.getPoint()); + coordinator.mouseClicked(e); + } - public static Clip clip; - protected static GameWindow gameWindow; - private static ScreenCoordinator coordinator; - private final ScreenManager screenManager; - // used to draw graphics to the panel - private final GraphicsHandler graphicsHandler; - private final JLabel health; - // used to create the game loop and cycle between update and draw calls - private Timer timer; - private boolean doPaint = false; - private GameThread gameThread; - // private ThreadManager gameThread; - // private ThreadManager renderThread; - - - /* - * The JPanel and various important class instances are setup here - */ - public GamePanel(ScreenCoordinator c1, GameWindow gameWindow) { - super(); - GamePanel.gameWindow = gameWindow; - this.setDoubleBuffered(true); - - health = new JLabel(); - add(health); - - this.setSize(Config.WIDTH, Config.HEIGHT); - // attaches Keyboard class's keyListener to this JPanel - this.addKeyListener(Keyboard.getKeyListener()); - - graphicsHandler = new GraphicsHandler(); - - screenManager = new ScreenManager(); - coordinator = c1; - - gameThread = new GameThread(this::repaint, this::update); - - // gameThread = new GameThreadDeprecated(() -> { - // update(); - // repaint(); - // }); - // renderThread = new RenderThread(() -> { - // - // }); - //WORKS - /* - However, current plan should be as follows: - - First get the system to work on a single thread (with the dynamic speed and such) - - THEN get the system to work on multiple threads for painting / etc - */ - - // timer = new Timer(1000 / Config.FPS, new ActionListener() { - // public void actionPerformed(ActionEvent e) { - // update(); - // changeHealth(); - // if(coordinator.getGameState() == GameState.LEVEL) { - // health.show(); - // } - // else { - // health.hide(); - // } - // repaint(); - // } - // }); - // timer.setRepeats(true); - // tickGame = new GameTick(new Runnable() { - // @Override - // public void run() { - // update(); - // } - // }); - // tickRender = new GameTick(new Runnable() { - // @Override - // public void run() { - // repaint(); - // } - // }); - } - - public void update() { - - screenManager.update(); - changeHealth(); - } - - // Checks the players health and accordingly changes to the image with the corresponding number of hearts - public void changeHealth() { - if (coordinator.getGameState() == GameState.LEVEL) { - if (Player.PLAYER_HEALTH == 3) { - health.setIcon(new ImageIcon(ImageLoader.load("3 Hearts.png"))); - } else if (Player.PLAYER_HEALTH == 2) { - health.setIcon(new ImageIcon(ImageLoader.load("2 Hearts.png"))); - } else if (Player.PLAYER_HEALTH == 1) { - health.setIcon(new ImageIcon(ImageLoader.load("1 Heart.png"))); - } else { - health.setIcon(new ImageIcon(ImageLoader.load("0 Hearts.png"))); - } - } - - if (coordinator.getGameState() == GameState.MENU) { - Player.PLAYER_HEALTH = 3; - } - } - - public static ScreenCoordinator getScreenCoordinator() { - return coordinator; - } - - public static GameWindow getGameWindow() { - return gameWindow; - } - - public static void setVolumeOff() { - - setVolume(0); - } - - public static void setVolume(double gain) { - try { - FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); - float dB = (float) (Math.log(gain) / Math.log(10.0) * 20.0); - gainControl.setValue(dB); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static void setVolumeLow() { - - setVolume(.05); - } - - public static void setVolumeMed() { - setVolume(.1); - } - - public static void setVolumeHigh() { - setVolume(.3); - } - - public static void mouseClicked(MouseEvent e) { - // System.out.println("Click: " + e.getPoint()); - coordinator.mouseClicked(e); - } - - // this is called later after instantiation, and will initialize screenManager - // this had to be done outside of the constructor because it needed to know the - // JPanel's width and height, which aren't available in the constructor - public void setupGame() { - setBackground(Colors.CORNFLOWER_BLUE); - screenManager.initialize(new Rectangle(getX(), getY(), getWidth(), getHeight())); - doPaint = true; - } - - // this starts the timer (the game loop is started here - public void startGame() { - // timer.start(); - gameThread.start(); - // renderThread.start(); - - try { - music("Resources/Music/music.wav", .05); - } catch (Exception e) { - try { - music("Resources/Music/music.mp3", .05); - } catch (Exception f) { - - } - } - } - - public static void music(String filepath, double gain) throws LineUnavailableException, UnsupportedAudioFileException, IOException { - - AudioInputStream audioInput = AudioSystem.getAudioInputStream(new File(filepath)); - clip = AudioSystem.getClip(); - clip.open(audioInput); - setVolume(gain); - clip.start(); - - clip.loop(Clip.LOOP_CONTINUOUSLY); - } - - public ScreenManager getScreenManager() { - return screenManager; - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - // every repaint call will schedule this method to be called - // when called, it will setup the graphics handler and then call this class's - // draw method - graphicsHandler.setGraphics((Graphics2D) g); - if (doPaint) { - draw(); - } - } - - public void draw() { - screenManager.draw(graphicsHandler); - } } diff --git a/src/Engine/GameWindow.java b/src/Engine/GameWindow.java index 32d4032..e5f01d0 100644 --- a/src/Engine/GameWindow.java +++ b/src/Engine/GameWindow.java @@ -1,13 +1,12 @@ package Engine; +import Game.ScreenCoordinator; + +import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import javax.swing.*; - -import Game.ScreenCoordinator; - /* * The JFrame that holds the GamePanel * Just does some setup and exposes the gamePanel's screenManager to allow an external class to setup their own content and attach it to this engine. @@ -16,6 +15,8 @@ public class GameWindow { private JFrame gameWindow; private GamePanel gamePanel; + + public GameWindow(ScreenCoordinator c1) { gameWindow = new JFrame("Game"); diff --git a/src/Engine/ScreenManager.java b/src/Engine/ScreenManager.java index 22489a3..142edd6 100644 --- a/src/Engine/ScreenManager.java +++ b/src/Engine/ScreenManager.java @@ -35,12 +35,12 @@ public void draw(GraphicsHandler graphicsHandler) { // gets width of currentScreen -- can be called from anywhere in an application public static int getScreenWidth() { - return Math.round(screenBounds.getWidth()); + return screenBounds.getWidth(); } // gets height of currentScreen -- can be called from anywhere in an application public static int getScreenHeight() { - return Math.round(screenBounds.getHeight()); + return screenBounds.getHeight(); } // gets bounds of currentScreen -- can be called from anywhere in an application diff --git a/src/Engine/Vector.java b/src/Engine/Vector.java deleted file mode 100644 index 5b9c338..0000000 --- a/src/Engine/Vector.java +++ /dev/null @@ -1,163 +0,0 @@ -package Engine; - -import Utils.Point; - -import java.awt.image.BufferedImage; - -public class Vector { - private float x,y; - - - public Vector() { - this(0.0f,0.0f); - } - - public Vector(float x, float y) { - this.x = x; - this.y = y; - } - - public Vector(Point point) { - this.x = point.x; - this.y = point.y; - } - - public float getX() { - return x; - } - - public float getY() { - return y; - } - - public void addX(float x) { - this.x += x; - } - - public void addY(float y) { - this.y += y; - } - - public void setY(float y) { - this.y = y; - } - - public void setX(float x) { - this.x = x; - } - - public float getMagnitude() { - return (float) Math.sqrt(x * x + y * y); - } - - public void set(float x, float y) { - this.x = x; - this.y = y; - } - - public void set(Vector location) { - this.x = location.x; - this.y = location.y; - } - - public Vector getDivided(float divisor) { - return new Vector(x / divisor, y / divisor); - } - - public Vector getMultiplied(float factor) { - return new Vector(x * factor, y * factor); - } - - public Vector getUnit() { - return getDivided(Math.abs(getMagnitude())); - } - - public Vector add(Vector vector) { - this.x += vector.x; - this.y += vector.y; - return this; - } - - public Vector multiply(float factor) { - this.x *= factor; - this.y *= factor; - return this; - } - - public Vector divide(float divisor) { - this.x /= divisor; - this.y /= divisor; - return this; - } - - public Vector subtract(float magnitude) { - return add(-magnitude); - } - - public Vector subtract(Vector vector) { - return add(vector.getNegative()); - } - - public Vector getSubtracted(Vector vector) { - return clone().subtract(vector); - } - - public Vector add(float magnitude) { - add(getUnit().multiply(magnitude)); - return this; - } - - public Vector getAdd(Vector vector) { - return new Vector(x + vector.x, y + vector.y); - } - - public Vector clone() { - return new Vector(x,y); - } - - public Vector getGreatestDirection() { - if(x > y) { - return new Vector(x,0); - } else if(y > x) { - return new Vector(0,y); - } else { - return clone(); - } - } - - public Vector getAbsolute() { - return new Vector(Math.abs(x), Math.abs(y)); - } - - public Vector getNegative() { - return clone().multiply(-1); - } - - public Point toPoint() { - return new Point(x, y); - } - - public String toString() { - return String.format("(%s,%s)",x,y); - } - - public Vector getFlipped() { - return new Vector(y,x); - } - - public boolean equals(Object other) { - return other instanceof Vector && ((Vector) other).x == this.x && ((Vector) other).y == this.y; - } - - public void multiplyX(float magnitude) { - x *= magnitude; - } - - public void multiplyY(float magnitude) { - y *= magnitude; - } - - public static Vector convertImageDimensions(BufferedImage bufferedImage) { - return new Vector(bufferedImage.getWidth(), bufferedImage.getHeight()); - } -} diff --git a/src/Game/Game.java b/src/Game/Game.java index bea8f84..517249d 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -1,7 +1,6 @@ package Game; import Engine.GameWindow; - import Engine.ScreenManager; /* @@ -18,13 +17,12 @@ public static void main(String[] args) { public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); + + new RenderThread(null); + gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); - gameWindow.startGame(); - // DEBUG USE ONLY // screenManager.setCurrentScreen(new DebugScreen()); } - - } diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index c2bbc1a..5346493 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -9,7 +9,7 @@ public class GameThread implements Runnable { public static final float UPDATE_FACTOR; static { - UPDATE_FIXED_MS = 5; + UPDATE_FIXED_MS = 12; UPDATE_FACTOR = UPDATE_FIXED_MS / 15.0f; } @@ -34,7 +34,7 @@ public void stop() { @Override public void run() { -// lastTime = System.currentTimeMillis(); + // lastTime = System.currentTimeMillis(); long nextUpdateTime = System.currentTimeMillis(); long currentTime; while(running) { @@ -45,17 +45,18 @@ public void run() { } render.run(); -// delta_time = ((double) timePassed) / 1000; -// while(timePassed >= UPDATE_FIXED_MS) { -// timePassed -= UPDATE_FIXED_MS; -// update.run(); -// } -// -// render.run(); -// currentTime = System.currentTimeMillis(); -// timePassed += currentTime - lastTime; -// lastTime = currentTime; + // delta_time = ((double) timePassed) / 1000; + // while(timePassed >= UPDATE_FIXED_MS) { + // timePassed -= UPDATE_FIXED_MS; + // update.run(); + // } + // + // render.run(); + // currentTime = System.currentTimeMillis(); + // timePassed += currentTime - lastTime; + // lastTime = currentTime; } running = true; } } + diff --git a/src/Game/GameThreadDeprecated.java b/src/Game/GameThreadDeprecated.java deleted file mode 100644 index 6d22188..0000000 --- a/src/Game/GameThreadDeprecated.java +++ /dev/null @@ -1,43 +0,0 @@ -package Game; - -import java.awt.*; - -@Deprecated -public class GameThreadDeprecated extends ThreadManager { - - - private static GameThreadDeprecated instance; - - private static final long RENDER_DELAY_MS; - - static { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - // Sets the highest refresh rate to be the highest display rate - int highestRefreshRate = 0; - for(GraphicsDevice device : ge.getScreenDevices()) { - int refreshRate = device.getDisplayMode().getRefreshRate(); - System.out.println(refreshRate); - if(refreshRate > highestRefreshRate) { - highestRefreshRate = refreshRate; - } - } - RENDER_DELAY_MS = 1000 / highestRefreshRate; - } - - public GameThreadDeprecated(Runnable runnable) { - super(runnable,5); - //Somehow setting tickDelay to 0 causes the game to break in some way? - //somehow even 1 is bad.... SOMETHING.. is going on here - /* - That something is probably due to the fact that rendering (painting) is done on a run-later class, so the updates is still technically - multithreaded in a way, so something's going wonky here.. - AND SOMEHOW THIS IS LAGGING ON LEVEL LOAD - */ - instance = this; - } - - public static float getScale() { - return ((float) instance.elapsedTick) / 1000; - } - -} diff --git a/src/Game/RenderThread.java b/src/Game/RenderThread.java index 10821a9..bdce73f 100644 --- a/src/Game/RenderThread.java +++ b/src/Game/RenderThread.java @@ -6,7 +6,6 @@ * Responsible for the looping of the class and containing values such as time since last tick, etc. * @author Thomas Kwashnak */ -@Deprecated public class RenderThread extends ThreadManager { /** diff --git a/src/Game/ThreadManager.java b/src/Game/ThreadManager.java index ff14695..4f6af6a 100644 --- a/src/Game/ThreadManager.java +++ b/src/Game/ThreadManager.java @@ -3,7 +3,6 @@ /** * @author Thomas Kwashnak */ -@Deprecated public class ThreadManager implements Runnable { private Thread thread; @@ -41,8 +40,4 @@ public void run() { } running = true; } - - public static float getTimeScale() { - return 0f; - } } diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index c62e20b..10ff80a 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -1,358 +1,281 @@ package GameObject; -import Engine.Drawable; import Engine.GraphicsHandler; -import Engine.Vector; import Utils.Stopwatch; import java.awt.*; import java.awt.image.BufferedImage; import java.util.HashMap; -/** - * Represents an animated sprite
- * Animations can either be passed in directly or loaded automatically in a subclass by overriding the getAnimations method
- * This class contains logic for transitioning animations as well as playing out the frames in an animation in a loop
- * Subclasses need to call down to this class's update method in order for animation logic to be performed
- * While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite - * (based on value of currentFrame)
- */ -public class AnimatedSprite implements Intersectable, Overlappable, Drawable { - - /** - * Position of the Animated Sprite - */ - protected Vector pos; - - /** - * maps animation name to an array of Frames representing one animation - */ - protected HashMap animations; - - /** - * keeps track of current animation the sprite is using - */ - protected String currentAnimationName = ""; - protected String previousAnimationName = ""; - - /** - * keeps track of current frame number in an animation the sprite is using - */ - protected int currentFrameIndex; - - /** - * if an animation has looped, this is set to true - */ - protected boolean hasAnimationLooped; - - /** - * current Frame object the animation is using based on currentAnimationName and currentFrameIndex - * this is essential for the class, as it uses this to be treated as "one sprite" - */ - protected Frame currentFrame; - - /** - * times frame delay before transitioning into the next frame of an animation - */ - private Stopwatch frameTimer = new Stopwatch(); - - public AnimatedSprite(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { - pos = new Vector(x, y); - this.animations = getAnimations(spriteSheet); - this.currentAnimationName = startingAnimationName; - updateCurrentFrame(); - } - - /** - * Subclasses can override this method in order to add their own animations, which will be loaded in at initialization time - * - * @param spriteSheet - * - * @return - */ - public HashMap getAnimations(SpriteSheet spriteSheet) { - return null; - } - - /** - * currentFrame is essentially a sprite, so each game loop cycle
- * the sprite needs to have its current state updated based on animation logic,
- * and location updated to match any changes to the animated sprite class - */ - protected void updateCurrentFrame() { - currentFrame = getCurrentFrame(); - currentFrame.setLocationReference(pos); - } - - /** - * gets the frame from current animation that the animated sprite class is currently using - * - * @return - */ - protected Frame getCurrentFrame() { - return animations.get(currentAnimationName)[currentFrameIndex]; - } +/* + Represents an animated sprite + Animations can either be passed in directly or loaded automatically in a subclass by overriding the getAnimations method + This class contains logic for transitioning animations as well as playing out the frames in an animation in a loop + Subclasses need to call down to this class's update method in order for animation logic to be performed + While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite (based on value of currentFrame) +*/ +public class AnimatedSprite implements IntersectableRectangle { + // location of entity + protected float x, y; + + // maps animation name to an array of Frames representing one animation + protected HashMap animations; + + // keeps track of current animation the sprite is using + protected String currentAnimationName = ""; + protected String previousAnimationName = ""; + + // keeps track of current frame number in an animation the sprite is using + protected int currentFrameIndex; + + // if an animation has looped, this is set to true + protected boolean hasAnimationLooped; + + // current Frame object the animation is using based on currentAnimationName and currentFrameIndex + // this is essential for the class, as it uses this to be treated as "one sprite" + protected Frame currentFrame; + + // times frame delay before transitioning into the next frame of an animation + private Stopwatch frameTimer = new Stopwatch(); + + public AnimatedSprite(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { + this.x = x; + this.y = y; + this.animations = getAnimations(spriteSheet); + this.currentAnimationName = startingAnimationName; + updateCurrentFrame(); + } public AnimatedSprite(float x, float y, HashMap animations, String startingAnimationName) { - pos = new Vector(x, y); + this.x = x; + this.y = y; this.animations = animations; this.currentAnimationName = startingAnimationName; updateCurrentFrame(); } - public AnimatedSprite(BufferedImage image, float x, float y, String startingAnimationName) { - pos = new Vector(x, y); - SpriteSheet spriteSheet = new SpriteSheet(image, image.getWidth(), image.getHeight()); + public AnimatedSprite(BufferedImage image, float x, float y, String startingAnimationName) { + this.x = x; + this.y = y; + SpriteSheet spriteSheet = new SpriteSheet(image, image.getWidth(), image.getHeight()); this.animations = getAnimations(spriteSheet); this.currentAnimationName = startingAnimationName; - updateCurrentFrame(); - } + updateCurrentFrame(); + } public AnimatedSprite(float x, float y) { - pos = new Vector(x, y); + this.x = x; + this.y = y; this.animations = new HashMap<>(); this.currentAnimationName = ""; } - public void update() { - // if animation name has been changed (previous no longer equals current), setup for the new animation and start using it - if (!previousAnimationName.equals(currentAnimationName)) { - currentFrameIndex = 0; - updateCurrentFrame(); - frameTimer.setWaitTime(getCurrentFrame().getDelay()); - hasAnimationLooped = false; - } else { - // if animation has more than one frame, check if it's time to transition to a new frame based on that frame's delay - if (getCurrentAnimation().length > 1 && currentFrame.getDelay() > 0) { - - // if enough time has passed based on current frame's delay and it's time to transition to a new frame, - // update frame index to the next frame - // It will also wrap around back to the first frame index if it was already on the last frame index (the animation will loop) - if (frameTimer.isTimeUp()) { - currentFrameIndex++; - if (currentFrameIndex >= animations.get(currentAnimationName).length) { - currentFrameIndex = 0; - hasAnimationLooped = true; - } - frameTimer.setWaitTime(getCurrentFrame().getDelay()); - updateCurrentFrame(); - } - } - } - previousAnimationName = currentAnimationName; - } - - /** - * gets the animation that the animated sprite class is currently using - * - * @return - */ - protected Frame[] getCurrentAnimation() { - return animations.get(currentAnimationName); - } - - public void setAnimations(HashMap animations) { - this.animations = animations; - } - - public void draw(GraphicsHandler graphicsHandler) { - currentFrame.draw(graphicsHandler); - } + public void update() { + // if animation name has been changed (previous no longer equals current), setup for the new animation and start using it + if (!previousAnimationName.equals(currentAnimationName)) { + currentFrameIndex = 0; + updateCurrentFrame(); + frameTimer.setWaitTime(getCurrentFrame().getDelay()); + hasAnimationLooped = false; + } else { + // if animation has more than one frame, check if it's time to transition to a new frame based on that frame's delay + if (getCurrentAnimation().length > 1 && currentFrame.getDelay() > 0) { + + // if enough time has passed based on current frame's delay and it's time to transition to a new frame, + // update frame index to the next frame + // It will also wrap around back to the first frame index if it was already on the last frame index (the animation will loop) + if (frameTimer.isTimeUp()) { + currentFrameIndex++; + if (currentFrameIndex >= animations.get(currentAnimationName).length) { + currentFrameIndex = 0; + hasAnimationLooped = true; + } + frameTimer.setWaitTime(getCurrentFrame().getDelay()); + updateCurrentFrame(); + } + } + } + previousAnimationName = currentAnimationName; + } + + // Subclasses can override this method in order to add their own animations, which will be loaded in at initialization time + public HashMap getAnimations(SpriteSheet spriteSheet) { + return null; + } + + public void setAnimations(HashMap animations) { + this.animations = animations; + + } + + // currentFrame is essentially a sprite, so each game loop cycle + // the sprite needs to have its current state updated based on animation logic, + // and location updated to match any changes to the animated sprite class + protected void updateCurrentFrame() { + currentFrame = getCurrentFrame(); + currentFrame.setX(x); + currentFrame.setY(y); + } + + // gets the frame from current animation that the animated sprite class is currently using + protected Frame getCurrentFrame() { + return animations.get(currentAnimationName)[currentFrameIndex]; + } + + // gets the animation that the animated sprite class is currently using + protected Frame[] getCurrentAnimation() { return animations.get(currentAnimationName); } + + public void draw(GraphicsHandler graphicsHandler) { + currentFrame.draw(graphicsHandler); + } public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - currentFrame.drawBounds(graphicsHandler, color); - } - - public float getX() { - return currentFrame.getBounds().getX1(); - } - - public void setX(float x) { - pos.setX(x); - } - - public float getY() { - return currentFrame.getBounds().getY1(); - } - - public void setY(float y) { - pos.setY(y); - } - - public float getX1() { - return currentFrame.getBounds().getX1(); - } - - public float getY1() { - return currentFrame.getBounds().getY1(); - } - - public float getX2() { - return currentFrame.getBounds().getX2(); - } - - public float getScaledX2() { - return currentFrame.getScaledBounds().getX2(); - } - - public float getY2() { - return currentFrame.getBounds().getY2(); - } - - public float getScaledY2() { - return currentFrame.getScaledBounds().getY2(); - } - - public void setLocation(Vector location) { - pos.set(location); - } - - public void setLocation(float x, float y) { - this.setX(x); - this.setY(y); - } - - public void moveRight(float dx) { - moveX(dx); - } - - public void moveX(float dx) { - move(new Vector(dx, 0)); - } - - public void move(Vector vector) { - pos.add(vector); - } - - public void moveLeft(float dx) { - moveX(-dx); - } - - public void moveDown(float dy) { - moveY(dy); - } - - public void moveY(float dy) { - this.pos.addY(dy); - currentFrame.move(new Vector(0, dy)); - } - - public void moveUp(float dy) { - moveY(-dy); - } - - public float getScale() { - return currentFrame.getScale(); - } - - public void setScale(float scale) { - currentFrame.setScale(scale); - } + currentFrame.drawBounds(graphicsHandler, color); + } + + public float getX() { return currentFrame.getX(); } + public float getY() { return currentFrame.getY(); } + public float getX1() { return currentFrame.getX1(); } + public float getY1() { return currentFrame.getY1(); } + public float getX2() { return currentFrame.getX2(); } + public float getScaledX2() { return currentFrame.getScaledX2(); } + public float getY2() { return currentFrame.getY2(); } + public float getScaledY2() { return currentFrame.getScaledY2(); } + + public void setX(float x) { + this.x = x; + currentFrame.setX(x); + } + public void setY(float y) { + this.y = y; + currentFrame.setY(y); + } + + public void setLocation(float x, float y) { + this.setX(x); + this.setY(y); + } + + public void moveX(float dx) { + this.x += dx; + currentFrame.moveX(dx); + } + + public void moveRight(float dx) { + this.x += dx; + currentFrame.moveRight(dx); + } + + public void moveLeft(float dx) { + this.x -= dx; + currentFrame.moveLeft(dx); + } + + public void moveY(float dy) { + this.y += dy; + currentFrame.moveY(dy); + } + + public void moveDown(float dy) { + this.y += dy; + currentFrame.moveDown(dy); + } + + public void moveUp(float dy) { + this.y -= dy; + currentFrame.moveUp(dy); + } + + public float getScale() { + return currentFrame.getScale(); + } + + public void setScale(float scale) { + currentFrame.setScale(scale); + } + + public int getWidth() { + return currentFrame.getWidth(); + } + public int getHeight() { + return currentFrame.getHeight(); + } + public void setWidth(int width) { + currentFrame.setWidth(width); + } + public void setHeight(int height) { + currentFrame.setHeight(height); + } + public int getScaledWidth() { + return currentFrame.getScaledWidth(); + } + public int getScaledHeight() { + return currentFrame.getScaledHeight(); + } + + public Rectangle getBounds() { + return currentFrame.getBounds(); + } + + public Rectangle getScaledBounds() { + return currentFrame.getScaledBounds(); + } - @Deprecated - public float getWidth() { - return currentFrame.getWidth(); - } - - @Deprecated - public void setWidth(float width) { - currentFrame.setWidth(width); - } - - @Deprecated - public float getHeight() { - return currentFrame.getHeight(); - } - - @Deprecated - public void setHeight(float height) { - currentFrame.setHeight(height); - } - - public Rectangle getBounds() { - return currentFrame.getBounds(); - } - - public void setBounds(Rectangle bounds) { - currentFrame.setBounds(bounds); + public float getBoundsX1() { + return currentFrame.getBoundsX1(); } - public float getBoundsX1() { - return currentFrame.getBounds().getX1(); + public float getScaledBoundsX1() { + return currentFrame.getScaledBoundsX1(); } public float getBoundsX2() { - return currentFrame.getBounds().getX2(); + return currentFrame.getBoundsX2(); } public float getScaledBoundsX2() { - return currentFrame.getBounds().getScaledX2(); + return currentFrame.getScaledBoundsX2(); } public float getBoundsY1() { - return currentFrame.getBounds().getY1(); - } - - public float getBoundsY2() { - return currentFrame.getBounds().getY2(); - } - - public float getScaledBoundsY2() { - return currentFrame.getBounds().getScaledY2(); + return currentFrame.getBoundsY1(); } - @Override - public boolean intersects(Intersectable other) { - return currentFrame.intersects(other); - } - - @Override - public boolean overlaps(Overlappable other) { - return currentFrame.overlaps(other); - } - - @Override - public String toString() { - return String.format("Current Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", pos.getX(), pos.getY(), getScaledWidth(), - getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight() - ); - } - - public float getScaledWidth() { - return currentFrame.getScaledBounds().getWidth(); - } - - public float getScaledHeight() { - return currentFrame.getScaledBounds().getWidth(); + public float getScaledBoundsY1() { + return currentFrame.getScaledBoundsY1(); } - public float getScaledBoundsX1() { - return currentFrame.getScaledBounds().getX1(); + public float getBoundsY2() { + return currentFrame.getBoundsY2(); } - public float getScaledBoundsY1() { - return currentFrame.getScaledBounds().getY1(); + public float getScaledBoundsY2() { + return currentFrame.getScaledBoundsY2(); } - public Rectangle getScaledBounds() { - return currentFrame.getScaledBounds(); - } + public void setBounds(Rectangle bounds) { + currentFrame.setBounds(bounds); + } - public void setCurrentAnimationName(String name) { - this.currentAnimationName = name; + @Override + public Rectangle getIntersectRectangle() { + return currentFrame.getIntersectRectangle(); } - public Vector getPos() { - return pos; + public boolean intersects(IntersectableRectangle other) { + return currentFrame.intersects(other); } - @Override - public Vector getMinLocation() { - return currentFrame.getMinLocation(); - } + public boolean overlaps(IntersectableRectangle other) { return currentFrame.overlaps(other); } - @Override - public Vector getMaxLocation() { - return currentFrame.getMaxLocation(); - } + @Override + public String toString() { + return String.format("Current Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", x, y, getScaledWidth(), getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); + } + + public void setCurrentAnimationName(String name) { + this.currentAnimationName = name; + } + + } diff --git a/src/GameObject/GameObject.java b/src/GameObject/GameObject.java index 18b6a54..d1c8bf8 100644 --- a/src/GameObject/GameObject.java +++ b/src/GameObject/GameObject.java @@ -3,64 +3,64 @@ import Builders.FrameBuilder; import Engine.Drawable; import Engine.GraphicsHandler; -import Engine.Vector; -import Game.GameThread; -import Game.GameThreadDeprecated; import Level.Map; -import Level.MapTile; import Level.MapTileCollisionHandler; -import Level.TileType; import Utils.Direction; import Utils.MathUtils; -import Utils.Point; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Arrays; import java.util.HashMap; -import java.util.List; - -/** - * The all important GameObject class is what every "entity" used in this game should be based off of - * It encapsulates all the other class logic in the GameObject package to be a "one stop shop" for all entity needs - * This includes: - * 1. displaying an image (as a sprite) to represent the entity - * 2. animation logic for the sprite - * 3. collision detection with a map - * 4. performing proper draw logic based on camera movement - * - * @author Thomas Kwashnak (Modified) - * @author Alex Thimineur (plus extra) - */ /* - * GOALS with a potential rewrite - * - Enable float-based locations -> more accurate positioning - * - Add "move velocity" to move a specific velocity, scale it with the current time difference, and check collisions + The all important GameObject class is what every "entity" used in this game should be based off of + It encapsulates all the other class logic in the GameObject package to be a "one stop shop" for all entity needs + This includes: + 1. displaying an image (as a sprite) to represent the entity + 2. animation logic for the sprite + 3. collision detection with a map + 4. performing proper draw logic based on camera movement */ public class GameObject extends AnimatedSprite implements Drawable { - protected Vector startPosition, amountMoved; + // stores game object's start position + // important to keep track of this as it's what allows the special draw logic to work + protected float startPositionX, startPositionY; + + // how much game object's position has changed from start position over time + // also important to keep track of for the special draw logic + protected float amountMovedX, amountMovedY; + + // previous location the game object was in from the last frame + protected float previousX, previousY; + - protected MapTile lastCollided; - protected boolean inAir; // the map instance this game object "belongs" to. protected Map map; public GameObject(SpriteSheet spriteSheet, float x, float y, String startingAnimation) { super(spriteSheet, x, y, startingAnimation); - startPosition = new Vector(x, y); + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } public GameObject(float x, float y, HashMap animations, String startingAnimation) { super(x, y, animations, startingAnimation); - startPosition = new Vector(x, y); + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } public GameObject(BufferedImage image, float x, float y, String startingAnimation) { super(image, x, y, startingAnimation); - startPosition = new Vector(x, y); + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } public GameObject(BufferedImage image, float x, float y) { @@ -72,7 +72,10 @@ public GameObject(BufferedImage image, float x, float y) { }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - startPosition = new Vector(x, y); + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } public GameObject(BufferedImage image, float x, float y, float scale) { @@ -86,7 +89,10 @@ public GameObject(BufferedImage image, float x, float y, float scale) { }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - startPosition = new Vector(x, y); + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { @@ -101,7 +107,10 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - startPosition = new Vector(x, y); + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } public GameObject(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect, Rectangle bounds) { @@ -117,323 +126,24 @@ public GameObject(BufferedImage image, float x, float y, float scale, ImageEffec }}; this.currentAnimationName = "DEFAULT"; updateCurrentFrame(); - startPosition = new Vector(x, y); - } - -// @Override -// public void update() { -// // call to animation logic -// super.update(); -// -// // update previous position to be the current position -// -// } - - public void moveHandleCollision(Vector providedVelocity) { - Vector velocity = providedVelocity.getMultiplied(GameThread.UPDATE_FACTOR); - Vector oVelocity = velocity.clone(); - Vector oPosition = pos.clone(); - Vector unit = velocity.getUnit(); - -// Vector[] startingPoints = new Vector[] { -// pos, pos.getAdd(new Vector(getBounds().getWidth(),0)), pos.getAdd(new Vector(0,getBounds().getHeight())), -// pos.getAdd(new Vector(getBounds().getWidth(),getBounds().getHeight())) -// }; - - float boundingVelocity = Math.max(velocity.getMagnitude(),getMap().getTileset().getScaledSpriteWidth() * 3); - - List tiles = map.getMapTilesInRange(getCenter(), boundingVelocity); - - while(velocity.getMagnitude() > 1) { - move(unit); //Move 1 unit ahead - velocity.subtract(1); - //If it collides, moves one back, sets lastCollided to that, set magnitude to 1 - if(getCollidedTile(tiles,velocity) != null) { - move(unit.getNegative()); - velocity.set(unit); - break; - } - } - -// see if it collides - move(velocity); - inAir = true; - if ((lastCollided = getCollidedTile(tiles,velocity)) != null) { - handleCollision(lastCollided,velocity); - System.out.println("Player = " + getPos() + ", Block = " + lastCollided.getPos()); -// move(unit.getNegative()); - } - } - - private MapTile getCollidedTile(List mapTiles, Vector velocity) { - System.out.println("\nPlayer: " + pos + " " + velocity); - for(MapTile mapTile : mapTiles) { - if((mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0)) && intersects(mapTile)) { - return mapTile; - } - } - return null; - } - - private void handleCollision(MapTile mapTile, Vector velocity) { - //initializing x1 x2 y1 y2 ox1 ox2 oy1 oy2 - float x1 = getScaledBoundsX1(), x2 = getScaledBoundsX2(), y1 = getScaledBoundsY1(), y2 = getScaledBoundsY2(); - float ox1 = mapTile.getScaledBoundsX1(), ox2 = mapTile.getScaledBoundsX2(), oy1 = mapTile.getScaledBoundsY1(), oy2 = - mapTile.getScaledBoundsY2(); - System.out.println(x1 + " " + x2 + " " + y1 + " " + y2 + " | " + ox1 + " " + ox2 + " " + oy1 + " " + oy2); - System.out.println(getBounds() + " " + mapTile.getBounds()); - if(getIntersected(x1,x2,ox1,ox2) > getIntersected(y1,y2,oy1,oy2)) { - //Vertical impact - if(y1 < oy1) { - //downwards - inAir = false; - move(new Vector(0,oy1 - y2)); - } else { - move(new Vector(0,oy2 - y1)); - } - - } else { - //Horizontal impact - if(x1 < ox1) { - move(new Vector(ox1 - x2,0)); - } else { - move(new Vector(ox2 - x1,0)); - } - - } - } - - /** - * Given 2 ranges that intersect, returns the amount of range intersected - *

Given that {@code x1 < x2} and {@code ox1 < ox2}

- * @param values - * @return Amount of range intersected - */ - private static float getIntersected(float... values) { - Arrays.sort(values); - return values[2] - values[1]; - } -// -// /** -// * -// * @param startPosition -// * @param velocity -// * @param mapTile -// * @return -// */ -// private boolean rayIntersects(Vector startPosition, Vector velocity, MapTile mapTile) { - -// float ySlope = velocity.getY() / velocity.getX(), xSlope = velocity.getX() / velocity.getY(); -// -// //Check left bound -// float y = ySlope * (x1 - startPosition.getX()) + startPosition.getY(); -// boolean intersectsLeft = y <= y2 && y >= y1; -// y = ySlope * (x2 - startPosition.getX()) + startPosition.getY(); -// boolean intersectsRight = y <= y2 && y >= y1; -// -// return false; -// } - - @Deprecated - private void checkMapTileOld(Vector[] startingPoints, Vector velocity, MapTile mapTile) { - if(mapTile != null && (mapTile.getTileType() == TileType.NOT_PASSABLE || (mapTile.getTileType() == TileType.JUMP_THROUGH_PLATFORM && velocity.getY() > 0))) { - updateVelocityOld(startingPoints, velocity, mapTile); - } - } - - @Deprecated - private void updateVelocity(Vector[] startingPoints, Vector velocity, MapTile mapTile) { - -// //x1 x2 y1 y2 are ordered values where x1 < x2 and y1 < y2. These indicate the x and y values of the edges of the bounding box -// float x1 = mapTile.getPos().getX(), x2 = mapTile.getPos().getX() + mapTile.getBounds().getWidth(); -// float y1 = mapTile.getPos().getY(), y2 = mapTile.getPos().getY() + mapTile.getBounds().getHeight(); -// /* -// xTest and yTest are the two faces that we will test intersections with (aka: the two faces that the velocity will hit first) -// xTestObj and yTestObj are the same thing except for this GameObject -// */ -// float xTest = x2, yTest = y2, xTestObj = pos.getX(), yTestObj = pos.getY(); -// if(velocity.getX() > 0) { -// xTest = x1; -// xTestObj += getBounds().getWidth(); -// } -// if(velocity.getY() > 0) { -// yTest = y1; -// yTestObj += getBounds().getHeight(); -// } - - - - } - - @Deprecated - private void updateVelocityOld(Vector[] startingPoints, Vector velocity, MapTile mapTile) { - float x1 = mapTile.getPos().getX(), x2 = mapTile.getPos().getX() + mapTile.getBounds().getWidth(); - float y1 = mapTile.getPos().getY(), y2 = mapTile.getPos().getY() + mapTile.getBounds().getHeight(); - - for(Vector start : startingPoints) { - System.out.print(velocity + " " + start + " " + x1 + " " + x2 + " " + y1 + " " + y2); - float xLambda = Math.min(findCoefficient(start, velocity, x1, y1, y2), findCoefficient(start, velocity, x2, y1, y2)); - float yLambda = Math.min( - findCoefficient(start.getFlipped(), velocity.getFlipped(), y1, x1, x2), - findCoefficient(start.getFlipped(), velocity.getFlipped(), y2, x1, x2)); - - if(xLambda > yLambda) { - velocity.multiplyY(yLambda); - velocity.multiplyX( Math.min(findCoefficient(start, velocity, x1, y1, y2), findCoefficient(start, velocity, x2, y1, y2))); - } else { - velocity.multiplyX(xLambda); - velocity.multiplyY(Math.min( - findCoefficient(start.getFlipped(), velocity.getFlipped(), y1, x1, x2), - findCoefficient(start.getFlipped(), velocity.getFlipped(), y2, x1, x2))); - } - - System.out.println(" " + xLambda + " " + yLambda); - } - } - - - - private float findCoefficient(Vector startPosition, Vector velocity, float v, float lowerBound, float upperBound) { - - if(velocity.getX() == 0) { - return 1; - } - - float lambda = (v - startPosition.getX()) / velocity.getX(); - float y = velocity.getY() * lambda + startPosition.getY(); - //return lambda only if it is less than 1 and the y position is within the bounds - return (lambda >= 0 && lambda < 1 && (y < upperBound && y > lowerBound)) ? lambda : 1; - } - - /** - * Moves the game object by a given velocity, barring impacts from collisions (within the map instance) - * @param providedVelocity Amount to move. Will not be modified during movement. Will scale down to the current scale from - * {@link GameThreadDeprecated#getScale()} - * @author Thomas Kwashnak - */ - @Deprecated - public void moveHandleCollisionIterative(Vector providedVelocity) { - //Copies the velocity scaled with current frame time - final Vector velocity = providedVelocity.getMultiplied(GameThread.UPDATE_FACTOR); - //Gets the unit vector, which is basically the unit-circle direction that the velocity is pointing towards - final Vector unit = providedVelocity.getUnit(); - final Vector negativeUnit = unit.getNegative(); - - System.out.println("Start Movement:\nVelocity = " + providedVelocity + ", Scaled = " + velocity); - - - //Inch the object by integer increments to get closer to the position - int intIterations = (int) velocity.getMagnitude(); - System.out.println(intIterations + " iterations"); - for(int i = 0; i < intIterations; i++) { - //Moves a unit closer and reduces the "velocity left" by 1 - move(unit); - velocity.add(negativeUnit); - MapTile collision = getCollisionBounds(unit); - if(collision != null) { - //Move back and then break out of the loop -// velocity.add(unit); - velocity.set(unit); - move(negativeUnit); - - break; - } - } - System.out.println("Configure Velocity: " + velocity); - move(velocity); - if((lastCollided = getCollisionBounds(unit)) != null) { - float xScale = 0, yScale = 0; - - if(velocity.getX() != 0) { //Preventing div by 0 - float xCol, xObj; - if(velocity.getX() > 0) { - xCol = lastCollided.getPos().getX(); - xObj = pos.getX() + getBounds().getWidth(); - } else { - xCol = lastCollided.getPos().getX() + lastCollided.getBounds().getWidth(); - xObj = pos.getX(); - } - if(xObj > xCol) { - xScale = (xObj - xCol) / unit.getX(); - } - } - - if(velocity.getY() != 0) { - float yCol, yObj; - if(velocity.getY() > 0) { - yCol = lastCollided.getPos().getY(); - yObj = pos.getY() + getBounds().getHeight(); - } else { - yCol = lastCollided.getPos().getY() + lastCollided.getBounds().getHeight(); - yObj = pos.getY(); - } - if(yObj > yCol) { - yScale = (yObj - yCol) / unit.getY(); - } - System.out.println(yCol + " " + yObj); - } - inAir = xScale > yScale; - - move(negativeUnit.getMultiplied(Math.max(xScale,yScale))); - } - } - - /** - * Checks if the game object has collided with any map tiles, and returns the collided map-tile if it has. Otherwise, returns null - * - * Copied from CollisionHandler - * - * Deprecated, no longer works with changes to {@link Rectangle} - * @param velocity - * @return - */ - @Deprecated - private MapTile getCollisionBounds(Vector velocity) { - //TODO modify / recreate this code to iterate through all neighbor blocks only in the half direction of the velocity -// int numberOfTilesToCheck = Math.max(getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth() + 2, 3); - - Point tileIndex = getMap().getTileIndexByPosition(getScaledBounds().getLocation()); - - int rangeWidth = (int) getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth() + 3; - int rangeHeight = (int) getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight() + 3; - - MapTile[] tiles = map.getTilesInIndexBounds((int) tileIndex.x - 1, (int) tileIndex.y - 1, rangeWidth, rangeHeight); - - for(MapTile tile : tiles) { - if(checkCollisionBounds(tile, velocity)) { - return tile; - } - } - - for(MapTile enhancedTile : map.getEnhancedMapTiles()) { - if(checkCollisionBounds(enhancedTile, velocity)) { - return enhancedTile; - } - } - - return null; + this.startPositionX = x; + this.startPositionY = y; + this.previousX = x; + this.previousY = y; } + @Override + public void update() { + // call to animation logic + super.update(); - /** - * Copied from CollisionHandler - * @param mapTile - * @param velocity - * @return - */ - @Deprecated - private boolean checkCollisionBounds(MapTile mapTile, Vector velocity) { - return mapTile != null && switch (mapTile.getTileType()) { - case NOT_PASSABLE, LETHAL -> intersects(mapTile); - case JUMP_THROUGH_PLATFORM -> velocity.getY() > 0 && intersects(mapTile) && Math.round(getScaledBoundsY2() -1) == Math.round( - mapTile.getScaledBoundsY1()); - case PASSABLE -> false; - }; + // update previous position to be the current position + previousX = x; + previousY = y; } // move game object along the x axis // will stop object from moving based on map collision logic (such as if it hits a solid tile) - @Deprecated public void moveXHandleCollision(float dx) { if (map != null) { handleCollisionX(dx); @@ -444,7 +154,6 @@ public void moveXHandleCollision(float dx) { // move game object along the y axis // will stop object from moving based on map collision logic (such as if it hits a solid tile) - @Deprecated public void moveYHandleCollision(float dy) { if (map != null) { handleCollisionY(dy); @@ -453,16 +162,10 @@ public void moveYHandleCollision(float dy) { } } - @Deprecated - private int magnitudeToInt(float magnitude) { - return (int) magnitude; - } - // performs collision check logic for moving along the x axis against the map's tiles - @Deprecated public float handleCollisionX(float moveAmountX) { // determines amount to move (whole number) - int amountToMove = magnitudeToInt(moveAmountX); + int amountToMove = (int)Math.abs(moveAmountX); // gets decimal remainder from amount to move float moveAmountXRemainder = MathUtils.getRemainder(moveAmountX); @@ -507,10 +210,9 @@ public float handleCollisionX(float moveAmountX) { } // performs collision check logic for moving along the y axis against the map's tiles - @Deprecated public float handleCollisionY(float moveAmountY) { // determines amount to move (whole number) - int amountToMove = magnitudeToInt(moveAmountY); + int amountToMove = (int)Math.abs(moveAmountY); // gets decimal remainder from amount to move float moveAmountYRemainder = MathUtils.getRemainder(moveAmountY); @@ -521,74 +223,58 @@ public float handleCollisionY(float moveAmountY) { // moves game object one pixel at a time until total move amount is reached // if at any point a map tile collision is determined to have occurred from the move, // move player back to right in front of the "solid" map tile's position, and stop attempting to move further -// float amountMoved = 0; -// boolean hasCollided = false; -// for (int i = 0; i < amountToMove; i++) { -// moveY(direction.getVelocity()); -// float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); -// if (newLocation != 0) { -// hasCollided = true; -// setY(newLocation); -// break; -// } -// amountMoved = (i + 1) * direction.getVelocity(); -// } -// -// // if no collision occurred in the above steps, this deals with the decimal remainder from the original move amount (stored in moveAmountYRemainder) -// // it starts by moving the game object by that decimal amount -// // it then does one more check for a collision in the case that this added decimal amount was enough to change the rounding and move the game object to the next pixel over -// // if a collision occurs from this move, the player is moved back to right in front of the "solid" map tile's position -// if (!hasCollided) { -// moveY(moveAmountYRemainder * direction.getVelocity()); -// float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); -// if (newLocation != 0) { -// hasCollided = true; -// setY(newLocation); -// } -// } + float amountMoved = 0; boolean hasCollided = false; - - - setY(moveAmountY + pos.getY()); - float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this,map,direction); - if(newLocation != 0) { - setY(newLocation); -// System.out.println(newLocation); - hasCollided = true; + for (int i = 0; i < amountToMove; i++) { + moveY(direction.getVelocity()); + float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); + if (newLocation != 0) { + hasCollided = true; + setY(newLocation); + break; + } + amountMoved = (i + 1) * direction.getVelocity(); } + // if no collision occurred in the above steps, this deals with the decimal remainder from the original move amount (stored in moveAmountYRemainder) + // it starts by moving the game object by that decimal amount + // it then does one more check for a collision in the case that this added decimal amount was enough to change the rounding and move the game object to the next pixel over + // if a collision occurs from this move, the player is moved back to right in front of the "solid" map tile's position + if (!hasCollided) { + moveY(moveAmountYRemainder * direction.getVelocity()); + float newLocation = MapTileCollisionHandler.getAdjustedPositionAfterCollisionCheckY(this, map, direction); + if (newLocation != 0) { + hasCollided = true; + setY(newLocation); + } + } // call this method which a game object subclass can override to listen for collision events and react accordingly onEndCollisionCheckY(hasCollided, direction); // returns the amount actually moved -- this isn't really used by the game, but I have it here for debug purposes - return (moveAmountYRemainder * direction.getVelocity()); + return amountMoved + (moveAmountYRemainder * direction.getVelocity()); } // game object subclass can override this method to listen for x axis collision events and react accordingly after calling "moveXHandleCollision" - @Deprecated public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { } // game object subclass can override this method to listen for y axis collision events and react accordingly after calling "moveYHandleCollision" - @Deprecated public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { } // gets x location taking into account map camera position - @Deprecated - //TODO change to vector public float getCalibratedXLocation() { if (map != null) { - return pos.getX() - map.getCamera().getX(); + return x - map.getCamera().getX(); } else { return getX(); } } // gets y location taking into account map camera position - @Deprecated public float getCalibratedYLocation() { if (map != null) { - return pos.getY() - map.getCamera().getY(); + return y - map.getCamera().getY(); } else { return getY(); } @@ -621,8 +307,8 @@ public void draw(GraphicsHandler graphicsHandler) { currentFrame.getImage(), Math.round(getCalibratedXLocation()), Math.round(getCalibratedYLocation()), - Math.round(currentFrame.getScaledWidth()), - Math.round(currentFrame.getScaledHeight()), + currentFrame.getScaledWidth(), + currentFrame.getScaledHeight(), currentFrame.getImageEffect()); } else { super.draw(graphicsHandler); @@ -639,13 +325,4 @@ public void drawBounds(GraphicsHandler graphicsHandler, Color color) { super.drawBounds(graphicsHandler, color); } } - - public Map getMap() { - return map; - } - - public Vector getCenter() { - return pos.getAdd(new Vector(getBounds().getWidth() / 2f, getBounds().getHeight() / 2f)); - } - } diff --git a/src/GameObject/Hitbox.java b/src/GameObject/Hitbox.java deleted file mode 100644 index 2b3599b..0000000 --- a/src/GameObject/Hitbox.java +++ /dev/null @@ -1,32 +0,0 @@ -package GameObject; - -import Engine.Vector; - -/** - * Indicates that a class contains a HitBox. The hitbox is split up into two locations, the min value and the max value. - * - *

- * Given a rectangle with 4 locations, as listed: {@code (x1, y1), (x1, y2), (x2, y1), (x2, y2)}, the min and max locations would be as follows - *

  • Min Location: {@code (x1, y1)}
  • - *
  • Max Location: {@code (x2, y2)}
- * Where {@code x1 < x2} and {@code y1 < y2} - *

- * @author Thomas Kwashnak - */ -public interface Hitbox { - - /** - * Returns the upper left point of a hitbox. (Assuming that the top left corner is {@code (0,0)}). In short, given a hitbox with the - * points {@code (x1, y1), (x1, y2), (x2, y1), (x2, y2)}, returns {@code (x1, y1)} where {@code x1 < x2} and {@code y1 < y2} - * @return A vector representing {@code (x1, y1)} - * @see Hitbox - */ - Vector getMinLocation(); - /** - * Returns the bottom right point of a hitbox. (Assuming that the top left corner is {@code (0,0)}). In short, given a hitbox with the - * points {@code (x1, y1), (x1, y2), (x2, y1), (x2, y2)}, returns {@code (x2, y2)} where {@code x2 > x1} and {@code y2 > y1} - * @return A vector representing {@code (x2, y2)} - * @see Hitbox - */ - Vector getMaxLocation(); -} diff --git a/src/GameObject/Intersectable.java b/src/GameObject/Intersectable.java deleted file mode 100644 index a19d47e..0000000 --- a/src/GameObject/Intersectable.java +++ /dev/null @@ -1,15 +0,0 @@ -package GameObject; - -/** - * Indicates that an object can be checked for intersection with another intersectable - * @author Thomas Kwashnak - */ -public interface Intersectable extends Hitbox { - - /** - * Checks the intersection with another intersectable - * @param other Intersectable to check intersection with - * @return {@code true} if this intersectable and the provided intersectable intersect - */ - boolean intersects(Intersectable other); -} diff --git a/src/GameObject/IntersectableRectangleOld.java b/src/GameObject/IntersectableRectangle.java similarity index 74% rename from src/GameObject/IntersectableRectangleOld.java rename to src/GameObject/IntersectableRectangle.java index 1944688..3a45d37 100644 --- a/src/GameObject/IntersectableRectangleOld.java +++ b/src/GameObject/IntersectableRectangle.java @@ -2,7 +2,6 @@ // This interface allows for specifying a rectangle that can be used in intersection logic by the Rectangle class // it really only exists so an AnimatedSprite can be checked for intersection directly against by a Sprite or Rectangle (and all other combinations of that) -@Deprecated -public interface IntersectableRectangleOld { - RectangleOld getIntersectRectangle(); +public interface IntersectableRectangle { + Rectangle getIntersectRectangle(); } diff --git a/src/GameObject/Overlappable.java b/src/GameObject/Overlappable.java deleted file mode 100644 index d4b8c98..0000000 --- a/src/GameObject/Overlappable.java +++ /dev/null @@ -1,14 +0,0 @@ -package GameObject; - -/** - * Indicates that an object can be checked if it overlaps with another overlappable - * @author Thomas Kwashnak - */ -public interface Overlappable extends Hitbox { - /** - * Checks the overlapping with another Overlappable - * @param other Overlappable to check overlapping with - * @return {@code true} if this intersectable and the provided intersectable intersect - */ - boolean overlaps(Overlappable other); -} diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index 8ea4b8e..bf9dc34 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -1,189 +1,191 @@ package GameObject; -import Engine.Drawable; import Engine.GraphicsHandler; -import Engine.Vector; import java.awt.*; -/** - * @author Thomas Kwashnak - */ -public class Rectangle implements Drawable, Intersectable, Overlappable { - - private static final int BORDER_THICKNESS = 0; - - protected Vector location, dimension; - protected float scale; - protected Color color, borderColor; - - public Rectangle(float x, float y, float width, float height) { - this(new Vector(x, y), new Vector(width, height)); - } - - public Rectangle(Vector location, Vector dimension) { - this(location, dimension, 1); +// This class represents a rectangle, which at its core is (x, y, width, height) +// it has some properties, rectangle math methods, and draw logic +// the methods here are pretty self explanatory +public class Rectangle implements IntersectableRectangle { + protected float x; + protected float y; + protected int width; + protected int height; + protected float scale; + protected Color color; + protected Color borderColor; + protected int borderThickness; + + public Rectangle(float x, float y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.scale = 1; + this.color = Color.white; + this.borderColor = null; + this.borderThickness = 0; + } + + public Rectangle(float x, float y, int width, int height, float scale) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.scale = scale; + this.color = Color.white; + this.borderColor = null; + this.borderThickness = 0; + } + + public float getX() { + return x; } - public Rectangle(Vector location, Vector dimension, float scale) { - this.location = location; - this.dimension = dimension; - this.scale = scale; - } - - public Rectangle(float x, float y, float width, float height, float scale) { - this(new Vector(x, y), new Vector(width, height), scale); + public float getX1() { + return x; } public float getX2() { - return location.getX() + dimension.getX(); + return x + width; } public float getScaledX2() { - return location.getX() + (dimension.getX() * scale); - } - - public float getY2() { - return location.getY() + dimension.getY(); - } - - public float getScaledY2() { - return location.getY() + (dimension.getY() * scale); - } - - public void move(Vector displacement) { - location.add(displacement); - } - - public Vector getDimension() { - return dimension; - } - - public Vector getScaledDimension() { - return dimension.getMultiplied(scale); - } - - public Vector getLocation() { - return location; - } - - public void setLocation(Vector vector) { - this.location.set(vector); - } - - public void setLocationReference(Vector location) { - this.location = location; - } - - public void update() { - } - - public boolean intersects(Intersectable other) { - Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); - boolean xIntersects = min.getX() > minOther.getX() && min.getX() < maxOther.getX(); - xIntersects |= max.getX() > minOther.getX() && max.getX() < maxOther.getX(); - xIntersects |= minOther.getX() > min.getX() && minOther.getX() < max.getX(); - xIntersects |= maxOther.getX() > min.getX() && maxOther.getX() < max.getX(); - boolean yIntersects = min.getY() > minOther.getY() && min.getY() < maxOther.getY(); - yIntersects |= max.getY() > minOther.getY() && max.getY() < maxOther.getY(); - yIntersects |= minOther.getY() > min.getY() && minOther.getY() < max.getY(); - yIntersects |= maxOther.getY() > min.getY() && maxOther.getY() < max.getY(); - return xIntersects && yIntersects; - } - - public Vector getMinLocation() { - return location; - } - - public Vector getMaxLocation() { - return location.getAdd(dimension); - } - - public boolean overlaps(Overlappable other) { - Vector min = getMinLocation(), max = getMaxLocation(), minOther = other.getMinLocation(), maxOther = other.getMaxLocation(); - boolean xIntersects = min.getX() >= minOther.getX() && min.getX() <= maxOther.getX(); - xIntersects |= max.getX() > minOther.getX() && max.getX() <= maxOther.getX(); - xIntersects |= minOther.getX() >= min.getX() && minOther.getX() <= max.getX(); - xIntersects |= maxOther.getX() >= min.getX() && maxOther.getX() <= max.getX(); - boolean yIntersects = min.getY() >= minOther.getY() && min.getY() <= maxOther.getY(); - yIntersects |= max.getY() >= minOther.getY() && max.getY() <= maxOther.getY(); - yIntersects |= minOther.getY() >= min.getY() && minOther.getY() <= max.getY(); - yIntersects |= maxOther.getY() >= min.getY() && maxOther.getY() <= max.getY(); - return xIntersects && yIntersects; - } - - public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawFilledRectangle( - Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), color); - if (borderColor != null && !borderColor.equals(color)) { - graphicsHandler.drawRectangle( - Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), borderColor, - BORDER_THICKNESS - ); - } - } - - public float getX1() { - return location.getX(); + return x + getScaledWidth(); + } + + public void setX(float x) { + this.x = x; + } + + public void moveX(float dx) { + this.x += dx; + } + + public void moveRight(float dx) { + this.x += dx; + } + + public void moveLeft(float dx) { + this.x -= dx; + } + + public float getY() { + return y; } public float getY1() { - return location.getY(); - } - - public float getScaledWidth() { - return dimension.getX() * scale; - } - - public float getScaledHeight() { - return dimension.getY() * scale; - } - - public String toString() { - return String.format("Rectangle: location = %s, dimensions = %s", location.toString(), dimension.toString()); - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public float getScale() { - return scale; - } - - public void setScale(float scale) { - this.scale = scale; - } - - public Color getBorderColor() { - return borderColor; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - public float getWidth() { - return dimension.getX(); + return y; } - public void setWidth(float width) { - dimension.setX(width); - } - - public float getHeight() { - return dimension.getY(); - } - - public void setHeight(float height) { - dimension.setY(height); - } - - public Rectangle getScaled() { - return new Rectangle(location,dimension.getMultiplied(scale)); - } + public float getY2() { + return y + height; + } + + public float getScaledY2() { + return y + getScaledHeight(); + } + + public void setY(float y) { + this.y = y; + } + + public void moveY(float dy) { + this.y += dy; + } + + public void moveDown(float dy) { + this.y += dy; + } + + public void moveUp(float dy) { + this.y -= dy; + } + + public void setLocation(float x, float y) { + this.x = x; + this.y = y; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getScaledWidth() { + return Math.round(width * scale); + } + + public int getScaledHeight() { + return Math.round(height * scale); + } + + public float getScale() { return scale; } + + public void setScale(float scale) { + this.scale = scale; + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public void setBorderColor(Color borderColor) { + this.borderColor = borderColor; + } + + public void setBorderThickness(int borderThickness) { + this.borderThickness = borderThickness; + } + + @Override + public String toString() { + return String.format("Rectangle: x=%s y=%s width=%s height=%s", getX(), getY(), getScaledWidth(), getScaledHeight()); + } + + public void update() { } + + public void draw(GraphicsHandler graphicsHandler) { + graphicsHandler.drawFilledRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), color); + if (borderColor != null && !borderColor.equals(color)) { + graphicsHandler.drawRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), borderColor, borderThickness); + } + } + + @Override + public Rectangle getIntersectRectangle() { + return new Rectangle(x, y, getScaledWidth(), getScaledHeight()); + } + + // check if this intersects with another rectangle + public boolean intersects(IntersectableRectangle other) { + Rectangle intersectRectangle = getIntersectRectangle(); + Rectangle otherIntersectRectangle = other.getIntersectRectangle(); + return Math.round(intersectRectangle.getX1()) < Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) > Math.round(otherIntersectRectangle.getX1()) && + Math.round(intersectRectangle.getY1()) < Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) > Math.round(otherIntersectRectangle.getY1()); + } + + // check if this overlaps with another rectangle + public boolean overlaps(IntersectableRectangle other) { + Rectangle intersectRectangle = getIntersectRectangle(); + Rectangle otherIntersectRectangle = other.getIntersectRectangle(); + return Math.round(intersectRectangle.getX1()) <= Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) >= Math.round(otherIntersectRectangle.getX1()) && + Math.round(intersectRectangle.getY1()) <= Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) >= Math.round(otherIntersectRectangle.getY1()); + } } diff --git a/src/GameObject/RectangleOld.java b/src/GameObject/RectangleOld.java deleted file mode 100644 index 9f14b53..0000000 --- a/src/GameObject/RectangleOld.java +++ /dev/null @@ -1,203 +0,0 @@ -package GameObject; - -import Engine.GraphicsHandler; -import Engine.Vector; - -import java.awt.*; - -// This class represents a rectangle, which at its core is (x, y, width, height) -// it has some properties, rectangle math methods, and draw logic -// the methods here are pretty self explanatory -@Deprecated -public class RectangleOld implements IntersectableRectangleOld { - protected Vector location, dimensions; - protected float x; - protected float y; - protected int width; - protected int height; - protected float scale; - protected Color color; - protected Color borderColor; - protected int borderThickness; - - public RectangleOld(float x, float y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.scale = 1; - this.color = Color.white; - this.borderColor = null; - this.borderThickness = 0; - } - - public RectangleOld(float x, float y, int width, int height, float scale) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.scale = scale; - this.color = Color.white; - this.borderColor = null; - this.borderThickness = 0; - } - - public float getX() { - return x; - } - - public float getX1() { - return x; - } - - public float getX2() { - return x + width; - } - - public float getScaledX2() { - return x + getScaledWidth(); - } - - public void setX(float x) { - this.x = x; - } - - public void moveX(float dx) { - this.x += dx; - } - - public void moveRight(float dx) { - this.x += dx; - } - - public void moveLeft(float dx) { - this.x -= dx; - } - - public float getY() { - return y; - } - - public float getY1() { - return y; - } - - public float getY2() { - return y + height; - } - - public float getScaledY2() { - return y + getScaledHeight(); - } - - public void setY(float y) { - this.y = y; - } - - public void moveY(float dy) { - this.y += dy; - } - - public void moveDown(float dy) { - this.y += dy; - } - - public void moveUp(float dy) { - this.y -= dy; - } - - public void setLocation(float x, float y) { - this.x = x; - this.y = y; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getScaledWidth() { - return Math.round(width * scale); - } - - public int getScaledHeight() { - return Math.round(height * scale); - } - - public float getScale() { return scale; } - - public void setScale(float scale) { - this.scale = scale; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public void setBorderColor(Color borderColor) { - this.borderColor = borderColor; - } - - public void setBorderThickness(int borderThickness) { - this.borderThickness = borderThickness; - } - - @Override - public String toString() { - return String.format("Rectangle: x=%s y=%s width=%s height=%s", getX(), getY(), getScaledWidth(), getScaledHeight()); - } - - public void update() { } - - public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawFilledRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), color); - if (borderColor != null && !borderColor.equals(color)) { - graphicsHandler.drawRectangle(Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), borderColor, borderThickness); - } - } - - @Override - public RectangleOld getIntersectRectangle() { - return new RectangleOld(x, y, getScaledWidth(), getScaledHeight()); - } - - // check if this intersects with another rectangle - public boolean intersects(IntersectableRectangleOld other) { - RectangleOld intersectRectangle = getIntersectRectangle(); - RectangleOld otherIntersectRectangle = other.getIntersectRectangle(); - return Math.round(intersectRectangle.getX1()) < Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) > Math.round(otherIntersectRectangle.getX1()) && - Math.round(intersectRectangle.getY1()) < Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) > Math.round(otherIntersectRectangle.getY1()); - } - - // check if this overlaps with another rectangle - public boolean overlaps(IntersectableRectangleOld other) { - RectangleOld intersectRectangle = getIntersectRectangle(); - RectangleOld otherIntersectRectangle = other.getIntersectRectangle(); - return Math.round(intersectRectangle.getX1()) <= Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) >= Math.round(otherIntersectRectangle.getX1()) && - Math.round(intersectRectangle.getY1()) <= Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) >= Math.round(otherIntersectRectangle.getY1()); - } - - //TODO reduce calls - public Vector getPos1() { - return new Vector(getX1(), getY1()); - } - - public Vector getPos2() { - return new Vector(getX2(), getY2()); - } -} diff --git a/src/GameObject/Sprite.java b/src/GameObject/Sprite.java index b79f4b4..1a52c77 100644 --- a/src/GameObject/Sprite.java +++ b/src/GameObject/Sprite.java @@ -1,100 +1,120 @@ package GameObject; import Engine.GraphicsHandler; -import Engine.Vector; +import Engine.ImageLoader; import java.awt.*; import java.awt.image.BufferedImage; -/** - * @author Thomas Kwashnak (re-wrote) - * @author Alex Thimineur (original) - */ -public class Sprite extends Rectangle { - - protected BufferedImage image; +// This class is for representing a Sprite, which is essentially a Rectangle with an image attached +// it also includes an attribute for "bounds", which can be thought of a sub rectangle on the image where it can be interacted with (like for collisions) +public class Sprite extends Rectangle implements IntersectableRectangle { + protected BufferedImage image; + protected Rectangle bounds; protected ImageEffect imageEffect; - protected Rectangle bounds, scaledBounds; - - public Sprite(BufferedImage image, float scale) { - this(image, scale, ImageEffect.NONE); - } - public Sprite(BufferedImage image, float scale, ImageEffect imageEffect) { - this(image, 0, 0, scale, imageEffect); + public Sprite (BufferedImage image, float scale, ImageEffect imageEffect) { + super(0, 0, image.getWidth(), image.getHeight(), scale); + this.image = image; + this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); + this.imageEffect = imageEffect; } public Sprite(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { - this(image, new Vector(x, y), scale, imageEffect); + super(x, y, image.getWidth(), image.getHeight(), scale); + this.image = image; + this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); + this.imageEffect = imageEffect; } - - public Sprite(BufferedImage image, Vector location, float scale, ImageEffect imageEffect) { - super(location, Vector.convertImageDimensions(image), scale); + + public BufferedImage getImage() { + return image; + } + + public void setImage(String imageFileName) { + image = ImageLoader.load(imageFileName); + } + + public void setImage(BufferedImage image) { this.image = image; + } + + public ImageEffect getImageEffect() { return imageEffect; } + + public void setImageEffect(ImageEffect imageEffect) { this.imageEffect = imageEffect; - bounds = new Rectangle(new Vector(0,0),dimension.clone()); - scaledBounds = scaleBounds(bounds); } - public BufferedImage getImage() { - return image; + public Rectangle getBounds() { + return new Rectangle(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); } - public ImageEffect getImageEffect() { - return imageEffect; + public float getBoundsX1() { + return x + bounds.getX1(); } - /* - Overrides the Rectangle to use bounds if a custom bounds was specified - */ - @Override - public Vector getMinLocation() { - return bounds.location; + public float getBoundsX2() { + return x + bounds.getX2(); } - /* - Overrides the Rectangle to use bounds if a custom bounds was specified - */ - @Override - public Vector getMaxLocation() { - return bounds.location.getAdd(dimension); + public float getBoundsY1() { + return y + bounds.getY1(); } - public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawImage( - image, Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), imageEffect); + public float getBoundsY2() { + return y + bounds.getY2(); } - public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - Rectangle scaledBounds = getScaledBounds(); - scaledBounds.setColor(color); - scaledBounds.draw(graphicsHandler); + public float getScaledBoundsX1() { + return getX() + (bounds.getX1() * scale); } - public Rectangle getBounds() { - return new Rectangle(location.getAdd(bounds.location),bounds.dimension,bounds.scale); + public float getScaledBoundsX2() { + return getScaledBoundsX1() + bounds.getScaledWidth(); + } + + public float getScaledBoundsY1() { + return getY() + (bounds.getY1() * scale); + } + + public float getScaledBoundsY2() { + return getScaledBoundsY1() + bounds.getScaledHeight(); } public Rectangle getScaledBounds() { - return new Rectangle(location.getAdd(scaledBounds.location),scaledBounds.dimension); + return new Rectangle(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); } public void setBounds(Rectangle bounds) { - this.bounds = bounds; - scaledBounds = scaleBounds(bounds); + this.bounds = new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), scale); } - public boolean intersects(Intersectable other) { - return getScaledBounds().intersects(other); + public void setBounds(float x, float y, int width, int height) { + this.bounds = new Rectangle(x, y, width, height, scale); } - /** - * Returns the scaled bounds of the given bounds - * @param bounds Bounds to scale to scale = 1 - * @return Scaled bounds where both the location and dimension are scaled - */ - private Rectangle scaleBounds(Rectangle bounds) { - return new Rectangle(bounds.location.getMultiplied(bounds.scale), bounds.dimension.getMultiplied(bounds.scale)); + public Rectangle getIntersectRectangle() { + return getScaledBounds(); } + @Override + public void update() { + super.update(); + } + + @Override + public void draw(GraphicsHandler graphicsHandler) { + graphicsHandler.drawImage(image, Math.round(getX()), Math.round(getY()), getScaledWidth(), getScaledHeight(), imageEffect); + } + + public void drawBounds(GraphicsHandler graphicsHandler, Color color) { + Rectangle scaledBounds = getScaledBounds(); + scaledBounds.setColor(color); + scaledBounds.draw(graphicsHandler); + } + + @Override + public String toString() { + return String.format("Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", getX(), getY(), getScaledWidth(), getScaledHeight(), getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); + } } diff --git a/src/GameObject/SpriteOld.java b/src/GameObject/SpriteOld.java deleted file mode 100644 index b03e55c..0000000 --- a/src/GameObject/SpriteOld.java +++ /dev/null @@ -1,122 +0,0 @@ -package GameObject; - -import Engine.GraphicsHandler; -import Engine.ImageLoader; - -import java.awt.*; -import java.awt.image.BufferedImage; - -// This class is for representing a Sprite, which is essentially a Rectangle with an image attached -// it also includes an attribute for "bounds", which can be thought of a sub rectangle on the image where it can be interacted with (like for collisions) -@Deprecated -public class SpriteOld extends Rectangle { - protected BufferedImage image; - protected Rectangle bounds; - protected ImageEffect imageEffect; - - public SpriteOld (BufferedImage image, float scale, ImageEffect imageEffect) { - super(0, 0, image.getWidth(), image.getHeight(), scale); - this.image = image; - this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); - this.imageEffect = imageEffect; - } - - public SpriteOld(BufferedImage image, float x, float y, float scale, ImageEffect imageEffect) { - super(x, y, image.getWidth(), image.getHeight(), scale); - this.image = image; - this.bounds = new Rectangle(0, 0, image.getWidth(), image.getHeight(), scale); - this.imageEffect = imageEffect; - } - - public BufferedImage getImage() { - return image; - } - - public void setImage(String imageFileName) { - image = ImageLoader.load(imageFileName); - } - - public void setImage(BufferedImage image) { - this.image = image; - } - - public ImageEffect getImageEffect() { return imageEffect; } - - public void setImageEffect(ImageEffect imageEffect) { - this.imageEffect = imageEffect; - } - - public Rectangle getBounds() { - return new Rectangle(getBoundsX1(), getBoundsY1(), bounds.getWidth(), bounds.getHeight(), scale); - } - - public float getBoundsX1() { - return getX1() + bounds.getX1(); - } - - public float getBoundsX2() { - return getX1() + bounds.getX2(); - } - - public float getBoundsY1() { - return getY1() + bounds.getY1(); - } - - public float getBoundsY2() { - return getY1() + bounds.getY2(); - } - - public float getScaledBoundsX1() { - return getX1() + (bounds.getX1() * scale); - } - - public float getScaledBoundsX2() { - return getScaledBoundsX1() + bounds.getScaledWidth(); - } - - public float getScaledBoundsY1() { - return getY1() + (bounds.getY1() * scale); - } - - public float getScaledBoundsY2() { - return getScaledBoundsY1() + bounds.getScaledHeight(); - } - - public Rectangle getScaledBounds() { - return new Rectangle(getScaledBoundsX1(), getScaledBoundsY1(), bounds.getScaledWidth(), bounds.getScaledHeight()); - } - - public void setBounds(Rectangle bounds) { - this.bounds = new Rectangle(bounds.getX1(), bounds.getY1(), bounds.getWidth(), bounds.getHeight(), scale); - } - - public void setBounds(float x, float y, int width, int height) { - this.bounds = new Rectangle(x, y, width, height, scale); - } - - public Rectangle getIntersectRectangle() { - return getScaledBounds(); - } - - @Override - public void update() { - super.update(); - } - - @Override - public void draw(GraphicsHandler graphicsHandler) { - graphicsHandler.drawImage(image, Math.round(getX1()), Math.round(getY1()), Math.round(getScaledWidth()), Math.round(getScaledHeight()), imageEffect); - } - - public void drawBounds(GraphicsHandler graphicsHandler, Color color) { - Rectangle scaledBounds = getScaledBounds(); - scaledBounds.setColor(color); - scaledBounds.draw(graphicsHandler); - } - - @Override - public String toString() { - return String.format("Sprite: x=%s y=%s width=%s height=%s bounds=(%s, %s, %s, %s)", getX1(), getY1(), getScaledWidth(), getScaledHeight(), - getScaledBoundsX1(), getScaledBoundsY1(), getScaledBounds().getWidth(), getScaledBounds().getHeight()); - } -} diff --git a/src/Level/Camera.java b/src/Level/Camera.java index 56c9c6e..ffeab9e 100644 --- a/src/Level/Camera.java +++ b/src/Level/Camera.java @@ -3,14 +3,14 @@ import Engine.GraphicsHandler; import Engine.ScreenManager; import GameObject.GameObject; -import GameObject.RectangleOld; +import GameObject.Rectangle; import java.awt.*; import java.util.ArrayList; // This class represents a Map's "Camera", aka a piece of the map that is currently included in a level's update/draw logic based on what should be shown on screen. // A majority of its job is just determining which map tiles, enemies, npcs, and enhanced map tiles are "active" each frame (active = included in update/draw cycle) -public class Camera extends RectangleOld { +public class Camera extends Rectangle { // the current map this camera is attached to private Map map; @@ -111,7 +111,7 @@ private ArrayList loadActiveEnemies() { } } else if (enemy.getMapEntityStatus() == MapEntityStatus.ACTIVE) { enemy.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (enemy.isRespawnEnabled()) { + if (enemy.isRespawnable()) { enemy.initialize(); } } else if (enemy.getMapEntityStatus() == MapEntityStatus.REMOVED) { @@ -133,7 +133,7 @@ private ArrayList loadActiveProjectiles() { } } else if (projectile.getMapEntityStatus() == MapEntityStatus.ACTIVE) { projectile.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (projectile.isRespawnEnabled()) { + if (projectile.isRespawnable()) { projectile.initialize(); } } else if (projectile.getMapEntityStatus() == MapEntityStatus.REMOVED) { @@ -162,7 +162,7 @@ private ArrayList loadActiveEnhancedMapTiles() { } } else if (enhancedMapTile.getMapEntityStatus() == MapEntityStatus.ACTIVE) { enhancedMapTile.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (enhancedMapTile.isRespawnEnabled()) { + if (enhancedMapTile.isRespawnable()) { enhancedMapTile.initialize(); } } else if (enhancedMapTile.getMapEntityStatus() == MapEntityStatus.REMOVED) { @@ -191,7 +191,7 @@ private ArrayList loadActiveNPCs() { } } else if (npc.getMapEntityStatus() == MapEntityStatus.ACTIVE) { npc.setMapEntityStatus(MapEntityStatus.INACTIVE); - if (npc.isRespawnEnabled()) { + if (npc.isRespawnable()) { npc.initialize(); } } else if (npc.getMapEntityStatus() == MapEntityStatus.REMOVED) { diff --git a/src/Level/CollisionHandler.java b/src/Level/CollisionHandler.java deleted file mode 100644 index 18fcc9a..0000000 --- a/src/Level/CollisionHandler.java +++ /dev/null @@ -1,86 +0,0 @@ -package Level; - -import Engine.Vector; -import Game.GameThread; -import GameObject.GameObject; -import Utils.Point; - -/** - * - */ -@Deprecated -public class CollisionHandler { - - private GameObject gameObject; - private MapTile lastCollidedTile; - - public CollisionHandler(GameObject gameObject) { - this.gameObject = gameObject; - } - - public Map getMap() { - return gameObject.getMap(); - } - - public Vector getAdjustedMovement(Vector velocity) { - velocity.multiply(GameThread.UPDATE_FACTOR); - Vector unit = velocity.getUnit(), cloned = velocity.clone(); - Vector originalPos = gameObject.getPos().clone(); - - while(cloned.getMagnitude() > 1) { - gameObject.move(unit); - cloned.subtract(1); - MapTile collision = getCollision(cloned); - if(collision != null) { - gameObject.move(unit.getNegative()); - cloned.add(1); - lastCollidedTile = collision; - return modifiedVelocity(collision,cloned); - } - } - return velocity; - } - - private Vector modifiedVelocity(MapTile collided, Vector velocity) { - System.out.println(velocity); - return null; - } - - /** - * Checks if the game object has collided with any map tiles, and returns the collided map-tile if it has. Otherwise, returns null - * @param velocity - * @return - */ - private MapTile getCollision(Vector velocity) { - int numberOfTilesToCheck = Math.max((int) gameObject.getScaledBounds().getWidth() / getMap().getTileset().getScaledSpriteWidth(),1); - Point tileIndex = getMap().getTileIndexByPosition(gameObject.getPos()); - for(int i = -1;i < numberOfTilesToCheck + 1; i++) { - for(int j = -1;j < numberOfTilesToCheck + 1; j++) { - MapTile mapTile = getMap().getTileByIntPosition((int) tileIndex.x + i, (int) tileIndex.y + j); - if(checkCollision(mapTile, velocity)) { - return mapTile; - } - } - } - - return null; - } - - public boolean checkCollision(MapTile mapTile, Vector velocity) { - return mapTile != null && hasCollidedWithMapTile(gameObject,mapTile,velocity); - } - - public static boolean hasCollidedWithMapTile(GameObject gameObject, MapTile mapTile, Vector velocity) { - return switch (mapTile.getTileType()) { - case NOT_PASSABLE, LETHAL -> gameObject.intersects(mapTile); - case JUMP_THROUGH_PLATFORM -> velocity.getY() < 0 && gameObject.intersects(mapTile) && Math.round(gameObject.getScaledBoundsY2() -1) == Math.round( - mapTile.getScaledBoundsY1()); - default -> false; - }; - } - - public MapTile getLastCollidedTile() { - return lastCollidedTile; - } - -} diff --git a/src/Level/Map.java b/src/Level/Map.java index 5a91deb..6b8c670 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -1,6 +1,9 @@ package Level; -import Engine.*; +import Engine.Config; +import Engine.Drawable; +import Engine.GraphicsHandler; +import Engine.ScreenManager; import Utils.Point; import java.io.File; @@ -8,7 +11,6 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; -import java.util.List; import java.util.Scanner; /* @@ -224,86 +226,19 @@ public void setMapTile(int x, int y, MapTile tile) { } // returns a tile based on a position in the map - /** - * uhh.. doesn't work? - */ - @Deprecated - public MapTile getTileByIntPosition(int xPosition, int yPosition) { + public MapTile getTileByPosition(int xPosition, int yPosition) { Point tileIndex = getTileIndexByPosition(xPosition, yPosition); - if (isInBounds(Math.round(tileIndex.x), Math.round(tileIndex.y))) { //useless as it already checks within getMapTile? + if (isInBounds(Math.round(tileIndex.x), Math.round(tileIndex.y))) { return getMapTile(Math.round(tileIndex.x), Math.round(tileIndex.y)); } else { return null; } } - /** - * Returns a list of Tiles within the bounds listed starting at x,y and going height,width - * @param x - * @param y - * @param width - * @param height - * @return - */ - @Deprecated - public MapTile[] getTilesInIndexBounds(int x, int y, int width, int height) { - MapTile[] ret = new MapTile[width * height]; - for(int i = 0; i < ret.length; i++) { - ret[i] = getMapTile(x + i / width, y + i % width); - } - return ret; - } - - public MapTile[] getTilesInBounds(Vector start, int width, int height) { - MapTile[] ret = new MapTile[width * height]; - Point s = getTileIndexByPosition(start); - int x = (int) s.x, y = (int) s.y; - for(int i = 0; i < ret.length; i++) { - ret[i] = getMapTile(x + i / width, y + i % width); - } - return ret; - } - - /** - * Cuts down the list of mapTiles to only ones that are at most 2 * length distance away. Also includes enhancedMapTiles - * @param origin - * @param length - * @return - */ - public List getMapTilesInRange(Vector origin, float length) { - List tiles = new ArrayList<>((int) (4 * length * length / tileset.getScaledSpriteHeight() / tileset.getScaledSpriteWidth())); - float lSquared = length * length; - for(MapTile tile : mapTiles) { - float dx = tile.getX() - origin.getX(), dy = tile.getY() - origin.getY(); - if(dx * dx + dy * dy < lSquared) { - tiles.add(tile); - } - } - for(MapTile tile : enhancedMapTiles) { - float dx = tile.getX() - origin.getX(), dy = tile.getY() - origin.getY(); - if(dx * dx + dy * dy < lSquared) { - tiles.add(tile); - } - } - return tiles; - } - - public MapTile getTileByPosition(Vector position) { - int xIndex = (int) (position.getX() / tileset.getScaledSpriteWidth()); - int yIndex = (int) (position.getY() / tileset.getScaledSpriteHeight()); - return getMapTile(xIndex,yIndex); - } - - public Point getTileIndexByPosition(Vector vector) { - int xIndex = Math.round(vector.getX() / tileset.getScaledSpriteWidth()); - int yIndex = Math.round(vector.getY() / tileset.getScaledSpriteHeight()); - return new Point(xIndex,yIndex); - } - // returns the index of a tile (x index and y index) based on a position in the map public Point getTileIndexByPosition(float xPosition, float yPosition) { - int xIndex = Math.round(xPosition / tileset.getScaledSpriteWidth()); - int yIndex = Math.round(yPosition / tileset.getScaledSpriteHeight()); + int xIndex = Math.round(xPosition) / tileset.getScaledSpriteWidth(); + int yIndex = Math.round(yPosition) / tileset.getScaledSpriteHeight(); return new Point(xIndex, yIndex); } diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index b41c034..8642e95 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -1,7 +1,6 @@ package Level; import Engine.CollisionType; -import Engine.Vector; import GameObject.*; import java.awt.image.BufferedImage; @@ -14,7 +13,7 @@ public class MapEntity extends GameObject { protected CollisionType collisionType = CollisionType.DEFAULT; // if true, if entity goes out of the camera's update range, and then ends up back in range, the entity will "respawn" back to its starting parameters - protected boolean respawnEnabled = true; + protected boolean isRespawnable = true; // if true, enemy cannot go out of camera's update range protected boolean isUpdateOffScreen = false; @@ -48,8 +47,12 @@ public MapEntity(BufferedImage image, float x, float y, float scale, ImageEffect } public void initialize() { - pos.set(startPosition); - amountMoved = new Vector(0, 0); + this.x = startPositionX; + this.y = startPositionY; + this.amountMovedX = 0; + this.amountMovedY = 0; + this.previousX = startPositionX; + this.previousY = startPositionY; updateCurrentFrame(); } @@ -61,12 +64,12 @@ public void setMapEntityStatus(MapEntityStatus mapEntityStatus) { this.mapEntityStatus = mapEntityStatus; } - public boolean isRespawnEnabled() { - return respawnEnabled; + public boolean isRespawnable() { + return isRespawnable; } public void setIsRespawnable(boolean isRespawnable) { - this.respawnEnabled = isRespawnable; + this.isRespawnable = isRespawnable; } public boolean isUpdateOffScreen() { diff --git a/src/Level/MapTileCollisionHandler.java b/src/Level/MapTileCollisionHandler.java index 8d1263d..bc99ba4 100644 --- a/src/Level/MapTileCollisionHandler.java +++ b/src/Level/MapTileCollisionHandler.java @@ -4,23 +4,14 @@ import Utils.Direction; import Utils.Point; - - -/* - * Why is this a static class - */ - -/** - * This class has methods to check if a game object has collided with a map tile - * it is used by the game object class to determine if a collision occurred - */ -@Deprecated +// This class has methods to check if a game object has collided with a map tile +// it is used by the game object class to determine if a collision occurred public class MapTileCollisionHandler { public static MapTile lastCollidedTileX, lastCollidedTileY; - + public static float getAdjustedPositionAfterCollisionCheckX(GameObject gameObject, Map map, Direction direction) { - int numberOfTilesToCheck = (int) Math.max(gameObject.getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight(), 1); + int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getHeight() / map.getTileset().getScaledSpriteHeight(), 1); float edgeBoundX = direction == Direction.LEFT ? gameObject.getScaledBounds().getX1() : gameObject.getScaledBounds().getX2(); Point tileIndex = map.getTileIndexByPosition(edgeBoundX, gameObject.getScaledBounds().getY1()); for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { @@ -50,31 +41,14 @@ public static float getAdjustedPositionAfterCollisionCheckX(GameObject gameObjec return 0; } - /** - * Firstly, totally going to be changing this in velocities - * - * Checks collisions between a list of tiles and enhanced tile-sets, returns 0 if no collision, or the new Y value if a collision does occur. - * @param gameObject Object to check collision - * @param map Map the object is on - * @param direction Direction the object is moving in - * @return - */ public static float getAdjustedPositionAfterCollisionCheckY(GameObject gameObject, Map map, Direction direction) { - //Tiles to check? getting a list of tiles - int numberOfTilesToCheck = (int) Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(), 1); - float edgeBoundY = direction == Direction.UP ? gameObject.getScaledBounds().getY1() : gameObject.getScaledBounds().getY2(); - /*Get the edge bounds... ok?*/ - Point tileIndex = map.getTileIndexByPosition(gameObject.getScaledBounds().getX1(), edgeBoundY); /*Gets the uh, bottom left item? */ - for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { /*Get only immediately surrounding map tiles. AHA */ - /* - So the bottom message rounds to a whole number to check the tile at that location - */ - MapTile mapTile = map.getMapTile(/*converts / grabs based on array*/Math.round(tileIndex.x) + j, Math.round(tileIndex.y)); /*Grab the map - tile relative to the gameObject position*/ - - if (mapTile != null && hasCollidedWithMapTile(gameObject, mapTile, direction)) { /* Checks if there's a tile there, and if it's collided*/ - lastCollidedTileY = mapTile; /*Update tile*/ - /*Normalizes the distance based on the direction + bounds of the block*/ + int numberOfTilesToCheck = Math.max(gameObject.getScaledBounds().getWidth() / map.getTileset().getScaledSpriteWidth(), 1); + float edgeBoundY = direction == Direction.UP ? gameObject.getScaledBounds().getY() : gameObject.getScaledBounds().getY2(); + Point tileIndex = map.getTileIndexByPosition(gameObject.getScaledBounds().getX1(), edgeBoundY); + for (int j = -1; j <= numberOfTilesToCheck + 1; j++) { + MapTile mapTile = map.getMapTile(Math.round(tileIndex.x) + j, Math.round(tileIndex.y)); + if (mapTile != null && hasCollidedWithMapTile(gameObject, mapTile, direction)) { + lastCollidedTileY = mapTile; if (direction == Direction.DOWN) { float boundsDifference = gameObject.getScaledY2() - gameObject.getScaledBoundsY2(); return mapTile.getScaledBoundsY1() - gameObject.getScaledHeight() + boundsDifference; diff --git a/src/Level/Player.java b/src/Level/Player.java index c43016a..fd277d0 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -1,8 +1,6 @@ package Level; import Engine.KeyboardAction; -import Engine.Vector; -import Game.GameThread; import GameObject.GameObject; import GameObject.SpriteSheet; import Level.PlayerState.Facing; @@ -27,9 +25,8 @@ public abstract class Player extends GameObject { private PlayerState playerState; private Facing facing; private LevelState levelState; + private boolean inAir; private float absVelocityX, velocityY; - private int moveDelay = 2; - public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { super(spriteSheet, x, y, startingAnimationName); @@ -46,6 +43,7 @@ public void update() { case DEAD -> updateDead(); case WIN -> updateWin(); } + setCurrentAnimationName(playerState.get(facing)); } @@ -57,7 +55,7 @@ private void updatePlaying() { boolean playerMove = moveLeftDown ^ KeyboardAction.GAME_MOVE_RIGHT.isDown(); //Only true if the player is moving in a direction facing = playerMove ? moveLeftDown ? Facing.LEFT : Facing.RIGHT : facing; //Update facing if the player moved //Only move if the player moved and is not going out of bounds - if (playerMove && ((facing == Facing.LEFT && pos.getX() > 0) ^ (facing == Facing.RIGHT && pos.getY() < map.getRightBound()))) { + if (playerMove && ((facing == Facing.LEFT && x > 0) ^ (facing == Facing.RIGHT && x < map.getRightBound()))) { playerState = PlayerState.WALK; if (KeyboardAction.GAME_SPRINT.isDown() && absVelocityX >= walkSpeed) { if (absVelocityX < sprintSpeed) { @@ -82,7 +80,7 @@ private void updatePlaying() { //Update Attack if (KeyboardAction.GAME_ATTACK.isDown() && attackDelay.isTimeUp()) { - int attackX = facing == Facing.RIGHT ? Math.round(getX() + getScaledWidth() - 20) : Math.round(getX()); + int attackX = facing == Facing.RIGHT ? Math.round(getX()) + getScaledWidth() - 20 : Math.round(getX()); map.addEnemy(new PlayerAttack(new Point(attackX, Math.round(getY()) + 10), facing.mod * 1.5f, 1000)); attackDelay.setWaitTime(ATTACK_DELAY); } @@ -101,25 +99,8 @@ private void updatePlaying() { } inAir = true; //air is decided in moveYHandleCollision() - /* - So what's happening here is that the player never actually "hits" the block until the velocity gets enough to actually - change the player's Y position (since it rounds movement to an int) - Thus, as the gravity increases the veloctyY, it still thinks its in the air as the player doesn't actually "hit" anything - (movement is set to 0). Something that might fix would be to make internal movements stored in floats, and then have - the rendering be "truncated" to ints? or maybe it also does floats? - Basically we're going away from int locations? Would need to keep some things as ints to allow for - */ - - -// super.moveYHandleCollision(velocityY * GameThread.getScale()); -// System.out.println(velocityY * GameThread.getScale() + " " + inAir); -// super.moveXHandleCollision(absVelocityX * facing.mod * GameThread.getScale()); -// collisionHandler.getAdjustedMovement(new Vector(absVelocityX * facing.mod, velocityY)); - if(moveDelay > 0) { - moveDelay--; - } else { - moveHandleCollision(new Vector(absVelocityX * facing.mod, velocityY)); - } + super.moveYHandleCollision(velocityY); + super.moveXHandleCollision(absVelocityX * facing.mod); } private void updateDead() { @@ -133,7 +114,7 @@ private void updateDead() { } else { velocityY = DEATH_Y_VELOCITY; } - setY(getY() + velocityY * GameThread.UPDATE_FACTOR); + setY(y + velocityY); } private void updateWin() { @@ -142,10 +123,10 @@ private void updateWin() { if (inAir) { playerState = PlayerState.FALL; applyGravity(MAX_FALL_VELOCITY); - moveYHandleCollision(velocityY * GameThread.UPDATE_FACTOR); + moveYHandleCollision(velocityY); } else { playerState = PlayerState.WALK; - moveXHandleCollision(walkSpeed * GameThread.UPDATE_FACTOR); + moveXHandleCollision(walkSpeed); } } else for (PlayerListener listener : playerListeners) { listener.onLevelCompleted(); @@ -154,7 +135,7 @@ private void updateWin() { private void applyGravity(float maxFallVelocity) { if (velocityY < maxFallVelocity) { - velocityY += gravity * GameThread.UPDATE_FACTOR; + velocityY += gravity; } } diff --git a/src/Level/PlayerAttack.java b/src/Level/PlayerAttack.java index 1996326..481c423 100644 --- a/src/Level/PlayerAttack.java +++ b/src/Level/PlayerAttack.java @@ -29,7 +29,7 @@ public PlayerAttack(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this enemy will not respawn after it has been removed - respawnEnabled = false; + isRespawnable = false; initialize(); } diff --git a/src/MapEditor/TileBuilder.java b/src/MapEditor/TileBuilder.java index f464783..8a55179 100644 --- a/src/MapEditor/TileBuilder.java +++ b/src/MapEditor/TileBuilder.java @@ -76,8 +76,8 @@ public void draw() { graphicsHandler.drawRectangle( Math.round(hoveredMapTile.getX()) + 2, Math.round(hoveredMapTile.getY()) + 2, - Math.round(hoveredMapTile.getScaledWidth() - 5), - Math.round(hoveredMapTile.getScaledHeight() - 5), + hoveredMapTile.getScaledWidth() - 5, + hoveredMapTile.getScaledHeight() - 5, Color.YELLOW, 5 ); diff --git a/src/MapEditor/TilePicker.java b/src/MapEditor/TilePicker.java index 036c304..5c09e8b 100644 --- a/src/MapEditor/TilePicker.java +++ b/src/MapEditor/TilePicker.java @@ -89,8 +89,8 @@ public void draw() { graphicsHandler.drawRectangle( Math.round(selectedTile.getX()) - 2, Math.round(selectedTile.getY()) - 2, - Math.round(selectedTile.getScaledWidth() + 4), - Math.round(selectedTile.getScaledHeight() + 4), + selectedTile.getScaledWidth() + 4, + selectedTile.getScaledHeight() + 4, Color.YELLOW, 4 ); diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index 7d5756f..6db1b67 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -45,7 +45,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(42, 13), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Maps/TestMap.java b/src/Maps/TestMap.java index d60b833..831cd12 100644 --- a/src/Maps/TestMap.java +++ b/src/Maps/TestMap.java @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Maps/TestMap2.java b/src/Maps/TestMap2.java index 52793f6..e17506f 100644 --- a/src/Maps/TestMap2.java +++ b/src/Maps/TestMap2.java @@ -3,7 +3,10 @@ import Enemies.BugEnemy; import Enemies.DinosaurEnemy; import EnhancedMapTiles.EndLevelBox; -import Level.*; +import Level.Enemy; +import Level.EnhancedMapTile; +import Level.Map; +import Level.NPC; import Tilesets.CommonTileset; import Utils.Direction; import Utils.Point; diff --git a/src/Maps/TestMap3.java b/src/Maps/TestMap3.java index d7cd747..d8d3b41 100644 --- a/src/Maps/TestMap3.java +++ b/src/Maps/TestMap3.java @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(17, 10), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Maps/TestMap4.java b/src/Maps/TestMap4.java index 7c0720c..dea654e 100644 --- a/src/Maps/TestMap4.java +++ b/src/Maps/TestMap4.java @@ -39,7 +39,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Maps/TestMap5.java b/src/Maps/TestMap5.java index 02903cf..c73fa3e 100644 --- a/src/Maps/TestMap5.java +++ b/src/Maps/TestMap5.java @@ -38,7 +38,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Maps/TestMap6.java b/src/Maps/TestMap6.java index 03dd6e4..d60eab2 100644 --- a/src/Maps/TestMap6.java +++ b/src/Maps/TestMap6.java @@ -45,7 +45,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(11, 8), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); @@ -55,7 +55,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(14, 5), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.LEFT )); @@ -65,7 +65,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(38, 5), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.LEFT )); diff --git a/src/Maps/TestMap7.java b/src/Maps/TestMap7.java index 3b753d8..2ae03a2 100644 --- a/src/Maps/TestMap7.java +++ b/src/Maps/TestMap7.java @@ -50,7 +50,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(7, 9), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); @@ -60,7 +60,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(26, 9), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Maps/TestTutorial.java b/src/Maps/TestTutorial.java index 9ecf6e5..d807055 100644 --- a/src/Maps/TestTutorial.java +++ b/src/Maps/TestTutorial.java @@ -20,7 +20,7 @@ public class TestTutorial extends Map { public TestTutorial() { - super("test_tutorial.txt", new CommonTileset(), new Point(1, 8)); + super("test_tutorial.txt", new CommonTileset(), new Point(1, 11)); } @Override @@ -41,7 +41,7 @@ public ArrayList loadEnhancedMapTiles() { getPositionByTileIndex(27, 6), TileType.JUMP_THROUGH_PLATFORM, 3, - new Rectangle(0, 6, 16, 4), + new Rectangle(0, 6,16,4), Direction.RIGHT )); diff --git a/src/Projectiles/Bone.java b/src/Projectiles/Bone.java index 73486d7..ab9fe55 100644 --- a/src/Projectiles/Bone.java +++ b/src/Projectiles/Bone.java @@ -6,10 +6,14 @@ import GameObject.Frame; import GameObject.ImageEffect; import GameObject.SpriteSheet; -import Level.*; +import Level.Enemy; +import Level.MapEntityStatus; +import Level.Player; +import Level.Projectile; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; + import java.util.HashMap; // This class is for the bone enemy that the dog class shoots out @@ -27,7 +31,7 @@ public Bone(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this will not respawn after it has been removed - respawnEnabled = false; + isRespawnable = false; initialize(); collisionType = CollisionType.PREVENT_JUMP; diff --git a/src/Projectiles/Fireball.java b/src/Projectiles/Fireball.java index bf6ec3b..c73ae76 100644 --- a/src/Projectiles/Fireball.java +++ b/src/Projectiles/Fireball.java @@ -28,7 +28,7 @@ public Fireball(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this will not respawn after it has been removed - respawnEnabled = false; + isRespawnable = false; initialize(); } diff --git a/src/Projectiles/LazerBeam.java b/src/Projectiles/LazerBeam.java index 7cdd8e5..61c4eb1 100644 --- a/src/Projectiles/LazerBeam.java +++ b/src/Projectiles/LazerBeam.java @@ -4,10 +4,14 @@ import Engine.ImageLoader; import GameObject.Frame; import GameObject.SpriteSheet; -import Level.*; +import Level.Enemy; +import Level.MapEntityStatus; +import Level.Player; +import Level.Projectile; import Utils.Direction; import Utils.Point; import Utils.Stopwatch; + import java.util.HashMap; // This class is for the lazer beam enemy that the DinosaurEnemy class shoots out @@ -25,7 +29,7 @@ public LazerBeam(Point location, float movementSpeed, int existenceTime) { existenceTimer.setWaitTime(existenceTime); // this will not respawn after it has been removed - respawnEnabled = false; + isRespawnable = false; initialize(); } diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 1b9bc53..f9a9e9b 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -100,7 +100,7 @@ public void update() { screenState = State.RUNNING; } } - case PAUSE,LEVEL_LOSE_MESSAGE -> alternateScreen.update(); //TODO for some reason this breaks.. + case PAUSE,LEVEL_LOSE_MESSAGE -> alternateScreen.update(); case PLAYER_DEAD -> screenState = State.LEVEL_LOSE_MESSAGE; case LEVEL_COMPLETED -> { alternateScreen = new LevelClearedScreen(); diff --git a/src/Utils/Point.java b/src/Utils/Point.java index 5b60c0d..cc9b6a3 100644 --- a/src/Utils/Point.java +++ b/src/Utils/Point.java @@ -33,8 +33,4 @@ public Point subtractX(int x) { public Point subtractY(int y) { return new Point(this.x, this.y - y); } - - public String toString() { - return "Point: " + x + ", " + y; - } } From 9fa3832d3687a67fd345960a83eda46ca4f0e5d9 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 16:48:27 -0500 Subject: [PATCH 090/164] Clean-up --- src/Engine/GamePanel.java | 43 ++++---------------------- src/Game/Game.java | 2 -- src/Game/GameThread.java | 60 +++++++++++++++++++++++-------------- src/Game/RenderThread.java | 33 -------------------- src/Game/ThreadManager.java | 43 -------------------------- 5 files changed, 43 insertions(+), 138 deletions(-) delete mode 100644 src/Game/RenderThread.java delete mode 100644 src/Game/ThreadManager.java diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 4155314..67de08e 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -14,7 +14,7 @@ import java.io.File; import java.io.IOException; -/* +/** * This is where the game loop starts * The JPanel uses a timer to continually call cycles of update and draw */ @@ -29,10 +29,10 @@ public class GamePanel extends JPanel { private static ScreenCoordinator coordinator; public static Clip clip; private final JLabel health; - private GameThread gameThread; + private final GameThread gameThread; - /* + /** * The JPanel and various important class instances are setup here */ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { @@ -52,36 +52,7 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { screenManager = new ScreenManager(); coordinator = c1; - - gameThread = new GameThread(this::repaint, this::update); - -// timer = new Timer(1000 / Config.FPS, new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// update(); -// changeHealth(); -// if(coordinator.getGameState() == GameState.LEVEL) { -// health.show(); -// } -// else { -// health.hide(); -// } -// repaint(); -// } -// }); -// timer.setRepeats(true); -// tickGame = new GameTick(new Runnable() { -// @Override -// public void run() { -// update(); -// } -// }); -// tickRender = new GameTick(new Runnable() { -// @Override -// public void run() { -// repaint(); -// } -// }); } public static ScreenCoordinator getScreenCoordinator() { @@ -143,7 +114,6 @@ public static void setVolumeHigh() { // this starts the timer (the game loop is started here public void startGame() { -// timer.start(); gameThread.start(); try { @@ -162,14 +132,12 @@ public ScreenManager getScreenManager() { } public void update() { - screenManager.update(); - changeHealth(); + screenManager.update(); + changeHealth(); } public void draw() { screenManager.draw(graphicsHandler); - - } // Checks the players health and accordingly changes to the image with the corresponding number of hearts @@ -210,7 +178,6 @@ protected void paintComponent(Graphics g) { } public static void mouseClicked(MouseEvent e) { -// System.out.println("Click: " + e.getPoint()); coordinator.mouseClicked(e); } diff --git a/src/Game/Game.java b/src/Game/Game.java index 517249d..a344919 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -17,8 +17,6 @@ public static void main(String[] args) { public Game() { ScreenCoordinator c1 = new ScreenCoordinator(); GameWindow gameWindow = new GameWindow(c1); - - new RenderThread(null); gameWindow.startGame(); ScreenManager screenManager = gameWindow.getScreenManager(); screenManager.setCurrentScreen(c1); diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 5346493..733c178 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -1,61 +1,77 @@ package Game; +/** + * Runs the base loops of the game, including updates and renders. Multiple updates may happen between frames if it takes too long, meaning the + * game will catch up once it gets too far ahead. + * @author Thomas Kwashnak + */ public class GameThread implements Runnable { - private static double delta_time; - - private static final long UPDATE_FIXED_MS; - - public static final float UPDATE_FACTOR; - - static { - UPDATE_FIXED_MS = 12; - UPDATE_FACTOR = UPDATE_FIXED_MS / 15.0f; - } + /** + * Static number of ms between updates + */ + private static final long UPDATE_FIXED_MS = 12; + /** + * Main thread to run the game on + */ private final Thread thread; + /** + * Methods to run for rendering and updating + */ private final Runnable render, update; + /** + * Provides a means of ending the loop manually + */ private boolean running = true; + /** + * Creates a new game thread + * @param render Runnable called when a render is needed + * @param update Runnable called when an update is needed + */ public GameThread(Runnable render, Runnable update) { thread = new Thread(this); this.render = render; this.update = update; } + /** + * Starts the thread + */ public void start() { thread.start(); } + /** + * Stops the thread + */ public void stop() { running = false; } @Override public void run() { - // lastTime = System.currentTimeMillis(); + //Sets the next update to the current time long nextUpdateTime = System.currentTimeMillis(); long currentTime; + + //Loop until running is false while(running) { + //Update current time currentTime = System.currentTimeMillis(); + + //Repeat until the update time is after (in the future) current time while(currentTime > nextUpdateTime) { update.run(); nextUpdateTime += UPDATE_FIXED_MS; } - render.run(); - // delta_time = ((double) timePassed) / 1000; - // while(timePassed >= UPDATE_FIXED_MS) { - // timePassed -= UPDATE_FIXED_MS; - // update.run(); - // } - // - // render.run(); - // currentTime = System.currentTimeMillis(); - // timePassed += currentTime - lastTime; - // lastTime = currentTime; + //Run a render + render.run(); } + //Reset running once it's set to false running = true; } } diff --git a/src/Game/RenderThread.java b/src/Game/RenderThread.java deleted file mode 100644 index bdce73f..0000000 --- a/src/Game/RenderThread.java +++ /dev/null @@ -1,33 +0,0 @@ -package Game; - -import java.awt.*; - -/** - * Responsible for the looping of the class and containing values such as time since last tick, etc. - * @author Thomas Kwashnak - */ -public class RenderThread extends ThreadManager { - - /** - * May not need refresh rate and only refresh time ms - */ - private static final long REFRESH_TIME_MS; - - static { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - // Sets the highest refresh rate to be the highest display rate - int highestRefreshRate = 0; - for(GraphicsDevice device : ge.getScreenDevices()) { - int refreshRate = device.getDisplayMode().getRefreshRate(); - System.out.println(refreshRate); - if(refreshRate > highestRefreshRate) { - highestRefreshRate = refreshRate; - } - } - REFRESH_TIME_MS = 1000 / highestRefreshRate; - } - - public RenderThread(Runnable runnable) { - super(runnable, REFRESH_TIME_MS); - } -} diff --git a/src/Game/ThreadManager.java b/src/Game/ThreadManager.java deleted file mode 100644 index 4f6af6a..0000000 --- a/src/Game/ThreadManager.java +++ /dev/null @@ -1,43 +0,0 @@ -package Game; - -/** - * @author Thomas Kwashnak - */ -public class ThreadManager implements Runnable { - - private Thread thread; - protected long lastTick, elapsedTick; - private final long tickDelay; - private boolean running = true; - private Runnable runnable; - - public ThreadManager(Runnable runnable, long tickDelay) { - thread = new Thread(this); - this.tickDelay = tickDelay; - this.runnable = runnable; - } - - public void start() { - thread.start(); - } - - public void stop() { - running = false; - } - - @Override - public void run() { - lastTick = System.currentTimeMillis(); - while(running) { - if(elapsedTick > tickDelay) { - runnable.run(); - elapsedTick = 0; - } - - long currentTick = System.currentTimeMillis(); - elapsedTick += currentTick - lastTick; - lastTick = currentTick; - } - running = true; - } -} From 9980858d3dacb6d4d6a78a2c88b6bc86fef5da7e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 16:49:03 -0500 Subject: [PATCH 091/164] Additional Cleanup --- src/Engine/GamePanel.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 67de08e..82cc411 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -20,9 +20,6 @@ */ public class GamePanel extends JPanel { private final ScreenManager screenManager; - // used to create the game loop and cycle between update and draw calls - private Timer timer; - // used to draw graphics to the panel private final GraphicsHandler graphicsHandler; private boolean doPaint = false; protected static GameWindow gameWindow; From 6309e476e308a3698550b57ad1408173cff5cf28 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 23 Nov 2021 17:01:33 -0500 Subject: [PATCH 092/164] Drafting up features for Test Case SCP-52 --- Team A2/Test Cases/Test Case SCP-52.md | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-52.md diff --git a/Team A2/Test Cases/Test Case SCP-52.md b/Team A2/Test Cases/Test Case SCP-52.md new file mode 100644 index 0000000..8f4bfd7 --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-52.md @@ -0,0 +1,28 @@ +### Test Case Information +| TEST CASE ID | SCP-52 | +| :--- | :--- | +| Owner of Test | Thomas Kwashnak | +| Test Name | Test Speed-Running Enhancements | +| Date of Last Revision | 11/23/2021 | +| Test Objective | Testing Additions and Functionality Changes of Speed-Running Enhancements | + +#### Tested Enhancements + - Stopwatch + - Top-Right of screen when playing + - Entering from main menu resets timer + - Stores time took to complete each level, displays current level's time, as well as total time for all previous times + - Some way to display the user's final result (breakdown of levels) after beating final boss + - Deaths are in some way detrimental to a user's level time (either make death animation slower, or make death screen longer) + - Pausing the game pauses the time + - Level Completed Screens display quicker (shorter time) + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens || + +### Test Completion +- **Tester**: [TESTER NAME] +- **Date of Test**: DATE OF TEST +- **Test Result**: TEST RESULT \ No newline at end of file From 76460b65d0d75b1df7ffa151ee3006027a90e7b2 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 24 Nov 2021 12:55:32 -0500 Subject: [PATCH 093/164] Drafted Test Case SCP-52 Procedure might change as development unfolds. --- Team A2/Test Cases/Test Case SCP-52.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-52.md b/Team A2/Test Cases/Test Case SCP-52.md index 8f4bfd7..2fc5bff 100644 --- a/Team A2/Test Cases/Test Case SCP-52.md +++ b/Team A2/Test Cases/Test Case SCP-52.md @@ -20,7 +20,14 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens || +|1|Run the game|The game loads up. There is no timer on the main menu.|| +|2|Click Play|The tutorial level is loaded. On the top right is one timer that times the amount of elapsed time since the player started.|| +|3|Navigate and die in the tutorial level|The dead screen has a count-down displayed.|| +|4|While the death screen's countdown is counting down, try to hit space to respawn|The player is not able to respawn until the countdown timer is over|| +|5|Navigate through the level and die once again. Once the death screen is loaded, hit escape to go back to the main menu|The main menu is loaded and the timer no longer displays|| +|6|Hit "Play" again to go back into the main menu|The tutorial level is loaded, and the timer is reset back to 0|| +|7|Complete the tutorial level|The level completed screen is shown, but only for a brief second before the next level is loaded. On the top right is now two timers, one that displays the total time, and another that displays the elapsed time for the current level|| +|8|Hit `P/Escape` to pause the game|While the game is paused, timers are also paused|| ### Test Completion - **Tester**: [TESTER NAME] From 16e6b3b699e3e78fb55ce0fb6e79d91e17eb4965 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 24 Nov 2021 14:37:41 -0500 Subject: [PATCH 094/164] Added Timer to top right of screen --- src/Engine/GamePanel.java | 2 +- src/Engine/Screen.java | 4 +- src/Engine/Updatable.java | 5 ++ src/Game/TimeTracker.java | 96 ++++++++++++++++++++++++++++++++ src/Maps/GameMaps.java | 16 ++++++ src/Menu/MenuOption.java | 3 +- src/Screens/PauseScreen.java | 2 +- src/Screens/PlayLevelScreen.java | 34 +++++++---- src/SpriteFont/SpriteFont.java | 22 ++++++-- src/SpriteFont/TimerElement.java | 37 ++++++++++++ src/Utils/GameTimer.java | 40 +++++++++++++ src/Utils/TimeParser.java | 55 ++++++++++++++++++ 12 files changed, 295 insertions(+), 21 deletions(-) create mode 100644 src/Engine/Updatable.java create mode 100644 src/Game/TimeTracker.java create mode 100644 src/Maps/GameMaps.java create mode 100644 src/SpriteFont/TimerElement.java create mode 100644 src/Utils/GameTimer.java create mode 100644 src/Utils/TimeParser.java diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 82cc411..bd3fa78 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -18,7 +18,7 @@ * This is where the game loop starts * The JPanel uses a timer to continually call cycles of update and draw */ -public class GamePanel extends JPanel { +public class GamePanel extends JPanel implements Updatable { private final ScreenManager screenManager; private final GraphicsHandler graphicsHandler; private boolean doPaint = false; diff --git a/src/Engine/Screen.java b/src/Engine/Screen.java index e29bc74..82bfad1 100644 --- a/src/Engine/Screen.java +++ b/src/Engine/Screen.java @@ -1,13 +1,13 @@ package Engine; -import java.awt.Graphics; import Level.Map; + import java.awt.event.MouseEvent; // Base Screen class // This game engine runs off the idea of "screens", which are classes that contain their own update/draw methods for a particular piece of the game // For example, there may be a "MenuScreen" or a "PlayGameScreen" -public abstract class Screen { +public abstract class Screen implements Updatable { public abstract void initialize(); public abstract void update(); public abstract void draw(GraphicsHandler graphicsHandler); diff --git a/src/Engine/Updatable.java b/src/Engine/Updatable.java new file mode 100644 index 0000000..8d186ea --- /dev/null +++ b/src/Engine/Updatable.java @@ -0,0 +1,5 @@ +package Engine; + +public interface Updatable { + void update(); +} diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java new file mode 100644 index 0000000..9a24641 --- /dev/null +++ b/src/Game/TimeTracker.java @@ -0,0 +1,96 @@ +package Game; + +import Engine.Drawable; +import Engine.GraphicsHandler; +import Engine.ScreenManager; +import Maps.GameMaps; +import Utils.GameTimer; +import Utils.TimeParser; + +import java.awt.*; + +public class TimeTracker implements Drawable { + + private static final Font FONT_BIG, FONT_SMALL; + + static { + String fontName = "Times New Roman"; + FONT_BIG = new Font(fontName,Font.PLAIN, 40); + FONT_SMALL = new Font(fontName,Font.PLAIN,30); + } + + + private int currentLevel; + + private GameTimer[] levels; + private GameTimer total; + + /** + * Whether the level-specific time should be listed + */ + private boolean showLevel; + + public TimeTracker() { + total = new GameTimer(); + levels = new GameTimer[GameMaps.MAPS.length]; + + for(int i = 0; i < levels.length; i++) { + levels[i] = new GameTimer(); + } + + currentLevel = -1; + showLevel = false; + } + + public void setCurrentLevel(int currentLevel) { + if(this.currentLevel != currentLevel) { + if(this.currentLevel == -1) { + total.start(); + } else { + levels[this.currentLevel].stop(); + showLevel = true; + } + this.currentLevel = currentLevel; + levels[currentLevel].start(); + } + } + + /** + * Usable when dealing with pausing + */ + public void start() { + total.start(); + levels[currentLevel].start(); + } + + public void stop() { + total.stop(); + levels[currentLevel].stop(); + } + + public TimeParser getElapsedTime() { + TimeParser timeParser = new TimeParser(); + for(GameTimer gameTimer : levels) { + timeParser.addTime(gameTimer.getElapsed()); + } + return timeParser; + } + + @Override + public void draw(GraphicsHandler graphicsHandler) { + //Custom rendering in order to place it correctly + FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_BIG); + String totalString = total.toString(); + int yTotal = metrics.getHeight(); + int xTotal = ScreenManager.getScreenWidth() - metrics.stringWidth(totalString); + graphicsHandler.drawString(totalString, Math.round(xTotal), yTotal, FONT_BIG, Color.WHITE); + + if(showLevel) { + metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_SMALL); + String mapString = levels[currentLevel].toString(); + int yMap = yTotal + metrics.getHeight(); + int xMap = ScreenManager.getScreenWidth() - metrics.stringWidth(mapString); + graphicsHandler.drawString(mapString,xMap, yMap, FONT_SMALL,Color.white); + } + } +} diff --git a/src/Maps/GameMaps.java b/src/Maps/GameMaps.java new file mode 100644 index 0000000..4ace188 --- /dev/null +++ b/src/Maps/GameMaps.java @@ -0,0 +1,16 @@ +package Maps; + +import Level.Map; + +/** + * Contains a centralized list of all game maps. Includes the name of the map, the function to create the map. + */ +public class GameMaps { + public static MapFactory[] MAPS= new MapFactory[]{ + TestTutorial::new, TestMap::new, TestMap2::new, TestMap3::new, TestMap4::new, TestMap5::new, TestMap6::new, TestMap7::new, BossBattle::new + }; + + public interface MapFactory { + Map generateMap(); + } +} diff --git a/src/Menu/MenuOption.java b/src/Menu/MenuOption.java index 6766842..833b144 100644 --- a/src/Menu/MenuOption.java +++ b/src/Menu/MenuOption.java @@ -1,11 +1,12 @@ package Menu; +import Engine.Drawable; import Engine.GraphicsHandler; import java.awt.*; import java.awt.event.MouseEvent; -public class MenuOption { +public class MenuOption implements Drawable { private static final Font DEFAULT_MENU_FONT = new Font("Comic sans", Font.PLAIN, 30); private static final Color DEFAULT_COLOR = new Color(49, 207, 240); diff --git a/src/Screens/PauseScreen.java b/src/Screens/PauseScreen.java index 288b477..d35b405 100644 --- a/src/Screens/PauseScreen.java +++ b/src/Screens/PauseScreen.java @@ -32,7 +32,7 @@ public PauseScreen(Map map, Player player, PlayLevelScreen playLevelScreen) { }); setMenuItemsAsGrid(new MenuOption[][]{ { - new MenuOption("Return to Game", 100, 100, () -> this.playLevelScreen.resume()) + new MenuOption("Return to Game", 100, 100, this.playLevelScreen::resume) }, { new MenuOption("Back to Menu", 100, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) } diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index f9a9e9b..db98bba 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -2,10 +2,11 @@ import Engine.*; import Game.GameState; +import Game.TimeTracker; import Level.Map; import Level.Player; import Level.PlayerListener; -import Maps.*; +import Maps.GameMaps; import SpriteFont.SpriteFont; import Utils.Stopwatch; @@ -14,7 +15,6 @@ public class PlayLevelScreen extends Screen implements PlayerListener { - private static final MapFactory[] MAPS; private static final Stopwatch screenTimer; private static final KeyLocker keyLocker; private static final SpriteFont SPRITE_FONT_PAUSE; @@ -23,19 +23,12 @@ public class PlayLevelScreen extends Screen implements PlayerListener { private static Map loadedMap; private static Screen alternateScreen; private static Player player; + private static TimeTracker timeTracker; static { screenTimer = new Stopwatch(); keyLocker = new KeyLocker(); - /* - * List of maps in the game, each map is given a constructor - * This is some new java funky stuff :D - */ - MAPS = new MapFactory[]{ - TestTutorial::new, TestMap::new, TestMap2::new, TestMap3::new, TestMap4::new, TestMap5::new, TestMap6::new, TestMap7::new, BossBattle::new - }; - SPRITE_FONT_PAUSE = new SpriteFont("Pause", 350, 250, "Comic Sans", 30, Color.white); SPRITE_FONT_INSTRUCTIONS = new SpriteFont[] { @@ -79,6 +72,7 @@ public PlayLevelScreen(int initialMap) { @Override public void initialize() { + timeTracker = new TimeTracker(); loadMap(currentMap); } @@ -88,8 +82,10 @@ public void update() { case RUNNING -> { if (KeyboardAction.GAME_PAUSE.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_PAUSE)) { screenState = State.PAUSE; + timeTracker.stop(); } else if (KeyboardAction.GAME_INSTRUCTIONS.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_INSTRUCTIONS)) { screenState = State.INSTRUCTIONS; + timeTracker.stop(); } else { player.update(); loadedMap.update(player); @@ -157,6 +153,13 @@ public void draw(GraphicsHandler graphicsHandler) { graphicsHandler.drawFilledRectangle(0, 0, ScreenManager.getScreenWidth(), ScreenManager.getScreenHeight(), COLOR_GREY_BACKGROUND); } } + if(timeTracker != null) { + timeTracker.draw(graphicsHandler); + } + } + + public Map getLoadedMap() { + return loadedMap; } @Override @@ -176,10 +179,10 @@ public void nextLevel() { * @param index index of map to load */ private void loadMap(int index) { - if(index < MAPS.length) { + if(index < GameMaps.MAPS.length) { currentMap = index; //Load map using the MapFactory - loadedMap = MAPS[index].generateMap(); + loadedMap = GameMaps.MAPS[index].generateMap(); loadedMap.reset(); //Load the cat using the Config setting @@ -187,7 +190,11 @@ private void loadMap(int index) { player.setMap(loadedMap); player.addListener(this); screenState = State.RUNNING; + + //Update Time + timeTracker.setCurrentLevel(index); } else { + //Add the other menu GamePanel.getScreenCoordinator().setGameState(GameState.MENU); } } @@ -213,9 +220,12 @@ public void backToMenu() { public void resume() { if (screenState == State.PAUSE || screenState == State.INSTRUCTIONS) { screenState = State.RUNNING; + timeTracker.start(); } } + + public enum State { RUNNING, LEVEL_COMPLETED, PLAYER_DEAD, LEVEL_WIN_MESSAGE, LEVEL_LOSE_MESSAGE, LEVEL_SELECT, PAUSE, INSTRUCTIONS, OPTIONS } diff --git a/src/SpriteFont/SpriteFont.java b/src/SpriteFont/SpriteFont.java index 217e97b..e35fae4 100644 --- a/src/SpriteFont/SpriteFont.java +++ b/src/SpriteFont/SpriteFont.java @@ -4,7 +4,6 @@ import Engine.GraphicsHandler; import java.awt.*; -import java.awt.font.FontRenderContext; // This class represents a sprite font, which is graphic text (text drawn to the screen as if it were an image) public class SpriteFont implements Drawable { @@ -17,6 +16,15 @@ public class SpriteFont implements Drawable { protected Color outlineColor; protected float outlineThickness = 1f; + public SpriteFont(String text, float x, float y, Font font, Color color) { + this.text = text; + this.font = font; + this.x = x; + this.y = y; + this.color = color; + updateDimensions(); + } + public SpriteFont(String text, float x, float y, String fontName, int fontSize, Color color) { this.text = text; font = new Font(fontName, Font.PLAIN, fontSize); @@ -30,6 +38,10 @@ public void setColor(Color color) { this.color = color; } + public Color getColor() { + return color; + } + public String getText() { return text; } @@ -108,11 +120,13 @@ public void moveUp(float dy) { y -= dy; } + + public void draw(GraphicsHandler graphicsHandler) { if (outlineColor != null && !outlineColor.equals(color)) { - graphicsHandler.drawStringWithOutline(text, Math.round(x), Math.round(y), font, color, outlineColor, outlineThickness); + graphicsHandler.drawStringWithOutline(getText(), Math.round(x), Math.round(y), font, color, outlineColor, outlineThickness); } else { - graphicsHandler.drawString(text, Math.round(x), Math.round(y), font, color); + graphicsHandler.drawString(getText(), Math.round(x), Math.round(y), font, color); } } @@ -126,7 +140,7 @@ public void drawWithParsedNewLines(GraphicsHandler graphicsHandler) { if(width == -1) { FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(font); height = metrics.getHeight(); - width = metrics.stringWidth(text); + width = metrics.stringWidth(getText()); } diff --git a/src/SpriteFont/TimerElement.java b/src/SpriteFont/TimerElement.java new file mode 100644 index 0000000..b393169 --- /dev/null +++ b/src/SpriteFont/TimerElement.java @@ -0,0 +1,37 @@ +package SpriteFont; + +import Utils.TimeParser; + +import java.awt.*; + +public class TimerElement extends SpriteFont { + + private TimeParser timeParser; + + public TimerElement(String text, float x, float y, String fontName, int fontSize, Color color) { + super(text, x, y, fontName, fontSize, color); + } + + public TimerElement(TimeParser timeParser, float x, float y, String fontName, int fontSize, Color color) { + super(null,x,y,fontName,fontSize,color); + this.timeParser= timeParser; + } + + public TimerElement(TimeParser timeParser, float x, float y, Font font, Color color) { + super(null,x,y,font,color); + this.timeParser = timeParser; + } + + public TimeParser getGameTimer() { + return timeParser; + } + + public void setGameTimer(TimeParser timeParser) { + this.timeParser = timeParser; + } + + @Override + public String getText() { + return timeParser != null ? timeParser.toString() : "NO TIME SPECIFIED"; + } +} diff --git a/src/Utils/GameTimer.java b/src/Utils/GameTimer.java new file mode 100644 index 0000000..57e7bd0 --- /dev/null +++ b/src/Utils/GameTimer.java @@ -0,0 +1,40 @@ +package Utils; + +public class GameTimer extends TimeParser { + + private long startTime, endTime, addTime; + private boolean running; + + public GameTimer() { + startTime = 0; + endTime = 0; + addTime = 0; + running = false; + } + + public void start() { + addTime = getElapsed(); + if(!running) { + startTime = System.currentTimeMillis(); + running = true; + } + } + + public void stop() { + endTime = System.currentTimeMillis(); + running = false; + } + + public void reset() { + addTime = 0; + startTime = System.currentTimeMillis(); + } + + public long getElapsed() { + return (running ? System.currentTimeMillis() : endTime ) + addTime - startTime; + } + + public long getTime() { + return getElapsed(); + } +} diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java new file mode 100644 index 0000000..868355b --- /dev/null +++ b/src/Utils/TimeParser.java @@ -0,0 +1,55 @@ +package Utils; + +public class TimeParser { + private static long MS_PER_SECOND, SECOND_PER_MINUTE, MINUTE_PER_HOUR, MS_PER_HOUR, MS_PER_MINUTE; + + private long time; + + static { + MS_PER_SECOND = 1000; + SECOND_PER_MINUTE = 60; + MINUTE_PER_HOUR = 60; + MS_PER_MINUTE = MS_PER_SECOND * SECOND_PER_MINUTE; + MS_PER_HOUR = MS_PER_MINUTE * MINUTE_PER_HOUR; + } + + public TimeParser() { + this(0); + } + + public TimeParser(long time) { + this.time = time; + } + + public void setTime(long time) { + this.time = time; + } + + public long getTime() { + return time; + } + + public void addTime(long time) { + this.time += time; + } + + public void subtractTime(long time) { + this.time -= time; + } + + public String toString() { + long elapsed = getTime(); + long hours = elapsed / MS_PER_HOUR; + long minutes = (elapsed %= MS_PER_HOUR) / MS_PER_MINUTE; + long seconds = (elapsed %= MS_PER_MINUTE) / MS_PER_SECOND; + elapsed %= MS_PER_SECOND; + + if(hours > 0) { + return String.format("%s:%s:%s.%s",hours,minutes,seconds,elapsed/10); + } else if(minutes > 0) { + return String.format("%s:%s.%s",minutes,seconds,elapsed/10); + } else { + return String.format("%s.%s",seconds,elapsed/10); + } + } +} From 8d80799bc618a19a5ccfc829f965141283799f6b Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 24 Nov 2021 15:00:34 -0500 Subject: [PATCH 095/164] Formatted Timer to remove un-needed 0s at the front --- src/Game/TimeTracker.java | 38 ++++++++++++++++++++++++++++++-------- src/Utils/TimeParser.java | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 9a24641..1ea2829 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -25,6 +25,8 @@ public class TimeTracker implements Drawable { private GameTimer[] levels; private GameTimer total; + private int xMap, yMap, xTotal, yTotal, charsTotal, charsMap; + /** * Whether the level-specific time should be listed */ @@ -79,18 +81,38 @@ public TimeParser getElapsedTime() { @Override public void draw(GraphicsHandler graphicsHandler) { //Custom rendering in order to place it correctly - FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_BIG); +// FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_BIG); +// String totalString = total.toString(); +// int yTotal = metrics.getHeight(); +// int xTotal = ScreenManager.getScreenWidth() - metrics.stringWidth(totalString); +// graphicsHandler.drawString(totalString, Math.round(xTotal), yTotal, FONT_BIG, Color.WHITE); +// +// if(showLevel) { +// metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_SMALL); +// String mapString = levels[currentLevel].toString(); +// int yMap = yTotal + metrics.getHeight(); +// int xMap = ScreenManager.getScreenWidth() - metrics.stringWidth(mapString); +// graphicsHandler.drawString(mapString,xMap, yMap, FONT_SMALL,Color.white); +// } String totalString = total.toString(); - int yTotal = metrics.getHeight(); - int xTotal = ScreenManager.getScreenWidth() - metrics.stringWidth(totalString); - graphicsHandler.drawString(totalString, Math.round(xTotal), yTotal, FONT_BIG, Color.WHITE); + if(totalString.length() != charsTotal) { + FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_BIG); + yTotal = metrics.getHeight(); + xTotal = ScreenManager.getScreenWidth() - metrics.stringWidth(totalString.replace(' ','0')); + charsTotal = totalString.length(); + } + graphicsHandler.drawString(totalString, xTotal, yTotal, FONT_BIG, Color.white); if(showLevel) { - metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_SMALL); String mapString = levels[currentLevel].toString(); - int yMap = yTotal + metrics.getHeight(); - int xMap = ScreenManager.getScreenWidth() - metrics.stringWidth(mapString); - graphicsHandler.drawString(mapString,xMap, yMap, FONT_SMALL,Color.white); + if(mapString.length() != charsMap) { + FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_SMALL); + yMap = metrics.getHeight() + yTotal; + xMap = ScreenManager.getScreenWidth() - metrics.stringWidth(mapString.replace(' ','0')); + charsMap = totalString.length(); + } + graphicsHandler.drawString(mapString,xMap,yMap,FONT_SMALL,Color.white); } + } } diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java index 868355b..36655fb 100644 --- a/src/Utils/TimeParser.java +++ b/src/Utils/TimeParser.java @@ -44,12 +44,37 @@ public String toString() { long seconds = (elapsed %= MS_PER_MINUTE) / MS_PER_SECOND; elapsed %= MS_PER_SECOND; - if(hours > 0) { - return String.format("%s:%s:%s.%s",hours,minutes,seconds,elapsed/10); - } else if(minutes > 0) { - return String.format("%s:%s.%s",minutes,seconds,elapsed/10); - } else { - return String.format("%s.%s",seconds,elapsed/10); + char[] chs = new char[hours > 0 ? 11 : minutes > 0 ? 8 : 5]; + + //milliseconds + chs[chs.length - 3] = '.'; + chs[chs.length - 2] = (char) ('0' + (elapsed / 100)); + chs[chs.length - 1] = (char) ('0' + (elapsed / 10) % 10); + //seconds + chs[chs.length - 5] = (char) ('0' + (seconds / 10)); + if(minutes == 0 && hours == 0 && chs[chs.length - 5] == '0') { + chs[chs.length - 5] = ' '; } + chs[chs.length - 4] = (char) ('0' + (seconds % 10)); + + if(minutes > 0 || hours > 0) { + chs[chs.length - 6] = ':'; + chs[chs.length - 7] = (char) ('0' + (minutes % 10)); + chs[chs.length - 8] = (char) ('0' + (minutes / 10)); + if(chs[chs.length - 8] == '0' && hours == 0) { + chs[chs.length - 8] = ' '; + } + + if(hours > 0) { + chs[0] = (char) ('0' + (hours / 10) % 10); + if(chs[0] == '0') { + chs[0] = ' '; + } + chs[1] = (char) ('0' + hours % 10); + chs[2] = ':'; + } + } + + return new String(chs); } } From 7b55a4f1aabd05ba061a530f195a8adb801639cd Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 24 Nov 2021 15:10:08 -0500 Subject: [PATCH 096/164] Reduced Next-Level wait time --- src/Game/TimeTracker.java | 14 -------------- src/Screens/PlayLevelScreen.java | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 1ea2829..ec69ba1 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -80,20 +80,6 @@ public TimeParser getElapsedTime() { @Override public void draw(GraphicsHandler graphicsHandler) { - //Custom rendering in order to place it correctly -// FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_BIG); -// String totalString = total.toString(); -// int yTotal = metrics.getHeight(); -// int xTotal = ScreenManager.getScreenWidth() - metrics.stringWidth(totalString); -// graphicsHandler.drawString(totalString, Math.round(xTotal), yTotal, FONT_BIG, Color.WHITE); -// -// if(showLevel) { -// metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_SMALL); -// String mapString = levels[currentLevel].toString(); -// int yMap = yTotal + metrics.getHeight(); -// int xMap = ScreenManager.getScreenWidth() - metrics.stringWidth(mapString); -// graphicsHandler.drawString(mapString,xMap, yMap, FONT_SMALL,Color.white); -// } String totalString = total.toString(); if(totalString.length() != charsTotal) { FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_BIG); diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index db98bba..11bf56a 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -101,7 +101,7 @@ public void update() { case LEVEL_COMPLETED -> { alternateScreen = new LevelClearedScreen(); alternateScreen.initialize(); - screenTimer.setWaitTime(2500); + screenTimer.setWaitTime(750); screenState = State.LEVEL_WIN_MESSAGE; } case LEVEL_WIN_MESSAGE -> { From 20bbbe23b772558b349eb5479294af9c967554b6 Mon Sep 17 00:00:00 2001 From: Jacob Conrad Date: Fri, 26 Nov 2021 16:09:43 -0500 Subject: [PATCH 097/164] Fixed character preview in options menu to show the selected cat color --- src/Screens/OptionsScreen.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Screens/OptionsScreen.java b/src/Screens/OptionsScreen.java index 0c4ffc1..f52a380 100644 --- a/src/Screens/OptionsScreen.java +++ b/src/Screens/OptionsScreen.java @@ -22,7 +22,7 @@ public class OptionsScreen extends Menu { private MenuOption[][] items; private BufferedImage cat; - public static int catColor; + public int catColor = 0; public OptionsScreen() { setBackground(new LevelSelectMap()); @@ -61,17 +61,17 @@ public OptionsScreen() { public void draw(GraphicsHandler handler) { super.draw(handler); - if(items[1][1].isSelected()) { + if(Config.playerAvatar == Avatar.CAT_ORANGE) { SpriteSheet orange = new SpriteSheet(ImageLoader.load("Cat.png"), 24, 24); cat = orange.getSprite(0, 0); handler.drawImage(cat, 210, 225, 100, 100); } - else if(items[1][2].isSelected()) { + else if(Config.playerAvatar == Avatar.CAT_BLUE) { SpriteSheet blue = new SpriteSheet(ImageLoader.load("CatBlue.png"), 24, 24); cat = blue.getSprite(0, 0); handler.drawImage(cat, 210, 225, 100, 100); } - else if(items[1][3].isSelected()) { + else if(Config.playerAvatar == Avatar.CAT_GREEN) { SpriteSheet green = new SpriteSheet(ImageLoader.load("CatGreen.png"), 24, 24); cat = green.getSprite(0, 0); handler.drawImage(cat, 210, 225, 100, 100); From 84f2244adfd6e482a1ce83a78dd23f487bbd3c03 Mon Sep 17 00:00:00 2001 From: Jacob Conrad Date: Fri, 26 Nov 2021 16:56:34 -0500 Subject: [PATCH 098/164] Fixed boss hitbox --- src/Enemies/Dog.java | 18 +++++++++--------- src/Maps/BossBattle.java | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index ab43a19..62db627 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -100,7 +100,7 @@ public void update(Player player) { // then the bone is actually shot out } else if (dogState == dogState.SHOOT) { if (previousdogState == dogState.WALK) { - shootTimer.setWaitTime(1000); + shootTimer.setWaitTime(500); currentAnimationName = facingDirection == Direction.RIGHT ? "SHOOT_RIGHT" : "SHOOT_LEFT"; } else if (shootTimer.isTimeUp()) { @@ -153,44 +153,44 @@ public HashMap getAnimations(SpriteSheet spriteSheet) { put("WALK_LEFT", new Frame[]{ new FrameBuilder(spriteSheet.getSprite(0, 0), 200) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(-5, 0, 35, 13) .build(), new FrameBuilder(spriteSheet.getSprite(0, 1), 200) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(-5, 0, 35, 13) .build(), new FrameBuilder(spriteSheet.getSprite(0, 2), 200) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(-5, 0, 35, 13) .build() }); put("WALK_RIGHT", new Frame[]{ new FrameBuilder(spriteSheet.getSprite(1, 0), 200) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(0, 0, 35, 13) .build(), new FrameBuilder(spriteSheet.getSprite(1, 1), 200) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(0, 0, 35, 13) .build(), new FrameBuilder(spriteSheet.getSprite(1, 2), 200) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(0, 0, 35, 13) .build() }); put("SHOOT_LEFT", new Frame[]{ new FrameBuilder(spriteSheet.getSprite(0, 2), 0) .withScale(2) - .withBounds(30, 0, 30, 13) + .withBounds(-5, 0, 35, 13) .build(), }); put("SHOOT_RIGHT", new Frame[]{ new FrameBuilder(spriteSheet.getSprite(1, 2), 0) .withScale(2) - .withBounds(0, 0, 30, 13) + .withBounds(0, 0, 35, 13) .build(), }); }}; diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index 1997d4c..00207c5 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -19,7 +19,7 @@ public class BossBattle extends Map { public BossBattle() { - super("BossBattle.txt", new CommonTileset(), new Point(1, 17)); + super("BossBattle.txt", new CommonTileset(), new Point(10, 1)); } @Override From 2d11f2a8091fa19ac46b9497362746bd42096204 Mon Sep 17 00:00:00 2001 From: Jacob Conrad Date: Fri, 26 Nov 2021 16:57:11 -0500 Subject: [PATCH 099/164] Reset spawn location for boss battle --- src/Maps/BossBattle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index 00207c5..1997d4c 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -19,7 +19,7 @@ public class BossBattle extends Map { public BossBattle() { - super("BossBattle.txt", new CommonTileset(), new Point(10, 1)); + super("BossBattle.txt", new CommonTileset(), new Point(1, 17)); } @Override From b566230bad1ac63aafa10f613cf919fef1d60b26 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sat, 27 Nov 2021 15:23:08 -0500 Subject: [PATCH 100/164] Added name field for each map --- src/Level/Map.java | 14 +++++++++++++- src/Maps/TestMap.java | 2 +- src/Maps/TestMap2.java | 2 +- src/Maps/TestMap3.java | 2 +- src/Maps/TestMap4.java | 2 +- src/Maps/TestMap5.java | 2 +- src/Maps/TestMap6.java | 2 +- src/Maps/TestMap7.java | 2 +- src/Maps/TestTutorial.java | 2 +- src/Maps/TitleScreenMap.java | 2 +- src/SpriteFont/TimerElement.java | 1 + 11 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/Level/Map.java b/src/Level/Map.java index 6b8c670..3365f8b 100644 --- a/src/Level/Map.java +++ b/src/Level/Map.java @@ -24,6 +24,9 @@ */ public abstract class Map implements Drawable { + + protected String name; + // the tile map (map tiles that make up the entire map image) protected MapTile[] mapTiles; @@ -64,7 +67,8 @@ public abstract class Map implements Drawable { // if set to false, camera will not move as player moves protected boolean adjustCamera = true; - public Map(String mapFileName, Tileset tileset, Point playerStartTile) { + public Map(String name, String mapFileName, Tileset tileset, Point playerStartTile) { + this.name = name; this.mapFileName = mapFileName; this.tileset = tileset; setupMap(); @@ -410,4 +414,12 @@ public void draw(GraphicsHandler graphicsHandler) { public int getRightBound() { return rightBound; } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } } diff --git a/src/Maps/TestMap.java b/src/Maps/TestMap.java index 831cd12..5835c65 100644 --- a/src/Maps/TestMap.java +++ b/src/Maps/TestMap.java @@ -17,7 +17,7 @@ // Represents a test map to be used in a level public class TestMap extends Map { public TestMap() { - super("test_map.txt", new CommonTileset(), new Point(1, 11)); + super("Level 1","test_map.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TestMap2.java b/src/Maps/TestMap2.java index e17506f..eaa6f66 100644 --- a/src/Maps/TestMap2.java +++ b/src/Maps/TestMap2.java @@ -17,7 +17,7 @@ public class TestMap2 extends Map { public TestMap2() { - super("test_map_2.txt", new CommonTileset(), new Point(1, 11)); + super("Level 2","test_map_2.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TestMap3.java b/src/Maps/TestMap3.java index d8d3b41..7e4130e 100644 --- a/src/Maps/TestMap3.java +++ b/src/Maps/TestMap3.java @@ -17,7 +17,7 @@ public class TestMap3 extends Map { public TestMap3() { - super("test_map3.txt", new CommonTileset(), new Point(1, 11)); + super("Level 3","test_map3.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TestMap4.java b/src/Maps/TestMap4.java index dea654e..4f0622d 100644 --- a/src/Maps/TestMap4.java +++ b/src/Maps/TestMap4.java @@ -17,7 +17,7 @@ public class TestMap4 extends Map { public TestMap4() { - super("test_map4.txt", new CommonTileset(), new Point(1, 11)); + super("Level 4","test_map4.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TestMap5.java b/src/Maps/TestMap5.java index c73fa3e..fee6dae 100644 --- a/src/Maps/TestMap5.java +++ b/src/Maps/TestMap5.java @@ -17,7 +17,7 @@ public class TestMap5 extends Map { public TestMap5() { - super("test_map5.txt", new CommonTileset(), new Point(1, 11)); + super("Level 5","test_map5.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TestMap6.java b/src/Maps/TestMap6.java index d60eab2..ff04e47 100644 --- a/src/Maps/TestMap6.java +++ b/src/Maps/TestMap6.java @@ -21,7 +21,7 @@ public class TestMap6 extends Map { public TestMap6() { - super("test_map6.txt", new CommonTileset(), new Point(1, 15)); + super("Level 6","test_map6.txt", new CommonTileset(), new Point(1, 15)); } @Override diff --git a/src/Maps/TestMap7.java b/src/Maps/TestMap7.java index 2ae03a2..f6cbda5 100644 --- a/src/Maps/TestMap7.java +++ b/src/Maps/TestMap7.java @@ -21,7 +21,7 @@ public class TestMap7 extends Map { public TestMap7() { - super("test_map7.txt", new CommonTileset(), new Point(1, 11)); + super("Level 7","test_map7.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TestTutorial.java b/src/Maps/TestTutorial.java index d807055..f1d2c4c 100644 --- a/src/Maps/TestTutorial.java +++ b/src/Maps/TestTutorial.java @@ -20,7 +20,7 @@ public class TestTutorial extends Map { public TestTutorial() { - super("test_tutorial.txt", new CommonTileset(), new Point(1, 11)); + super("Tutorial","test_tutorial.txt", new CommonTileset(), new Point(1, 11)); } @Override diff --git a/src/Maps/TitleScreenMap.java b/src/Maps/TitleScreenMap.java index 23ac457..408b1db 100644 --- a/src/Maps/TitleScreenMap.java +++ b/src/Maps/TitleScreenMap.java @@ -8,7 +8,7 @@ public class TitleScreenMap extends Map { public TitleScreenMap() { - super("title_screen_map.txt", new CommonTileset(), new Point(1, 9)); + super("","title_screen_map.txt", new CommonTileset(), new Point(1, 9)); } } diff --git a/src/SpriteFont/TimerElement.java b/src/SpriteFont/TimerElement.java index b393169..5f8d8d1 100644 --- a/src/SpriteFont/TimerElement.java +++ b/src/SpriteFont/TimerElement.java @@ -4,6 +4,7 @@ import java.awt.*; +@Deprecated public class TimerElement extends SpriteFont { private TimeParser timeParser; From 1776743ef6e77a8b090c6f527e80ba17782ecbc4 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Sat, 27 Nov 2021 16:11:45 -0500 Subject: [PATCH 101/164] Started work on GameScoreScreen.java --- src/Engine/Pausable.java | 6 ++++ src/Engine/Screen.java | 4 ++- src/Game/Game.java | 3 ++ src/Game/TimeTracker.java | 7 +++-- src/Level/Player.java | 5 ++++ src/Level/PlayerListener.java | 9 ++++++ src/Maps/BossBattle.java | 2 +- src/Maps/GameMaps.java | 50 ++++++++++++++++++++++++++++++-- src/Maps/LevelSelectMap.java | 2 +- src/Menu/Menu.java | 26 ++++++++++------- src/Menu/MenuOption.java | 10 +++---- src/Menu/SelectableMenu.java | 5 ++++ src/Screens/GameScoreScreen.java | 45 ++++++++++++++++++++++++++++ src/Screens/PauseScreen.java | 10 +++---- src/Screens/PlayLevelScreen.java | 44 ++++++++++++++++++---------- src/SpriteFont/SpriteFont.java | 13 +++------ src/Utils/GameTimer.java | 9 ++++-- src/Utils/TimeParser.java | 11 ++++++- 18 files changed, 203 insertions(+), 58 deletions(-) create mode 100644 src/Engine/Pausable.java create mode 100644 src/Menu/SelectableMenu.java create mode 100644 src/Screens/GameScoreScreen.java diff --git a/src/Engine/Pausable.java b/src/Engine/Pausable.java new file mode 100644 index 0000000..a09e8c3 --- /dev/null +++ b/src/Engine/Pausable.java @@ -0,0 +1,6 @@ +package Engine; + +public interface Pausable { + void resume(); + void pause(); +} diff --git a/src/Engine/Screen.java b/src/Engine/Screen.java index 82bfad1..9c721b2 100644 --- a/src/Engine/Screen.java +++ b/src/Engine/Screen.java @@ -7,9 +7,11 @@ // Base Screen class // This game engine runs off the idea of "screens", which are classes that contain their own update/draw methods for a particular piece of the game // For example, there may be a "MenuScreen" or a "PlayGameScreen" -public abstract class Screen implements Updatable { +public abstract class Screen implements Updatable, Drawable { public abstract void initialize(); + @Override public abstract void update(); + @Override public abstract void draw(GraphicsHandler graphicsHandler); public abstract void mouseClicked(MouseEvent e); private Map background; diff --git a/src/Game/Game.java b/src/Game/Game.java index a344919..81c6b32 100644 --- a/src/Game/Game.java +++ b/src/Game/Game.java @@ -2,6 +2,7 @@ import Engine.GameWindow; import Engine.ScreenManager; +import Maps.GameMaps; /* * The game starts here @@ -11,6 +12,8 @@ public class Game { public static void main(String[] args) { + //Loads all maps before anything else happens + new GameMaps(); new Game(); } diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index ec69ba1..7dac23a 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -46,9 +46,8 @@ public TimeTracker() { public void setCurrentLevel(int currentLevel) { if(this.currentLevel != currentLevel) { - if(this.currentLevel == -1) { - total.start(); - } else { + total.start(); + if(this.currentLevel > -1) { levels[this.currentLevel].stop(); showLevel = true; } @@ -101,4 +100,6 @@ public void draw(GraphicsHandler graphicsHandler) { } } + + } diff --git a/src/Level/Player.java b/src/Level/Player.java index fd277d0..ed6c435 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -119,6 +119,11 @@ private void updateDead() { private void updateWin() { if (map.getCamera().containsDraw(this)) { + + for(PlayerListener listener : playerListeners) { + listener.onLevelFinished(); + } + facing = Facing.RIGHT; if (inAir) { playerState = PlayerState.FALL; diff --git a/src/Level/PlayerListener.java b/src/Level/PlayerListener.java index fdeccd7..6f2ff55 100644 --- a/src/Level/PlayerListener.java +++ b/src/Level/PlayerListener.java @@ -2,6 +2,15 @@ // Other classes can use this interface to listen for events from the Player class public interface PlayerListener { + + /** + * Whenever the player leaves the level in its completed state + */ void onLevelCompleted(); void onDeath(); + + /** + * Whenever the player finishes the level by hitting the finish button + */ + void onLevelFinished(); } diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index 6db1b67..bfabd4a 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -20,7 +20,7 @@ public class BossBattle extends Map { private boolean bossKilled = false; public BossBattle() { - super("BossBattle.txt", new CommonTileset(), new Point(1, 17)); + super("Final Boss","BossBattle.txt", new CommonTileset(), new Point(1, 0)); } @Override diff --git a/src/Maps/GameMaps.java b/src/Maps/GameMaps.java index 4ace188..ff1893c 100644 --- a/src/Maps/GameMaps.java +++ b/src/Maps/GameMaps.java @@ -6,9 +6,53 @@ * Contains a centralized list of all game maps. Includes the name of the map, the function to create the map. */ public class GameMaps { - public static MapFactory[] MAPS= new MapFactory[]{ - TestTutorial::new, TestMap::new, TestMap2::new, TestMap3::new, TestMap4::new, TestMap5::new, TestMap6::new, TestMap7::new, BossBattle::new - }; + public static final MapManager[] MAPS; + + static { + /* + List of all maps registered in the game, in order + */ + MapFactory[] MAP_FACTORIES = new MapFactory[]{ + TestTutorial::new, + TestMap::new, + TestMap2::new, + TestMap3::new, + TestMap4::new, + TestMap5::new, + TestMap6::new, + TestMap7::new, + BossBattle::new + }; + + MAPS = new MapManager[MAP_FACTORIES.length]; + for(int i = 0; i < MAPS.length; i++) { + MAPS[i] = new MapManager(MAP_FACTORIES[i]); + } + } + + /** + * Sub-class that pulls out + */ + public static class MapManager implements MapFactory { + + private MapFactory mapFactory; + private String name; + + public MapManager(MapFactory mapFactory) { + this.mapFactory = mapFactory; + + Map map = mapFactory.generateMap(); + name = map.getName(); + } + + public String getName() { + return name; + } + + public Map generateMap() { + return mapFactory.generateMap(); + } + } public interface MapFactory { Map generateMap(); diff --git a/src/Maps/LevelSelectMap.java b/src/Maps/LevelSelectMap.java index a2196c2..408633f 100644 --- a/src/Maps/LevelSelectMap.java +++ b/src/Maps/LevelSelectMap.java @@ -8,7 +8,7 @@ public class LevelSelectMap extends Map { public LevelSelectMap() { - super("level_select_map.txt", new CommonTileset(), new Point(5, 9)); + super("","level_select_map.txt", new CommonTileset(), new Point(5, 9)); } } diff --git a/src/Menu/Menu.java b/src/Menu/Menu.java index a5ef189..bbeb31f 100644 --- a/src/Menu/Menu.java +++ b/src/Menu/Menu.java @@ -7,8 +7,9 @@ import java.awt.*; import java.awt.event.MouseEvent; +import java.util.List; -public abstract class Menu extends Screen { +public abstract class Menu extends Screen implements SelectableMenu { private final Stopwatch keyTimer = new Stopwatch(); private MenuOption[] menuOptions; @@ -174,23 +175,24 @@ protected void setMenuItemsAsGrid(MenuOption[][] grid) { } } - SelectFunction function = (newSelection) -> { - selectedItem.setSelected(false); - newSelection.setSelected(true); - selectedItem = newSelection; - }; - menuOptions = new MenuOption[count]; for (int i = 0; i < grid.length; i++) { for (int j = 0; j < grid[i].length; j++) { if (grid[i][j] != null) { menuOptions[menuOptions.length - (count--)] = grid[i][j]; - grid[i][j].setSelectFunction(function); + grid[i][j].setSelectFunction(this); } } } } + @Override + public void select(MenuOption menuOption) { + selectedItem.setSelected(false); + menuOption.setSelected(true); + selectedItem = menuOption; + } + protected void setBackground(Map background) { this.background = background; } @@ -199,8 +201,10 @@ protected void setDrawables(Drawable[] drawables) { this.drawables = drawables; } - public interface SelectFunction { - - void select(MenuOption item); + protected void setDrawables(List drawables) { + this.drawables = new Drawable[drawables.size()]; + for(int i = 0; i < this.drawables.length; i++) { + this.drawables[i] = drawables.get(i); + } } } diff --git a/src/Menu/MenuOption.java b/src/Menu/MenuOption.java index 833b144..5c28463 100644 --- a/src/Menu/MenuOption.java +++ b/src/Menu/MenuOption.java @@ -14,7 +14,7 @@ public class MenuOption implements Drawable { private static final Color OUTLINE_COLOR = new Color(0, 0, 0); private static final int OUTLINE_THICKNESS = 3; - private Menu.SelectFunction selectFunction; + private SelectableMenu selectableMenu; private final MenuOption[] neighbors; @@ -129,8 +129,8 @@ public void drawWithParsedNewLines(GraphicsHandler graphicsHandler) { public void mouseMoved(Point p) { softSelected = contains(p); - if (selected != softSelected && selectFunction != null) { - selectFunction.select(this); + if (selected != softSelected && selectableMenu != null) { + selectableMenu.select(this); } } @@ -150,7 +150,7 @@ public void execute() { } } - public void setSelectFunction(Menu.SelectFunction function) { - this.selectFunction = function; + public void setSelectFunction(SelectableMenu function) { + this.selectableMenu = function; } } diff --git a/src/Menu/SelectableMenu.java b/src/Menu/SelectableMenu.java new file mode 100644 index 0000000..f94ac0e --- /dev/null +++ b/src/Menu/SelectableMenu.java @@ -0,0 +1,5 @@ +package Menu; + +public interface SelectableMenu { + void select(MenuOption menuOption); +} diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java new file mode 100644 index 0000000..68f90b4 --- /dev/null +++ b/src/Screens/GameScoreScreen.java @@ -0,0 +1,45 @@ +package Screens; + +import Engine.Drawable; +import Engine.GraphicsHandler; +import Game.TimeTracker; +import Maps.TitleScreenMap; +import Menu.Menu; +import Utils.GameTimer; + +import java.awt.*; + +public class GameScoreScreen extends Menu { + + private static final Font FONT_LEVEL; + private static final Color COLOR_LEVEL; + + static { + String fontName = "Times New Roman"; + FONT_LEVEL = new Font(fontName, Font.PLAIN, 30); + COLOR_LEVEL = Color.WHITE; + } + + private TimeTracker timeTracker; + + public GameScoreScreen(TimeTracker timeTracker) { + this.timeTracker = timeTracker; + setBackground(new TitleScreenMap()); + } + + @Deprecated //Maybe? + public class LevelScores implements Drawable { + + private int x, y, height, width; + + + public LevelScores(GameTimer[] scores, int x, int y, int height, int width) { + + } + + @Override + public void draw(GraphicsHandler graphicsHandler) { + + } + } +} diff --git a/src/Screens/PauseScreen.java b/src/Screens/PauseScreen.java index d35b405..d3963ab 100644 --- a/src/Screens/PauseScreen.java +++ b/src/Screens/PauseScreen.java @@ -21,18 +21,18 @@ public class PauseScreen extends Menu { PAUSE_INSTRUCTIONS = new SpriteFont("SOMETHING SOMETHING ", 350, 250, "Comic Sans", 30, Color.white); } - private final PlayLevelScreen playLevelScreen; + private final Pausable parent; private boolean menuEscape; - public PauseScreen(Map map, Player player, PlayLevelScreen playLevelScreen) { - this.playLevelScreen = playLevelScreen; + public PauseScreen(Map map, Player player, Pausable parent) { + this.parent = parent; menuEscape = false; setDrawables(new Drawable[]{ player, map }); setMenuItemsAsGrid(new MenuOption[][]{ { - new MenuOption("Return to Game", 100, 100, this.playLevelScreen::resume) + new MenuOption("Return to Game", 100, 100, this.parent::resume) }, { new MenuOption("Back to Menu", 100, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) } @@ -45,7 +45,7 @@ public PauseScreen(Map map, Player player, PlayLevelScreen playLevelScreen) { public void update() { updateMenu(); if (menuEscape && KeyboardAction.GAME_PAUSE.isDown()) { - playLevelScreen.resume(); + parent.resume(); } if (!KeyboardAction.GAME_PAUSE.isDown()) { menuEscape = true; diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 11bf56a..33c3eb3 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -13,11 +13,10 @@ import java.awt.*; import java.awt.event.MouseEvent; -public class PlayLevelScreen extends Screen implements PlayerListener { +public class PlayLevelScreen extends Screen implements PlayerListener, Pausable { private static final Stopwatch screenTimer; private static final KeyLocker keyLocker; - private static final SpriteFont SPRITE_FONT_PAUSE; private static final SpriteFont[] SPRITE_FONT_INSTRUCTIONS; private static final Color COLOR_GREY_BACKGROUND; private static Map loadedMap; @@ -29,8 +28,6 @@ public class PlayLevelScreen extends Screen implements PlayerListener { screenTimer = new Stopwatch(); keyLocker = new KeyLocker(); - SPRITE_FONT_PAUSE = new SpriteFont("Pause", 350, 250, "Comic Sans", 30, Color.white); - SPRITE_FONT_INSTRUCTIONS = new SpriteFont[] { new SpriteFont("To JUMP: UP arrow key, or 'W', or SPACEBAR", 130, 140, "Times New Roman", 20, Color.white), @@ -81,8 +78,7 @@ public void update() { switch (screenState) { case RUNNING -> { if (KeyboardAction.GAME_PAUSE.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_PAUSE)) { - screenState = State.PAUSE; - timeTracker.stop(); + pause(); } else if (KeyboardAction.GAME_INSTRUCTIONS.isDown() && !keyLocker.isActionLocked(KeyboardAction.GAME_INSTRUCTIONS)) { screenState = State.INSTRUCTIONS; timeTracker.stop(); @@ -96,7 +92,11 @@ public void update() { screenState = State.RUNNING; } } - case PAUSE,LEVEL_LOSE_MESSAGE -> alternateScreen.update(); + case PAUSE,LEVEL_LOSE_MESSAGE,GAME_COMPLETED -> { + if(alternateScreen != null) { + alternateScreen.update(); + } + } case PLAYER_DEAD -> screenState = State.LEVEL_LOSE_MESSAGE; case LEVEL_COMPLETED -> { alternateScreen = new LevelClearedScreen(); @@ -107,8 +107,8 @@ public void update() { case LEVEL_WIN_MESSAGE -> { alternateScreen.update(); if (screenTimer.isTimeUp()) { - nextLevel(); screenState = State.RUNNING; + nextLevel(); } } } @@ -152,6 +152,13 @@ public void draw(GraphicsHandler graphicsHandler) { } graphicsHandler.drawFilledRectangle(0, 0, ScreenManager.getScreenWidth(), ScreenManager.getScreenHeight(), COLOR_GREY_BACKGROUND); } + case GAME_COMPLETED -> { + if(!(alternateScreen instanceof GameScoreScreen)) { + alternateScreen = new GameScoreScreen(timeTracker); + alternateScreen.initialize(); + } + alternateScreen.draw(graphicsHandler); + } } if(timeTracker != null) { timeTracker.draw(graphicsHandler); @@ -195,10 +202,16 @@ private void loadMap(int index) { timeTracker.setCurrentLevel(index); } else { //Add the other menu - GamePanel.getScreenCoordinator().setGameState(GameState.MENU); + System.out.println("complete game"); + screenState = State.GAME_COMPLETED; } } + @Override + public void onLevelFinished() { + timeTracker.stop(); + } + @Override public void onLevelCompleted() { screenState = State.LEVEL_COMPLETED; @@ -217,6 +230,7 @@ public void backToMenu() { GamePanel.getScreenCoordinator().setGameState(GameState.MENU); } + @Override public void resume() { if (screenState == State.PAUSE || screenState == State.INSTRUCTIONS) { screenState = State.RUNNING; @@ -224,14 +238,14 @@ public void resume() { } } - - - public enum State { - RUNNING, LEVEL_COMPLETED, PLAYER_DEAD, LEVEL_WIN_MESSAGE, LEVEL_LOSE_MESSAGE, LEVEL_SELECT, PAUSE, INSTRUCTIONS, OPTIONS + @Override + public void pause() { + screenState = State.PAUSE; + timeTracker.stop(); } - private interface MapFactory { - Map generateMap(); + public enum State { + RUNNING, LEVEL_COMPLETED, PLAYER_DEAD, LEVEL_WIN_MESSAGE, LEVEL_LOSE_MESSAGE, PAUSE, INSTRUCTIONS, GAME_COMPLETED } } diff --git a/src/SpriteFont/SpriteFont.java b/src/SpriteFont/SpriteFont.java index e35fae4..6816199 100644 --- a/src/SpriteFont/SpriteFont.java +++ b/src/SpriteFont/SpriteFont.java @@ -16,18 +16,13 @@ public class SpriteFont implements Drawable { protected Color outlineColor; protected float outlineThickness = 1f; - public SpriteFont(String text, float x, float y, Font font, Color color) { - this.text = text; - this.font = font; - this.x = x; - this.y = y; - this.color = color; - updateDimensions(); + public SpriteFont(String text, float x, float y, String fontName, int fontSize, Color color) { + this(text,x,y,new Font(fontName,Font.PLAIN,fontSize),color); } - public SpriteFont(String text, float x, float y, String fontName, int fontSize, Color color) { + public SpriteFont(String text, float x, float y, Font font, Color color) { this.text = text; - font = new Font(fontName, Font.PLAIN, fontSize); + this.font = font; this.x = x; this.y = y; this.color = color; diff --git a/src/Utils/GameTimer.java b/src/Utils/GameTimer.java index 57e7bd0..7ecd9d3 100644 --- a/src/Utils/GameTimer.java +++ b/src/Utils/GameTimer.java @@ -13,16 +13,18 @@ public GameTimer() { } public void start() { - addTime = getElapsed(); if(!running) { + addTime = getElapsed(); startTime = System.currentTimeMillis(); running = true; } } public void stop() { - endTime = System.currentTimeMillis(); - running = false; + if(running) { + endTime = System.currentTimeMillis(); + running = false; + } } public void reset() { @@ -34,6 +36,7 @@ public long getElapsed() { return (running ? System.currentTimeMillis() : endTime ) + addTime - startTime; } + @Override public long getTime() { return getElapsed(); } diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java index 36655fb..fd409f4 100644 --- a/src/Utils/TimeParser.java +++ b/src/Utils/TimeParser.java @@ -1,7 +1,7 @@ package Utils; public class TimeParser { - private static long MS_PER_SECOND, SECOND_PER_MINUTE, MINUTE_PER_HOUR, MS_PER_HOUR, MS_PER_MINUTE; + private static final long MS_PER_SECOND, SECOND_PER_MINUTE, MINUTE_PER_HOUR, MS_PER_HOUR, MS_PER_MINUTE; private long time; @@ -37,7 +37,16 @@ public void subtractTime(long time) { this.time -= time; } + /** + * Converts the time to a readable string + * @return + */ public String toString() { + /* + Implementation Note: + While yes, there is a more efficient method... I did it this way + Refrain from changing as the ' ' characters are important for rendering in the right spot + */ long elapsed = getTime(); long hours = elapsed / MS_PER_HOUR; long minutes = (elapsed %= MS_PER_HOUR) / MS_PER_MINUTE; From 514836a6539781edb77f7d5c1c5a8c2b7e570a0a Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Sun, 28 Nov 2021 02:01:45 -0500 Subject: [PATCH 102/164] Created the floating platform and added it to some levels --- MapFiles/test_map.txt | 2 +- MapFiles/test_map4.txt | 2 +- MapFiles/test_tutorial.txt | 2 +- Resources/CommonTileset.png | Bin 1920 -> 2049 bytes Team A2/Test Cases/Test Case SCP-62.md | 23 +++++++++++++++++++++++ src/Tilesets/CommonTileset.java | 12 ++++++++++++ 6 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 Team A2/Test Cases/Test Case SCP-62.md diff --git a/MapFiles/test_map.txt b/MapFiles/test_map.txt index 32d1335..8fdb213 100644 --- a/MapFiles/test_map.txt +++ b/MapFiles/test_map.txt @@ -5,7 +5,7 @@ 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 17 1 5 11 11 12 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 18 1 1 1 1 17 1 5 11 11 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 13 11 6 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/MapFiles/test_map4.txt b/MapFiles/test_map4.txt index afd1802..d5a69f9 100644 --- a/MapFiles/test_map4.txt +++ b/MapFiles/test_map4.txt @@ -8,7 +8,7 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 17 1 1 5 11 11 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 13 11 6 1 1 1 1 1 1 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 1 5 8 8 8 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 4 1 1 1 +1 1 1 1 1 1 18 1 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 10 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/MapFiles/test_tutorial.txt b/MapFiles/test_tutorial.txt index 80b8f73..abab15c 100644 --- a/MapFiles/test_tutorial.txt +++ b/MapFiles/test_tutorial.txt @@ -6,7 +6,7 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 17 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 18 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 diff --git a/Resources/CommonTileset.png b/Resources/CommonTileset.png index 04a727a2a3ffc80e30409545c91b6ea0d1574e0b..deb2ab79858b9aa97ca579d8fa6ffadbe5d306f6 100644 GIT binary patch delta 2048 zcmV+b2>Px+x=BPqRCr$PoIi*j zMHIkiwNSB<6sJLuLx`tM6f7)M5DSTrU?qZq99SfsjS5z|B$c3P>@J0H0R>CBK!Syc ze+mmhZS)MtAxL71AcClc`Q)v6cW>YK-n=)vvwP#0*(SF;vwv@A-f!NYd2^TM!H*8l z0=s^B{flt_J5TY);{8uATnOu1*Ia$IPA68D!seMHJI!BzvKbzKcK03{q-Rv#k&~NQ z#*t$#LuE7o#exuP9|KAXVT4to5Uu5eVp&5B*1|!tR;Fet@ci$~zh!Y7)O~5=i9x&N zplC{(8VVf;1%CuTpZYXpSsX*-0mR3lGTN9zCu_wQ4k)Mlk^;KdrAe0Z=-dB;DvD{En%l6(X z@l>wI+R=N)(S#7@&Qm=8y!IJS1I^Kc|3NvhFNDk2yC0ICVGnG3|GN+#`{9*ABmCy! z_XZd7tQG1RU@0wC|OL9G_vZ#!{U?zhSgEmH>Kc3)n zVo;zhMHUC!2TZm=Z&^wz6jYQaB3{WU zacXeM8tA1G3Jz$mpy2n1fXykx1E?1iYAvxcORVOFgNxO^raoL6^N`B}1N#&Wg}N>r zaOnqBqsJ6a_1GIzVk^a}5|`q7a*V@cG4+tkqos-aH0xW}2Aw?SFjrcd@N8JAj(_N3 z+tA;3&ovG#v%uKkuK_$4yn}OzLV-;aFZ}Tjil%(ea|?N4rzCqTkLh6T>!hg37F&DrE1~ayxaBG47 zV?)v08h4{Z=c2}xwg`9giYYnfzEWiL366AyQ7CY5L@)1gY~Mg{K|xEFtc3%FJ|YyV zObd)!b0SbZGN@0rtOVt8C_@jIsO!;On3WyIWO$R7IVcj4m{P?v2my#C<9}9wf;zCk zHnZP%e?t=7lm&&mB!q&`Q)Hl9(tW?v>33ZO16HSS}Rjrdf(7{gq-(J>>GNnu+^l zIpkWocy-XQx1PT*tgWqeWNdG5hvnsEx7^dGPlt{3=iB~&J#lF6y?;Bux@5Mk9y^w$ zs5u+>7mGzf@qmCnaB*M=1r!T#C>Q_&&*9SA;CY2Y*0N+N*vvu2pg{J80I2fON>C;O z<9&0*$HA5Ye;wR6m4r#aHHQ20`YnV8mV)z$fzg2EOj-s*xiOo~ZfhXk`wxi_#*Nu5 zz`Hr2XqI3>qEMhO2Y*9jiUh4VC^%t+BLPAX&;~H*J0(KlU?@~6?i2-O<>J*=!`~me zx3d^2APxfVAG!2v+aKaV4k)XutL|(|vL>_?o@L=Z4fHT>>c;S%E$Qe^K_vIN2Sl7nJ#@ue4?@zcazVk0; zpCZK+k0P*7Zub@Yc5KJLP$_Y#P^|q5Z(pd*Px+I7vi7RCr$Pn>~nK zMHGPNX`!X0SPgZ^4+GhIpBZ=cv}{`Rx&^!T&;_s}3cqw-F?wOwQ! zCFass#sr{v5UlngpyUunSW75GYbBw0)?mR}I4IuA)GP&_|9$0;B5s4aFKs*)wA&7f zrlhf<&~Z>e@PGf=&r^}b(KjAIeC#Wui79llUVPzzO1dv8phsPrWGRon`%n7*jXRqm z)BmM=cveE8C1g|s+yEcMpHi zyNKtl(8vI5k_NP#8eEq99_d`!Uuz&ZQ_kp%0l(yQkp>TjpC~bw7ur||u zNp5XyD5pPqx;5+bFMlaoV+mypA>-h{gVoD$PC23T0Uk!}ccH~fSZkjk8 zO`%b!k==MimNX6z3~wJ53XLZ;&WKPBucUNtIuGX7v-4NmtB)%q7pes%M^-Kr3D_Q# zoPP|gtEEJta3y^D&P$EOJoo0u`uEEvbhqmf)s?^6_tHks!FB;tEYN$Fk_!bD70Gxc*OL>RU4JMUnP7>uI(whO6M|@&r7INpyhstR=9D-$ zxD*ZaQV9hIbWl+6^ZS4;DI)@?6BKGKR++`BdEwx!+Sk~JOG6%VMPOi`s-aNVg#)hr zfNJoV5~&_XV~Vv>yee@muBXH}A{MheaFfE|ttJm#4{~ei+QygTk!^`VS37 zb8Fm<_MM9wQ<@^&t;??FLJmaK&Xggzn^s!R`z zT5}>$BQmH@^{fQtaVUKcm#FK}T$q;~S~8+Z%N!I5h^18V3_<|n$+#V$pnncLu#?%J z``?fRH|0U$E(xLF^BfuI7Wols)KWOep)JKzCQXSo01+AgYfBjuispK>l(;AqOj&tQ z(t>^In3A&#)&jkienOj;2xx)c+As0gBc;SvN-e>wGW)72CH7pYl$uK!l?R4eTy^^t zTzOv2Xy|=PpK)lVpm3naf`4S6-8gRA`pA$b;<*jJYc9EYwDuOv8BT3=sp$=Kc9O{=S`VYwR{8)@spg{J>sPaK-AECri6C<_W?UkHFIAFTvsA~4<;;$sz- z0>2LKno7bX;2OexMg0~+153eqSYR|Dm~d19<>qWQyJG_JK7L4qFmBFf3EnLUMY9AC z5`_YNIT#vKBxuz^!G8%O90?GDfHr_Z->DG_2ScGsai=OM(@WPH4gYxT-qvEIfH(-a zf8_G-O@D|7C7`UWt%b8K$(qnoc$S6tG|OK!y{ha>g5vq_A)!RGEj~t`5_5M&?{}9_0)(xUIPiMYW#Qdd zR1qa(isrr|V*%^h+S;1?iV@$Ra9MokUv*50C<6No9aHF7tR4SCrNp(x6f3}UKr{hZ zsLkV|L0O10OHEKB1xd}dE>uCXCMeNZCc#^z(*3{1e defineTiles() { .withTileType(TileType.LETHAL); mapTiles.add(lethalSpikeTile); + + // middle branch + Frame floatingPlatformFrame = new FrameBuilder(getSubImage(3, 4), 0) + .withScale(tileScale) + .withBounds(0, 6, 16, 4) + .build(); + + MapTileBuilder floatingPlatformTile = new MapTileBuilder(floatingPlatformFrame) + .withTileType(TileType.JUMP_THROUGH_PLATFORM); + + mapTiles.add(floatingPlatformTile); + return mapTiles; } } From ff4f506c4d1b6628933abc74036fcee4ed6576cb Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Sun, 28 Nov 2021 22:51:54 -0500 Subject: [PATCH 103/164] Created Test Case SCP-49 --- Team A2/Test Cases/Test Case SCP-49.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-49.md diff --git a/Team A2/Test Cases/Test Case SCP-49.md b/Team A2/Test Cases/Test Case SCP-49.md new file mode 100644 index 0000000..55aaa73 --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-49.md @@ -0,0 +1,26 @@ +### Test Case Information +| TEST CASE ID | SCP-49 | +| :--- | :--- | +| Owner of Test | Nicholas Tourony | +| Test Name | Difficulty Test | +| Date of Last Revision | 11/28/2021 | +| Test Objective | Ensure that the difficulty settings change the amount of health the cat has and changes the movement speed of the enemies. | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens |P| +|2| Select the difficulty menu. | The difficulty menu opens. | [RESULT] | +|3| Select normal difficulty | The game lets you select normal difficulty. | [RESULT] | +|4| Go back to the main menu and start the game. | The cat is loaded into the first level with 3 health and the enemies move at their slowest speed. | [RESULT] | +|5| Take projectile damage until the character dies | The cat can take 3 projectile hits before dying. | [RESULT] | +|6| Select hard difficulty and start the game | The cat is loaded into the first level with 2 health and the enemies move faster. | [RESULT] | +|7| Take projectile damage until the character dies | The cat can take 2 projectile hits before dying. | [RESULT] | +|8| Select hardcore difficulty and start the game. | The cat is loaded into the first level with 1 health and the enemies move even faster. | [RESULT] | +|9| Take damage. | The player is sent back to the main menu. | [RESULT] | + +### Test Completion +- **Tester**: [TESTER NAME] +- **Date of Test**: DATE OF TEST +- **Test Result**: TEST RESULT \ No newline at end of file From c998bb8e3522b1acbf6877bc3e890bb54a4f56e8 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Mon, 29 Nov 2021 00:36:17 -0500 Subject: [PATCH 104/164] Created the Difficulty Selection Menu --- src/Game/GameState.java | 2 +- src/Game/ScreenCoordinator.java | 1 + src/Screens/DifficultySelectScreen.java | 31 +++++++++++++++++++++++++ src/Screens/MenuScreen.java | 30 ++++++++++++++---------- 4 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/Screens/DifficultySelectScreen.java diff --git a/src/Game/GameState.java b/src/Game/GameState.java index 89b3b6b..216681b 100644 --- a/src/Game/GameState.java +++ b/src/Game/GameState.java @@ -4,5 +4,5 @@ * This is used by the ScreenCoordinator class to determine which "state" the game is currently in */ public enum GameState { - MENU, LEVEL, LEVELSELECT, CREDITS, INSTRUCTIONS , OPENING, OPTIONS; + MENU, LEVEL, LEVELSELECT, CREDITS, INSTRUCTIONS , OPENING, OPTIONS, DIFFICULTYSELECT; } diff --git a/src/Game/ScreenCoordinator.java b/src/Game/ScreenCoordinator.java index 299ef71..43c71cf 100644 --- a/src/Game/ScreenCoordinator.java +++ b/src/Game/ScreenCoordinator.java @@ -58,6 +58,7 @@ public void update() { case LEVELSELECT -> currentScreen = new LevelSelectScreen(); case OPENING -> currentScreen = new OpeningScreen(this); case OPTIONS -> currentScreen = new OptionsScreen(); + case DIFFICULTYSELECT -> currentScreen = new DifficultySelectScreen(); } currentScreen.initialize(); } diff --git a/src/Screens/DifficultySelectScreen.java b/src/Screens/DifficultySelectScreen.java new file mode 100644 index 0000000..90f1b5a --- /dev/null +++ b/src/Screens/DifficultySelectScreen.java @@ -0,0 +1,31 @@ +package Screens; + +import Engine.GamePanel; +import Game.GameState; +import Maps.TitleScreenMap; +import Menu.Menu; +import Menu.Direction; +import Menu.MenuOption; + +public class DifficultySelectScreen extends Menu { + + public DifficultySelectScreen() { + MenuOption[][] menu = new MenuOption[][]{ + { + new MenuOption("Normal", 100, 150, null), + new MenuOption("Hard", 320, 150, null), + new MenuOption("Hardcore", 500, 150, null) + }, + { + new MenuOption( + "Back to Main Menu", 225, 375, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) + } + }; + setBackground(new TitleScreenMap()); + setMenuItemsAsGrid(menu); + menu[0][0].setNeighborItem(menu[1][0], Direction.DOWN); + menu[0][1].setNeighborItem(menu[1][0], Direction.DOWN); + menu[0][2].setNeighborItem(menu[1][0], Direction.DOWN); + menu[1][0].setNeighborItem(menu[0][1],Direction.UP); + } +} diff --git a/src/Screens/MenuScreen.java b/src/Screens/MenuScreen.java index 0d9568d..a13a12e 100644 --- a/src/Screens/MenuScreen.java +++ b/src/Screens/MenuScreen.java @@ -3,6 +3,7 @@ import Engine.GamePanel; import Game.GameState; import Maps.TitleScreenMap; +import Menu.Direction; import Menu.Menu; import Menu.MenuOption; @@ -10,18 +11,23 @@ public class MenuScreen extends Menu { public MenuScreen() { super(); - setMenuItemsAsGrid(new MenuOption[][]{ - { - new MenuOption("PLAY GAME", 80, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVEL)), - new MenuOption("LEVEL SELECT", 350, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVELSELECT)) - }, { - new MenuOption("CREDITS", 80, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.CREDITS)), - new MenuOption("NARRATIVE", 350, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPENING)) - }, { - new MenuOption("INSTRUCTIONS", 80, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), - new MenuOption("OPTIONS", 350, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) - } - }); + MenuOption[][] menu = new MenuOption[][]{ + { + new MenuOption("PLAY GAME", 80, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVEL)), + new MenuOption("LEVEL SELECT", 350, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVELSELECT)) + }, { + new MenuOption("CREDITS", 80, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.CREDITS)), + new MenuOption("NARRATIVE", 350, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPENING)) + }, { + new MenuOption("INSTRUCTIONS", 80, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), + new MenuOption("OPTIONS", 350, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) + }, + { + new MenuOption("SELECT DIFFICULTY", 80, 400, () -> GamePanel.getScreenCoordinator().setGameState(GameState.DIFFICULTYSELECT)) + } + }; + setMenuItemsAsGrid(menu); + menu[2][1].setNeighborItem(menu[3][0], Direction.DOWN); setBackground(new TitleScreenMap()); } } From a50f9c3c0f355c402f699a79103483dd1c80ab42 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:15:26 -0500 Subject: [PATCH 105/164] Passed Test Case SCP-62 --- Team A2/Test Cases/Test Case SCP-62.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-62.md b/Team A2/Test Cases/Test Case SCP-62.md index 5aada90..c906095 100644 --- a/Team A2/Test Cases/Test Case SCP-62.md +++ b/Team A2/Test Cases/Test Case SCP-62.md @@ -10,14 +10,14 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens | [RESULT] | -|2| Press the spacebar to start the game.| The game starts and the character is loaded into the first level. | [RESULT] | -|3| Navigate to the passable floating platform by going to the right and jumping over the tree. | The character is under the passable floating platform. | [RESULT] | -|4| Jump onto the passable floating platform by jumping from directly below it. | The character passes through the platform and lands on top of it. | [RESULT] | -|5| Close the game and launch the map editor | The map editor opens | [RESULT] | -|6| Select the passable floating platform tile and click on the map to place it. | The passable floating platform is placed on the map. | [RESULT] | +|1| Run the game| The game successfully opens | Pass | +|2| Press the spacebar to start the game.| The game starts and the character is loaded into the first level. | Pass | +|3| Navigate to the passable floating platform by going to the right and jumping over the tree. | The character is under the passable floating platform. | Pass | +|4| Jump onto the passable floating platform by jumping from directly below it. | The character passes through the platform and lands on top of it. | Pass | +|5| Close the game and launch the map editor | The map editor opens | Pass | +|6| Select the passable floating platform tile and click on the map to place it. | The passable floating platform is placed on the map. | Pass | ### Test Completion -- **Tester**: [TESTER NAME] -- **Date of Test**: DATE OF TEST -- **Test Result**: TEST RESULT \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 10:14 AM +- **Test Result**: Passed \ No newline at end of file From 77ecdbf88808a99c9a4778809e42ff529918941e Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:17:36 -0500 Subject: [PATCH 106/164] Passed Test Case SCP-55 --- Team A2/Test Cases/Test Case SCP-55.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-55.md b/Team A2/Test Cases/Test Case SCP-55.md index a7092c4..983eca9 100644 --- a/Team A2/Test Cases/Test Case SCP-55.md +++ b/Team A2/Test Cases/Test Case SCP-55.md @@ -10,14 +10,14 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1|Run the game|The main menu displays successfully|| -|2|Press space on "Options"|The options menu should load|| -|3|Click on orange and then hover over blue or green|The orange cat should be displayed|| -|4|Click on blue and then hover over orange or green|The blue cat should be displayed|| -|5|Click on green and then hover over blue or orange|The green cat should be displayed|| +|1|Run the game|The main menu displays successfully|Pass| +|2|Press space on "Options"|The options menu should load|Pass| +|3|Click on orange and then hover over blue or green|The orange cat should be displayed|Pass| +|4|Click on blue and then hover over orange or green|The blue cat should be displayed|Pass| +|5|Click on green and then hover over blue or orange|The green cat should be displayed|Pass| ### Test Completion -- **Tester**: -- **Date of Test**: -- **Test Result**: \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 10:17 AM +- **Test Result**: Passed \ No newline at end of file From 0b454fa62d61aae5b9b820588a85c3a426348117 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:20:50 -0500 Subject: [PATCH 107/164] Passed Test Case SCP-58 --- Team A2/Test Cases/Test Case SCP-58.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-58.md b/Team A2/Test Cases/Test Case SCP-58.md index 4072af2..a55f4c8 100644 --- a/Team A2/Test Cases/Test Case SCP-58.md +++ b/Team A2/Test Cases/Test Case SCP-58.md @@ -10,14 +10,14 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1|Run the game|The main menu displays successfully|| -|2|Press space on "Level Select"|The list of levels should load|| -|3|Press Space on "Boss Battle"|The user should be at the start of the level "Boss Battle"|| -|4|Get within one tile in front of the boss |The cat should not die|| -|5|Get within one tile behind the boss |The cat should not die|| -|4|Touch the boss |The cat should die|| +|1|Run the game|The main menu displays successfully|Pass| +|2|Press space on "Level Select"|The list of levels should load|Pass| +|3|Press Space on "Boss Battle"|The user should be at the start of the level "Boss Battle"|Pass| +|4|Get within one tile in front of the boss |The cat should not die|Pass| +|5|Get within one tile behind the boss |The cat should not die|Pass| +|4|Touch the boss |The cat should die|Pass| ### Test Completion -- **Tester**: -- **Date of Test**: -- **Test Result**: \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 10:20 AM +- **Test Result**: Passed \ No newline at end of file From 726cd58e19f7d4fee6a077914979b11d4612de24 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:23:31 -0500 Subject: [PATCH 108/164] Updated Test Case SCP-57 --- Team A2/Test Cases/Test Case SCP-57.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index d10970e..a760d57 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -19,7 +19,7 @@ Functionality of `Player.java` tested: |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|0a| **Evaluated on Each Step:** | Player Animation changes as expected |`N/A`| +|0a| **Evaluated on Each Step:** | Player Animation changes as expected (*If a step does not pass this result, fail that step and indicate "Failed Step 0a"*) |`N/A`| |1| Run the game| The game successfully opens || |2| Click "*Play*" |The tutorial level is entered, game does not crash. 3 hearts are displayed on the top of the screen.|| |3| Hold `A/Left Arrow` |The player moves to the left. The player does not fall off the map and is instead stopped at the edge|| @@ -47,9 +47,6 @@ Functionality of `Player.java` tested: |25|Hit "Play Game"|The first level is loaded|| |26|Play all levels of the game|Each level is completable|| - - - ### Test Completion - **Tester**: [TESTER NAME] - **Date of Test**: DATE OF TEST From 1997304a3efc071c8fd31e2c9bbaacb40b078470 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:32:41 -0500 Subject: [PATCH 109/164] Added Comments to Player.java --- src/Level/Player.java | 65 +++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index fd277d0..0d8fd8b 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -12,6 +12,7 @@ import java.util.List; /** + * Represents the player as it navigates through a map. * @author Thomas Kwashnak */ public abstract class Player extends GameObject { @@ -28,6 +29,7 @@ public abstract class Player extends GameObject { private boolean inAir; private float absVelocityX, velocityY; + public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimationName) { super(spriteSheet, x, y, startingAnimationName); @@ -38,16 +40,23 @@ public Player(SpriteSheet spriteSheet, float x, float y, String startingAnimatio public void update() { super.update(); + + //Redirects to update depending on player state switch (levelState) { case PLAYING -> updatePlaying(); case DEAD -> updateDead(); case WIN -> updateWin(); } + //Updates animation using the player's current playerState setCurrentAnimationName(playerState.get(facing)); } + /** + * Updates the player as whenever it is in the playing state + */ private void updatePlaying() { + //Applies gravity applyGravity(MAX_FALL_VELOCITY); //Update Player Action and Direction @@ -98,41 +107,53 @@ private void updatePlaying() { levelState = LevelState.DEAD; } - inAir = true; //air is decided in moveYHandleCollision() - super.moveYHandleCollision(velocityY); - super.moveXHandleCollision(absVelocityX * facing.mod); + inAir = true; //inAir is updated in collisions + //Moves while handling collisions + moveYHandleCollision(velocityY); + moveXHandleCollision(absVelocityX * facing.mod); } + /** + * Updates the player while it is dead + */ private void updateDead() { - playerState = PlayerState.DEATH; - if (currentFrameIndex > 0) { + if (currentFrameIndex > 0) { //Checks if it is not the first frame of the player's death animation if (map.getCamera().containsDraw(this)) { applyGravity(MAX_DEATH_FALL_VELOCITY); } else for (PlayerListener listener : playerListeners) { listener.onDeath(); } - } else { + } else { //Only activates on the first frame of death animation velocityY = DEATH_Y_VELOCITY; } + //Updates Y. Does not use "moveYHandleCollision" since the player can move through the map setY(y + velocityY); } + /** + * Updates the player after it completes a level + */ private void updateWin() { - if (map.getCamera().containsDraw(this)) { + if (map.getCamera().containsDraw(this)) { //If the player can seen on the map facing = Facing.RIGHT; - if (inAir) { + if (inAir) { //If the player is still falling playerState = PlayerState.FALL; applyGravity(MAX_FALL_VELOCITY); moveYHandleCollision(velocityY); - } else { + } else { //Once the player hits the ground, walk to the right playerState = PlayerState.WALK; - moveXHandleCollision(walkSpeed); + moveX(walkSpeed); } } else for (PlayerListener listener : playerListeners) { + //When the player is off the map, send a onLevelCompleted() to all listeners listener.onLevelCompleted(); } } + /** + * Updates the current velocityY with the current gravity + * @param maxFallVelocity Gravity Force + */ private void applyGravity(float maxFallVelocity) { if (velocityY < maxFallVelocity) { velocityY += gravity; @@ -141,9 +162,9 @@ private void applyGravity(float maxFallVelocity) { @Override public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { - if (hasCollided) { + if (hasCollided) { //If it has collided, handles the collision and sets the player's animation to standing handleCollision(MapTileCollisionHandler.lastCollidedTileX); - if (playerState == PlayerState.WALK) { + if (playerState == PlayerState.WALK) { //If the player is walking (aka, not falling), then make the player standing playerState = PlayerState.STAND; } } @@ -152,21 +173,23 @@ public void onEndCollisionCheckX(boolean hasCollided, Direction direction) { @Override public void onEndCollisionCheckY(boolean hasCollided, Direction direction) { if (hasCollided) { - if (direction == Direction.DOWN) { + if (direction == Direction.DOWN) { //If direction is down, make inAir false as the player is ontop of something inAir = false; } - velocityY = 0; + velocityY = 0; //Reset velocity handleCollision(MapTileCollisionHandler.lastCollidedTileY); } } private void handleCollision(MapTile tile) { if (tile != null && tile.getTileType() == TileType.LETHAL) { + //If the player hits a lethal tile, set its state to dead levelState = LevelState.DEAD; } } public void hurtPlayer(MapEntity mapEntity) { + //Checks the collision type of the entity that collided with the player switch (mapEntity.getCollisionType()) { case DAMAGE -> PLAYER_HEALTH -= 1; case INSTANT_DEATH -> PLAYER_HEALTH = 0; @@ -174,18 +197,32 @@ public void hurtPlayer(MapEntity mapEntity) { } } + /** + * Indicates that the player wins, and starts the winning animation + */ public void completeLevel() { levelState = LevelState.WIN; } + /** + * @return {@code True} if the player is in the air, {@code false} if the player is on some surface + */ public boolean isInAir() { return inAir; } + /** + * Adds a listener + * @param listener Methods to be checked whenever the player executes an event + */ public void addListener(PlayerListener listener) { playerListeners.add(listener); } + /** + * Updates the jump height of the player + * @param height Velocity to apply when the player jumps + */ public void setJumpHeight(int height) { this.jumpHeight = height; } From f5dc5891794737fe0454a14ee2c6a4e5042844f8 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:40:08 -0500 Subject: [PATCH 110/164] Moved Rendering to happen immediately after any update Prevented the situation where a render would run before any updates had been executed (threw errors when changing scenes) --- Team A2/Test Cases/Test Case SCP-56.md | 1 + src/Game/GameThread.java | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index dbe980b..e89de75 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -33,6 +33,7 @@ Instances of tests are listed in table below (template provided). Measurements l |:---:|:---|:---|:---:|:---:|:---:|:---:|:---:|:---:| |[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[MEASURE 5]|[PASS/FAIL]| + [comment]: <> (Add test rows to end here ^^) ### Completion Criteria diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index 733c178..c0233c5 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -66,10 +66,12 @@ public void run() { while(currentTime > nextUpdateTime) { update.run(); nextUpdateTime += UPDATE_FIXED_MS; + + //Run a render + render.run(); } - //Run a render - render.run(); + } //Reset running once it's set to false running = true; From 48b82b859c4277e1fe111127cdc8555e0759490f Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:49:38 -0500 Subject: [PATCH 111/164] Added Laptop Measurements to Test Case SCP-56 --- Team A2/Test Cases/Test Case SCP-56.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index e89de75..be1d2f8 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -32,7 +32,7 @@ Instances of tests are listed in table below (template provided). Measurements l |Date|Name|Device Information | Measure 1|Measure 2|Measure 3|Measure 5|Measure 4|Pass/Fail| |:---:|:---|:---|:---:|:---:|:---:|:---:|:---:|:---:| |[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[MEASURE 5]|[PASS/FAIL]| - +|11/29/2021 10:41 AM|Thomas Kwashnak|Kubuntu 21.10 Laptop, Intel i7 CPU, NVIDIA MX330 GPU|\~ 2 seconds|\~1 second|\~1 second|\~1-2 seconds|~3 seconds|Pass. Game runs at expected speed| [comment]: <> (Add test rows to end here ^^) From 7d11412431264d861dd4a72d4b36d8569713e5be Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:56:15 -0500 Subject: [PATCH 112/164] Added Prerequisite for Test Case SCP-56 --- Team A2/Test Cases/Test Case SCP-56.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index be1d2f8..8218e43 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -7,6 +7,7 @@ | Test Objective | Ensure that the game runs consistently through multiple distributions | | Test Notes| Due to the nature of this test case, multiple runs of the test must be conducted on various machines of different make and models. Measurements will be taken using a recording software, and should not be expected to be perfect| |Software Requirement|**Screen recording software:** Needs to be able to record the screen such that the tester can go back and accurately measure the time between events. *Suggested:* OBS| +|Prerequisites|Test Case SCP-56 must be completed prior to this merge| ### Procedure From 4617d3a47de088ea25385e677fcfddd9b01b9c84 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 10:56:30 -0500 Subject: [PATCH 113/164] Added Prerequisite for Test Case SCP-57 --- Team A2/Test Cases/Test Case SCP-56.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 8218e43..c32e8ac 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -7,7 +7,7 @@ | Test Objective | Ensure that the game runs consistently through multiple distributions | | Test Notes| Due to the nature of this test case, multiple runs of the test must be conducted on various machines of different make and models. Measurements will be taken using a recording software, and should not be expected to be perfect| |Software Requirement|**Screen recording software:** Needs to be able to record the screen such that the tester can go back and accurately measure the time between events. *Suggested:* OBS| -|Prerequisites|Test Case SCP-56 must be completed prior to this merge| +|Prerequisites|Test Case SCP-57 must be completed prior to this merge| ### Procedure From 45d78871676aad5c9bacd5a211cab60102946b8f Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 11:11:11 -0500 Subject: [PATCH 114/164] Game Timer now stops only when the player completes the last map --- src/Screens/PlayLevelScreen.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 33c3eb3..b309a5b 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -209,7 +209,10 @@ private void loadMap(int index) { @Override public void onLevelFinished() { - timeTracker.stop(); + //Only complete on final level + if(currentMap == GameMaps.MAPS.length - 1) { + timeTracker.stop(); + } } @Override From 225cf88caa234830c28b82931a4cb485d8ea1cfd Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 11:42:50 -0500 Subject: [PATCH 115/164] Continued work on GameScoreScreen.java --- src/Game/TimeTracker.java | 4 +++- src/Screens/GameScoreScreen.java | 28 ++++++++++++++++++++++++++++ src/SpriteFont/SpriteFont.java | 30 +++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 7dac23a..ba27a79 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -101,5 +101,7 @@ public void draw(GraphicsHandler graphicsHandler) { } - + public GameTimer[] getLevels() { + return levels; + } } diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index 68f90b4..ac4f5db 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -3,8 +3,10 @@ import Engine.Drawable; import Engine.GraphicsHandler; import Game.TimeTracker; +import Maps.GameMaps; import Maps.TitleScreenMap; import Menu.Menu; +import SpriteFont.SpriteFont; import Utils.GameTimer; import java.awt.*; @@ -21,10 +23,36 @@ public class GameScoreScreen extends Menu { } private TimeTracker timeTracker; + private SpriteFont levels; public GameScoreScreen(TimeTracker timeTracker) { this.timeTracker = timeTracker; setBackground(new TitleScreenMap()); + System.out.println(getLevels(timeTracker)); + } + + private String getLevels(TimeTracker timeTracker) { + StringBuilder stringBuilder = new StringBuilder(); + GameTimer[] gameTimers = timeTracker.getLevels(); + + for(int i = 0; i < GameMaps.MAPS.length; i++) { + if(gameTimers[i].getElapsed() > 0) { + if(!stringBuilder.isEmpty()) { + stringBuilder.append('\n'); + } + stringBuilder.append(GameMaps.MAPS[i].getName()).append(": ").append(gameTimers[i].toString()); + } + } + + return stringBuilder.toString(); + } + + private GameTimer getTotalTimes(TimeTracker timeTracker) { + GameTimer totalTime = new GameTimer(); + for(GameTimer gameTimer : timeTracker.getLevels()) { + totalTime.addTime(gameTimer.getElapsed()); + } + return totalTime; } @Deprecated //Maybe? diff --git a/src/SpriteFont/SpriteFont.java b/src/SpriteFont/SpriteFont.java index 6816199..c9d17f0 100644 --- a/src/SpriteFont/SpriteFont.java +++ b/src/SpriteFont/SpriteFont.java @@ -4,8 +4,11 @@ import Engine.GraphicsHandler; import java.awt.*; +import java.util.Arrays; // This class represents a sprite font, which is graphic text (text drawn to the screen as if it were an image) + + public class SpriteFont implements Drawable { protected String text; protected Font font; @@ -15,6 +18,10 @@ public class SpriteFont implements Drawable { protected Color color; protected Color outlineColor; protected float outlineThickness = 1f; + /** + * Whether to automatically multi-line the text if `\n` is present + */ + protected boolean multiLine, containsNewLines; public SpriteFont(String text, float x, float y, String fontName, int fontSize, Color color) { this(text,x,y,new Font(fontName,Font.PLAIN,fontSize),color); @@ -44,6 +51,11 @@ public String getText() { public void setText(String text) { this.text = text; updateDimensions(); + updateContainsNewLines(); + } + + public void updateContainsNewLines() { + containsNewLines = text.contains("\n"); } public void setFontName(String fontName) { @@ -118,10 +130,14 @@ public void moveUp(float dy) { public void draw(GraphicsHandler graphicsHandler) { - if (outlineColor != null && !outlineColor.equals(color)) { - graphicsHandler.drawStringWithOutline(getText(), Math.round(x), Math.round(y), font, color, outlineColor, outlineThickness); + if(multiLine && containsNewLines) { + drawWithParsedNewLines(graphicsHandler); } else { - graphicsHandler.drawString(getText(), Math.round(x), Math.round(y), font, color); + if (outlineColor != null && !outlineColor.equals(color)) { + graphicsHandler.drawStringWithOutline(getText(), Math.round(x), Math.round(y), font, color, outlineColor, outlineThickness); + } else { + graphicsHandler.drawString(getText(), Math.round(x), Math.round(y), font, color); + } } } @@ -156,6 +172,14 @@ public void updateDimensions() { height = -1; } + public void setMultiLine(boolean multiLine) { + this.multiLine = multiLine; + } + + public boolean isMultiLine() { + return multiLine; + } + public boolean contains(Point point) { return point.x > x && point.y > y && point.x < x + width && point.y < y + height; } From 812546222c96f88a2c9f805d54b3a8f09f1d3397 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 11:43:35 -0500 Subject: [PATCH 116/164] Set Default Value for SpriteFont.java --- src/SpriteFont/SpriteFont.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SpriteFont/SpriteFont.java b/src/SpriteFont/SpriteFont.java index c9d17f0..f9e9a71 100644 --- a/src/SpriteFont/SpriteFont.java +++ b/src/SpriteFont/SpriteFont.java @@ -21,7 +21,7 @@ public class SpriteFont implements Drawable { /** * Whether to automatically multi-line the text if `\n` is present */ - protected boolean multiLine, containsNewLines; + protected boolean multiLine = false, containsNewLines; public SpriteFont(String text, float x, float y, String fontName, int fontSize, Color color) { this(text,x,y,new Font(fontName,Font.PLAIN,fontSize),color); From 66be104b9eed97b1961e121f0d0ef36042608024 Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:34:01 -0500 Subject: [PATCH 117/164] Added SCp-60 Test Cases and implemented bug fix --- Team A2/Test Cases/Test Case SCP-47.md | 22 ++++++++++++++++++++++ Team A2/Test Cases/Test Case SCP-60.md | 21 +++++++++++++++++++++ src/Screens/OptionsScreen.java | 2 +- 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 Team A2/Test Cases/Test Case SCP-47.md create mode 100644 Team A2/Test Cases/Test Case SCP-60.md diff --git a/Team A2/Test Cases/Test Case SCP-47.md b/Team A2/Test Cases/Test Case SCP-47.md new file mode 100644 index 0000000..f296f3c --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-47.md @@ -0,0 +1,22 @@ +### Test Case Information +| TEST CASE ID | SCP-47| +| :--- | :--- | +| Owner of Test | Ty Hutchison| +| Test Name | Update Instructions | +| Date of Last Revision | 11/29/2021 | +| Test Objective | Add Solid Floating block for user to use | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens || +|2| Enter Level 1 | The User will enter level 1 | | +|3| Go through the level and test implemented floating block | The User will go through the level completing it while using the floating block | | +|4| Complete level 1 | The User will complete level 1 | | +|5| Exit the game | The User will exit the game | | + +### Test Completion +- **Tester**: +- **Date of Test**: +- **Test Result**: \ No newline at end of file diff --git a/Team A2/Test Cases/Test Case SCP-60.md b/Team A2/Test Cases/Test Case SCP-60.md new file mode 100644 index 0000000..a931726 --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-60.md @@ -0,0 +1,21 @@ +### Test Case Information +| TEST CASE ID | SCP-60| +| :--- | :--- | +| Owner of Test | Ty Hutchison| +| Test Name | Update Instructions | +| Date of Last Revision | 11/29/2021 | +| Test Objective | Add Solid Floating block for user to use | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens || +|2| Enter Options Menu | The User will enter option menu| | +|3| Use the back to main menu button at bottom | The User will exit the options screen using the back to menu feature at the bottom | | +|4| Enter Main Menu Screen | The User will enter the Main Menu screen | | + +### Test Completion +- **Tester**: +- **Date of Test**: +- **Test Result**: \ No newline at end of file diff --git a/src/Screens/OptionsScreen.java b/src/Screens/OptionsScreen.java index f1ee687..1a4c851 100644 --- a/src/Screens/OptionsScreen.java +++ b/src/Screens/OptionsScreen.java @@ -30,7 +30,7 @@ public OptionsScreen() { new MenuOption("Blue",500,300, () -> Config.playerAvatar = Avatar.CAT_BLUE), new MenuOption("Green",630,300, () -> Config.playerAvatar = Avatar.CAT_GREEN) },{ - new MenuOption("Hit [Escape] to go back to main menu",100,450) + new MenuOption("Hit [Escape] to go back to main menu",100,450, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) } }; setMenuItemsAsGrid(items); From 763f20e767bd264b4fb8b563ed41d7f6a1b8e592 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 14:39:05 -0500 Subject: [PATCH 118/164] Game no longer renders while behind on ticks Should minimize update fails --- src/Game/GameThread.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Game/GameThread.java b/src/Game/GameThread.java index c0233c5..f4d9452 100644 --- a/src/Game/GameThread.java +++ b/src/Game/GameThread.java @@ -63,15 +63,14 @@ public void run() { currentTime = System.currentTimeMillis(); //Repeat until the update time is after (in the future) current time - while(currentTime > nextUpdateTime) { - update.run(); - nextUpdateTime += UPDATE_FIXED_MS; - + if(currentTime > nextUpdateTime) { + do { + update.run(); + nextUpdateTime += UPDATE_FIXED_MS; + } while(currentTime > nextUpdateTime); //Run a render render.run(); } - - } //Reset running once it's set to false running = true; From 06e5de5d5670a266c455a0f584b915e5f2068f2b Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:39:41 -0500 Subject: [PATCH 119/164] Added Test Cases and implemented Quit feature for SCP-51 --- Team A2/Test Cases/Test Case SCP-51.md | 21 +++++++++++++++++++++ src/Screens/MenuScreen.java | 2 ++ 2 files changed, 23 insertions(+) create mode 100644 Team A2/Test Cases/Test Case SCP-51.md diff --git a/Team A2/Test Cases/Test Case SCP-51.md b/Team A2/Test Cases/Test Case SCP-51.md new file mode 100644 index 0000000..3ab8ea2 --- /dev/null +++ b/Team A2/Test Cases/Test Case SCP-51.md @@ -0,0 +1,21 @@ +### Test Case Information +| TEST CASE ID | SCP-51| +| :--- | :--- | +| Owner of Test | Ty Hutchison| +| Test Name | Update Instructions | +| Date of Last Revision | 11/29/2021 | +| Test Objective | Add Quit option in main menu | + +### Procedure + +|Step | Action | Expected Result | Pass/Fail | +|:---:| :--- | :---- | :---: | +|1| Run the game| The game successfully opens || +|2| Hit Quit Option | The User will select the quit option in the main menu | | +|3| The game will close | The game will close | | + + +### Test Completion +- **Tester**: +- **Date of Test**: +- **Test Result**: \ No newline at end of file diff --git a/src/Screens/MenuScreen.java b/src/Screens/MenuScreen.java index 0d9568d..373b9f4 100644 --- a/src/Screens/MenuScreen.java +++ b/src/Screens/MenuScreen.java @@ -20,6 +20,8 @@ public MenuScreen() { }, { new MenuOption("INSTRUCTIONS", 80, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), new MenuOption("OPTIONS", 350, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) + }, { + new MenuOption("QUIT", 80, 400, () -> System.exit(1)) } }); setBackground(new TitleScreenMap()); From 41d39589658b0ef96577ffe11171630a32c3a998 Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:42:05 -0500 Subject: [PATCH 120/164] Corrected Test Case Name and Objective --- Team A2/Test Cases/Test Case SCP-47.md | 2 +- Team A2/Test Cases/Test Case SCP-60.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-47.md b/Team A2/Test Cases/Test Case SCP-47.md index f296f3c..0a0f472 100644 --- a/Team A2/Test Cases/Test Case SCP-47.md +++ b/Team A2/Test Cases/Test Case SCP-47.md @@ -2,7 +2,7 @@ | TEST CASE ID | SCP-47| | :--- | :--- | | Owner of Test | Ty Hutchison| -| Test Name | Update Instructions | +| Test Name | Add Solid Floating Block | | Date of Last Revision | 11/29/2021 | | Test Objective | Add Solid Floating block for user to use | diff --git a/Team A2/Test Cases/Test Case SCP-60.md b/Team A2/Test Cases/Test Case SCP-60.md index a931726..bf36772 100644 --- a/Team A2/Test Cases/Test Case SCP-60.md +++ b/Team A2/Test Cases/Test Case SCP-60.md @@ -2,9 +2,9 @@ | TEST CASE ID | SCP-60| | :--- | :--- | | Owner of Test | Ty Hutchison| -| Test Name | Update Instructions | +| Test Name | Fix back-to-menu not working | | Date of Last Revision | 11/29/2021 | -| Test Objective | Add Solid Floating block for user to use | +| Test Objective | Fix bug preventing back to menu option not working in options menu | ### Procedure From 0e8afeec0034aa509c79545e24451de1f1dba98c Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:43:04 -0500 Subject: [PATCH 121/164] Corrected Test Name --- Team A2/Test Cases/Test Case SCP-51.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-51.md b/Team A2/Test Cases/Test Case SCP-51.md index 3ab8ea2..efa0386 100644 --- a/Team A2/Test Cases/Test Case SCP-51.md +++ b/Team A2/Test Cases/Test Case SCP-51.md @@ -2,7 +2,7 @@ | TEST CASE ID | SCP-51| | :--- | :--- | | Owner of Test | Ty Hutchison| -| Test Name | Update Instructions | +| Test Name | Implement Quit Option | | Date of Last Revision | 11/29/2021 | | Test Objective | Add Quit option in main menu | From 07e5cbc01b71e8e4507f1704d8eed8f2a367d8f7 Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 14:46:06 -0500 Subject: [PATCH 122/164] Corrected exit status --- src/Screens/MenuScreen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Screens/MenuScreen.java b/src/Screens/MenuScreen.java index 373b9f4..2171935 100644 --- a/src/Screens/MenuScreen.java +++ b/src/Screens/MenuScreen.java @@ -21,7 +21,7 @@ public MenuScreen() { new MenuOption("INSTRUCTIONS", 80, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), new MenuOption("OPTIONS", 350, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) }, { - new MenuOption("QUIT", 80, 400, () -> System.exit(1)) + new MenuOption("QUIT", 80, 400, () -> System.exit(0)) } }); setBackground(new TitleScreenMap()); From 0402c1a27c07634788d35e56c15e9dcc50ce99bb Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 15:12:47 -0500 Subject: [PATCH 123/164] Fixed rendering of time above a certain point --- src/Game/TimeTracker.java | 1 + src/Utils/TimeParser.java | 75 ++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index ba27a79..5fb2dc2 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -88,6 +88,7 @@ public void draw(GraphicsHandler graphicsHandler) { } graphicsHandler.drawString(totalString, xTotal, yTotal, FONT_BIG, Color.white); + if(showLevel) { String mapString = levels[currentLevel].toString(); if(mapString.length() != charsMap) { diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java index fd409f4..107460f 100644 --- a/src/Utils/TimeParser.java +++ b/src/Utils/TimeParser.java @@ -53,37 +53,56 @@ public String toString() { long seconds = (elapsed %= MS_PER_MINUTE) / MS_PER_SECOND; elapsed %= MS_PER_SECOND; - char[] chs = new char[hours > 0 ? 11 : minutes > 0 ? 8 : 5]; + StringBuilder stringBuilder = new StringBuilder(); - //milliseconds - chs[chs.length - 3] = '.'; - chs[chs.length - 2] = (char) ('0' + (elapsed / 100)); - chs[chs.length - 1] = (char) ('0' + (elapsed / 10) % 10); - //seconds - chs[chs.length - 5] = (char) ('0' + (seconds / 10)); - if(minutes == 0 && hours == 0 && chs[chs.length - 5] == '0') { - chs[chs.length - 5] = ' '; - } - chs[chs.length - 4] = (char) ('0' + (seconds % 10)); - - if(minutes > 0 || hours > 0) { - chs[chs.length - 6] = ':'; - chs[chs.length - 7] = (char) ('0' + (minutes % 10)); - chs[chs.length - 8] = (char) ('0' + (minutes / 10)); - if(chs[chs.length - 8] == '0' && hours == 0) { - chs[chs.length - 8] = ' '; - } + /* + TODO clean / optimize + */ - if(hours > 0) { - chs[0] = (char) ('0' + (hours / 10) % 10); - if(chs[0] == '0') { - chs[0] = ' '; - } - chs[1] = (char) ('0' + hours % 10); - chs[2] = ':'; - } + if(hours > 0) { + stringBuilder.append(hours).append(':').append((char) ('0' + minutes / 10)).append((char) ('0' + minutes % 10)).append(':'); + stringBuilder.append((char) ('0' + seconds / 10)); + } else if(minutes > 0) { + stringBuilder.append((char) ('0' + minutes / 10)).append((char) ('0' + minutes % 10)).append(':'); + stringBuilder.append((char) ('0' + seconds / 10)); + } else if(seconds > 9) { + stringBuilder.append((char) ('0' + seconds / 10)); } + stringBuilder.append((char) ('0' + seconds % 10)).append('.'); + stringBuilder.append((char) ('0' + elapsed / 100)).append((char) ('0' + (elapsed / 10) % 10)); - return new String(chs); +// char[] chs = new char[hours > 0 ? 11 : minutes > 0 ? 8 : 5]; +// +// //milliseconds +// chs[chs.length - 3] = '.'; +// chs[chs.length - 2] = (char) ('0' + (elapsed / 100)); +// chs[chs.length - 1] = (char) ('0' + (elapsed / 10) % 10); +// //seconds +// chs[chs.length - 5] = (char) ('0' + (seconds / 10)); +// if(minutes == 0 && hours == 0 && chs[chs.length - 5] == '0') { +// chs[chs.length - 5] = ' '; +// } +// chs[chs.length - 4] = (char) ('0' + (seconds % 10)); +// +// if(minutes > 0 || hours > 0) { +// chs[chs.length - 6] = ':'; +// chs[chs.length - 7] = (char) ('0' + (minutes % 10)); +// chs[chs.length - 8] = (char) ('0' + (minutes / 10)); +// if(chs[chs.length - 8] == '0' && hours == 0) { +// chs[chs.length - 8] = ' '; +// } +// +// if(hours > 0) { +// chs[0] = (char) ('0' + (hours / 10) % 10); +// if(chs[0] == '0') { +// chs[0] = ' '; +// } +// chs[1] = (char) ('0' + hours % 10); +// chs[2] = ':'; +// } +// } +// +// return new String(chs); + return stringBuilder.toString(); } } From 2428ce92f699d344e7bf3d1324ffbc55a98afd9e Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 15:25:36 -0500 Subject: [PATCH 124/164] added solid floating platform --- MapFiles/test_map.txt | 2 +- Resources/CommonTileset.png | Bin 1920 -> 2073 bytes src/Tilesets/CommonTileset.java | 10 ++++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/MapFiles/test_map.txt b/MapFiles/test_map.txt index 32d1335..debc526 100644 --- a/MapFiles/test_map.txt +++ b/MapFiles/test_map.txt @@ -7,7 +7,7 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 17 1 5 11 11 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 13 11 6 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 18 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 14 0 0 0 0 diff --git a/Resources/CommonTileset.png b/Resources/CommonTileset.png index 04a727a2a3ffc80e30409545c91b6ea0d1574e0b..a53ad152071a23ee7c5d111354e296c7098eec8e 100644 GIT binary patch delta 2056 zcmV+j2>17Z519~<7k^X;1^@s6n_BtD00001b5ch_0Itp)=>Px+(n&-?RCr$PoIi+O zMG(OEX`x~xDNchRhY(MjC|FpiAQloK!Ab-JIj~4N8x^c_xm1FtvAYz)1tM6=1rjVo z{8Ly6YNKaB4nY!A1QA3n%qR2Ad^g{GGdr{I?R&TRvad_}(-8v3URUOBce%_BB^ut<#B>rLcAS$h7&JPq)I8&+pztgY=BbJ92U> z%Q$k(rLT+zpjZ%M?L$CGA&jsp6r#19P%LYR!CE*d*2>f@1)l$N`S&btgSszmJTYju z9TZJTV?&|ipnrhi|EE3+Sr$j%cmVOSuZ%XP(8*fyg#*gzzNCQeb!n2NJpS&#;k&o) zY==z$FWtkl916`LqZlZso(ppsm*rMH*%!iqf8hd191zOk3QdI?1Dhgi4vM7+Zb`W< z#rnSH!nBxzFt}W_Ao^TdxUm{MZACECsmY|IeDR4?hCU%Isj>b%vg%YGEm^qP&@&jT937P>;nbIGL{TC z6b>vml#>tw6n{#MD=|yqO4VFgY~wek3^CBBxUt+&Qp@({^7GTvp)Ok z7os)hP{t54uAEp3`!~{lhM`kT>Epg6jY{sTh4IF=916~?1P(`2s28edH|~)ojl%-N z+ed{$;|Yy3B9#40A)Hy62Xph;*(tW+oxuql+346LiAc%g75eDcmK zt;M|X_J2pamcy)N4oV`_D3kODhn6K=Pxf=>QLLG zP&|7V%)UJ7ur`X^?kiQ1I4;Tcq{^Z)x`G)EN(|Z%f&O@c%ZWjOwiH<$Y!@)u0=;D^ zsZdZ+o{UFwJt@K2gp!a6=18lP_bEIf@RnJ+LVtnpd5U-?r^KnjC2OFUN+>v>y@G<@ z?*lfc3=g1AP^h)U$}F*(7Y;5~`x^UjX~;t^4-D*6G!*K(aKNP>Pz@eaJk?`wOo^=& zt4dso>&Y<=kHyqOE{~Q*?$c~+U+Z=9n8RFYX~MH%r8=UAZGC^*J=Zv}%mQPB-v;np z@P7`@B?<*LO}y~OKadlO1O(h8y=YyD*WhwN@wjbiVZbvOFI6xfzXk|?ng>sQTPT|H zJ+yei+Qyg2Jr@`VS37b8Fm<_MM9wQ`#cj z%`2wlnEOhR(Iq(26-J@J!4bW@$FW@ly#)m=S+W)m5c-Hvs4^`uYR!p2^~j(;)v^+l z$D#B+T%xW=b759?7?a^mTIQfgKw?T2&maUKmWZjm3MdM$;69NJPWWzv*b1K^QyOIymAP&C)0rNmjGV9Lsak{0Z9$CQ*^uomcJ z=_j;liGUX9WBVl@d!&>&mQqXbip;)BN{KC3Dy8O9MrDDa7FXOp1y`O`Ga7oI(q|l6 zDaak@u^`!JH;$XOJ~E_Um?l2*_~88JWXsoD-vX0co-&P}rvPx>pxntI6PSv4c~$#TfGa`9@fVQ;_qKv-K_ zn~|}zvlEt=m)&yL*Vn`5xpQs*zn?lZ_uk!KUozWPj~&ZW)a)DEih|++0e^kq;=m9J zC>G#QFaQLe!=<&s^9qHmWyw;onS+W!ffb4XsPfTDP$mN7eRIXf-j)Kt9o$t2OaiVU z+?UsHAvCZQoJS0d1|(D0-NC9yWaR1n)-`f5V z4{|_RU0ro&Taq=QrSL2Z?`fciaZ@*j_jKV|mN{g5gHY&4I3R385VUVDC_E*`Z%6<% zD40QEYK$@v2;NKW_%8JM>-4>ybbimtKd0~UZ+Hd5SVbsa0XZ!Np?`R@Ej~t`5_5M& z?<*7s;aE!Sc)jgXn)_NPOYuUW{lL05H#g^Y<9vU@W%HeXu6>H;Cat-ln=Q_L#ReYR z@t2koW76QY7z6@)oMNF^`xV|^;^r|mo5M}#!a-SxGK-WFTfT3ol-N^{)W)_@1<8`2 zco%~NZ=p)}_0JW0mwm!`{hCQ2g{%(WZ9)?!J^u`4l`*UM3WeySn8i^oWtU2YQsN3N z#T8desg@$962-WUYAFS-&**9l$w1xN?A3g)R-bKle$l- m1xeL`6tg&Lpf4}b{|9FBFE8KLh%5jA002ovPDHLkV1fX`NYKjw delta 1918 zcmV-^2Z8vR5P%Pm7k@(t1^@s6g^A1L00001b5ch_0Itp)=>Px+I7vi7RCr$Pn>~nK zMHGPNX`!X0SPgZ^4+GhIpBZ=cv}{`Rx&^!T&;_s}3cqw-F?wOwQ! zCFass#sr{v5UlngpyUunSW75GYbBw0)?mR}I4IuA)GP&_|9$0;B5s4aFKs*)wA&7f zrlhf<&~Z>e@PGf=&r^}b(KjAIeC#Wui79llUVPzzO1dv8phsPrWGRon`%n7*jXRqm z)BmM=cveE8C1g|s+yEcMpHi zyNKtl(8vI5k_NP#8eEq99_d`!Uuz&ZQ_kp%0l(yQkp>TjpC~bw7ur||u zNp5XyD5pPqx;5+bFMlaoV+mypA>-h{gVoD$PC23T0Uk!}ccH~fSZkjk8 zO`%b!k==MimNX6z3~wJ53XLZ;&WKPBucUNtIuGX7v-4NmtB)%q7pes%M^-Kr3D_Q# zoPP|gtEEJta3y^D&P$EOJoo0u`uEEvbhqmf)s?^6_tHks!FB;tEYN$Fk_!bD70Gxc*OL>RU4JMUnP7>uI(whO6M|@&r7INpyhstR=9D-$ zxD*ZaQV9hIbWl+6^ZS4;DI)@?6BKGKR++`BdEwx!+Sk~JOG6%VMPOi`s-aNVg#)hr zfNJoV5~&_XV~Vv>yee@muBXH}A{MheaFfE|ttJm#4{~ei+QygTk!^`VS37 zb8Fm<_MM9wQ<@^&t;??FLJmaK&Xggzn^s!R`z zT5}>$BQmH@^{fQtaVUKcm#FK}T$q;~S~8+Z%N!I5h^18V3_<|n$+#V$pnncLu#?%J z``?fRH|0U$E(xLF^BfuI7Wols)KWOep)JKzCQXSo01+AgYfBjuispK>l(;AqOj&tQ z(t>^In3A&#)&jkienOj;2xx)c+As0gBc;SvN-e>wGW)72CH7pYl$uK!l?R4eTy^^t zTzOv2Xy|=PpK)lVpm3naf`4S6-8gRA`pA$b;<*jJYc9EYwDuOv8BT3=sp$=Kc9O{=S`VYwR{8)@spg{J>sPaK-AECri6C<_W?UkHFIAFTvsA~4<;;$sz- z0>2LKno7bX;2OexMg0~+153eqSYR|Dm~d19<>qWQyJG_JK7L4qFmBFf3EnLUMY9AC z5`_YNIT#vKBxuz^!G8%O90?GDfHr_Z->DG_2ScGsai=OM(@WPH4gYxT-qvEIfH(-a zf8_G-O@D|7C7`UWt%b8K$(qnoc$S6tG|OK!y{ha>g5vq_A)!RGEj~t`5_5M&?{}9_0)(xUIPiMYW#Qdd zR1qa(isrr|V*%^h+S;1?iV@$Ra9MokUv*50C<6No9aHF7tR4SCrNp(x6f3}UKr{hZ zsLkV|L0O10OHEKB1xd}dE>uCXCMeNZCc#^z(*3{1e defineTiles() { .withTileType(TileType.LETHAL); mapTiles.add(lethalSpikeTile); + + // solid floating block + Frame solidFloatingFrame = new FrameBuilder(getSubImage(3, 5), 0) + .withScale(tileScale) + .build(); + + MapTileBuilder solidFloatingTile = new MapTileBuilder(solidFloatingFrame) + .withTileType(TileType.NOT_PASSABLE); + + mapTiles.add(solidFloatingTile); return mapTiles; } } From 2150adb43f41f7b0d8e4d2ac9349e83c36462a47 Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 15:35:50 -0500 Subject: [PATCH 125/164] Added floating block and corrected where cat interacts with block --- src/Tilesets/CommonTileset.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tilesets/CommonTileset.java b/src/Tilesets/CommonTileset.java index d056c23..b3fa348 100644 --- a/src/Tilesets/CommonTileset.java +++ b/src/Tilesets/CommonTileset.java @@ -232,6 +232,7 @@ public ArrayList defineTiles() { // solid floating block Frame solidFloatingFrame = new FrameBuilder(getSubImage(3, 5), 0) .withScale(tileScale) + .withBounds(0, 6, 16, 3) .build(); MapTileBuilder solidFloatingTile = new MapTileBuilder(solidFloatingFrame) From fd0ccaaa0d1539dd764236f81241386449264215 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 15:47:08 -0500 Subject: [PATCH 126/164] Time now renders "1" minute instead of "01" minutes --- src/Utils/TimeParser.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java index 107460f..7bb08e0 100644 --- a/src/Utils/TimeParser.java +++ b/src/Utils/TimeParser.java @@ -60,10 +60,16 @@ public String toString() { */ if(hours > 0) { - stringBuilder.append(hours).append(':').append((char) ('0' + minutes / 10)).append((char) ('0' + minutes % 10)).append(':'); + if(hours > 9) { + stringBuilder.append((char) ('0' + hours / 10)); + } + stringBuilder.append((char) ('0' + hours % 10)).append(':').append((char) ('0' + minutes / 10)).append((char) ('0' + minutes % 10)).append(':'); stringBuilder.append((char) ('0' + seconds / 10)); } else if(minutes > 0) { - stringBuilder.append((char) ('0' + minutes / 10)).append((char) ('0' + minutes % 10)).append(':'); + if(minutes > 9) { + stringBuilder.append((char) ('0' + minutes / 10)); + } + stringBuilder.append((char) ('0' + minutes % 10)).append(':'); stringBuilder.append((char) ('0' + seconds / 10)); } else if(seconds > 9) { stringBuilder.append((char) ('0' + seconds / 10)); From cb3eb5eb49e46a91c260ff5eca72e9f0a8b326ac Mon Sep 17 00:00:00 2001 From: hutch445 <65507983+hutch445@users.noreply.github.com> Date: Mon, 29 Nov 2021 15:48:54 -0500 Subject: [PATCH 127/164] Added Test Case and Sand Tile and implemented into game --- MapFiles/test_map.txt | 4 ++-- MapFiles/test_map3.txt | 4 ++-- MapFiles/test_map4.txt | 6 +++--- MapFiles/test_map5.txt | 4 ++-- MapFiles/test_map7.txt | 4 ++-- MapFiles/test_map_2.txt | 4 ++-- MapFiles/test_tutorial.txt | 6 +++--- Resources/CommonTileset.png | Bin 2073 -> 2133 bytes Team A2/Test Cases/Test Case SCP-34.md | 22 ++++++++++++++++++++++ src/Tilesets/CommonTileset.java | 12 ++++++++++++ 10 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 Team A2/Test Cases/Test Case SCP-34.md diff --git a/MapFiles/test_map.txt b/MapFiles/test_map.txt index debc526..9ed115e 100644 --- a/MapFiles/test_map.txt +++ b/MapFiles/test_map.txt @@ -10,6 +10,6 @@ 1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 18 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 14 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 15 15 15 0 0 0 0 +1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 19 19 14 14 14 14 19 19 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 15 15 15 15 19 0 0 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 16 16 16 16 2 2 2 2 \ No newline at end of file diff --git a/MapFiles/test_map3.txt b/MapFiles/test_map3.txt index 9109457..5960f12 100644 --- a/MapFiles/test_map3.txt +++ b/MapFiles/test_map3.txt @@ -11,5 +11,5 @@ 1 1 1 1 1 5 11 11 4 7 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 9 0 0 0 0 0 1 10 1 1 1 1 1 1 1 1 7 7 10 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 2 2 2 2 2 2 2 2 2 2 2 2 16 16 16 16 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 \ No newline at end of file +0 0 0 0 0 0 0 0 0 0 0 0 19 14 14 14 14 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 2 2 2 2 2 2 2 2 2 2 19 16 16 16 16 19 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 \ No newline at end of file diff --git a/MapFiles/test_map4.txt b/MapFiles/test_map4.txt index afd1802..24df9d9 100644 --- a/MapFiles/test_map4.txt +++ b/MapFiles/test_map4.txt @@ -10,6 +10,6 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 1 5 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 7 1 1 1 -1 1 1 1 10 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 2 2 2 2 16 16 16 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 16 16 16 16 2 2 2 2 \ No newline at end of file +1 1 1 10 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 19 14 14 14 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 2 2 19 16 16 16 19 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 16 16 16 16 2 2 2 2 \ No newline at end of file diff --git a/MapFiles/test_map5.txt b/MapFiles/test_map5.txt index 3dc62c5..5e25dea 100644 --- a/MapFiles/test_map5.txt +++ b/MapFiles/test_map5.txt @@ -11,5 +11,5 @@ 1 1 1 1 5 11 7 1 1 1 1 1 1 0 0 0 0 0 1 1 7 1 1 1 1 1 1 1 1 5 11 11 13 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 0 0 0 0 0 0 0 1 7 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 0 0 0 0 0 0 0 0 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 16 16 16 2 2 2 2 2 2 2 2 \ No newline at end of file +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 14 14 14 19 0 0 0 0 0 0 0 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 19 16 16 16 19 2 2 2 2 2 2 2 \ No newline at end of file diff --git a/MapFiles/test_map7.txt b/MapFiles/test_map7.txt index 175a59b..9cd277b 100644 --- a/MapFiles/test_map7.txt +++ b/MapFiles/test_map7.txt @@ -11,5 +11,5 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 11 11 6 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 7 7 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 1 2 2 1 1 1 1 2 2 1 1 1 1 1 1 1 -0 0 0 14 14 14 14 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 14 14 0 0 16 16 0 0 0 0 16 16 0 0 0 0 16 16 0 0 0 0 0 0 0 -2 2 2 2 15 15 15 15 15 2 2 2 2 2 2 2 2 2 2 2 2 2 2 15 15 15 2 2 2 16 16 2 2 2 2 16 16 2 2 2 2 16 16 2 2 2 2 2 2 2 \ No newline at end of file +0 0 19 14 14 14 14 14 14 14 19 0 0 0 0 0 0 0 0 0 0 19 14 14 14 14 14 19 0 16 16 0 0 0 0 16 16 0 0 0 0 16 16 0 0 0 0 0 0 0 +2 2 19 19 15 15 15 15 15 19 19 2 2 2 2 2 2 2 2 2 2 19 19 15 15 15 19 19 2 16 16 2 2 2 2 16 16 2 2 2 2 16 16 2 2 2 2 2 2 2 \ No newline at end of file diff --git a/MapFiles/test_map_2.txt b/MapFiles/test_map_2.txt index 0e156fe..67857f3 100644 --- a/MapFiles/test_map_2.txt +++ b/MapFiles/test_map_2.txt @@ -11,5 +11,5 @@ 1 1 1 5 8 8 8 1 1 1 1 1 4 1 1 1 1 1 0 9 1 1 1 1 1 1 4 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 5 7 6 1 1 1 0 0 0 0 1 1 1 1 5 7 1 1 1 1 1 1 1 1 1 1 1 10 7 9 1 1 1 1 1 7 1 1 1 0 0 0 0 0 0 1 1 1 9 7 1 1 1 1 1 1 1 -0 0 0 0 0 0 0 0 0 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2 2 2 2 2 2 2 2 2 16 16 16 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 \ No newline at end of file +0 0 0 0 0 0 0 0 19 14 14 14 19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 2 2 2 2 2 2 2 19 16 16 16 19 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 \ No newline at end of file diff --git a/MapFiles/test_tutorial.txt b/MapFiles/test_tutorial.txt index 80b8f73..516912b 100644 --- a/MapFiles/test_tutorial.txt +++ b/MapFiles/test_tutorial.txt @@ -10,6 +10,6 @@ 1 1 1 1 1 8 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 15 15 0 0 0 0 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 16 16 16 2 2 2 2 \ No newline at end of file +1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 14 14 14 19 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 19 15 15 15 19 0 0 0 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 19 16 16 16 19 2 2 2 \ No newline at end of file diff --git a/Resources/CommonTileset.png b/Resources/CommonTileset.png index a53ad152071a23ee7c5d111354e296c7098eec8e..03391b2ada241d026ec2278f49e5643bb049f4ba 100644 GIT binary patch delta 2108 zcmV-C2*dZ85Y-TnFn-F)-S z?99Hm@7?-kUz5DI`{wP=Z|Bd>-d*$X$A>3@UBABhRe12dr+@il@&4zRE`-&M>#n|9 zrxS|{Vg2-xt>$k(TMth>w|x%{(laXW$jS9Aed5-?O+4>b|t`#Gu`AP&6ft4TX+_0)qda`aEP=9DU;f#K*oe z+L%HoYsD81D1WE>k^;KdrAe0Z_`Cmv@7}t*9WwpDbPvyRC^UzRVxXLQHq2yPmRt2? zUkC&Kg$p2YKq!YRG!<$LY>KQID3&6)CFQmh>-(Au(_#w3;BwJ|=yPe6r$Du=%`2<9 zXa9W@@16ucS`rkmrAVMtpm^W+K=H_mLh;0xAuJ^pM}M@oAuYwDNX-S(cfD2{bzeIL zMN)zl@M9@4SB7LI+A8-dvIr;$YzRw{vandJ@ubABAAY12arVMbswgdU@ z{)4iAPY73TOn*pvhCQ(DgYQE)_~UE6MtJ$r_j?!dtQG1RU@0uBQDAL#LS1$9+i}mE2bg$|II}nl=JvC5SEpAWS4Jw-7?c!QsZb zvwxNuD2Y&`P!eRpIF26hj0L3&R1He1ELj@$6kN`|_m2 z+9-0nuT(|ixFpw;DvQeK3T8AYF=#^s`r`>MCk6%DQe<(kUBF}u^p>ThLP14&G9JnG zqy%RZNBdt!}r|^WpTW0AB1-|Dg;(wK#5~l{2tbtxCq2Pda3JQL|57?YCJb*eu zq1F;Bv&3p%IJj8tYwW|NArHAcFtAV2P^jy|0hfM2HF!+%RFAzeCALzmDsd^UC&xHE z7E=$oJX#vLPqVslz1PWO4s)fY3D1U=>WCh;_5Er0T;sqp3yckZ8^CkHJ2;mp6o1$> z@xmYfKu#zU5O9z5qID%+gUbcQ zF2RwmFbV|@j_Bn*j_n%gEhuQolC^Mv&_{$qm1%)dYfc2JM+Wt&mX)A94yEtm5_LVA z3$wDrm<(^yG6O{d5>u*p1|a~kWZVf*PzM&+X7b1OPe_8BvY>F6gi!E#ihm4ri~I=H zYbhM$(3WB;lcvNP0FR9SwWW*+MRPq`N}Lr6rmQ?DX~8~sOi9@VYk@wNenOj;2xx&m zwqN40M@orfDYXQz$n2}6l-P2mQfe+`R2CR&amDRZaOGJwqoMaHea4}cg4}@~3zB_y z@PIp^jvwtu(a?va;Ox{Bv13_^ntfwiQBXV}pbuOe7=J*+fv}SgS!fWNx(IP`||oNga(#^ z^N4}bfaFYCy6O|>+}xT>CU-Ru@BN2F2;$4GDk-1v4m2jZp>y z!F#D4--SMZo!;F^=l7ocbL&0+4X;2Ls|dv_Ag84u6mPc0$A8FEV(zZ!eTCv697~BE zueV)Fb6<01DP9P)A6VDg+S<%+obOM#Y`*i)wNKI9q%}8mv&Ffu*uY~u{?bxnOd7lv zgFs-9Q!Er~zrx!~+&rdcbGYf8J1BEeW|2~2%l8eH5_<}g+Sul*AXyR=?_!YP%~k2X z{<%W$QW&paGk>|nWD7sAH&HCJD) z(}|U(uyy*#wE3G)x5AUp@7_a$^o+_oa&jxnIC9LTuZ#wuSP)|ELqJI(jIb&cqP3h* zENh6tS~w`y%G4|cp8s?C_bhIMx-V@!F=)3P6irEEL!slKfZ+e9J_}hEN8fk=@v*Or zHm1qX_BQp{_elwySMIahfM!3-NUmS3e6#-7$~Qn3v(Hl`o8AEw3vc0xLmX#`dnJ&DNrqI^U7-O zI&j~_yC;E*Rg{)Fd7)bF3$s2t z0BM2DSc=CoP~gx|JOQ6tkF|O10|m!2mJBx(4lFm6p;BU0B!?_njAkig%jgURCpnb+ zN{uTqOMl@?)m&I?<2R-ZG0>;DvD{En%l6(X@mQ|M+R=N)(S#7@&Qm=8y!IJR1I^Kc z|3f*jFNDk2XFnu8!yedn{`(M~`0=$~BmDN!4|*5ztQG1RU@04&Dzc^_!2P-fMZ421)%P-YdH!`hJK~oLQL%bMx8RE3>PQDQR9^3E%*#k}zLN4u88 ztbb(=N+Q%KlmuBYj-v-Xxt`u9D->%eV?pTxRfCc$3m3=dFE3f@P}`$WJbM?+zC7u$ zHj3QtD^-y=F3I(z%Azv5f*B1;4B8NZ{&<4Ri9vz36j>Z>7ckiZy=5t>P*72xj7M@k zDZ$xWcz-3Q#Hqn0YoM1(C^(?Kf`Z@g12(4&51>v^ zsI|n(EU}sw4lY*v8vAf*$U`m<4D3@h6zaNgz@;Bh4IWcG)nji=iLDf?N?eNT$uSO( z#neMCkCsO6(`;;C>vi&&!(3@;!n0weI--YdeSg|L*Eq1u0%L>U2Jl?)4$dVC1%Eb8 zyzs|AkQ0go1l%LNXkCfd;BrCnxNT`+z%v*xRWKjF1_*wd2Ty)mD4Oy;&n+lkuyi6g zaBV_b-@Sk$oiBBPLKoZAQY7Vho>3^C{-AK)PjVa93Zp9vS7M^T zE{xA*#(i0c9fqO#ayY2}y8M78LH15DGp|k$-`1ksqOY zEro*|+EOfK(v(;O;E{1lTgsSFG}oi0#95(W%F2V17VLA!l$2et7U*N?C$wpafEMUu z`z0QGq?9<8QcLiP%)UxWi7i(urRGvbWr3jv0Nz5O|ukF`YXknddTHjH6!=Qa>%uE@oKMOZ@>6JSX*10k+HM06PA~k z-E!C0*Td$yb8Y{>pE@-6-rZkcGTT;<9m`VG>>JyPg5m)Iec{6$7&j)90Pp66qFI6ki9&(C91M*q613u=;Diy5 z1PDPu8^ECNln8}`p?^@NxKk9Am5Wzf4gYZH{+Y!{0dWv;|JbG9+Wrs^azI&KU3F($ zk~N{F@GJ}OX`qL3Q#Xe9bm3W+Ib?f-Q0PZEAZ$Yrv~MmbJSE0&NB}e_m_cD`j4}`i z-b?NHF7)~9^u3*Qe$UB2r| defineTiles() { .withTileType(TileType.NOT_PASSABLE); mapTiles.add(solidFloatingTile); + + + // Sand + Frame sandFrame = new FrameBuilder(getSubImage(4, 0), 0) + .withScale(tileScale) + .build(); + + MapTileBuilder sandTile = new MapTileBuilder(sandFrame) + .withTileType(TileType.NOT_PASSABLE); + + mapTiles.add(sandTile); + return mapTiles; } } From c2b17d121ecdd701edaaf6f732502c772bc361ec Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 15:53:22 -0500 Subject: [PATCH 128/164] Added Ctrl to KeyboardAction.GAME_CROUCH --- Team A2/Test Cases/Test Case SCP-57.md | 2 +- src/Engine/GamePanel.java | 2 +- src/Engine/Key.java | 3 +- src/Engine/Keyboard.java | 78 ++++++++++++++++---------- src/Engine/KeyboardAction.java | 2 +- 5 files changed, 52 insertions(+), 35 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index a760d57..a2b91fe 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -28,7 +28,7 @@ Functionality of `Player.java` tested: |6| Tap `Space/W/Up Arrow` | The player short-jumps. The player then falls back down after the button is let go and lands on the ground|| |7|Hold `Space/W/Up Arrow` | The player high-jumps. The player falls back down after a certain height and and falls back down to the ground|| |8|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|| -|9|Hold `ctrl`|The player crouches|| +|9|Hold `ctrl/W/Down Arrow`|The player crouches|| |10|Tap `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|| |11|Tap `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|| |12|Tap `A/Left Arrow`, then tap `e` (*Attack Button*)|The player faces to the left, and attacks, sending a projectile to the left|| diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index bc6d7fd..0e95d34 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -56,7 +56,7 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { this.setSize(Config.WIDTH, Config.HEIGHT); // attaches Keyboard class's keyListener to this JPanel - this.addKeyListener(Keyboard.getKeyListener()); + this.addKeyListener(new Keyboard()); graphicsHandler = new GraphicsHandler(); diff --git a/src/Engine/Key.java b/src/Engine/Key.java index 6f69570..ad435ec 100644 --- a/src/Engine/Key.java +++ b/src/Engine/Key.java @@ -45,7 +45,8 @@ public enum Key { NINE(57), ZERO(48), SPACE(32), - ESC(27); + ESC(27), + CTRL(17); private int keyCode; Key(int keyCode) { diff --git a/src/Engine/Keyboard.java b/src/Engine/Keyboard.java index 24a3971..f5fc5f6 100644 --- a/src/Engine/Keyboard.java +++ b/src/Engine/Keyboard.java @@ -10,46 +10,33 @@ * This class is used throughout the engine for detecting keyboard state * This includes if a key is pressed, if a key is not pressed, and if multiple keys are pressed/not pressed at the same time */ -public class Keyboard { +public class Keyboard extends KeyAdapter { - // hashmaps keep track of if a key is currently down or up private static final Set keysDown; - private static final KeyListener keyListener; - static { - keyListener = new KeyAdapter() { - - @Override - public void keyPressed(KeyEvent e) { - keysDown.add(e.getKeyCode()); - } - - @Override - public void keyReleased(KeyEvent e) { - keysDown.remove(e.getKeyCode()); - } - }; - keysDown = new HashSet<>(); } - // prevents Keyboard from being instantiated -- it's my way of making a "static" class like C# has - private Keyboard() { } - - public static KeyListener getKeyListener() { - return keyListener; - } + @Override + public void keyPressed(KeyEvent keyEvent) { + keysDown.add(keyEvent.getKeyCode()); + } - // returns if a key is currently being pressed - public static boolean isKeyDown(Key key) { - return keysDown.contains(key.getKeyCode()); - } + @Override + public void keyReleased(KeyEvent keyEvent) { + keysDown.remove(keyEvent.getKeyCode()); + } + + // returns if a key is currently being pressed + public static boolean isKeyDown(Key key) { + return keysDown.contains(key.getKeyCode()); + } - // returns if a key is currently not being pressed - public static boolean isKeyUp(Key key) { - return !keysDown.contains(key.getKeyCode()); - } + // returns if a key is currently not being pressed + public static boolean isKeyUp(Key key) { + return !keysDown.contains(key.getKeyCode()); + } /** * Returns if one of the keys is down @@ -64,4 +51,33 @@ public static boolean isKeyDown(int... keyCode) { } return false; } + // +// // hashmaps keep track of if a key is currently down or up +// private static final Set keysDown; +// +// private static final KeyListener keyListener; +// +// static { +// keyListener = new KeyAdapter() { +// +// @Override +// public void keyPressed(KeyEvent e) { +// keysDown.add(e.getKeyCode()); +// System.out.println(e.getKeyCode()); +// } +// +// @Override +// public void keyReleased(KeyEvent e) { +// keysDown.remove(e.getKeyCode()); +// } +// }; +// +// keysDown = new HashSet<>(); +// } +// +// // prevents Keyboard from being instantiated -- it's my way of making a "static" class like C# has +// private Keyboard() { } +// + + } diff --git a/src/Engine/KeyboardAction.java b/src/Engine/KeyboardAction.java index f034845..4b12c43 100644 --- a/src/Engine/KeyboardAction.java +++ b/src/Engine/KeyboardAction.java @@ -16,7 +16,7 @@ public enum KeyboardAction { GAME_JUMP(Key.W,Key.SPACE,Key.UP), GAME_INSTRUCTIONS(Key.X), GAME_INTERACT(Key.SPACE), - GAME_CROUCH(Key.S,Key.DOWN), + GAME_CROUCH(Key.S,Key.DOWN,Key.CTRL), GAME_ATTACK(Key.E), GAME_SPRINT(Key.SHIFT), GAME_RESPAWN(Key.SPACE); From 363946011b5109f368f669d31f995b0549664ec2 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 15:54:06 -0500 Subject: [PATCH 129/164] Fixed Typo --- Team A2/Test Cases/Test Case SCP-57.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index a2b91fe..ce72d98 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -28,7 +28,7 @@ Functionality of `Player.java` tested: |6| Tap `Space/W/Up Arrow` | The player short-jumps. The player then falls back down after the button is let go and lands on the ground|| |7|Hold `Space/W/Up Arrow` | The player high-jumps. The player falls back down after a certain height and and falls back down to the ground|| |8|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|| -|9|Hold `ctrl/W/Down Arrow`|The player crouches|| +|9|Hold `ctrl/S/Down Arrow`|The player crouches|| |10|Tap `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|| |11|Tap `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|| |12|Tap `A/Left Arrow`, then tap `e` (*Attack Button*)|The player faces to the left, and attacks, sending a projectile to the left|| From a4334c8dd92d8984da4b3a63419ec70763dd51ec Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 15:57:47 -0500 Subject: [PATCH 130/164] Passed Test Case SCP-60 --- Team A2/Test Cases/Test Case SCP-60.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-60.md b/Team A2/Test Cases/Test Case SCP-60.md index bf36772..a7a9aa6 100644 --- a/Team A2/Test Cases/Test Case SCP-60.md +++ b/Team A2/Test Cases/Test Case SCP-60.md @@ -10,12 +10,12 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens || -|2| Enter Options Menu | The User will enter option menu| | -|3| Use the back to main menu button at bottom | The User will exit the options screen using the back to menu feature at the bottom | | -|4| Enter Main Menu Screen | The User will enter the Main Menu screen | | +|1| Run the game| The game successfully opens |Pass| +|2| Enter Options Menu | The User will enter option menu|Pass| +|3| Use the back to main menu button at bottom | The User will exit the options screen using the back to menu feature at the bottom |Pass| +|4| Enter Main Menu Screen | The User will enter the Main Menu screen |Pass| ### Test Completion -- **Tester**: -- **Date of Test**: -- **Test Result**: \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 3:57 PM +- **Test Result**: Passed \ No newline at end of file From 45e6a21cb1685933d0f37bac4fc306ee77d75871 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 15:59:32 -0500 Subject: [PATCH 131/164] Passed Test Case SCP-51 --- Team A2/Test Cases/Test Case SCP-51.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-51.md b/Team A2/Test Cases/Test Case SCP-51.md index efa0386..95d43ec 100644 --- a/Team A2/Test Cases/Test Case SCP-51.md +++ b/Team A2/Test Cases/Test Case SCP-51.md @@ -10,12 +10,12 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens || -|2| Hit Quit Option | The User will select the quit option in the main menu | | -|3| The game will close | The game will close | | +|1| Run the game| The game successfully opens |Pass| +|2| Hit Quit Option | The User will select the quit option in the main menu |Pass| +|3| The game will close | The game will close |Pass| ### Test Completion -- **Tester**: -- **Date of Test**: -- **Test Result**: \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 3:59 PM +- **Test Result**: Passed \ No newline at end of file From 7b012cb25e8f72ee4cad208caa8bba4ce6e8640a Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 16:16:30 -0500 Subject: [PATCH 132/164] Fixing Merge oooo boy --- src/Screens/OptionsScreen.java | 1 + src/Tilesets/CommonTileset.java | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Screens/OptionsScreen.java b/src/Screens/OptionsScreen.java index 757d8a5..53d7330 100644 --- a/src/Screens/OptionsScreen.java +++ b/src/Screens/OptionsScreen.java @@ -4,6 +4,7 @@ import Engine.GamePanel; import Engine.GraphicsHandler; import Engine.ImageLoader; +import Game.GameState; import GameObject.SpriteSheet; import Maps.LevelSelectMap; import Menu.Direction; diff --git a/src/Tilesets/CommonTileset.java b/src/Tilesets/CommonTileset.java index 6662d7c..05d0cfe 100644 --- a/src/Tilesets/CommonTileset.java +++ b/src/Tilesets/CommonTileset.java @@ -241,27 +241,28 @@ public ArrayList defineTiles() { mapTiles.add(floatingPlatformTile); - // solid floating block - Frame solidFloatingFrame = new FrameBuilder(getSubImage(3, 5), 0) + // Sand + Frame sandFrame = new FrameBuilder(getSubImage(4, 0), 0) .withScale(tileScale) - .withBounds(0, 6, 16, 3) .build(); - MapTileBuilder solidFloatingTile = new MapTileBuilder(solidFloatingFrame) + MapTileBuilder sandTile = new MapTileBuilder(sandFrame) .withTileType(TileType.NOT_PASSABLE); - mapTiles.add(solidFloatingTile); + mapTiles.add(sandTile); - // Sand - Frame sandFrame = new FrameBuilder(getSubImage(4, 0), 0) + // solid floating block + Frame solidFloatingFrame = new FrameBuilder(getSubImage(3, 5), 0) .withScale(tileScale) + .withBounds(0, 6, 16, 3) .build(); - MapTileBuilder sandTile = new MapTileBuilder(sandFrame) + MapTileBuilder solidFloatingTile = new MapTileBuilder(solidFloatingFrame) .withTileType(TileType.NOT_PASSABLE); - mapTiles.add(sandTile); + mapTiles.add(solidFloatingTile); + return mapTiles; } From 02ea089b79949a81f4931e023310d41c648ae505 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 16:17:58 -0500 Subject: [PATCH 133/164] Fixed Block ID in Map 1 --- MapFiles/test_map.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MapFiles/test_map.txt b/MapFiles/test_map.txt index 5b183d8..23f66ec 100644 --- a/MapFiles/test_map.txt +++ b/MapFiles/test_map.txt @@ -7,7 +7,7 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 18 1 1 1 1 17 1 5 11 11 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 13 11 6 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 18 1 1 1 1 1 1 +1 1 1 1 1 8 8 8 1 1 1 1 1 1 9 1 1 1 1 1 7 1 1 1 1 1 1 20 1 1 1 1 1 1 1 1 1 1 1 8 8 8 1 1 1 1 1 0 0 0 0 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 19 19 14 14 14 14 19 19 0 0 From 36e0a031b0adb825271ef881486830287b481f87 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 16:18:57 -0500 Subject: [PATCH 134/164] Passed Test Case SCP-34 --- Team A2/Test Cases/Test Case SCP-34.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-34.md b/Team A2/Test Cases/Test Case SCP-34.md index 2c3753a..b9b69bb 100644 --- a/Team A2/Test Cases/Test Case SCP-34.md +++ b/Team A2/Test Cases/Test Case SCP-34.md @@ -10,13 +10,13 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game | The game successfully opens || -|2| Enter level 1 | The User will enter level 1 | | -|3| Find new map tile next to water tile | User will find the new map tile, sand, next to water tiles in game | | -|4| User will exit the game | The User will properly exit the game | | +|1| Run the game | The game successfully opens |Passed| +|2| Enter level 1 | The User will enter level 1 |Passed| +|3| Find new map tile next to water tile | User will find the new map tile, sand, next to water tiles in game |Passed| +|4| User will exit the game | The User will properly exit the game |Passed| ### Test Completion -- **Tester**: [TESTER NAME] -- **Date of Test**: DATE OF TEST -- **Test Result**: TEST RESULT \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 +- **Test Result**: Passed \ No newline at end of file From 3dfdfe1bc55e76e1458214c7600b8d34517df23f Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Mon, 29 Nov 2021 16:22:10 -0500 Subject: [PATCH 135/164] Passed Test Case SCP-47 --- Team A2/Test Cases/Test Case SCP-47.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-47.md b/Team A2/Test Cases/Test Case SCP-47.md index 0a0f472..18c7f0d 100644 --- a/Team A2/Test Cases/Test Case SCP-47.md +++ b/Team A2/Test Cases/Test Case SCP-47.md @@ -10,13 +10,13 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens || -|2| Enter Level 1 | The User will enter level 1 | | -|3| Go through the level and test implemented floating block | The User will go through the level completing it while using the floating block | | -|4| Complete level 1 | The User will complete level 1 | | -|5| Exit the game | The User will exit the game | | +|1| Run the game| The game successfully opens |Passed| +|2| Enter Level 1 | The User will enter level 1 |Passed| +|3| Go through the level and test implemented floating block | The User will go through the level completing it while using the floating block |Passed| +|4| Complete level 1 | The User will complete level 1 |Passed| +|5| Exit the game | The User will exit the game |Passed| ### Test Completion -- **Tester**: -- **Date of Test**: -- **Test Result**: \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/29/2021 4:21 PM +- **Test Result**: Passed \ No newline at end of file From bc59bb9f3439081c980f00bf280d8e6a6f13f666 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Mon, 29 Nov 2021 16:25:15 -0500 Subject: [PATCH 136/164] Added a difficulty holder that sets player health based on difficulty --- src/Engine/DifficultyHolder.java | 20 ++++++++++++++++++++ src/Engine/GamePanel.java | 10 ++++++++-- src/Level/Player.java | 5 +++++ src/Screens/DifficultySelectScreen.java | 15 ++++++++++++--- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/Engine/DifficultyHolder.java diff --git a/src/Engine/DifficultyHolder.java b/src/Engine/DifficultyHolder.java new file mode 100644 index 0000000..1c11dc3 --- /dev/null +++ b/src/Engine/DifficultyHolder.java @@ -0,0 +1,20 @@ +package Engine; + +public class DifficultyHolder + +{ + private int difficulty = 3; + public DifficultyHolder(int difficulty) + { + this.difficulty = difficulty; + } + + public int getDifficulty() + { + return difficulty; + } + public void setDifficulty(int difficulty) + { + this.difficulty = difficulty; + } +} diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 313e7a1..d8c9fe3 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -47,6 +47,7 @@ public class GamePanel extends JPanel { public static Clip clip; private Point previousMousePoint = new Point(0,0); private JLabel health; + private static DifficultyHolder difficultyHolder; /* @@ -69,7 +70,7 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { screenManager = new ScreenManager(); coordinator = c1; - + difficultyHolder = new DifficultyHolder(0); @@ -89,6 +90,11 @@ public void actionPerformed(ActionEvent e) { timer.setRepeats(true); } + public static DifficultyHolder getDifficultyHolder() + { + return difficultyHolder; + } + public static ScreenCoordinator getScreenCoordinator() { return coordinator; } @@ -196,7 +202,7 @@ else if(Player.playerHealth == 1) { } if(coordinator.getGameState() == GameState.MENU) { - Player.playerHealth = 3; + Player.playerHealth = difficultyHolder.getDifficulty(); } } diff --git a/src/Level/Player.java b/src/Level/Player.java index a54b4da..7e771b1 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -526,6 +526,11 @@ public void setFacingDirection(Direction facingDirection) { public void setLevelState(LevelState levelState) { this.levelState = levelState; } + + public void setPlayerHealth(int health) + { + playerHealth = health; + } public void addListener(PlayerListener listener) { listeners.add(listener); diff --git a/src/Screens/DifficultySelectScreen.java b/src/Screens/DifficultySelectScreen.java index 90f1b5a..1bbb7ec 100644 --- a/src/Screens/DifficultySelectScreen.java +++ b/src/Screens/DifficultySelectScreen.java @@ -1,5 +1,6 @@ package Screens; +import Engine.DifficultyHolder; import Engine.GamePanel; import Game.GameState; import Maps.TitleScreenMap; @@ -8,13 +9,21 @@ import Menu.MenuOption; public class DifficultySelectScreen extends Menu { + + private final DifficultyHolder difficultyHolder; + + //these values also correspond to the health given at each difficulty + private final static int NORMAL = 3; + private final static int HARD = 2; + private final static int HARDCORE = 1; public DifficultySelectScreen() { + difficultyHolder = GamePanel.getDifficultyHolder(); MenuOption[][] menu = new MenuOption[][]{ { - new MenuOption("Normal", 100, 150, null), - new MenuOption("Hard", 320, 150, null), - new MenuOption("Hardcore", 500, 150, null) + new MenuOption("Normal", 100, 150, () -> difficultyHolder.setDifficulty(NORMAL)), + new MenuOption("Hard", 320, 150, () -> difficultyHolder.setDifficulty(HARD)), + new MenuOption("Hardcore", 500, 150, () -> difficultyHolder.setDifficulty(HARDCORE)) }, { new MenuOption( From 7b7911e8526ee8d113b0a1bbdda4a3606d91ebd9 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Mon, 29 Nov 2021 16:29:07 -0500 Subject: [PATCH 137/164] Fixed the starting difficulty --- src/Engine/GamePanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index d8c9fe3..d878f24 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -70,7 +70,7 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { screenManager = new ScreenManager(); coordinator = c1; - difficultyHolder = new DifficultyHolder(0); + difficultyHolder = new DifficultyHolder(3); From 8a909853b20649da0dbc9b934893d2f254dd6b34 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Mon, 29 Nov 2021 16:40:59 -0500 Subject: [PATCH 138/164] Hardcore mode restarts the user on the first level --- src/Screens/LevelLoseScreen.java | 13 +++++++++++-- src/Screens/PlayLevelScreen.java | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Screens/LevelLoseScreen.java b/src/Screens/LevelLoseScreen.java index 413098b..d9b1825 100644 --- a/src/Screens/LevelLoseScreen.java +++ b/src/Screens/LevelLoseScreen.java @@ -1,6 +1,7 @@ package Screens; import Engine.Drawable; +import Engine.GamePanel; import Engine.KeyboardAction; import Level.Player; import Level.PlayerAttack; @@ -25,8 +26,16 @@ public LevelLoseScreen(PlayLevelScreen playLevelScreen) { public void update() { super.update(); if (KeyboardAction.GAME_RESPAWN.isDown()) { - playLevelScreen.resetLevel(); - Player.playerHealth = 3; + // if the player is in hardcore difficulty restart them at the first level otherwise restart them on the current level + if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + { + playLevelScreen.loadMap(0); + } + else + { + playLevelScreen.resetLevel(); + } + Player.playerHealth = GamePanel.getDifficultyHolder().getDifficulty(); PlayerAttack.dogHealth = 8; } } diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 5d397f3..b7957c5 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -176,7 +176,7 @@ public void nextLevel() { * * @param index index of map to load */ - private void loadMap(int index) { + protected void loadMap(int index) { if(index < MAPS.length) { currentMap = index; //Load map using the MapFactory From 15bd3e4762aa737f2792a5f32f0a231efa2baa90 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 29 Nov 2021 19:09:24 -0500 Subject: [PATCH 139/164] Added Entry to Test Case SCP-56 --- Team A2/Test Cases/Test Case SCP-56.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index c32e8ac..7e52241 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -34,6 +34,7 @@ Instances of tests are listed in table below (template provided). Measurements l |:---:|:---|:---|:---:|:---:|:---:|:---:|:---:|:---:| |[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[MEASURE 5]|[PASS/FAIL]| |11/29/2021 10:41 AM|Thomas Kwashnak|Kubuntu 21.10 Laptop, Intel i7 CPU, NVIDIA MX330 GPU|\~ 2 seconds|\~1 second|\~1 second|\~1-2 seconds|~3 seconds|Pass. Game runs at expected speed| +|11/29/2021 7:05 PM|Thomas Kwashnak|Windows 11 Desktop, Ryzen 5 3600 CPU, Nvidia RTX 2060 GPU|\~ 1.5 Seconds|\~ 1 second|\~ 1 second|\~1-2 seconds|3 seconds|Pass. Game runs at expected speed| [comment]: <> (Add test rows to end here ^^) From 226bdfa3e54be8e74beaea8a7d55616ea952164c Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 29 Nov 2021 19:19:42 -0500 Subject: [PATCH 140/164] Final Screen now displays per-level times --- src/Level/Player.java | 6 ------ src/Menu/Menu.java | 10 +--------- src/Screens/GameScoreScreen.java | 8 +++++--- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index d8e79cf..ed6c435 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -194,10 +194,4 @@ public void addListener(PlayerListener listener) { public void setJumpHeight(int height) { this.jumpHeight = height; } - - - public void setPlayerHealth(int health) - { - PLAYER_HEALTH = health; - } } diff --git a/src/Menu/Menu.java b/src/Menu/Menu.java index bbeb31f..9f25c20 100644 --- a/src/Menu/Menu.java +++ b/src/Menu/Menu.java @@ -7,7 +7,6 @@ import java.awt.*; import java.awt.event.MouseEvent; -import java.util.List; public abstract class Menu extends Screen implements SelectableMenu { @@ -197,14 +196,7 @@ protected void setBackground(Map background) { this.background = background; } - protected void setDrawables(Drawable[] drawables) { + protected void setDrawables(Drawable... drawables) { this.drawables = drawables; } - - protected void setDrawables(List drawables) { - this.drawables = new Drawable[drawables.size()]; - for(int i = 0; i < this.drawables.length; i++) { - this.drawables[i] = drawables.get(i); - } - } } diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index ac4f5db..911f16c 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -2,6 +2,7 @@ import Engine.Drawable; import Engine.GraphicsHandler; +import Engine.ScreenManager; import Game.TimeTracker; import Maps.GameMaps; import Maps.TitleScreenMap; @@ -22,13 +23,14 @@ public class GameScoreScreen extends Menu { COLOR_LEVEL = Color.WHITE; } - private TimeTracker timeTracker; - private SpriteFont levels; public GameScoreScreen(TimeTracker timeTracker) { - this.timeTracker = timeTracker; setBackground(new TitleScreenMap()); System.out.println(getLevels(timeTracker)); + + SpriteFont levels = new SpriteFont(getLevels(timeTracker), 30, ScreenManager.getScreenHeight() - 125, FONT_LEVEL, COLOR_LEVEL); + + setDrawables(levels); } private String getLevels(TimeTracker timeTracker) { From 6e98819c8ba93437120c964885e7fa4d71c779cb Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Mon, 29 Nov 2021 23:39:13 -0500 Subject: [PATCH 141/164] Enemy movement and projectile speed increases with difficulty --- src/Enemies/BugEnemy.java | 17 ++++++++++++++++- src/Enemies/CyborgEnemy.java | 26 +++++++++++++++++++++----- src/Enemies/DinosaurEnemy.java | 25 ++++++++++++++++++++----- src/Enemies/Dog.java | 26 +++++++++++++++++++++----- src/Engine/GamePanel.java | 2 ++ 5 files changed, 80 insertions(+), 16 deletions(-) diff --git a/src/Enemies/BugEnemy.java b/src/Enemies/BugEnemy.java index b3296a8..30ca2e3 100644 --- a/src/Enemies/BugEnemy.java +++ b/src/Enemies/BugEnemy.java @@ -1,6 +1,7 @@ package Enemies; import Builders.FrameBuilder; +import Engine.GamePanel; import Engine.ImageLoader; import GameObject.Frame; import GameObject.ImageEffect; @@ -18,7 +19,11 @@ public class BugEnemy extends Enemy { private float gravity = .5f; - private float movementSpeed = .5f; + + // different speeds depending on the difficulty + private static final float NORMAL_SPEED = 0.5f, HARD_SPEED = 0.7f, HARDCORE_SPEED = 0.9f; + float movementSpeed = NORMAL_SPEED; + private Direction startFacingDirection; private Direction facingDirection; private boolean isInAir; @@ -46,6 +51,16 @@ public void update(Player player) { float moveAmountX = 0; float moveAmountY = 0; + // set the movement speed of the enemy depending on what difficulty it selected + if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + { + movementSpeed = HARD_SPEED; + } + else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + { + movementSpeed = HARDCORE_SPEED; + } + // add gravity (if in air, this will cause bug to fall) moveAmountY += gravity; diff --git a/src/Enemies/CyborgEnemy.java b/src/Enemies/CyborgEnemy.java index 462e4db..96c2654 100644 --- a/src/Enemies/CyborgEnemy.java +++ b/src/Enemies/CyborgEnemy.java @@ -1,6 +1,7 @@ package Enemies; import Builders.FrameBuilder; +import Engine.GamePanel; import Engine.ImageLoader; import GameObject.Frame; import GameObject.ImageEffect; @@ -27,7 +28,11 @@ public class CyborgEnemy extends Enemy { // Whether or not the game is waiting for LazerBeams to launch private boolean wait = false; - protected float movementSpeed = 0.5f; + // different speeds depending on the difficulty + private static final float NORMAL_SPEED = 0.5f, HARD_SPEED = 0.7f, HARDCORE_SPEED = 0.9f; + float movementSpeed = NORMAL_SPEED; + private static final float NORMAL_LAZER_SPEED = 1.5f, HARD_LAZER_SPEED = 1.7f, HARDCORE_LAZER_SPEED = 1.9f; + private Direction startFacingDirection; protected Direction facingDirection; protected boolean isInAir; @@ -70,7 +75,20 @@ public void initialize() { public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; + float lazerMovementSpeed = NORMAL_LAZER_SPEED; + // set the movement speed of the enemy and lazer attack depending on what difficulty it selected + if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + { + movementSpeed = HARD_SPEED; + lazerMovementSpeed = HARD_LAZER_SPEED; + } + else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + { + movementSpeed = HARDCORE_SPEED; + lazerMovementSpeed = HARDCORE_LAZER_SPEED; + } + // if shoot timer is up and cyborg is not currently shooting, set its state to SHOOT if (shootTimer.isTimeUp() && cyborgState != cyborgState.SHOOT) { cyborgState = cyborgState.SHOOT; @@ -112,16 +130,14 @@ public void update(Player player) { // define where LazerBeam will spawn on map (x location) relative to cyborg enemy's location // and define its movement speed int LazerBeamX; - float movementSpeed; LazerBeamX = Math.round(getX()); - movementSpeed = 1.5f; // define where LazerBeam will spawn on the map (y location) relative to cyborg enemy's location int LazerBeamY = Math.round(getY() + 15); // create LazerBeam enemy - LazerBeam LazerBeam = new LazerBeam(new Point(LazerBeamX + 20, LazerBeamY), movementSpeed, 1000); - LazerBeam LazerBeam2 = new LazerBeam(new Point(LazerBeamX - 10, LazerBeamY), -movementSpeed, 1000); + LazerBeam LazerBeam = new LazerBeam(new Point(LazerBeamX + 20, LazerBeamY), lazerMovementSpeed, 1000); + LazerBeam LazerBeam2 = new LazerBeam(new Point(LazerBeamX - 10, LazerBeamY), -lazerMovementSpeed, 1000); // add LazerBeam enemy to the map for it to offically spawn in the level map.addProjectile(LazerBeam); diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index ce79082..81711dc 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -1,6 +1,7 @@ package Enemies; import Builders.FrameBuilder; +import Engine.GamePanel; import Engine.ImageLoader; import GameObject.Frame; import GameObject.ImageEffect; @@ -24,7 +25,11 @@ public class DinosaurEnemy extends Enemy { protected Point startLocation; protected Point endLocation; - protected float movementSpeed = 1f; + // different speeds depending on the difficulty + private static final float NORMAL_SPEED = 1f, HARD_SPEED = 1.2f, HARDCORE_SPEED = 1.4f; + float movementSpeed = NORMAL_SPEED; + + private static final float NORMAL_FIREBALL_SPEED = 1.5f, HARD_FIREBALL_SPEED = 1.7f, HARDCORE_FIREBALL_SPEED = 1.9f; private Direction startFacingDirection; protected Direction facingDirection; protected boolean isInAir; @@ -65,7 +70,19 @@ public void initialize() { public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; + float fireballMovementSpeed = NORMAL_FIREBALL_SPEED; + // set the movement speed of the enemy and fireball attack depending on what difficulty it selected + if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + { + movementSpeed = HARD_SPEED; + fireballMovementSpeed = HARD_FIREBALL_SPEED; + } + else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + { + movementSpeed = HARDCORE_SPEED; + fireballMovementSpeed = HARDCORE_FIREBALL_SPEED; + } // if shoot timer is up and dinosaur is not currently shooting, set its state to SHOOT if (shootTimer.isTimeUp() && dinosaurState != DinosaurState.SHOOT) { dinosaurState = DinosaurState.SHOOT; @@ -107,20 +124,18 @@ public void update(Player player) { // define where fireball will spawn on map (x location) relative to dinosaur enemy's location // and define its movement speed int fireballX; - float movementSpeed; if (facingDirection == Direction.RIGHT) { fireballX = Math.round(getX()) + getScaledWidth(); - movementSpeed = 1.5f; } else { fireballX = Math.round(getX()); - movementSpeed = -1.5f; + fireballMovementSpeed = -fireballMovementSpeed; } // define where fireball will spawn on the map (y location) relative to dinosaur enemy's location int fireballY = Math.round(getY()) + 4; // create Fireball enemy - Fireball fireball = new Fireball(new Point(fireballX, fireballY), movementSpeed, 1000); + Fireball fireball = new Fireball(new Point(fireballX, fireballY), fireballMovementSpeed, 1000); // add fireball enemy to the map for it to offically spawn in the level map.addProjectile(fireball); diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index 5f123fa..c257522 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -1,6 +1,7 @@ package Enemies; import Builders.FrameBuilder; +import Engine.GamePanel; import Engine.ImageLoader; import GameObject.Frame; import GameObject.SpriteSheet; @@ -23,7 +24,11 @@ public class Dog extends Enemy { protected Point startLocation; protected Point endLocation; - protected float movementSpeed = 1f; + // different speeds depending on the difficulty + private static final float NORMAL_SPEED = 1f, HARD_SPEED = 1.2f, HARDCORE_SPEED = 1.4f; + float movementSpeed = NORMAL_SPEED; + + private static final float NORMAL_BONE_SPEED = 1.5f, HARD_BONE_SPEED = 1.7f, HARDCORE_BONE_SPEED = 1.9f; private Direction startFacingDirection; protected Direction facingDirection; protected boolean isInAir; @@ -63,6 +68,19 @@ public void initialize() { public void update(Player player) { float startBound = startLocation.x; float endBound = endLocation.x; + float boneMovementSpeed = NORMAL_BONE_SPEED; + + // set the movement speed of the enemy and fireball attack depending on what difficulty it selected + if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + { + movementSpeed = HARD_SPEED; + boneMovementSpeed = HARD_BONE_SPEED; + } + else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + { + movementSpeed = HARDCORE_SPEED; + boneMovementSpeed = HARDCORE_BONE_SPEED; + } // if shoot timer is up and dog is not currently shooting, set its state to SHOOT if (shootTimer.isTimeUp() && dogState != dogState.SHOOT) { @@ -105,20 +123,18 @@ public void update(Player player) { // define where bone will spawn on map (x location) relative to dog enemy's location // and define its movement speed int boneX; - float movementSpeed; if (facingDirection == Direction.RIGHT) { boneX = Math.round(getX()) + getScaledWidth(); - movementSpeed = 1.5f; } else { boneX = Math.round(getX()); - movementSpeed = -1.5f; + boneMovementSpeed = -boneMovementSpeed; } // define where bone will spawn on the map (y location) relative to dog enemy's location int boneY = Math.round(getY()) + 4; // create bone enemy - Bone bone = new Bone(new Point(boneX, boneY), movementSpeed, 2000); + Bone bone = new Bone(new Point(boneX, boneY), boneMovementSpeed, 2000); // add bone enemy to the map for it to offically spawn in the level map.addProjectile(bone); diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index df40744..8ae1c9e 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -164,6 +164,8 @@ else if(Player.PLAYER_HEALTH == 1) { } } + // Each difficulty is represented as an integer while also representing the amount of health the user has + // normal is 3 hard is 2 and hardcore is 1 if(coordinator.getGameState() == GameState.MENU) { Player.PLAYER_HEALTH = difficultyHolder.getDifficulty(); } From aa288f440b11e03ba5e230c5790a5afd2e39f279 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 00:03:58 -0500 Subject: [PATCH 142/164] Selecting a difficulty returns the user to the main menu --- src/Menu/MenuOption.java | 19 +++++++++++++++++++ src/Screens/DifficultySelectScreen.java | 10 ++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Menu/MenuOption.java b/src/Menu/MenuOption.java index 5c28463..22fdff0 100644 --- a/src/Menu/MenuOption.java +++ b/src/Menu/MenuOption.java @@ -1,7 +1,9 @@ package Menu; import Engine.Drawable; +import Engine.GamePanel; import Engine.GraphicsHandler; +import Game.GameState; import java.awt.*; import java.awt.event.MouseEvent; @@ -30,6 +32,8 @@ public class MenuOption implements Drawable { private final int y; private int width; private int height; + + private CloseOnExecute actionAfterExecute = CloseOnExecute.REMAINOPEN; public MenuOption(String text, int x, int y, MenuItemListener listener) { this(text, x, y); @@ -42,6 +46,12 @@ public MenuOption(String text, int x, int y) { this.x = x; this.y = y; } + + public MenuOption(String text, int x, int y, MenuItemListener listener, CloseOnExecute closeOnExecute) { + this(text, x, y); + setListener(listener); + actionAfterExecute = closeOnExecute; + } public void setNeighborItem(MenuOption item, Direction direction) { neighbors[direction.getIndex()] = item; @@ -148,9 +158,18 @@ public void execute() { if (listener != null) { listener.event(); } + if (actionAfterExecute == CloseOnExecute.CLOSE) + { + GamePanel.getScreenCoordinator().setGameState(GameState.MENU); + } } public void setSelectFunction(SelectableMenu function) { this.selectableMenu = function; } + + public enum CloseOnExecute + { + REMAINOPEN, CLOSE; + } } diff --git a/src/Screens/DifficultySelectScreen.java b/src/Screens/DifficultySelectScreen.java index 1bbb7ec..7ee2bdc 100644 --- a/src/Screens/DifficultySelectScreen.java +++ b/src/Screens/DifficultySelectScreen.java @@ -7,6 +7,7 @@ import Menu.Menu; import Menu.Direction; import Menu.MenuOption; +import Menu.MenuOption.CloseOnExecute; public class DifficultySelectScreen extends Menu { @@ -21,9 +22,9 @@ public DifficultySelectScreen() { difficultyHolder = GamePanel.getDifficultyHolder(); MenuOption[][] menu = new MenuOption[][]{ { - new MenuOption("Normal", 100, 150, () -> difficultyHolder.setDifficulty(NORMAL)), - new MenuOption("Hard", 320, 150, () -> difficultyHolder.setDifficulty(HARD)), - new MenuOption("Hardcore", 500, 150, () -> difficultyHolder.setDifficulty(HARDCORE)) + new MenuOption("Normal", 100, 150, () -> difficultyHolder.setDifficulty(NORMAL), CloseOnExecute.CLOSE), + new MenuOption("Hard", 320, 150, () -> difficultyHolder.setDifficulty(HARD), CloseOnExecute.CLOSE), + new MenuOption("Hardcore", 500, 150, () -> difficultyHolder.setDifficulty(HARDCORE), CloseOnExecute.CLOSE) }, { new MenuOption( @@ -35,6 +36,7 @@ public DifficultySelectScreen() { menu[0][0].setNeighborItem(menu[1][0], Direction.DOWN); menu[0][1].setNeighborItem(menu[1][0], Direction.DOWN); menu[0][2].setNeighborItem(menu[1][0], Direction.DOWN); - menu[1][0].setNeighborItem(menu[0][1],Direction.UP); + menu[1][0].setNeighborItem(menu[0][1], Direction.UP); } + } From af81349148eda21b885a555931a61cb59b79fbb7 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 00:25:24 -0500 Subject: [PATCH 143/164] Updated Test Case SCP-49 --- Team A2/Test Cases/Test Case SCP-49.md | 16 ++++++++++------ src/Menu/MenuOption.java | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-49.md b/Team A2/Test Cases/Test Case SCP-49.md index 55aaa73..aa1ef7d 100644 --- a/Team A2/Test Cases/Test Case SCP-49.md +++ b/Team A2/Test Cases/Test Case SCP-49.md @@ -12,13 +12,17 @@ |:---:| :--- | :---- | :---: | |1| Run the game| The game successfully opens |P| |2| Select the difficulty menu. | The difficulty menu opens. | [RESULT] | -|3| Select normal difficulty | The game lets you select normal difficulty. | [RESULT] | -|4| Go back to the main menu and start the game. | The cat is loaded into the first level with 3 health and the enemies move at their slowest speed. | [RESULT] | +|3| Select normal difficulty | The game lets you select normal difficulty and automatically puts you back to the main menu. | [RESULT] | +|4| Start the game. | The cat is loaded into the first level with 3 health and the enemies and projectiles move at their slowest speed. | [RESULT] | |5| Take projectile damage until the character dies | The cat can take 3 projectile hits before dying. | [RESULT] | -|6| Select hard difficulty and start the game | The cat is loaded into the first level with 2 health and the enemies move faster. | [RESULT] | -|7| Take projectile damage until the character dies | The cat can take 2 projectile hits before dying. | [RESULT] | -|8| Select hardcore difficulty and start the game. | The cat is loaded into the first level with 1 health and the enemies move even faster. | [RESULT] | -|9| Take damage. | The player is sent back to the main menu. | [RESULT] | +|6| Respawn and run into an enemy. | The cat instantly dies. | [RESULT] | +|7| Select hard difficulty and start the game | The cat is loaded into the first level with 2 health and the enemies move faster. | [RESULT] | +|8| Take projectile damage until the character dies | The cat can take 2 projectile hits before dying. | [RESULT] | +|9| Respawn and run into an enemy. | The cat instantly dies. | [RESULT] | +|10| Select hardcore difficulty and start the game. | The cat is loaded into the first level with 1 health and the enemies move even faster. | [RESULT] | +|11| Take damage. | The cat dies. | [RESULT] | +|12| Press escape. | The player is returned to the main menu. | [RESULT] | +|13| Load into level 6, die to any enemy, and press space. | The player is restarted at the tutorial level. | [RESULT] | ### Test Completion - **Tester**: [TESTER NAME] diff --git a/src/Menu/MenuOption.java b/src/Menu/MenuOption.java index 22fdff0..755d45b 100644 --- a/src/Menu/MenuOption.java +++ b/src/Menu/MenuOption.java @@ -158,6 +158,7 @@ public void execute() { if (listener != null) { listener.event(); } + // allows a menu option the ability to close after selecting them if (actionAfterExecute == CloseOnExecute.CLOSE) { GamePanel.getScreenCoordinator().setGameState(GameState.MENU); From 45a38b78b80b8bdd98f94f79ddecce7266d7f2c1 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 00:53:29 -0500 Subject: [PATCH 144/164] Updated Test Case SCP-49 --- Team A2/Test Cases/Test Case SCP-49.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-49.md b/Team A2/Test Cases/Test Case SCP-49.md index aa1ef7d..0102ea3 100644 --- a/Team A2/Test Cases/Test Case SCP-49.md +++ b/Team A2/Test Cases/Test Case SCP-49.md @@ -4,7 +4,7 @@ | Owner of Test | Nicholas Tourony | | Test Name | Difficulty Test | | Date of Last Revision | 11/28/2021 | -| Test Objective | Ensure that the difficulty settings change the amount of health the cat has and changes the movement speed of the enemies. | +| Test Objective | Ensure that the difficulty settings change the amount of health the cat has and changes the movement speed of the enemies and their projectiles. | ### Procedure From 1bca979639d0fd2db228b747819dd0974ec8e98d Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 12:13:40 -0500 Subject: [PATCH 145/164] Jumping ontop of enemies now kills the player --- src/Level/Player.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Level/Player.java b/src/Level/Player.java index 0d8fd8b..1717a2b 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -102,21 +102,23 @@ private void updatePlaying() { playerState = PlayerState.CROUCH; } - //Updates player to death if their health hits 0 - if (PLAYER_HEALTH <= 0) { - levelState = LevelState.DEAD; - } - inAir = true; //inAir is updated in collisions //Moves while handling collisions moveYHandleCollision(velocityY); moveXHandleCollision(absVelocityX * facing.mod); + + + //Updates player to death if their health hits 0 + if (PLAYER_HEALTH <= 0) { + levelState = LevelState.DEAD; + } } /** * Updates the player while it is dead */ private void updateDead() { + playerState = PlayerState.DEATH; if (currentFrameIndex > 0) { //Checks if it is not the first frame of the player's death animation if (map.getCamera().containsDraw(this)) { applyGravity(MAX_DEATH_FALL_VELOCITY); From 8c46ad6b9c748b3294bdc5efa1d3e23832e43805 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 12:29:12 -0500 Subject: [PATCH 146/164] Moved Collision Types to Interface structure Dog bones now causes damage --- src/Engine/Collidable.java | 20 ++++++++++++++++++++ src/Engine/CollisionType.java | 9 --------- src/GameObject/AnimatedSprite.java | 9 ++++++--- src/GameObject/Rectangle.java | 8 +++++--- src/Level/Enemy.java | 5 ++--- src/Level/MapEntity.java | 10 ---------- src/Level/Player.java | 15 +++++++++------ src/Level/Projectile.java | 9 ++++++--- src/Projectiles/Bone.java | 9 ++++++--- 9 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 src/Engine/Collidable.java delete mode 100644 src/Engine/CollisionType.java diff --git a/src/Engine/Collidable.java b/src/Engine/Collidable.java new file mode 100644 index 0000000..d9623e1 --- /dev/null +++ b/src/Engine/Collidable.java @@ -0,0 +1,20 @@ +package Engine; + +import GameObject.IntersectableRectangle; + +/** + * Indicates that an object is able to collide + * @author Thomas Kwashnak + */ +public interface Collidable extends IntersectableRectangle { + boolean intersects(Collidable other); + boolean overlaps(Collidable other); + + interface InstantDeath extends Collidable {} + interface Damage extends Collidable { + int getDamage(); + } + interface PreventJump extends Collidable { + int getJumpDelay(); + } +} diff --git a/src/Engine/CollisionType.java b/src/Engine/CollisionType.java deleted file mode 100644 index c65fdcb..0000000 --- a/src/Engine/CollisionType.java +++ /dev/null @@ -1,9 +0,0 @@ -package Engine; - -/** - * Indicates the type of collision that a player should have when it collides with - * a given entity. - */ -public enum CollisionType { - DEFAULT,INSTANT_DEATH,DAMAGE,PREVENT_JUMP -} diff --git a/src/GameObject/AnimatedSprite.java b/src/GameObject/AnimatedSprite.java index 10ff80a..88b5324 100644 --- a/src/GameObject/AnimatedSprite.java +++ b/src/GameObject/AnimatedSprite.java @@ -1,5 +1,6 @@ package GameObject; +import Engine.Collidable; import Engine.GraphicsHandler; import Utils.Stopwatch; @@ -14,7 +15,7 @@ Subclasses need to call down to this class's update method in order for animation logic to be performed While this calls does not extend from Sprite, it is set up in a way where it is still treated by other classes as if it is a singular sprite (based on value of currentFrame) */ -public class AnimatedSprite implements IntersectableRectangle { +public class AnimatedSprite implements Collidable { // location of entity protected float x, y; @@ -262,11 +263,13 @@ public Rectangle getIntersectRectangle() { return currentFrame.getIntersectRectangle(); } - public boolean intersects(IntersectableRectangle other) { + public boolean intersects(Collidable other) { return currentFrame.intersects(other); } - public boolean overlaps(IntersectableRectangle other) { return currentFrame.overlaps(other); } + public boolean overlaps(Collidable other) { + return currentFrame.overlaps(other); + } @Override public String toString() { diff --git a/src/GameObject/Rectangle.java b/src/GameObject/Rectangle.java index bf9dc34..77d1f82 100644 --- a/src/GameObject/Rectangle.java +++ b/src/GameObject/Rectangle.java @@ -1,5 +1,6 @@ package GameObject; +import Engine.Collidable; import Engine.GraphicsHandler; import java.awt.*; @@ -7,7 +8,7 @@ // This class represents a rectangle, which at its core is (x, y, width, height) // it has some properties, rectangle math methods, and draw logic // the methods here are pretty self explanatory -public class Rectangle implements IntersectableRectangle { +public class Rectangle implements Collidable { protected float x; protected float y; protected int width; @@ -174,7 +175,7 @@ public Rectangle getIntersectRectangle() { } // check if this intersects with another rectangle - public boolean intersects(IntersectableRectangle other) { + public boolean intersects(Collidable other) { Rectangle intersectRectangle = getIntersectRectangle(); Rectangle otherIntersectRectangle = other.getIntersectRectangle(); return Math.round(intersectRectangle.getX1()) < Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) > Math.round(otherIntersectRectangle.getX1()) && @@ -182,10 +183,11 @@ public boolean intersects(IntersectableRectangle other) { } // check if this overlaps with another rectangle - public boolean overlaps(IntersectableRectangle other) { + public boolean overlaps(Collidable other) { Rectangle intersectRectangle = getIntersectRectangle(); Rectangle otherIntersectRectangle = other.getIntersectRectangle(); return Math.round(intersectRectangle.getX1()) <= Math.round(otherIntersectRectangle.getX2()) && Math.round(intersectRectangle.getX2()) >= Math.round(otherIntersectRectangle.getX1()) && Math.round(intersectRectangle.getY1()) <= Math.round(otherIntersectRectangle.getY2()) && Math.round(intersectRectangle.getY2()) >= Math.round(otherIntersectRectangle.getY1()); } + } diff --git a/src/Level/Enemy.java b/src/Level/Enemy.java index c89baa4..1a47320 100644 --- a/src/Level/Enemy.java +++ b/src/Level/Enemy.java @@ -1,6 +1,6 @@ package Level; -import Engine.CollisionType; +import Engine.Collidable; import GameObject.Frame; import GameObject.ImageEffect; import GameObject.Rectangle; @@ -10,7 +10,7 @@ import java.util.HashMap; // This class is a base class for all enemies in the game -- all enemies should extend from it -public class Enemy extends MapEntity { +public class Enemy extends MapEntity implements Collidable.InstantDeath { public Enemy(float x, float y, SpriteSheet spriteSheet, String startingAnimation) { super(x, y, spriteSheet, startingAnimation); @@ -43,7 +43,6 @@ public Enemy(BufferedImage image, float x, float y, float scale, ImageEffect ima @Override public void initialize() { super.initialize(); - collisionType = CollisionType.INSTANT_DEATH; } public void update(Player player) { diff --git a/src/Level/MapEntity.java b/src/Level/MapEntity.java index 8642e95..0f849ea 100644 --- a/src/Level/MapEntity.java +++ b/src/Level/MapEntity.java @@ -1,6 +1,5 @@ package Level; -import Engine.CollisionType; import GameObject.*; import java.awt.image.BufferedImage; @@ -10,7 +9,6 @@ // it is basically a game object with a few extra features for handling things like respawning public class MapEntity extends GameObject { protected MapEntityStatus mapEntityStatus = MapEntityStatus.ACTIVE; - protected CollisionType collisionType = CollisionType.DEFAULT; // if true, if entity goes out of the camera's update range, and then ends up back in range, the entity will "respawn" back to its starting parameters protected boolean isRespawnable = true; @@ -79,12 +77,4 @@ public boolean isUpdateOffScreen() { public void setIsUpdateOffScreen(boolean isUpdateOffScreen) { this.isUpdateOffScreen = isUpdateOffScreen; } - - public void setCollisionType(CollisionType collisionType) { - this.collisionType = collisionType; - } - - public CollisionType getCollisionType() { - return collisionType; - } } diff --git a/src/Level/Player.java b/src/Level/Player.java index 1717a2b..777ce5d 100644 --- a/src/Level/Player.java +++ b/src/Level/Player.java @@ -1,5 +1,6 @@ package Level; +import Engine.Collidable; import Engine.KeyboardAction; import GameObject.GameObject; import GameObject.SpriteSheet; @@ -17,7 +18,7 @@ */ public abstract class Player extends GameObject { - private static final int ATTACK_DELAY = 1500, JUMP_DELAY = 5000; + private static final int ATTACK_DELAY = 1500; private static final float MAX_FALL_VELOCITY = 6f, MAX_DEATH_FALL_VELOCITY = 10f, DEATH_Y_VELOCITY = -2.5f; public static int PLAYER_HEALTH = 3; protected float gravity, jumpHeight, walkSpeed, sprintSpeed, sprintAcceleration; @@ -191,11 +192,13 @@ private void handleCollision(MapTile tile) { } public void hurtPlayer(MapEntity mapEntity) { - //Checks the collision type of the entity that collided with the player - switch (mapEntity.getCollisionType()) { - case DAMAGE -> PLAYER_HEALTH -= 1; - case INSTANT_DEATH -> PLAYER_HEALTH = 0; - case PREVENT_JUMP -> jumpDelay.setWaitTime(JUMP_DELAY); + if(mapEntity instanceof Collidable.Damage) { + PLAYER_HEALTH -= ((Damage) mapEntity).getDamage(); + } else if(mapEntity instanceof Collidable.InstantDeath) { + PLAYER_HEALTH = 0; + } + if(mapEntity instanceof Collidable.PreventJump) { + jumpDelay.setWaitTime(((Collidable.PreventJump) mapEntity).getJumpDelay()); } } diff --git a/src/Level/Projectile.java b/src/Level/Projectile.java index 00c62c9..46ed516 100644 --- a/src/Level/Projectile.java +++ b/src/Level/Projectile.java @@ -1,6 +1,6 @@ package Level; -import Engine.CollisionType; +import Engine.Collidable; import GameObject.Frame; import GameObject.ImageEffect; import GameObject.Rectangle; @@ -9,7 +9,7 @@ import java.util.HashMap; // This class is a base class for all projectiles in the game -- all projectiles should extend from it -public class Projectile extends MapEntity { +public class Projectile extends MapEntity implements Collidable.Damage { public Projectile(float x, float y, SpriteSheet spriteSheet, String startingAnimation) { super(x, y, spriteSheet, startingAnimation); @@ -42,7 +42,6 @@ public Projectile(BufferedImage image, float x, float y, float scale, ImageEffec @Override public void initialize() { super.initialize(); - collisionType = CollisionType.DAMAGE; } public void update(Player player) { @@ -52,6 +51,10 @@ public void update(Player player) { } } + public int getDamage() { + return 1; + } + // A subclass can override this method to specify what it does when it touches the player public void touchedPlayer(Player player) { player.hurtPlayer(this); diff --git a/src/Projectiles/Bone.java b/src/Projectiles/Bone.java index 0dbc507..db685dc 100644 --- a/src/Projectiles/Bone.java +++ b/src/Projectiles/Bone.java @@ -1,7 +1,7 @@ package Projectiles; import Builders.FrameBuilder; -import Engine.CollisionType; +import Engine.Collidable; import Engine.ImageLoader; import GameObject.Frame; import GameObject.ImageEffect; @@ -15,7 +15,7 @@ // This class is for the bone enemy that the dog class shoots out // it will travel in a straight line (x axis) for a set time before disappearing // it will disappear early if it collides with a solid map tile -public class Bone extends Projectile { +public class Bone extends Projectile implements Collidable.PreventJump { private float movementSpeed; private Stopwatch existenceTimer = new Stopwatch(); @@ -30,7 +30,6 @@ public Bone(Point location, float movementSpeed, int existenceTime) { isRespawnable = false; initialize(); - collisionType = CollisionType.PREVENT_JUMP; } @Override @@ -89,4 +88,8 @@ public HashMap getAnimations(SpriteSheet spriteSheet) { }); }}; } + + public int getJumpDelay() { + return 5000; + } } From b81e48283da431057793a2ec7e490cdfa8310082 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 12:37:27 -0500 Subject: [PATCH 147/164] Added Total Time to Score Screen --- src/Screens/GameScoreScreen.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index 911f16c..5daccc9 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -14,26 +14,33 @@ public class GameScoreScreen extends Menu { - private static final Font FONT_LEVEL; - private static final Color COLOR_LEVEL; + private static final Font FONT_LEVEL, FONT_TOTAL; + private static final Color COLOR_LEVEL, COLOR_TOTAL; static { String fontName = "Times New Roman"; FONT_LEVEL = new Font(fontName, Font.PLAIN, 30); + FONT_TOTAL = new Font(fontName,Font.PLAIN,60); COLOR_LEVEL = Color.WHITE; + COLOR_TOTAL = Color.WHITE; } public GameScoreScreen(TimeTracker timeTracker) { setBackground(new TitleScreenMap()); - System.out.println(getLevels(timeTracker)); + System.out.println(levelsToString(timeTracker)); - SpriteFont levels = new SpriteFont(getLevels(timeTracker), 30, ScreenManager.getScreenHeight() - 125, FONT_LEVEL, COLOR_LEVEL); + SpriteFont levels = new SpriteFont(levelsToString(timeTracker), 10, ScreenManager.getScreenHeight() - 150, FONT_LEVEL, COLOR_LEVEL); + SpriteFont total = new SpriteFont(totalToString(timeTracker),500,100,FONT_TOTAL,COLOR_TOTAL); - setDrawables(levels); + setDrawables(levels,total); } - private String getLevels(TimeTracker timeTracker) { + private String totalToString(TimeTracker timeTracker) { + return new StringBuilder("Total: ").append(getTotalTimes(timeTracker)).toString(); + } + + private String levelsToString(TimeTracker timeTracker) { StringBuilder stringBuilder = new StringBuilder(); GameTimer[] gameTimers = timeTracker.getLevels(); From 25d889347d2cafa3c4b22fe25ca9546c63ee4d65 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 12:53:04 -0500 Subject: [PATCH 148/164] Fixed Game Score Rendering --- src/Menu/Menu.java | 6 ++++-- src/Screens/GameScoreScreen.java | 10 ++++++---- src/Screens/PlayLevelScreen.java | 7 ++++--- src/SpriteFont/SpriteFont.java | 1 + src/Utils/GameTimer.java | 10 +++++----- src/Utils/TimeParser.java | 2 +- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Menu/Menu.java b/src/Menu/Menu.java index 9f25c20..cdc11f9 100644 --- a/src/Menu/Menu.java +++ b/src/Menu/Menu.java @@ -125,8 +125,10 @@ protected void drawDrawables(GraphicsHandler graphicsHandler) { } public void mouseClicked(MouseEvent e) { - for (MenuOption option : menuOptions) { - option.mouseClicked(e); + if(menuOptions != null) { + for (MenuOption option : menuOptions) { + option.mouseClicked(e); + } } } diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index 5daccc9..a11ed73 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -9,6 +9,7 @@ import Menu.Menu; import SpriteFont.SpriteFont; import Utils.GameTimer; +import Utils.TimeParser; import java.awt.*; @@ -30,8 +31,9 @@ public GameScoreScreen(TimeTracker timeTracker) { setBackground(new TitleScreenMap()); System.out.println(levelsToString(timeTracker)); - SpriteFont levels = new SpriteFont(levelsToString(timeTracker), 10, ScreenManager.getScreenHeight() - 150, FONT_LEVEL, COLOR_LEVEL); - SpriteFont total = new SpriteFont(totalToString(timeTracker),500,100,FONT_TOTAL,COLOR_TOTAL); + SpriteFont levels = new SpriteFont(levelsToString(timeTracker), 10, 100, FONT_LEVEL, COLOR_LEVEL); + levels.setMultiLine(true); + SpriteFont total = new SpriteFont(totalToString(timeTracker),300,100,FONT_TOTAL,COLOR_TOTAL); setDrawables(levels,total); } @@ -56,8 +58,8 @@ private String levelsToString(TimeTracker timeTracker) { return stringBuilder.toString(); } - private GameTimer getTotalTimes(TimeTracker timeTracker) { - GameTimer totalTime = new GameTimer(); + private TimeParser getTotalTimes(TimeTracker timeTracker) { + TimeParser totalTime = new TimeParser(); for(GameTimer gameTimer : timeTracker.getLevels()) { totalTime.addTime(gameTimer.getElapsed()); } diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 3b3411e..12cbb9d 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -122,6 +122,7 @@ public void draw(GraphicsHandler graphicsHandler) { alternateScreen = null; loadedMap.draw(graphicsHandler); player.draw(graphicsHandler); + timeTracker.draw(graphicsHandler); } case LEVEL_WIN_MESSAGE -> { if (!(alternateScreen instanceof LevelClearedScreen)) { @@ -129,6 +130,7 @@ public void draw(GraphicsHandler graphicsHandler) { alternateScreen.initialize(); } alternateScreen.draw(graphicsHandler); + timeTracker.draw(graphicsHandler); } case LEVEL_LOSE_MESSAGE -> { if (!(alternateScreen instanceof LevelLoseScreen)) { @@ -136,6 +138,7 @@ public void draw(GraphicsHandler graphicsHandler) { alternateScreen.initialize(); } alternateScreen.draw(graphicsHandler); + timeTracker.draw(graphicsHandler); } case PAUSE -> { if (!(alternateScreen instanceof PauseScreen)) { @@ -143,6 +146,7 @@ public void draw(GraphicsHandler graphicsHandler) { alternateScreen.initialize(); } alternateScreen.draw(graphicsHandler); + timeTracker.draw(graphicsHandler); } case INSTRUCTIONS -> { loadedMap.draw(graphicsHandler); @@ -160,9 +164,6 @@ public void draw(GraphicsHandler graphicsHandler) { alternateScreen.draw(graphicsHandler); } } - if(timeTracker != null) { - timeTracker.draw(graphicsHandler); - } } public Map getLoadedMap() { diff --git a/src/SpriteFont/SpriteFont.java b/src/SpriteFont/SpriteFont.java index f9e9a71..395d8c4 100644 --- a/src/SpriteFont/SpriteFont.java +++ b/src/SpriteFont/SpriteFont.java @@ -34,6 +34,7 @@ public SpriteFont(String text, float x, float y, Font font, Color color) { this.y = y; this.color = color; updateDimensions(); + updateContainsNewLines(); } public void setColor(Color color) { diff --git a/src/Utils/GameTimer.java b/src/Utils/GameTimer.java index 7ecd9d3..e18878c 100644 --- a/src/Utils/GameTimer.java +++ b/src/Utils/GameTimer.java @@ -2,19 +2,19 @@ public class GameTimer extends TimeParser { - private long startTime, endTime, addTime; + private long startTime, endTime; private boolean running; public GameTimer() { startTime = 0; endTime = 0; - addTime = 0; + time = 0; running = false; } public void start() { if(!running) { - addTime = getElapsed(); + time = getElapsed(); startTime = System.currentTimeMillis(); running = true; } @@ -28,12 +28,12 @@ public void stop() { } public void reset() { - addTime = 0; + time = 0; startTime = System.currentTimeMillis(); } public long getElapsed() { - return (running ? System.currentTimeMillis() : endTime ) + addTime - startTime; + return (running ? System.currentTimeMillis() : endTime ) + time - startTime; } @Override diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java index 7bb08e0..2c7fd1b 100644 --- a/src/Utils/TimeParser.java +++ b/src/Utils/TimeParser.java @@ -3,7 +3,7 @@ public class TimeParser { private static final long MS_PER_SECOND, SECOND_PER_MINUTE, MINUTE_PER_HOUR, MS_PER_HOUR, MS_PER_MINUTE; - private long time; + protected long time; static { MS_PER_SECOND = 1000; From 264baa439e7a973309ddd32a4b7a8d2759ffb437 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 13:06:07 -0500 Subject: [PATCH 149/164] Added Main-Menu option to GameScoreScreen.java --- src/Maps/BossBattle.java | 1 + src/Menu/Menu.java | 6 +++++- src/Screens/CreditsScreen.java | 9 ++++----- src/Screens/GameScoreScreen.java | 7 ++++++- src/Screens/LevelSelectScreen.java | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index bfabd4a..6157d76 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -19,6 +19,7 @@ public class BossBattle extends Map { private boolean bossKilled = false; + //original 17 public BossBattle() { super("Final Boss","BossBattle.txt", new CommonTileset(), new Point(1, 0)); } diff --git a/src/Menu/Menu.java b/src/Menu/Menu.java index cdc11f9..dde82eb 100644 --- a/src/Menu/Menu.java +++ b/src/Menu/Menu.java @@ -47,7 +47,7 @@ protected void updateBackground() { protected void updateMenuEscape() { if (KeyboardAction.MENU_ESCAPE.isDown()) { - GamePanel.getScreenCoordinator().setGameState(GameState.MENU); + backToMainMenu(); } } @@ -201,4 +201,8 @@ protected void setBackground(Map background) { protected void setDrawables(Drawable... drawables) { this.drawables = drawables; } + + protected void backToMainMenu() { + GamePanel.getScreenCoordinator().setGameState(GameState.MENU); + } } diff --git a/src/Screens/CreditsScreen.java b/src/Screens/CreditsScreen.java index e8d8c3d..2dbabda 100644 --- a/src/Screens/CreditsScreen.java +++ b/src/Screens/CreditsScreen.java @@ -18,16 +18,15 @@ public CreditsScreen() { setMenuItemsAsGrid(new MenuOption[][]{ { new MenuOption( - "Hit [Escape] to go back to main menu", 100, 450, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) + "Hit [Escape] to go back to main menu", 100, 450, this::backToMainMenu) } }); - setDrawables(new Drawable[]{ + setDrawables( new SpriteFont("Credits", 15, 35, "Times New Roman", 30, Color.black), new SpriteFont("Created by Alex Thimineur for Quinnipiac's SER225 Course.", 130, 140, "Times New Roman", 20, Color.black), new SpriteFont("Thank you to QU Alumni Brian Carducci, Joseph White,\nand Alex Hutman for their contributions.", 60, 220, "Times New Roman", 20, Color.black - ), - new SpriteFont("Press Space to return to the menu", 20, 560, "Times New Roman", 30, Color.black) - }); + ), new SpriteFont("Press Space to return to the menu", 20, 560, "Times New Roman", 30, Color.black) + ); } } diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index a11ed73..bbce161 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -1,8 +1,10 @@ package Screens; import Engine.Drawable; +import Engine.GamePanel; import Engine.GraphicsHandler; import Engine.ScreenManager; +import Game.GameState; import Game.TimeTracker; import Maps.GameMaps; import Maps.TitleScreenMap; @@ -10,6 +12,7 @@ import SpriteFont.SpriteFont; import Utils.GameTimer; import Utils.TimeParser; +import Menu.MenuOption; import java.awt.*; @@ -34,8 +37,10 @@ public GameScoreScreen(TimeTracker timeTracker) { SpriteFont levels = new SpriteFont(levelsToString(timeTracker), 10, 100, FONT_LEVEL, COLOR_LEVEL); levels.setMultiLine(true); SpriteFont total = new SpriteFont(totalToString(timeTracker),300,100,FONT_TOTAL,COLOR_TOTAL); - setDrawables(levels,total); + + MenuOption close = new MenuOption("Main Menu", 550, 550,this::backToMainMenu); + setMenuItemsAsGrid(new MenuOption[][]{{close}}); } private String totalToString(TimeTracker timeTracker) { diff --git a/src/Screens/LevelSelectScreen.java b/src/Screens/LevelSelectScreen.java index a29e56e..5e7f57b 100644 --- a/src/Screens/LevelSelectScreen.java +++ b/src/Screens/LevelSelectScreen.java @@ -32,7 +32,7 @@ public LevelSelectScreen() { new MenuOption("Boss Battle", x_right_column, 300, () -> coordinator.loadLevel(8)) }, { new MenuOption( - "Back to Main Menu", x_left_column, 375, () -> GamePanel.getScreenCoordinator().setGameState(GameState.MENU)) + "Back to Main Menu", x_left_column, 375, this::backToMainMenu) } }; menu[4][1].setNeighborItem(menu[5][0], Direction.DOWN); From a410fab399f66b0b04ecfcbe3895ec28d9165a5b Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 13:15:31 -0500 Subject: [PATCH 150/164] Fixed Scaling issue with TimeTracker.java --- src/Game/TimeTracker.java | 2 +- src/Screens/GameScoreScreen.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 5fb2dc2..9bde3ef 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -95,7 +95,7 @@ public void draw(GraphicsHandler graphicsHandler) { FontMetrics metrics = graphicsHandler.getGraphics2D().getFontMetrics(FONT_SMALL); yMap = metrics.getHeight() + yTotal; xMap = ScreenManager.getScreenWidth() - metrics.stringWidth(mapString.replace(' ','0')); - charsMap = totalString.length(); + charsMap = mapString.length(); } graphicsHandler.drawString(mapString,xMap,yMap,FONT_SMALL,Color.white); } diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index bbce161..8bf8ce7 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -1,10 +1,7 @@ package Screens; import Engine.Drawable; -import Engine.GamePanel; import Engine.GraphicsHandler; -import Engine.ScreenManager; -import Game.GameState; import Game.TimeTracker; import Maps.GameMaps; import Maps.TitleScreenMap; From 054d330fe1a0079b744c66bd2bf9aa061cdcca06 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 14:26:49 -0500 Subject: [PATCH 151/164] Fixed the overlapping Menu Screen --- src/Screens/MenuScreen.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Screens/MenuScreen.java b/src/Screens/MenuScreen.java index fc72ef7..d620e80 100644 --- a/src/Screens/MenuScreen.java +++ b/src/Screens/MenuScreen.java @@ -13,18 +13,18 @@ public MenuScreen() { super(); MenuOption[][] menu = new MenuOption[][]{ { - new MenuOption("PLAY GAME", 80, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVEL)), - new MenuOption("LEVEL SELECT", 350, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVELSELECT)) + new MenuOption("PLAY GAME", 60, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVEL)), + new MenuOption("LEVEL SELECT", 372, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVELSELECT)) }, { - new MenuOption("CREDITS", 80, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.CREDITS)), - new MenuOption("NARRATIVE", 350, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPENING)) + new MenuOption("CREDITS", 60, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.CREDITS)), + new MenuOption("NARRATIVE", 372, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPENING)) }, { - new MenuOption("INSTRUCTIONS", 80, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), - new MenuOption("OPTIONS", 350, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) + new MenuOption("INSTRUCTIONS", 60, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), + new MenuOption("OPTIONS", 372, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) }, { - new MenuOption("SELECT DIFFICULTY", 80, 400, () -> GamePanel.getScreenCoordinator().setGameState(GameState.DIFFICULTYSELECT)), - new MenuOption("QUIT", 80, 400, () -> System.exit(0)) + new MenuOption("SELECT DIFFICULTY", 60, 400, () -> GamePanel.getScreenCoordinator().setGameState(GameState.DIFFICULTYSELECT)), + new MenuOption("QUIT", 372, 400, () -> System.exit(0)) } }; setMenuItemsAsGrid(menu); From 88b8611c68547384bd582241e07df29968dad995 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 14:36:01 -0500 Subject: [PATCH 152/164] Moved Text placement in GameScoreSCreen.java --- src/Screens/GameScoreScreen.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index 8bf8ce7..dcd86f5 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -15,15 +15,14 @@ public class GameScoreScreen extends Menu { - private static final Font FONT_LEVEL, FONT_TOTAL; - private static final Color COLOR_LEVEL, COLOR_TOTAL; + private static final Font FONT_LEVEL, FONT_TITLE; + private static final Color COLOR_LEVEL, COLOR_TITLE; static { String fontName = "Times New Roman"; FONT_LEVEL = new Font(fontName, Font.PLAIN, 30); - FONT_TOTAL = new Font(fontName,Font.PLAIN,60); - COLOR_LEVEL = Color.WHITE; - COLOR_TOTAL = Color.WHITE; + FONT_TITLE = new Font(fontName, Font.BOLD,60); + COLOR_LEVEL = COLOR_TITLE = Color.WHITE; } @@ -31,10 +30,11 @@ public GameScoreScreen(TimeTracker timeTracker) { setBackground(new TitleScreenMap()); System.out.println(levelsToString(timeTracker)); - SpriteFont levels = new SpriteFont(levelsToString(timeTracker), 10, 100, FONT_LEVEL, COLOR_LEVEL); + SpriteFont levels = new SpriteFont(levelsToString(timeTracker), 10, 150, FONT_LEVEL, COLOR_LEVEL); levels.setMultiLine(true); - SpriteFont total = new SpriteFont(totalToString(timeTracker),300,100,FONT_TOTAL,COLOR_TOTAL); - setDrawables(levels,total); + SpriteFont title = new SpriteFont("Game Complete",200,75,FONT_TITLE,COLOR_TITLE); +// SpriteFont total = new SpriteFont(totalToString(timeTracker),300,100,FONT_TOTAL,COLOR_TOTAL); + setDrawables(levels,title); MenuOption close = new MenuOption("Main Menu", 550, 550,this::backToMainMenu); setMenuItemsAsGrid(new MenuOption[][]{{close}}); @@ -56,6 +56,7 @@ private String levelsToString(TimeTracker timeTracker) { stringBuilder.append(GameMaps.MAPS[i].getName()).append(": ").append(gameTimers[i].toString()); } } + stringBuilder.append("\n\nTotal: ").append(getTotalTimes(timeTracker)); return stringBuilder.toString(); } From e857c31f8872606b908425fa35f6454c89ea34ef Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 16:39:21 -0500 Subject: [PATCH 153/164] No longer utilizing the difficultyHolder class --- Team A2/Test Cases/Test Case SCP-49.md | 1 + src/Enemies/BugEnemy.java | 4 ++-- src/Enemies/CyborgEnemy.java | 4 ++-- src/Enemies/DinosaurEnemy.java | 4 ++-- src/Enemies/Dog.java | 4 ++-- src/Engine/DifficultyHolder.java | 1 + src/Engine/GamePanel.java | 28 +++++++++++++++++++------ src/Maps/BossBattle.java | 2 +- src/Screens/DifficultySelectScreen.java | 8 +++---- src/Screens/LevelLoseScreen.java | 4 ++-- src/Screens/MenuScreen.java | 8 +++---- src/Tilesets/CommonTileset.java | 2 +- 12 files changed, 43 insertions(+), 27 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-49.md b/Team A2/Test Cases/Test Case SCP-49.md index 0102ea3..2ea305c 100644 --- a/Team A2/Test Cases/Test Case SCP-49.md +++ b/Team A2/Test Cases/Test Case SCP-49.md @@ -23,6 +23,7 @@ |11| Take damage. | The cat dies. | [RESULT] | |12| Press escape. | The player is returned to the main menu. | [RESULT] | |13| Load into level 6, die to any enemy, and press space. | The player is restarted at the tutorial level. | [RESULT] | +|14| Restart the game and beat each level at every difficulty to ensure the levels are still possible. (Use the level select to make hardcore mode easier) | Each level is beat on every difficulty | [RESULT] | ### Test Completion - **Tester**: [TESTER NAME] diff --git a/src/Enemies/BugEnemy.java b/src/Enemies/BugEnemy.java index 30ca2e3..a46ebc9 100644 --- a/src/Enemies/BugEnemy.java +++ b/src/Enemies/BugEnemy.java @@ -52,11 +52,11 @@ public void update(Player player) { float moveAmountY = 0; // set the movement speed of the enemy depending on what difficulty it selected - if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + if (GamePanel.getDifficulty() == 2) { movementSpeed = HARD_SPEED; } - else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + else if (GamePanel.getDifficulty() == 1) { movementSpeed = HARDCORE_SPEED; } diff --git a/src/Enemies/CyborgEnemy.java b/src/Enemies/CyborgEnemy.java index 96c2654..395beed 100644 --- a/src/Enemies/CyborgEnemy.java +++ b/src/Enemies/CyborgEnemy.java @@ -78,12 +78,12 @@ public void update(Player player) { float lazerMovementSpeed = NORMAL_LAZER_SPEED; // set the movement speed of the enemy and lazer attack depending on what difficulty it selected - if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + if (GamePanel.getDifficulty() == 2) { movementSpeed = HARD_SPEED; lazerMovementSpeed = HARD_LAZER_SPEED; } - else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + else if (GamePanel.getDifficulty() == 1) { movementSpeed = HARDCORE_SPEED; lazerMovementSpeed = HARDCORE_LAZER_SPEED; diff --git a/src/Enemies/DinosaurEnemy.java b/src/Enemies/DinosaurEnemy.java index 81711dc..5994cb0 100644 --- a/src/Enemies/DinosaurEnemy.java +++ b/src/Enemies/DinosaurEnemy.java @@ -73,12 +73,12 @@ public void update(Player player) { float fireballMovementSpeed = NORMAL_FIREBALL_SPEED; // set the movement speed of the enemy and fireball attack depending on what difficulty it selected - if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + if (GamePanel.getDifficulty() == 2) { movementSpeed = HARD_SPEED; fireballMovementSpeed = HARD_FIREBALL_SPEED; } - else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + else if (GamePanel.getDifficulty() == 1) { movementSpeed = HARDCORE_SPEED; fireballMovementSpeed = HARDCORE_FIREBALL_SPEED; diff --git a/src/Enemies/Dog.java b/src/Enemies/Dog.java index c257522..6679362 100644 --- a/src/Enemies/Dog.java +++ b/src/Enemies/Dog.java @@ -71,12 +71,12 @@ public void update(Player player) { float boneMovementSpeed = NORMAL_BONE_SPEED; // set the movement speed of the enemy and fireball attack depending on what difficulty it selected - if (GamePanel.getDifficultyHolder().getDifficulty() == 2) + if (GamePanel.getDifficulty() == 2) { movementSpeed = HARD_SPEED; boneMovementSpeed = HARD_BONE_SPEED; } - else if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + else if (GamePanel.getDifficulty() == 1) { movementSpeed = HARDCORE_SPEED; boneMovementSpeed = HARDCORE_BONE_SPEED; diff --git a/src/Engine/DifficultyHolder.java b/src/Engine/DifficultyHolder.java index 1c11dc3..d2263b8 100644 --- a/src/Engine/DifficultyHolder.java +++ b/src/Engine/DifficultyHolder.java @@ -1,5 +1,6 @@ package Engine; +@Deprecated public class DifficultyHolder { diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 8ae1c9e..21fe1eb 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -25,7 +25,11 @@ public class GamePanel extends JPanel implements Updatable { protected static GameWindow gameWindow; private static ScreenCoordinator coordinator; public static Clip clip; - private static DifficultyHolder difficultyHolder; + + // these difficulty values are not only just used for the the logic of the game but + // to determine how much health the user gets at each difficulty; + private final static int NORMAL = 3, HARD = 2, HARDCORE = 1; + private static int difficulty; private final JLabel health; private final GameThread gameThread; @@ -50,13 +54,18 @@ public GamePanel(ScreenCoordinator c1,GameWindow gameWindow) { screenManager = new ScreenManager(); coordinator = c1; - difficultyHolder = new DifficultyHolder(3); + difficulty = NORMAL; + gameThread = new GameThread(this::repaint, this::update); } - - public static DifficultyHolder getDifficultyHolder() + + public static void setDifficulty(int newDifficulty) { - return difficultyHolder; + difficulty = newDifficulty; + } + public static int getDifficulty() + { + return difficulty; } public static ScreenCoordinator getScreenCoordinator() { @@ -166,8 +175,15 @@ else if(Player.PLAYER_HEALTH == 1) { // Each difficulty is represented as an integer while also representing the amount of health the user has // normal is 3 hard is 2 and hardcore is 1 + // hide the health whenever in a menu if(coordinator.getGameState() == GameState.MENU) { - Player.PLAYER_HEALTH = difficultyHolder.getDifficulty(); + Player.PLAYER_HEALTH = difficulty; + health.hide(); + } + // show the health when in a level + else if (coordinator.getGameState() == GameState.LEVEL) + { + health.show(); } } diff --git a/src/Maps/BossBattle.java b/src/Maps/BossBattle.java index bfabd4a..a6a9b86 100644 --- a/src/Maps/BossBattle.java +++ b/src/Maps/BossBattle.java @@ -20,7 +20,7 @@ public class BossBattle extends Map { private boolean bossKilled = false; public BossBattle() { - super("Final Boss","BossBattle.txt", new CommonTileset(), new Point(1, 0)); + super("Final Boss","BossBattle.txt", new CommonTileset(), new Point(1, 17)); } @Override diff --git a/src/Screens/DifficultySelectScreen.java b/src/Screens/DifficultySelectScreen.java index 7ee2bdc..fd4f09a 100644 --- a/src/Screens/DifficultySelectScreen.java +++ b/src/Screens/DifficultySelectScreen.java @@ -11,7 +11,6 @@ public class DifficultySelectScreen extends Menu { - private final DifficultyHolder difficultyHolder; //these values also correspond to the health given at each difficulty private final static int NORMAL = 3; @@ -19,12 +18,11 @@ public class DifficultySelectScreen extends Menu { private final static int HARDCORE = 1; public DifficultySelectScreen() { - difficultyHolder = GamePanel.getDifficultyHolder(); MenuOption[][] menu = new MenuOption[][]{ { - new MenuOption("Normal", 100, 150, () -> difficultyHolder.setDifficulty(NORMAL), CloseOnExecute.CLOSE), - new MenuOption("Hard", 320, 150, () -> difficultyHolder.setDifficulty(HARD), CloseOnExecute.CLOSE), - new MenuOption("Hardcore", 500, 150, () -> difficultyHolder.setDifficulty(HARDCORE), CloseOnExecute.CLOSE) + new MenuOption("Normal", 100, 150, () -> GamePanel.setDifficulty(NORMAL), CloseOnExecute.CLOSE), + new MenuOption("Hard", 320, 150, () -> GamePanel.setDifficulty(HARD), CloseOnExecute.CLOSE), + new MenuOption("Hardcore", 500, 150, () -> GamePanel.setDifficulty(HARDCORE), CloseOnExecute.CLOSE) }, { new MenuOption( diff --git a/src/Screens/LevelLoseScreen.java b/src/Screens/LevelLoseScreen.java index 3ea3e64..f9f8928 100644 --- a/src/Screens/LevelLoseScreen.java +++ b/src/Screens/LevelLoseScreen.java @@ -27,7 +27,7 @@ public void update() { super.update(); if (KeyboardAction.GAME_RESPAWN.isDown()) { // if the player is in hardcore difficulty restart them at the first level otherwise restart them on the current level - if (GamePanel.getDifficultyHolder().getDifficulty() == 1) + if (GamePanel.getDifficulty() == 1) { playLevelScreen.loadMap(0); } @@ -35,7 +35,7 @@ public void update() { { playLevelScreen.resetLevel(); } - Player.PLAYER_HEALTH = GamePanel.getDifficultyHolder().getDifficulty(); + Player.PLAYER_HEALTH = GamePanel.getDifficulty(); PlayerAttack.dogHealth = 8; } } diff --git a/src/Screens/MenuScreen.java b/src/Screens/MenuScreen.java index d620e80..5bf6a4c 100644 --- a/src/Screens/MenuScreen.java +++ b/src/Screens/MenuScreen.java @@ -14,17 +14,17 @@ public MenuScreen() { MenuOption[][] menu = new MenuOption[][]{ { new MenuOption("PLAY GAME", 60, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVEL)), - new MenuOption("LEVEL SELECT", 372, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVELSELECT)) + new MenuOption("LEVEL SELECT", 392, 100, () -> GamePanel.getScreenCoordinator().setGameState(GameState.LEVELSELECT)) }, { new MenuOption("CREDITS", 60, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.CREDITS)), - new MenuOption("NARRATIVE", 372, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPENING)) + new MenuOption("NARRATIVE", 392, 200, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPENING)) }, { new MenuOption("INSTRUCTIONS", 60, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.INSTRUCTIONS)), - new MenuOption("OPTIONS", 372, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) + new MenuOption("OPTIONS", 392, 300, () -> GamePanel.getScreenCoordinator().setGameState(GameState.OPTIONS)) }, { new MenuOption("SELECT DIFFICULTY", 60, 400, () -> GamePanel.getScreenCoordinator().setGameState(GameState.DIFFICULTYSELECT)), - new MenuOption("QUIT", 372, 400, () -> System.exit(0)) + new MenuOption("QUIT", 392, 400, () -> System.exit(0)) } }; setMenuItemsAsGrid(menu); diff --git a/src/Tilesets/CommonTileset.java b/src/Tilesets/CommonTileset.java index 05d0cfe..fd687f6 100644 --- a/src/Tilesets/CommonTileset.java +++ b/src/Tilesets/CommonTileset.java @@ -229,7 +229,7 @@ public ArrayList defineTiles() { mapTiles.add(lethalSpikeTile); - // middle branch + // passable floating platform Frame floatingPlatformFrame = new FrameBuilder(getSubImage(3, 4), 0) .withScale(tileScale) .withBounds(0, 6, 16, 4) From 08ecb59aeb782a41c100f4a6c729d2babeb31baa Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 16:40:35 -0500 Subject: [PATCH 154/164] Updated Test Case SCP-49 --- Team A2/Test Cases/Test Case SCP-49.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-49.md b/Team A2/Test Cases/Test Case SCP-49.md index 2ea305c..5d4c352 100644 --- a/Team A2/Test Cases/Test Case SCP-49.md +++ b/Team A2/Test Cases/Test Case SCP-49.md @@ -3,7 +3,7 @@ | :--- | :--- | | Owner of Test | Nicholas Tourony | | Test Name | Difficulty Test | -| Date of Last Revision | 11/28/2021 | +| Date of Last Revision | 11/30/2021 | | Test Objective | Ensure that the difficulty settings change the amount of health the cat has and changes the movement speed of the enemies and their projectiles. | ### Procedure From d035048c6c20493274c96e214ce026fc035a4adc Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 17:03:17 -0500 Subject: [PATCH 155/164] Passes Test Case SCP-57 --- Team A2/Test Cases/Test Case SCP-57.md | 58 +++++++++++++------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-57.md b/Team A2/Test Cases/Test Case SCP-57.md index ce72d98..ca6eca9 100644 --- a/Team A2/Test Cases/Test Case SCP-57.md +++ b/Team A2/Test Cases/Test Case SCP-57.md @@ -20,34 +20,34 @@ Functionality of `Player.java` tested: |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | |0a| **Evaluated on Each Step:** | Player Animation changes as expected (*If a step does not pass this result, fail that step and indicate "Failed Step 0a"*) |`N/A`| -|1| Run the game| The game successfully opens || -|2| Click "*Play*" |The tutorial level is entered, game does not crash. 3 hearts are displayed on the top of the screen.|| -|3| Hold `A/Left Arrow` |The player moves to the left. The player does not fall off the map and is instead stopped at the edge|| -|4| Hold `D/Right Arrow`|The player moves to the right. The player is stopped once they hit the tree|| -|5| Hold both `A/Left Arrow` and `D/Right Arrow`|The player stands still|| -|6| Tap `Space/W/Up Arrow` | The player short-jumps. The player then falls back down after the button is let go and lands on the ground|| -|7|Hold `Space/W/Up Arrow` | The player high-jumps. The player falls back down after a certain height and and falls back down to the ground|| -|8|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|| -|9|Hold `ctrl/S/Down Arrow`|The player crouches|| -|10|Tap `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|| -|11|Tap `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|| -|12|Tap `A/Left Arrow`, then tap `e` (*Attack Button*)|The player faces to the left, and attacks, sending a projectile to the left|| -|13|Hold `A/Left Arrow`, then tap `e` |The player moves to the left, and attacks while moving|| -|14|Tap `Space/W/Up Arrow`, then tap `e` while in the air|The player jumps while facing left, and then shoots a projectile while in the air|| -|15|Tap `D/Right Arrow`, then tap `e` |The player faces to the right, and attacks, sending a projectile to the right|| -|16|Hold `D/Right Arrow`, then tap `e` |The player moves to the right, and attacks while moving|| -|17|Tap `Space/W/Up Arrow`, then tap `e` while in the air|The player jumps while facing right, and then shoots a projectile while in the air|| -|18|Hold `e`|The player shoots once, then cannot shoot for a specified duration of time|| -|19|Navigate and run into enemy|The player's health is set to 0 and the player dies. Death animation is played and player falls down to the ground|| -|20|Restart the game|The level is loaded again, and the player's health is back to full|| -|21|Navigate and run into a projectile from an enemy|The player's health is now 2 (reduced by 1)|| -|22|Navigate and attempt to run off the right-most edge of the map (*without hitting the gold level-complete box*)|The player is stopped and cannot run off of the map|| -|23|Hit the complete-level gold box|The level is completed and the player walks off to the right of the screen|| -|24|Hit Escape, go back to main menu|The main menu is displayed|| -|25|Hit "Play Game"|The first level is loaded|| -|26|Play all levels of the game|Each level is completable|| +|1| Run the game| The game successfully opens |Pass| +|2| Click "*Play*" |The tutorial level is entered, game does not crash. 3 hearts are displayed on the top of the screen.|Pass| +|3| Hold `A/Left Arrow` |The player moves to the left. The player does not fall off the map and is instead stopped at the edge|Pass| +|4| Hold `D/Right Arrow`|The player moves to the right. The player is stopped once they hit the tree|Pass| +|5| Hold both `A/Left Arrow` and `D/Right Arrow`|The player stands still|Pass| +|6| Tap `Space/W/Up Arrow` | The player short-jumps. The player then falls back down after the button is let go and lands on the ground|Pass| +|7|Hold `Space/W/Up Arrow` | The player high-jumps. The player falls back down after a certain height and and falls back down to the ground|Pass| +|8|Hold `Shift` and repeat steps 3-5|The player moves in the same ways as stated above, but faster|Pass| +|9|Hold `ctrl/S/Down Arrow`|The player crouches|Pass| +|10|Tap `A/Left Arrow`, then hit `Space/W/Up Arrow` quickly followed by `D/Right Arrow`|The player faces left, then switches to facing right while in the air|Pass| +|11|Tap `D/Right Arrow`, then hit `Space/W/Up Arrow` quickly followed by `A/Left Arrow`|The player faces right, then switches to facing left while in the air|Pass| +|12|Tap `A/Left Arrow`, then tap `e` (*Attack Button*)|The player faces to the left, and attacks, sending a projectile to the left|Pass| +|13|Hold `A/Left Arrow`, then tap `e` |The player moves to the left, and attacks while moving|Pass| +|14|Tap `Space/W/Up Arrow`, then tap `e` while in the air|The player jumps while facing left, and then shoots a projectile while in the air|Pass| +|15|Tap `D/Right Arrow`, then tap `e` |The player faces to the right, and attacks, sending a projectile to the right|Pass| +|16|Hold `D/Right Arrow`, then tap `e` |The player moves to the right, and attacks while moving|Pass| +|17|Tap `Space/W/Up Arrow`, then tap `e` while in the air|The player jumps while facing right, and then shoots a projectile while in the air|Pass| +|18|Hold `e`|The player shoots once, then cannot shoot for a specified duration of time|Pass| +|19|Navigate and run into enemy|The player's health is set to 0 and the player dies. Death animation is played and player falls down to the ground|Pass| +|20|Restart the game|The level is loaded again, and the player's health is back to full|Pass| +|21|Navigate and run into a projectile from an enemy|The player's health is now 2 (reduced by 1)|Pass| +|22|Navigate and attempt to run off the right-most edge of the map (*without hitting the gold level-complete box*)|The player is stopped and cannot run off of the map|Pass| +|23|Hit the complete-level gold box|The level is completed and the player walks off to the right of the screen|Pass| +|24|Hit Escape, go back to main menu|The main menu is displayed|Pass| +|25|Hit "Play Game"|The first level is loaded|Pass| +|26|Play all levels of the game|Each level is completable|Pass| ### Test Completion -- **Tester**: [TESTER NAME] -- **Date of Test**: DATE OF TEST -- **Test Result**: TEST RESULT \ No newline at end of file +- **Tester**: Nicholas Tourony +- **Date of Test**: 11/30/2021 +- **Test Result**: Passed \ No newline at end of file From 74299c3db013592c370cb406c202929dbad083d6 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 17:12:02 -0500 Subject: [PATCH 156/164] Passed Test Case SCP-49.md --- Team A2/Test Cases/Test Case SCP-49.md | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-49.md b/Team A2/Test Cases/Test Case SCP-49.md index 5d4c352..c11eb6d 100644 --- a/Team A2/Test Cases/Test Case SCP-49.md +++ b/Team A2/Test Cases/Test Case SCP-49.md @@ -10,22 +10,22 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1| Run the game| The game successfully opens |P| -|2| Select the difficulty menu. | The difficulty menu opens. | [RESULT] | -|3| Select normal difficulty | The game lets you select normal difficulty and automatically puts you back to the main menu. | [RESULT] | -|4| Start the game. | The cat is loaded into the first level with 3 health and the enemies and projectiles move at their slowest speed. | [RESULT] | -|5| Take projectile damage until the character dies | The cat can take 3 projectile hits before dying. | [RESULT] | -|6| Respawn and run into an enemy. | The cat instantly dies. | [RESULT] | -|7| Select hard difficulty and start the game | The cat is loaded into the first level with 2 health and the enemies move faster. | [RESULT] | -|8| Take projectile damage until the character dies | The cat can take 2 projectile hits before dying. | [RESULT] | -|9| Respawn and run into an enemy. | The cat instantly dies. | [RESULT] | -|10| Select hardcore difficulty and start the game. | The cat is loaded into the first level with 1 health and the enemies move even faster. | [RESULT] | -|11| Take damage. | The cat dies. | [RESULT] | -|12| Press escape. | The player is returned to the main menu. | [RESULT] | -|13| Load into level 6, die to any enemy, and press space. | The player is restarted at the tutorial level. | [RESULT] | -|14| Restart the game and beat each level at every difficulty to ensure the levels are still possible. (Use the level select to make hardcore mode easier) | Each level is beat on every difficulty | [RESULT] | +|1| Run the game| The game successfully opens |Pass| +|2| Select the difficulty menu. | The difficulty menu opens. | Pass | +|3| Select normal difficulty | The game lets you select normal difficulty and automatically puts you back to the main menu. | Pass| +|4| Start the game. | The cat is loaded into the first level with 3 health and the enemies and projectiles move at their slowest speed. | Pass| +|5| Take projectile damage until the character dies | The cat can take 3 projectile hits before dying. | Pass| +|6| Respawn and run into an enemy. | The cat instantly dies. | Pass | +|7| Select hard difficulty and start the game | The cat is loaded into the first level with 2 health and the enemies move faster. | Pass | +|8| Take projectile damage until the character dies | The cat can take 2 projectile hits before dying. | Pass| +|9| Respawn and run into an enemy. | The cat instantly dies. | Pass | +|10| Select hardcore difficulty and start the game. | The cat is loaded into the first level with 1 health and the enemies move even faster. | Pass | +|11| Take damage. | The cat dies. | Pass | +|12| Press escape. | The player is returned to the main menu. | Pass | +|13| Load into level 6, die to any enemy, and press space. | The player is restarted at the tutorial level. | Pass | +|14| Restart the game and beat each level at every difficulty to ensure the levels are still possible. (Use the level select to make hardcore mode easier) | Each level is beat on every difficulty | Passed | ### Test Completion -- **Tester**: [TESTER NAME] -- **Date of Test**: DATE OF TEST -- **Test Result**: TEST RESULT \ No newline at end of file +- **Tester**: Thomas Kwashnak +- **Date of Test**: 11/30/2021 +- **Test Result**: Passed \ No newline at end of file From 56a2a70af5954289d5d114c83780cfdaa6bdd49a Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 17:27:32 -0500 Subject: [PATCH 157/164] Added Difficulty display to GameScoreScreen --- src/Engine/GamePanel.java | 4 ++++ src/Screens/GameScoreScreen.java | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Engine/GamePanel.java b/src/Engine/GamePanel.java index 21fe1eb..ad33422 100644 --- a/src/Engine/GamePanel.java +++ b/src/Engine/GamePanel.java @@ -67,6 +67,10 @@ public static int getDifficulty() { return difficulty; } + + public static String getDifficultyString() { + return difficulty == 3 ? "Normal" : difficulty == 2 ? "Hard" : "Hardcore"; + } public static ScreenCoordinator getScreenCoordinator() { return coordinator; diff --git a/src/Screens/GameScoreScreen.java b/src/Screens/GameScoreScreen.java index dcd86f5..30304d4 100644 --- a/src/Screens/GameScoreScreen.java +++ b/src/Screens/GameScoreScreen.java @@ -1,6 +1,7 @@ package Screens; import Engine.Drawable; +import Engine.GamePanel; import Engine.GraphicsHandler; import Game.TimeTracker; import Maps.GameMaps; @@ -34,7 +35,8 @@ public GameScoreScreen(TimeTracker timeTracker) { levels.setMultiLine(true); SpriteFont title = new SpriteFont("Game Complete",200,75,FONT_TITLE,COLOR_TITLE); // SpriteFont total = new SpriteFont(totalToString(timeTracker),300,100,FONT_TOTAL,COLOR_TOTAL); - setDrawables(levels,title); + SpriteFont difficulty = new SpriteFont(GamePanel.getDifficultyString() + " Difficulty",500,150,FONT_LEVEL,COLOR_LEVEL); + setDrawables(levels,title,difficulty); MenuOption close = new MenuOption("Main Menu", 550, 550,this::backToMainMenu); setMenuItemsAsGrid(new MenuOption[][]{{close}}); From 6c16211f6896857c3ed4ffae69274bdd35d3ce34 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 17:28:35 -0500 Subject: [PATCH 158/164] Passed Test Case SCP-56 --- Team A2/Test Cases/Test Case SCP-56.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 7e52241..6cb960f 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -15,9 +15,9 @@ |Step | Action | Expected Result | Measurement Field | |:---:| :--- | :---- | :----:| |1|Run the game|The game successfully opens|| -|2|Begin recording|A screen recorder is started that records the game|| -|3|Click *Play Game*|The tutorial level is successfully opened|| -|4|Walk to the left-most edge of the level|The cat is at the left most bound of the tutorial level|| +|2|Begin recording|A screen recorder is started that records the game|pass| +|3|Click *Play Game*|The tutorial level is successfully opened|pass| +|4|Walk to the left-most edge of the level|The cat is at the left most bound of the tutorial level|pass| |5|Hold `D/Right Arrow` until the cat is blocked from moving by the tree|The cat moves from the edge of the map into the tree|**Measurement 1:** The time it takes starting when the cat begins moving to when the cat finishes moving| |6|Hold `Shift`, then hold `A/Left Arrow` until the cat stops moving at the left edge of the map|The player sprints to the left-most edge of the map|**Measurement 2:** The time it takes for the cat to move starting when the cat begins moving to when the cat is stopped by the map edge| |7|Hold `Space/W/Up Arrow` until the cat reaches the ground again|The cat jumps and lands back on the ground|**Measurement 3:** The time it takes starting when the cat begins jumping to when the cat hits the ground again| @@ -35,6 +35,7 @@ Instances of tests are listed in table below (template provided). Measurements l |[DATE]|[TESTER_NAME]|[CONFIG]|[MEASURE 1]|[MEASURE 2]|[MEASURE 3]|[MEASURE 4]|[MEASURE 5]|[PASS/FAIL]| |11/29/2021 10:41 AM|Thomas Kwashnak|Kubuntu 21.10 Laptop, Intel i7 CPU, NVIDIA MX330 GPU|\~ 2 seconds|\~1 second|\~1 second|\~1-2 seconds|~3 seconds|Pass. Game runs at expected speed| |11/29/2021 7:05 PM|Thomas Kwashnak|Windows 11 Desktop, Ryzen 5 3600 CPU, Nvidia RTX 2060 GPU|\~ 1.5 Seconds|\~ 1 second|\~ 1 second|\~1-2 seconds|3 seconds|Pass. Game runs at expected speed| +|11/30/2021 5:13 PM|Nicholas Tourony|Windows 10 Laptop, Intel i7-9750H CPU, Nvidia GTX 1660Ti GPU|\~ 1.75 Seconds|\~ 1 second|\~ 1 second|\~1.5 seconds|~3 seconds|Pass. Game runs at expected speed| [comment]: <> (Add test rows to end here ^^) @@ -42,6 +43,6 @@ Instances of tests are listed in table below (template provided). Measurements l - There are no outliers on all measurements ### Test Completion -- **Tester**: [TEST REVIEWER NAME] -- **Date of Test**: [TEST COMPLETION DATE] -- **Test Result**: [TEST RESULT] \ No newline at end of file +- **Tester**: Nicholas Tourony +- **Date of Test**: 11/30/2021 +- **Test Result**: Pass \ No newline at end of file From 3d1a6a3b5636a467d54d06e14333e666c981ba2f Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 17:30:05 -0500 Subject: [PATCH 159/164] Forgot a to pass a line --- Team A2/Test Cases/Test Case SCP-56.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Team A2/Test Cases/Test Case SCP-56.md b/Team A2/Test Cases/Test Case SCP-56.md index 6cb960f..ad163af 100644 --- a/Team A2/Test Cases/Test Case SCP-56.md +++ b/Team A2/Test Cases/Test Case SCP-56.md @@ -14,7 +14,7 @@ |Step | Action | Expected Result | Measurement Field | |:---:| :--- | :---- | :----:| -|1|Run the game|The game successfully opens|| +|1|Run the game|The game successfully opens|pass| |2|Begin recording|A screen recorder is started that records the game|pass| |3|Click *Play Game*|The tutorial level is successfully opened|pass| |4|Walk to the left-most edge of the level|The cat is at the left most bound of the tutorial level|pass| From 3c767a7c4b9785ab68114d1749bd731f229d5bfe Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 17:34:52 -0500 Subject: [PATCH 160/164] Dying on hardcore resets timer --- Team A2/Test Cases/Test Case SCP-52.md | 3 +++ src/Game/TimeTracker.java | 7 +++++++ src/Screens/LevelLoseScreen.java | 6 +++--- src/Screens/PlayLevelScreen.java | 5 +++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-52.md b/Team A2/Test Cases/Test Case SCP-52.md index 2fc5bff..6d8c153 100644 --- a/Team A2/Test Cases/Test Case SCP-52.md +++ b/Team A2/Test Cases/Test Case SCP-52.md @@ -28,6 +28,9 @@ |6|Hit "Play" again to go back into the main menu|The tutorial level is loaded, and the timer is reset back to 0|| |7|Complete the tutorial level|The level completed screen is shown, but only for a brief second before the next level is loaded. On the top right is now two timers, one that displays the total time, and another that displays the elapsed time for the current level|| |8|Hit `P/Escape` to pause the game|While the game is paused, timers are also paused|| +|9|Exit back to main menu, Select "Difficulty", and select "Hardcore"|The player is brought back to the main menu, and the hardcore difficulty is selected|| +|10|Select "Level Select", then select "Level 3"|Level 3 is loaded, the timer starts running|| +|11|Die, and then respawn|The timer is reset back to 0|| ### Test Completion - **Tester**: [TESTER NAME] diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 9bde3ef..90a4203 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -56,6 +56,13 @@ public void setCurrentLevel(int currentLevel) { } } + public void reset() { + total.reset(); + for(GameTimer gameTimer : levels) { + gameTimer.reset(); + } + } + /** * Usable when dealing with pausing */ diff --git a/src/Screens/LevelLoseScreen.java b/src/Screens/LevelLoseScreen.java index f9f8928..e63941c 100644 --- a/src/Screens/LevelLoseScreen.java +++ b/src/Screens/LevelLoseScreen.java @@ -17,10 +17,10 @@ public class LevelLoseScreen extends Menu { public LevelLoseScreen(PlayLevelScreen playLevelScreen) { super(); this.playLevelScreen = playLevelScreen; - setDrawables(new Drawable[]{ + setDrawables( new SpriteFont("You lose!", 350, 270, "Comic Sans", 30, Color.white), new SpriteFont("Press Space to try again or Escape to go back to the main menu", 120, 300, "Comic Sans", 20, Color.white) - }); + ); } public void update() { @@ -29,7 +29,7 @@ public void update() { // if the player is in hardcore difficulty restart them at the first level otherwise restart them on the current level if (GamePanel.getDifficulty() == 1) { - playLevelScreen.loadMap(0); + playLevelScreen.resetHardcore(); } else { diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index 12cbb9d..dc154c5 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -248,6 +248,11 @@ public void pause() { timeTracker.stop(); } + public void resetHardcore() { + loadMap(0); + timeTracker.reset(); + } + public enum State { RUNNING, LEVEL_COMPLETED, PLAYER_DEAD, LEVEL_WIN_MESSAGE, LEVEL_LOSE_MESSAGE, PAUSE, INSTRUCTIONS, GAME_COMPLETED From ea6981c0e4e888cd842fffc2ef57b05c605b504a Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 17:53:54 -0500 Subject: [PATCH 161/164] Fixed secondary timer displaying after resetting on hardcore mode --- src/Game/TimeTracker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 90a4203..8bea599 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -61,6 +61,7 @@ public void reset() { for(GameTimer gameTimer : levels) { gameTimer.reset(); } + showLevel = false; } /** From 54c3e5fdc023d1449f331ea797faa520324ca6c9 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 18:00:18 -0500 Subject: [PATCH 162/164] TimeTracker.java gets a new instance on hardcore reset --- src/Game/TimeTracker.java | 8 -------- src/Screens/PlayLevelScreen.java | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Game/TimeTracker.java b/src/Game/TimeTracker.java index 8bea599..9bde3ef 100644 --- a/src/Game/TimeTracker.java +++ b/src/Game/TimeTracker.java @@ -56,14 +56,6 @@ public void setCurrentLevel(int currentLevel) { } } - public void reset() { - total.reset(); - for(GameTimer gameTimer : levels) { - gameTimer.reset(); - } - showLevel = false; - } - /** * Usable when dealing with pausing */ diff --git a/src/Screens/PlayLevelScreen.java b/src/Screens/PlayLevelScreen.java index dc154c5..6da04ef 100644 --- a/src/Screens/PlayLevelScreen.java +++ b/src/Screens/PlayLevelScreen.java @@ -249,8 +249,8 @@ public void pause() { } public void resetHardcore() { + timeTracker = new TimeTracker(); loadMap(0); - timeTracker.reset(); } From ca94f59957eca4aa7925701822c8ef64e86a28d2 Mon Sep 17 00:00:00 2001 From: NicholasTourony Date: Tue, 30 Nov 2021 18:08:12 -0500 Subject: [PATCH 163/164] Passes Test Case SCP-52 --- Team A2/Test Cases/Test Case SCP-52.md | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Team A2/Test Cases/Test Case SCP-52.md b/Team A2/Test Cases/Test Case SCP-52.md index 6d8c153..b2c28d8 100644 --- a/Team A2/Test Cases/Test Case SCP-52.md +++ b/Team A2/Test Cases/Test Case SCP-52.md @@ -20,19 +20,19 @@ |Step | Action | Expected Result | Pass/Fail | |:---:| :--- | :---- | :---: | -|1|Run the game|The game loads up. There is no timer on the main menu.|| -|2|Click Play|The tutorial level is loaded. On the top right is one timer that times the amount of elapsed time since the player started.|| -|3|Navigate and die in the tutorial level|The dead screen has a count-down displayed.|| -|4|While the death screen's countdown is counting down, try to hit space to respawn|The player is not able to respawn until the countdown timer is over|| -|5|Navigate through the level and die once again. Once the death screen is loaded, hit escape to go back to the main menu|The main menu is loaded and the timer no longer displays|| -|6|Hit "Play" again to go back into the main menu|The tutorial level is loaded, and the timer is reset back to 0|| -|7|Complete the tutorial level|The level completed screen is shown, but only for a brief second before the next level is loaded. On the top right is now two timers, one that displays the total time, and another that displays the elapsed time for the current level|| -|8|Hit `P/Escape` to pause the game|While the game is paused, timers are also paused|| -|9|Exit back to main menu, Select "Difficulty", and select "Hardcore"|The player is brought back to the main menu, and the hardcore difficulty is selected|| -|10|Select "Level Select", then select "Level 3"|Level 3 is loaded, the timer starts running|| -|11|Die, and then respawn|The timer is reset back to 0|| +|1|Run the game|The game loads up. There is no timer on the main menu.|Pass| +|2|Click Play|The tutorial level is loaded. On the top right is one timer that times the amount of elapsed time since the player started.|Pass| +|3|Navigate and die in the tutorial level|The dead screen has a count-down displayed.|Not implemented| +|4|While the death screen's countdown is counting down, try to hit space to respawn|The player is not able to respawn until the countdown timer is over|Not implemented| +|5|Navigate through the level and die once again. Once the death screen is loaded, hit escape to go back to the main menu|The main menu is loaded and the timer no longer displays|Pass| +|6|Hit "Play" again to go back into the main menu|The tutorial level is loaded, and the timer is reset back to 0|Pass| +|7|Complete the tutorial level|The level completed screen is shown, but only for a brief second before the next level is loaded. On the top right is now two timers, one that displays the total time, and another that displays the elapsed time for the current level|Pass| +|8|Hit `P/Escape` to pause the game|While the game is paused, timers are also paused|Pass| +|9|Exit back to main menu, Select "Difficulty", and select "Hardcore"|The player is brought back to the main menu, and the hardcore difficulty is selected|Pass| +|10|Select "Level Select", then select "Level 3"|Level 3 is loaded, the timer starts running|Pass| +|11|Die, and then respawn|The timer is reset back to 0|Pass| ### Test Completion -- **Tester**: [TESTER NAME] -- **Date of Test**: DATE OF TEST -- **Test Result**: TEST RESULT \ No newline at end of file +- **Tester**: Nicholas Tourony +- **Date of Test**: 11/30/2021 +- **Test Result**: Pass \ No newline at end of file From da6dd4dcf5bd3443d774a8e84f7a08c29349d11f Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 30 Nov 2021 18:09:41 -0500 Subject: [PATCH 164/164] Quick Cleanup of Comments --- src/Utils/TimeParser.java | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/Utils/TimeParser.java b/src/Utils/TimeParser.java index 2c7fd1b..7d7b729 100644 --- a/src/Utils/TimeParser.java +++ b/src/Utils/TimeParser.java @@ -55,10 +55,6 @@ public String toString() { StringBuilder stringBuilder = new StringBuilder(); - /* - TODO clean / optimize - */ - if(hours > 0) { if(hours > 9) { stringBuilder.append((char) ('0' + hours / 10)); @@ -77,38 +73,6 @@ public String toString() { stringBuilder.append((char) ('0' + seconds % 10)).append('.'); stringBuilder.append((char) ('0' + elapsed / 100)).append((char) ('0' + (elapsed / 10) % 10)); -// char[] chs = new char[hours > 0 ? 11 : minutes > 0 ? 8 : 5]; -// -// //milliseconds -// chs[chs.length - 3] = '.'; -// chs[chs.length - 2] = (char) ('0' + (elapsed / 100)); -// chs[chs.length - 1] = (char) ('0' + (elapsed / 10) % 10); -// //seconds -// chs[chs.length - 5] = (char) ('0' + (seconds / 10)); -// if(minutes == 0 && hours == 0 && chs[chs.length - 5] == '0') { -// chs[chs.length - 5] = ' '; -// } -// chs[chs.length - 4] = (char) ('0' + (seconds % 10)); -// -// if(minutes > 0 || hours > 0) { -// chs[chs.length - 6] = ':'; -// chs[chs.length - 7] = (char) ('0' + (minutes % 10)); -// chs[chs.length - 8] = (char) ('0' + (minutes / 10)); -// if(chs[chs.length - 8] == '0' && hours == 0) { -// chs[chs.length - 8] = ' '; -// } -// -// if(hours > 0) { -// chs[0] = (char) ('0' + (hours / 10) % 10); -// if(chs[0] == '0') { -// chs[0] = ' '; -// } -// chs[1] = (char) ('0' + hours % 10); -// chs[2] = ':'; -// } -// } -// -// return new String(chs); return stringBuilder.toString(); } }