diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 00000000..188bbe03 --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,44 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: Java CI with Gradle + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'temurin' +# - name: Build with Gradle +# uses: gradle/gradle-build-action@937999e9cc2425eddc7fd62d1053baf041147db7 +# with: +# arguments: desktop:dist + + - name: Make gradlew executable + run: chmod +x ./gradlew + + - name: Build with Gradle + run: ./gradlew desktop:dist + - name: Run tests with Gradle + run: ./gradlew test + - name: Upload a Build Artifact + uses: actions/upload-artifact@v2.3.1 + with: + name: Spice_Traders + path: desktop/build/libs/desktop-1.0.jar diff --git a/.gitignore b/.gitignore index a4b5d51c..ccfd13be 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,4 @@ Thumbs.db /ios/xcode/native/ /ios/IOSLauncher.app /ios/IOSLauncher.app.dSYM +core/src/com/mygdx/pirategame/gameobjects/CannonFire_Old.java diff --git a/build.gradle b/build.gradle index 8a465fee..89f57f7f 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,38 @@ project(":core") { dependencies { api "com.badlogicgames.gdx:gdx:$gdxVersion" api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" - + + testCompile "junit:junit:4.+" + testCompile "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + testCompile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop" + + testImplementation "org.mockito:mockito-core:3.+" + } +} + +project(":test") { + apply plugin: "java-library" + + sourceSets.test.java.srcDirs = ["src/"] + + + dependencies { + compile project(":desktop") + compile project(":core") + + api "com.badlogicgames.gdx:gdx:$gdxVersion" + api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + + testCompile 'junit:junit:4.+' + testCompile "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + testCompile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + testCompile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop" + + testImplementation "org.mockito:mockito-core:3.+" } } diff --git a/core/assets/Tutorial.png b/core/assets/Tutorial.png new file mode 100644 index 00000000..7526c021 Binary files /dev/null and b/core/assets/Tutorial.png differ diff --git a/core/assets/W.png b/core/assets/Unused/W.png similarity index 100% rename from core/assets/W.png rename to core/assets/Unused/W.png diff --git a/core/assets/minimap.png b/core/assets/Unused/minimap.png similarity index 100% rename from core/assets/minimap.png rename to core/assets/Unused/minimap.png diff --git a/core/assets/alcuin_flag.png b/core/assets/college/Flags/alcuin_flag.png similarity index 100% rename from core/assets/alcuin_flag.png rename to core/assets/college/Flags/alcuin_flag.png diff --git a/core/assets/anne_lister_flag.png b/core/assets/college/Flags/anne_lister_flag.png similarity index 100% rename from core/assets/anne_lister_flag.png rename to core/assets/college/Flags/anne_lister_flag.png diff --git a/core/assets/constantine_flag.png b/core/assets/college/Flags/constantine_flag.png similarity index 100% rename from core/assets/constantine_flag.png rename to core/assets/college/Flags/constantine_flag.png diff --git a/core/assets/derwent_flag.png b/core/assets/college/Flags/derwent_flag.png similarity index 100% rename from core/assets/derwent_flag.png rename to core/assets/college/Flags/derwent_flag.png diff --git a/core/assets/goodricke_flag.png b/core/assets/college/Flags/goodricke_flag.png similarity index 100% rename from core/assets/goodricke_flag.png rename to core/assets/college/Flags/goodricke_flag.png diff --git a/core/assets/halifax_flag.png b/core/assets/college/Flags/halifax_flag.png similarity index 100% rename from core/assets/halifax_flag.png rename to core/assets/college/Flags/halifax_flag.png diff --git a/core/assets/james_flag.png b/core/assets/college/Flags/james_flag.png similarity index 100% rename from core/assets/james_flag.png rename to core/assets/college/Flags/james_flag.png diff --git a/core/assets/langwith_flag.png b/core/assets/college/Flags/langwith_flag.png similarity index 100% rename from core/assets/langwith_flag.png rename to core/assets/college/Flags/langwith_flag.png diff --git a/core/assets/vanbrugh_flag.png b/core/assets/college/Flags/vanbrugh_flag.png similarity index 100% rename from core/assets/vanbrugh_flag.png rename to core/assets/college/Flags/vanbrugh_flag.png diff --git a/core/assets/alcuin_ship.png b/core/assets/college/Ships/alcuin_ship.png similarity index 100% rename from core/assets/alcuin_ship.png rename to core/assets/college/Ships/alcuin_ship.png diff --git a/core/assets/anne_lister_ship.png b/core/assets/college/Ships/anne_lister_ship.png similarity index 100% rename from core/assets/anne_lister_ship.png rename to core/assets/college/Ships/anne_lister_ship.png diff --git a/core/assets/constantine_ship.png b/core/assets/college/Ships/constantine_ship.png similarity index 100% rename from core/assets/constantine_ship.png rename to core/assets/college/Ships/constantine_ship.png diff --git a/core/assets/derwent_ship.png b/core/assets/college/Ships/derwent_ship.png similarity index 100% rename from core/assets/derwent_ship.png rename to core/assets/college/Ships/derwent_ship.png diff --git a/core/assets/enemyShip1.png b/core/assets/college/Ships/enemyShip1.png similarity index 100% rename from core/assets/enemyShip1.png rename to core/assets/college/Ships/enemyShip1.png diff --git a/core/assets/goodricke_ship.png b/core/assets/college/Ships/goodricke_ship.png similarity index 100% rename from core/assets/goodricke_ship.png rename to core/assets/college/Ships/goodricke_ship.png diff --git a/core/assets/player_ship.png b/core/assets/college/Ships/player_ship.png similarity index 100% rename from core/assets/player_ship.png rename to core/assets/college/Ships/player_ship.png diff --git a/core/assets/ship.png b/core/assets/college/Ships/ship.png similarity index 100% rename from core/assets/ship.png rename to core/assets/college/Ships/ship.png diff --git a/core/assets/ship1.png b/core/assets/college/Ships/ship1.png similarity index 100% rename from core/assets/ship1.png rename to core/assets/college/Ships/ship1.png diff --git a/core/assets/unaligned_ship.png b/core/assets/college/Ships/unaligned_ship.png similarity index 100% rename from core/assets/unaligned_ship.png rename to core/assets/college/Ships/unaligned_ship.png diff --git a/core/assets/islands.tsx b/core/assets/map/islands.tsx similarity index 100% rename from core/assets/islands.tsx rename to core/assets/map/islands.tsx diff --git a/core/assets/map.tmx b/core/assets/map/map.tmx similarity index 99% rename from core/assets/map.tmx rename to core/assets/map/map.tmx index d96cd359..0b952dab 100644 --- a/core/assets/map.tmx +++ b/core/assets/map/map.tmx @@ -1,5 +1,5 @@ - + @@ -659,6 +659,7 @@ + diff --git a/core/assets/rocks.tsx b/core/assets/map/rocks.tsx similarity index 100% rename from core/assets/rocks.tsx rename to core/assets/map/rocks.tsx diff --git a/core/assets/tile_01.png b/core/assets/map/tile_01.png similarity index 100% rename from core/assets/tile_01.png rename to core/assets/map/tile_01.png diff --git a/core/assets/tile_02.png b/core/assets/map/tile_02.png similarity index 100% rename from core/assets/tile_02.png rename to core/assets/map/tile_02.png diff --git a/core/assets/tile_03.png b/core/assets/map/tile_03.png similarity index 100% rename from core/assets/tile_03.png rename to core/assets/map/tile_03.png diff --git a/core/assets/tile_04.png b/core/assets/map/tile_04.png similarity index 100% rename from core/assets/tile_04.png rename to core/assets/map/tile_04.png diff --git a/core/assets/tile_05.png b/core/assets/map/tile_05.png similarity index 100% rename from core/assets/tile_05.png rename to core/assets/map/tile_05.png diff --git a/core/assets/tile_06.png b/core/assets/map/tile_06.png similarity index 100% rename from core/assets/tile_06.png rename to core/assets/map/tile_06.png diff --git a/core/assets/tile_07.png b/core/assets/map/tile_07.png similarity index 100% rename from core/assets/tile_07.png rename to core/assets/map/tile_07.png diff --git a/core/assets/tile_08.png b/core/assets/map/tile_08.png similarity index 100% rename from core/assets/tile_08.png rename to core/assets/map/tile_08.png diff --git a/core/assets/tile_09.png b/core/assets/map/tile_09.png similarity index 100% rename from core/assets/tile_09.png rename to core/assets/map/tile_09.png diff --git a/core/assets/tile_10.png b/core/assets/map/tile_10.png similarity index 100% rename from core/assets/tile_10.png rename to core/assets/map/tile_10.png diff --git a/core/assets/tile_11.png b/core/assets/map/tile_11.png similarity index 100% rename from core/assets/tile_11.png rename to core/assets/map/tile_11.png diff --git a/core/assets/tile_12.png b/core/assets/map/tile_12.png similarity index 100% rename from core/assets/tile_12.png rename to core/assets/map/tile_12.png diff --git a/core/assets/tile_13.png b/core/assets/map/tile_13.png similarity index 100% rename from core/assets/tile_13.png rename to core/assets/map/tile_13.png diff --git a/core/assets/tile_14.png b/core/assets/map/tile_14.png similarity index 100% rename from core/assets/tile_14.png rename to core/assets/map/tile_14.png diff --git a/core/assets/tile_15.png b/core/assets/map/tile_15.png similarity index 100% rename from core/assets/tile_15.png rename to core/assets/map/tile_15.png diff --git a/core/assets/tile_16.png b/core/assets/map/tile_16.png similarity index 100% rename from core/assets/tile_16.png rename to core/assets/map/tile_16.png diff --git a/core/assets/tile_17.png b/core/assets/map/tile_17.png similarity index 100% rename from core/assets/tile_17.png rename to core/assets/map/tile_17.png diff --git a/core/assets/tile_18.png b/core/assets/map/tile_18.png similarity index 100% rename from core/assets/tile_18.png rename to core/assets/map/tile_18.png diff --git a/core/assets/tile_19.png b/core/assets/map/tile_19.png similarity index 100% rename from core/assets/tile_19.png rename to core/assets/map/tile_19.png diff --git a/core/assets/tile_20.png b/core/assets/map/tile_20.png similarity index 100% rename from core/assets/tile_20.png rename to core/assets/map/tile_20.png diff --git a/core/assets/tile_21.png b/core/assets/map/tile_21.png similarity index 100% rename from core/assets/tile_21.png rename to core/assets/map/tile_21.png diff --git a/core/assets/tile_22.png b/core/assets/map/tile_22.png similarity index 100% rename from core/assets/tile_22.png rename to core/assets/map/tile_22.png diff --git a/core/assets/tile_23.png b/core/assets/map/tile_23.png similarity index 100% rename from core/assets/tile_23.png rename to core/assets/map/tile_23.png diff --git a/core/assets/tile_24.png b/core/assets/map/tile_24.png similarity index 100% rename from core/assets/tile_24.png rename to core/assets/map/tile_24.png diff --git a/core/assets/tile_25.png b/core/assets/map/tile_25.png similarity index 100% rename from core/assets/tile_25.png rename to core/assets/map/tile_25.png diff --git a/core/assets/tile_26.png b/core/assets/map/tile_26.png similarity index 100% rename from core/assets/tile_26.png rename to core/assets/map/tile_26.png diff --git a/core/assets/tile_27.png b/core/assets/map/tile_27.png similarity index 100% rename from core/assets/tile_27.png rename to core/assets/map/tile_27.png diff --git a/core/assets/tile_28.png b/core/assets/map/tile_28.png similarity index 100% rename from core/assets/tile_28.png rename to core/assets/map/tile_28.png diff --git a/core/assets/tile_29.png b/core/assets/map/tile_29.png similarity index 100% rename from core/assets/tile_29.png rename to core/assets/map/tile_29.png diff --git a/core/assets/tile_30.png b/core/assets/map/tile_30.png similarity index 100% rename from core/assets/tile_30.png rename to core/assets/map/tile_30.png diff --git a/core/assets/tile_31.png b/core/assets/map/tile_31.png similarity index 100% rename from core/assets/tile_31.png rename to core/assets/map/tile_31.png diff --git a/core/assets/tile_32.png b/core/assets/map/tile_32.png similarity index 100% rename from core/assets/tile_32.png rename to core/assets/map/tile_32.png diff --git a/core/assets/tile_33.png b/core/assets/map/tile_33.png similarity index 100% rename from core/assets/tile_33.png rename to core/assets/map/tile_33.png diff --git a/core/assets/tile_34.png b/core/assets/map/tile_34.png similarity index 100% rename from core/assets/tile_34.png rename to core/assets/map/tile_34.png diff --git a/core/assets/tile_35.png b/core/assets/map/tile_35.png similarity index 100% rename from core/assets/tile_35.png rename to core/assets/map/tile_35.png diff --git a/core/assets/tile_36.png b/core/assets/map/tile_36.png similarity index 100% rename from core/assets/tile_36.png rename to core/assets/map/tile_36.png diff --git a/core/assets/tile_37.png b/core/assets/map/tile_37.png similarity index 100% rename from core/assets/tile_37.png rename to core/assets/map/tile_37.png diff --git a/core/assets/tile_38.png b/core/assets/map/tile_38.png similarity index 100% rename from core/assets/tile_38.png rename to core/assets/map/tile_38.png diff --git a/core/assets/tile_39.png b/core/assets/map/tile_39.png similarity index 100% rename from core/assets/tile_39.png rename to core/assets/map/tile_39.png diff --git a/core/assets/tile_40.png b/core/assets/map/tile_40.png similarity index 100% rename from core/assets/tile_40.png rename to core/assets/map/tile_40.png diff --git a/core/assets/tile_41.png b/core/assets/map/tile_41.png similarity index 100% rename from core/assets/tile_41.png rename to core/assets/map/tile_41.png diff --git a/core/assets/tile_42.png b/core/assets/map/tile_42.png similarity index 100% rename from core/assets/tile_42.png rename to core/assets/map/tile_42.png diff --git a/core/assets/tile_43.png b/core/assets/map/tile_43.png similarity index 100% rename from core/assets/tile_43.png rename to core/assets/map/tile_43.png diff --git a/core/assets/tile_44.png b/core/assets/map/tile_44.png similarity index 100% rename from core/assets/tile_44.png rename to core/assets/map/tile_44.png diff --git a/core/assets/tile_45.png b/core/assets/map/tile_45.png similarity index 100% rename from core/assets/tile_45.png rename to core/assets/map/tile_45.png diff --git a/core/assets/tile_46.png b/core/assets/map/tile_46.png similarity index 100% rename from core/assets/tile_46.png rename to core/assets/map/tile_46.png diff --git a/core/assets/tile_47.png b/core/assets/map/tile_47.png similarity index 100% rename from core/assets/tile_47.png rename to core/assets/map/tile_47.png diff --git a/core/assets/tile_48.png b/core/assets/map/tile_48.png similarity index 100% rename from core/assets/tile_48.png rename to core/assets/map/tile_48.png diff --git a/core/assets/tile_49.png b/core/assets/map/tile_49.png similarity index 100% rename from core/assets/tile_49.png rename to core/assets/map/tile_49.png diff --git a/core/assets/tile_50.png b/core/assets/map/tile_50.png similarity index 100% rename from core/assets/tile_50.png rename to core/assets/map/tile_50.png diff --git a/core/assets/tile_51.png b/core/assets/map/tile_51.png similarity index 100% rename from core/assets/tile_51.png rename to core/assets/map/tile_51.png diff --git a/core/assets/tile_52.png b/core/assets/map/tile_52.png similarity index 100% rename from core/assets/tile_52.png rename to core/assets/map/tile_52.png diff --git a/core/assets/tile_53.png b/core/assets/map/tile_53.png similarity index 100% rename from core/assets/tile_53.png rename to core/assets/map/tile_53.png diff --git a/core/assets/tile_54.png b/core/assets/map/tile_54.png similarity index 100% rename from core/assets/tile_54.png rename to core/assets/map/tile_54.png diff --git a/core/assets/tile_55.png b/core/assets/map/tile_55.png similarity index 100% rename from core/assets/tile_55.png rename to core/assets/map/tile_55.png diff --git a/core/assets/tile_56.png b/core/assets/map/tile_56.png similarity index 100% rename from core/assets/tile_56.png rename to core/assets/map/tile_56.png diff --git a/core/assets/tile_57.png b/core/assets/map/tile_57.png similarity index 100% rename from core/assets/tile_57.png rename to core/assets/map/tile_57.png diff --git a/core/assets/tile_58.png b/core/assets/map/tile_58.png similarity index 100% rename from core/assets/tile_58.png rename to core/assets/map/tile_58.png diff --git a/core/assets/tile_59.png b/core/assets/map/tile_59.png similarity index 100% rename from core/assets/tile_59.png rename to core/assets/map/tile_59.png diff --git a/core/assets/tile_60.png b/core/assets/map/tile_60.png similarity index 100% rename from core/assets/tile_60.png rename to core/assets/map/tile_60.png diff --git a/core/assets/tile_61.png b/core/assets/map/tile_61.png similarity index 100% rename from core/assets/tile_61.png rename to core/assets/map/tile_61.png diff --git a/core/assets/tile_62.png b/core/assets/map/tile_62.png similarity index 100% rename from core/assets/tile_62.png rename to core/assets/map/tile_62.png diff --git a/core/assets/tile_63.png b/core/assets/map/tile_63.png similarity index 100% rename from core/assets/tile_63.png rename to core/assets/map/tile_63.png diff --git a/core/assets/tile_64.png b/core/assets/map/tile_64.png similarity index 100% rename from core/assets/tile_64.png rename to core/assets/map/tile_64.png diff --git a/core/assets/tile_65.png b/core/assets/map/tile_65.png similarity index 100% rename from core/assets/tile_65.png rename to core/assets/map/tile_65.png diff --git a/core/assets/tile_66.png b/core/assets/map/tile_66.png similarity index 100% rename from core/assets/tile_66.png rename to core/assets/map/tile_66.png diff --git a/core/assets/tile_67.png b/core/assets/map/tile_67.png similarity index 100% rename from core/assets/tile_67.png rename to core/assets/map/tile_67.png diff --git a/core/assets/tile_68.png b/core/assets/map/tile_68.png similarity index 100% rename from core/assets/tile_68.png rename to core/assets/map/tile_68.png diff --git a/core/assets/tile_69.png b/core/assets/map/tile_69.png similarity index 100% rename from core/assets/tile_69.png rename to core/assets/map/tile_69.png diff --git a/core/assets/tile_70.png b/core/assets/map/tile_70.png similarity index 100% rename from core/assets/tile_70.png rename to core/assets/map/tile_70.png diff --git a/core/assets/tile_71.png b/core/assets/map/tile_71.png similarity index 100% rename from core/assets/tile_71.png rename to core/assets/map/tile_71.png diff --git a/core/assets/tile_72.png b/core/assets/map/tile_72.png similarity index 100% rename from core/assets/tile_72.png rename to core/assets/map/tile_72.png diff --git a/core/assets/tile_73.png b/core/assets/map/tile_73.png similarity index 100% rename from core/assets/tile_73.png rename to core/assets/map/tile_73.png diff --git a/core/assets/tile_74.png b/core/assets/map/tile_74.png similarity index 100% rename from core/assets/tile_74.png rename to core/assets/map/tile_74.png diff --git a/core/assets/tile_75.png b/core/assets/map/tile_75.png similarity index 100% rename from core/assets/tile_75.png rename to core/assets/map/tile_75.png diff --git a/core/assets/tile_76.png b/core/assets/map/tile_76.png similarity index 100% rename from core/assets/tile_76.png rename to core/assets/map/tile_76.png diff --git a/core/assets/tile_77.png b/core/assets/map/tile_77.png similarity index 100% rename from core/assets/tile_77.png rename to core/assets/map/tile_77.png diff --git a/core/assets/tile_78.png b/core/assets/map/tile_78.png similarity index 100% rename from core/assets/tile_78.png rename to core/assets/map/tile_78.png diff --git a/core/assets/tile_79.png b/core/assets/map/tile_79.png similarity index 100% rename from core/assets/tile_79.png rename to core/assets/map/tile_79.png diff --git a/core/assets/tile_80.png b/core/assets/map/tile_80.png similarity index 100% rename from core/assets/tile_80.png rename to core/assets/map/tile_80.png diff --git a/core/assets/tile_81.png b/core/assets/map/tile_81.png similarity index 100% rename from core/assets/tile_81.png rename to core/assets/map/tile_81.png diff --git a/core/assets/tile_82.png b/core/assets/map/tile_82.png similarity index 100% rename from core/assets/tile_82.png rename to core/assets/map/tile_82.png diff --git a/core/assets/tile_83.png b/core/assets/map/tile_83.png similarity index 100% rename from core/assets/tile_83.png rename to core/assets/map/tile_83.png diff --git a/core/assets/tile_84.png b/core/assets/map/tile_84.png similarity index 100% rename from core/assets/tile_84.png rename to core/assets/map/tile_84.png diff --git a/core/assets/tile_85.png b/core/assets/map/tile_85.png similarity index 100% rename from core/assets/tile_85.png rename to core/assets/map/tile_85.png diff --git a/core/assets/tile_86.png b/core/assets/map/tile_86.png similarity index 100% rename from core/assets/tile_86.png rename to core/assets/map/tile_86.png diff --git a/core/assets/tile_87.png b/core/assets/map/tile_87.png similarity index 100% rename from core/assets/tile_87.png rename to core/assets/map/tile_87.png diff --git a/core/assets/tile_88.png b/core/assets/map/tile_88.png similarity index 100% rename from core/assets/tile_88.png rename to core/assets/map/tile_88.png diff --git a/core/assets/tile_93.png b/core/assets/map/tile_93.png similarity index 100% rename from core/assets/tile_93.png rename to core/assets/map/tile_93.png diff --git a/core/assets/tile_94.png b/core/assets/map/tile_94.png similarity index 100% rename from core/assets/tile_94.png rename to core/assets/map/tile_94.png diff --git a/core/assets/water.tsx b/core/assets/map/water.tsx similarity index 100% rename from core/assets/water.tsx rename to core/assets/map/water.tsx diff --git a/core/assets/map_blurred.png b/core/assets/map_blurred.png new file mode 100644 index 00000000..cb5b7f4b Binary files /dev/null and b/core/assets/map_blurred.png differ diff --git a/core/assets/coin-pickup.mp3 b/core/assets/sfx_and_music/coin-pickup.mp3 similarity index 100% rename from core/assets/coin-pickup.mp3 rename to core/assets/sfx_and_music/coin-pickup.mp3 diff --git a/core/assets/sfx_and_music/explode.mp3 b/core/assets/sfx_and_music/explode.mp3 new file mode 100644 index 00000000..6bb444b0 Binary files /dev/null and b/core/assets/sfx_and_music/explode.mp3 differ diff --git a/core/assets/explosion.wav b/core/assets/sfx_and_music/explosion.wav similarity index 100% rename from core/assets/explosion.wav rename to core/assets/sfx_and_music/explosion.wav diff --git a/core/assets/pirate-music.mp3 b/core/assets/sfx_and_music/pirate-music.mp3 similarity index 100% rename from core/assets/pirate-music.mp3 rename to core/assets/sfx_and_music/pirate-music.mp3 diff --git a/core/assets/ship-explosion-2.wav b/core/assets/sfx_and_music/ship-explosion-2.wav similarity index 100% rename from core/assets/ship-explosion-2.wav rename to core/assets/sfx_and_music/ship-explosion-2.wav diff --git a/core/assets/ship-hit.wav b/core/assets/sfx_and_music/ship-hit.wav similarity index 100% rename from core/assets/ship-hit.wav rename to core/assets/sfx_and_music/ship-hit.wav diff --git a/core/assets/wood-bump.mp3 b/core/assets/sfx_and_music/wood-bump.mp3 similarity index 100% rename from core/assets/wood-bump.mp3 rename to core/assets/sfx_and_music/wood-bump.mp3 diff --git a/core/build.gradle b/core/build.gradle index d192d041..627eab8d 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,6 +1,13 @@ sourceCompatibility = 1.7 +dependencies { + implementation 'com.badlogicgames.gdx:gdx-backend-headless:1.10.0' + implementation 'junit:junit:4.11' + implementation 'org.mockito:mockito-all:1.10.7' +} [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' -sourceSets.main.java.srcDirs = [ "src/" ] +sourceSets.main.java.srcDirs = [ "src/main/java" ] +sourceSets.test.java.srcDirs = [ "src/test/java" ] +sourceSets.test.resources.srcDirs = ["../core/assets"] eclipse.project.name = appName + "-core" diff --git a/core/src/com/mygdx/pirategame/Coin.java b/core/src/com/mygdx/pirategame/Coin.java deleted file mode 100644 index 31175291..00000000 --- a/core/src/com/mygdx/pirategame/Coin.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.mygdx.pirategame; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.audio.Sound; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.Batch; -import com.badlogic.gdx.physics.box2d.BodyDef; -import com.badlogic.gdx.physics.box2d.CircleShape; -import com.badlogic.gdx.physics.box2d.FixtureDef; - -/** - * Coin - * Creates an object for each coin - * Extends the entity class to define coin as an entity - * - *@author Joe Dickinson - *@version 1.0 - */ -public class Coin extends Entity { - private Texture coin; - private boolean setToDestroyed; - private boolean destroyed; - private Sound coinPickup; - - /** - * Instantiates a new Coin. - * - * @param screen the screen its going onto - * @param x the x value to be placed at - * @param y the y value to be placed at - */ - public Coin(GameScreen screen, float x, float y) { - super(screen, x, y); - //Set coin image - coin = new Texture("coin.png"); - //Set the position and size of the coin - setBounds(0,0,48 / PirateGame.PPM, 48 / PirateGame.PPM); - //Set the texture - setRegion(coin); - //Sets origin of the coin - setOrigin(24 / PirateGame.PPM,24 / PirateGame.PPM); - coinPickup = Gdx.audio.newSound(Gdx.files.internal("coin-pickup.mp3")); - } - - /** - * Updates the coins state. If needed, deletes the coin if picked up. - */ - public void update() { - //If coin is set to destroy and isnt, destroy it - if(setToDestroyed && !destroyed) { - world.destroyBody(b2body); - destroyed = true; - } - //Update position of coin - else if(!destroyed) { - setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); - } - } - - /** - * Defines all the parts of the coins physical model. Sets it up for collisons - */ - @Override - protected void defineEntity() { - //sets the body definitions - BodyDef bdef = new BodyDef(); - bdef.position.set(getX(), getY()); - bdef.type = BodyDef.BodyType.DynamicBody; - b2body = world.createBody(bdef); - - //Sets collision boundaries - FixtureDef fdef = new FixtureDef(); - CircleShape shape = new CircleShape(); - shape.setRadius(24 / PirateGame.PPM); - // setting BIT identifier - fdef.filter.categoryBits = PirateGame.COIN_BIT; - // determining what this BIT can collide with - fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT; - fdef.shape = shape; - fdef.isSensor = true; - b2body.createFixture(fdef).setUserData(this); - } - - /** - * What happens when an entity collides with the coin. The only entity that is able to do so is the player ship - */ - @Override - public void entityContact() { - //Add a coin - Hud.changeCoins(1); - //Set to destroy - setToDestroyed = true; - Gdx.app.log("coin", "collision"); - //Play pickup sound - if (screen.game.getPreferences().isEffectsEnabled()) { - coinPickup.play(screen.game.getPreferences().getEffectsVolume()); - } - - } - - /** - * Draws the coin using batch - * - * @param batch The batch of the program - */ - public void draw(Batch batch) { - if(!destroyed) { - super.draw(batch); - } - } -} diff --git a/core/src/com/mygdx/pirategame/EnemyShip.java b/core/src/com/mygdx/pirategame/EnemyShip.java deleted file mode 100644 index f44e6197..00000000 --- a/core/src/com/mygdx/pirategame/EnemyShip.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.mygdx.pirategame; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.audio.Sound; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.Batch; -import com.badlogic.gdx.physics.box2d.BodyDef; -import com.badlogic.gdx.physics.box2d.CircleShape; -import com.badlogic.gdx.physics.box2d.FixtureDef; - -/** - * Enemy Ship - * Generates enemy ship data - * Instantiates an enemy ship - * - *@author Ethan Alabaster, Sam Pearson, Edward Poulter - *@version 1.0 - */ -public class EnemyShip extends Enemy{ - private Texture enemyShip; - public String college; - private Sound destroy; - private Sound hit; - - /** - * Instantiates enemy ship - * - * @param screen Visual data - * @param x x coordinates of entity - * @param y y coordinates of entity - * @param path path of texture file - * @param assignment College ship is assigned to - */ - public EnemyShip(GameScreen screen, float x, float y, String path, String assignment) { - super(screen, x, y); - enemyShip = new Texture(path); - //Assign college - college = assignment; - //Set audios - destroy = Gdx.audio.newSound(Gdx.files.internal("ship-explosion-2.wav")); - hit = Gdx.audio.newSound(Gdx.files.internal("ship-hit.wav")); - //Set the position and size of the college - setBounds(0,0,64 / PirateGame.PPM, 110 / PirateGame.PPM); - setRegion(enemyShip); - setOrigin(32 / PirateGame.PPM,55 / PirateGame.PPM); - - damage = 20; - } - - /** - * Updates the state of each object with delta time - * Checks for ship destruction - * - * @param dt Delta time (elapsed time since last game tick) - */ - public void update(float dt) { - //If ship is set to destroy and isnt, destroy it - if(setToDestroy && !destroyed) { - //Play death noise - if (screen.game.getPreferences().isEffectsEnabled()) { - destroy.play(screen.game.getPreferences().getEffectsVolume()); - } - world.destroyBody(b2body); - destroyed = true; - //Change player coins and points - Hud.changePoints(20); - Hud.changeCoins(10); - } - else if(!destroyed) { - //Update position and angle of ship - setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); - float angle = (float) Math.atan2(b2body.getLinearVelocity().y, b2body.getLinearVelocity().x); - b2body.setTransform(b2body.getWorldCenter(), angle - ((float) Math.PI) / 2.0f); - setRotation((float) (b2body.getAngle() * 180 / Math.PI)); - //Update health bar - bar.update(); - } - if(health <= 0) { - setToDestroy = true; - } - - // below code is to move the ship to a coordinate (target) - //Vector2 target = new Vector2(960 / PirateGame.PPM, 2432 / PirateGame.PPM); - //target.sub(b2body.getPosition()); - //target.nor(); - //float speed = 1.5f; - //b2body.setLinearVelocity(target.scl(speed)); - } - - /** - * Constructs the ship batch - * - * @param batch The batch of visual data of the ship - */ - public void draw(Batch batch) { - if(!destroyed) { - super.draw(batch); - //Render health bar - bar.render(batch); - } - } - - /** - * Defines the ship as an enemy - * Sets data to act as an enemy - */ - @Override - protected void defineEnemy() { - //sets the body definitions - BodyDef bdef = new BodyDef(); - bdef.position.set(getX(), getY()); - bdef.type = BodyDef.BodyType.DynamicBody; - b2body = world.createBody(bdef); - - //Sets collision boundaries - FixtureDef fdef = new FixtureDef(); - CircleShape shape = new CircleShape(); - shape.setRadius(55 / PirateGame.PPM); - // setting BIT identifier - fdef.filter.categoryBits = PirateGame.ENEMY_BIT; - // determining what this BIT can collide with - fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT | PirateGame.CANNON_BIT; - fdef.shape = shape; - fdef.restitution = 0.7f; - b2body.createFixture(fdef).setUserData(this); - } - - /** - * Checks contact - * Changes health in accordance with contact and damage - */ - @Override - public void onContact() { - Gdx.app.log("enemy", "collision"); - //Play collision sound - if (screen.game.getPreferences().isEffectsEnabled()) { - hit.play(screen.game.getPreferences().getEffectsVolume()); - } - //Deal with the damage - health -= damage; - bar.changeHealth(damage); - Hud.changePoints(5); - } - - /** - * Updates the ship image. Particuarly change texture on college destruction - * - * @param alignment Associated college - * @param path Path of new texture - */ - public void updateTexture(String alignment, String path){ - college = alignment; - enemyShip = new Texture(path); - setRegion(enemyShip); - } -} diff --git a/core/src/com/mygdx/pirategame/GameScreen.java b/core/src/com/mygdx/pirategame/GameScreen.java deleted file mode 100644 index 34489e6b..00000000 --- a/core/src/com/mygdx/pirategame/GameScreen.java +++ /dev/null @@ -1,562 +0,0 @@ -package com.mygdx.pirategame; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Input; -import com.badlogic.gdx.Screen; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.maps.tiled.TiledMap; -import com.badlogic.gdx.maps.tiled.TmxMapLoader; -import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.physics.box2d.*; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.ui.Skin; -import com.badlogic.gdx.scenes.scene2d.ui.Table; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; -import com.badlogic.gdx.utils.viewport.*; -import java.util.Random; - -import java.util.ArrayList; -import java.util.HashMap; - - -/** - * Game Screen - * Class to generate the various screens used to play the game. - * Instantiates all screen types and displays current screen. - * - *@author Ethan Alabaster, Adam Crook, Joe Dickinson, Sam Pearson, Tom Perry, Edward Poulter - *@version 1.0 - */ -public class GameScreen implements Screen { - private static float maxSpeed = 2.5f; - private static float accel = 0.05f; - private float stateTime; - - protected static PirateGame game; - private OrthographicCamera camera; - private Viewport viewport; - private final Stage stage; - - private TmxMapLoader maploader; - private TiledMap map; - private OrthogonalTiledMapRenderer renderer; - - private World world; - private Box2DDebugRenderer b2dr; - - private Player player; - private static HashMap colleges = new HashMap<>(); - private static ArrayList ships = new ArrayList<>(); - private static ArrayList Coins = new ArrayList<>(); - private AvailableSpawn invalidSpawn = new AvailableSpawn(); - private Hud hud; - - public static final int GAME_RUNNING = 0; - public static final int GAME_PAUSED = 1; - private static int gameStatus; - - private Table pauseTable; - private Table table; - - public Random rand = new Random(); - - /** - * Initialises the Game Screen, - * generates the world data and data for entities that exist upon it, - * @param game passes game data to current class, - */ - public GameScreen(PirateGame game){ - gameStatus = GAME_RUNNING; - this.game = game; - // Initialising camera and extendable viewport for viewing game - camera = new OrthographicCamera(); - camera.zoom = 0.0155f; - viewport = new ScreenViewport(camera); - camera.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0); - - // Initialize a hud - hud = new Hud(game.batch); - - // Initialising box2d physics - world = new World(new Vector2(0,0), true); - b2dr = new Box2DDebugRenderer(); - player = new Player(this); - - // making the Tiled tmx file render as a map - maploader = new TmxMapLoader(); - map = maploader.load("map.tmx"); - renderer = new OrthogonalTiledMapRenderer(map, 1 / PirateGame.PPM); - new WorldCreator(this); - - // Setting up contact listener for collisions - world.setContactListener(new WorldContactListener()); - - // Spawning enemy ship and coin. x and y is spawn location - colleges = new HashMap<>(); - colleges.put("Alcuin", new College(this, "Alcuin", 1900 / PirateGame.PPM, 2100 / PirateGame.PPM, - "alcuin_flag.png", "alcuin_ship.png", 0, invalidSpawn)); - colleges.put("Anne Lister", new College(this, "Anne Lister", 6304 / PirateGame.PPM, 1199 / PirateGame.PPM, - "anne_lister_flag.png", "anne_lister_ship.png", 8, invalidSpawn)); - colleges.put("Constantine", new College(this, "Constantine", 6240 / PirateGame.PPM, 6703 / PirateGame.PPM, - "constantine_flag.png", "constantine_ship.png", 8, invalidSpawn)); - colleges.put("Goodricke", new College(this, "Goodricke", 1760 / PirateGame.PPM, 6767 / PirateGame.PPM, - "goodricke_flag.png", "goodricke_ship.png", 8, invalidSpawn)); - ships = new ArrayList<>(); - ships.addAll(colleges.get("Alcuin").fleet); - ships.addAll(colleges.get("Anne Lister").fleet); - ships.addAll(colleges.get("Constantine").fleet); - ships.addAll(colleges.get("Goodricke").fleet); - - //Random ships - Boolean validLoc; - int a = 0; - int b = 0; - for (int i = 0; i < 20; i++) { - validLoc = false; - while (!validLoc) { - //Get random x and y coords - a = rand.nextInt(AvailableSpawn.xCap - AvailableSpawn.xBase) + AvailableSpawn.xBase; - b = rand.nextInt(AvailableSpawn.yCap - AvailableSpawn.yBase) + AvailableSpawn.yBase; - //Check if valid - validLoc = checkGenPos(a, b); - } - //Add a ship at the random coords - ships.add(new EnemyShip(this, a, b, "unaligned_ship.png", "Unaligned")); - } - - //Random coins - Coins = new ArrayList<>(); - for (int i = 0; i < 100; i++) { - validLoc = false; - while (!validLoc) { - //Get random x and y coords - a = rand.nextInt(AvailableSpawn.xCap - AvailableSpawn.xBase) + AvailableSpawn.xBase; - b = rand.nextInt(AvailableSpawn.yCap - AvailableSpawn.yBase) + AvailableSpawn.yBase; - validLoc = checkGenPos(a, b); - } - //Add a coins at the random coords - Coins.add(new Coin(this, a, b)); - } - - //Setting stage - stage = new Stage(new ScreenViewport()); - } - - /** - * Makes this the current screen for the game. - * Generates the buttons to be able to interact with what screen is being displayed. - * Creates the escape menu and pause button - */ - @Override - public void show() { - Gdx.input.setInputProcessor(stage); - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); - - //GAME BUTTONS - final TextButton pauseButton = new TextButton("Pause",skin); - final TextButton skill = new TextButton("Skill Tree", skin); - - //PAUSE MENU BUTTONS - final TextButton start = new TextButton("Resume", skin); - final TextButton options = new TextButton("Options", skin); - TextButton exit = new TextButton("Exit", skin); - - - //Create main table and pause tables - table = new Table(); - table.setFillParent(true); - stage.addActor(table); - - pauseTable = new Table(); - pauseTable.setFillParent(true); - stage.addActor(pauseTable); - - - //Set the visability of the tables. Particuarly used when coming back from options or skillTree - if (gameStatus == GAME_PAUSED){ - table.setVisible(false); - pauseTable.setVisible(true); - } - else{ - pauseTable.setVisible(false); - table.setVisible(true); - } - - //ADD TO TABLES - table.add(pauseButton); - table.row().pad(10, 0, 10, 0); - table.left().top(); - - pauseTable.add(start).fillX().uniformX(); - pauseTable.row().pad(20, 0, 10, 0); - pauseTable.add(skill).fillX().uniformX(); - pauseTable.row().pad(20, 0, 10, 0); - pauseTable.add(options).fillX().uniformX(); - pauseTable.row().pad(20, 0, 10, 0); - pauseTable.add(exit).fillX().uniformX(); - pauseTable.center(); - - - pauseButton.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor){ - table.setVisible(false); - pauseTable.setVisible(true); - pause(); - - } - }); - skill.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor){ - pauseTable.setVisible(false); - game.changeScreen(PirateGame.SKILL); - } - }); - start.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor) { - pauseTable.setVisible(false); - table.setVisible(true); - resume(); - } - }); - options.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor) { - pauseTable.setVisible(false); - game.setScreen(new Options(game,game.getScreen())); - } - } - ); - exit.addListener(new ChangeListener() { - @Override - public void changed(ChangeEvent event, Actor actor) { - Gdx.app.exit(); - } - }); - } - - /** - * Checks for input and performs an action - * Applies to keys "W" "A" "S" "D" "E" "Esc" - * - * Caps player velocity - * - * @param dt Delta time (elapsed time since last game tick) - */ - public void handleInput(float dt) { - if (gameStatus == GAME_RUNNING) { - // Left physics impulse on 'A' - if (Gdx.input.isKeyPressed(Input.Keys.A)) { - player.b2body.applyLinearImpulse(new Vector2(-accel, 0), player.b2body.getWorldCenter(), true); - } - // Right physics impulse on 'D' - if (Gdx.input.isKeyPressed(Input.Keys.D)) { - player.b2body.applyLinearImpulse(new Vector2(accel, 0), player.b2body.getWorldCenter(), true); - } - // Up physics impulse on 'W' - if (Gdx.input.isKeyPressed(Input.Keys.W)) { - player.b2body.applyLinearImpulse(new Vector2(0, accel), player.b2body.getWorldCenter(), true); - } - // Down physics impulse on 'S' - if (Gdx.input.isKeyPressed(Input.Keys.S)) { - player.b2body.applyLinearImpulse(new Vector2(0, -accel), player.b2body.getWorldCenter(), true); - } - // Cannon fire on 'E' - if (Gdx.input.isKeyJustPressed(Input.Keys.E)) { - player.fire(); - } - // Checking if player at max velocity, and keeping them below max - if (player.b2body.getLinearVelocity().x >= maxSpeed) { - player.b2body.applyLinearImpulse(new Vector2(-accel, 0), player.b2body.getWorldCenter(), true); - } - if (player.b2body.getLinearVelocity().x <= -maxSpeed) { - player.b2body.applyLinearImpulse(new Vector2(accel, 0), player.b2body.getWorldCenter(), true); - } - if (player.b2body.getLinearVelocity().y >= maxSpeed) { - player.b2body.applyLinearImpulse(new Vector2(0, -accel), player.b2body.getWorldCenter(), true); - } - if (player.b2body.getLinearVelocity().y <= -maxSpeed) { - player.b2body.applyLinearImpulse(new Vector2(0, accel), player.b2body.getWorldCenter(), true); - } - } - if (Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) { - if(gameStatus == GAME_PAUSED) { - resume(); - table.setVisible(true); - pauseTable.setVisible(false); - } - else { - table.setVisible(false); - pauseTable.setVisible(true); - pause(); - } - } - } - - /** - * Updates the state of each object with delta time - * - * @param dt Delta time (elapsed time since last game tick) - */ - public void update(float dt) { - stateTime += dt; - handleInput(dt); - // Stepping the physics engine by time of 1 frame - world.step(1 / 60f, 6, 2); - - // Update all players and entities - player.update(dt); - colleges.get("Alcuin").update(dt); - colleges.get("Anne Lister").update(dt); - colleges.get("Constantine").update(dt); - colleges.get("Goodricke").update(dt); - - //Update ships - for (int i = 0; i < ships.size(); i++) { - ships.get(i).update(dt); - } - - //Updates coin - for (int i = 0; i < Coins.size(); i++) { - Coins.get(i).update(); - } - //After a delay check if a college is destroyed. If not, if can fire - if (stateTime > 1) { - if (!colleges.get("Anne Lister").destroyed) { - colleges.get("Anne Lister").fire(); - } - if (!colleges.get("Constantine").destroyed) { - colleges.get("Constantine").fire(); - } - if (!colleges.get("Goodricke").destroyed) { - colleges.get("Goodricke").fire(); - } - stateTime = 0; - } - - hud.update(dt); - - // Centre camera on player boat - camera.position.x = player.b2body.getPosition().x; - camera.position.y = player.b2body.getPosition().y; - camera.update(); - renderer.setView(camera); - } - - /** - * Renders the visual data for all objects - * Changes and renders new visual data for ships - * - * @param dt Delta time (elapsed time since last game tick) - */ - @Override - public void render(float dt) { - if (gameStatus == GAME_RUNNING) { - update(dt); - } - else{handleInput(dt);} - - Gdx.gl.glClearColor(46/255f, 204/255f, 113/255f, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - renderer.render(); - // b2dr is the hitbox shapes, can be commented out to hide - //b2dr.render(world, camera.combined); - - game.batch.setProjectionMatrix(camera.combined); - game.batch.begin(); - // Order determines layering - - //Renders coins - for(int i=0;i yTest = invalidSpawn.tileBlocked.get(x); - if (yTest.contains(y)) { - return false; - } - } - return true; - } - - /** - * Pauses game - */ - @Override - public void pause() { - gameStatus = GAME_PAUSED; - } - - /** - * Resumes game - */ - @Override - public void resume() { - gameStatus = GAME_RUNNING; - } - - /** - * (Not Used) - * Hides game - */ - @Override - public void hide() { - - } - - /** - * Disposes game data - */ - @Override - public void dispose() { - map.dispose(); - renderer.dispose(); - world.dispose(); - b2dr.dispose(); - hud.dispose(); - stage.dispose(); - } -} diff --git a/core/src/main/java/com/mygdx/pirategame/DebugUtils.java b/core/src/main/java/com/mygdx/pirategame/DebugUtils.java new file mode 100644 index 00000000..6f369173 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/DebugUtils.java @@ -0,0 +1,72 @@ +package com.mygdx.pirategame; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector2; + +/** + * Methods to make debugging bugs easier (for example drawing lines to track pathfinding) + */ +public class DebugUtils { + + private static final ShapeRenderer debugRenderer = new ShapeRenderer(); + + /** + * Used to draw a debug line with the specified parameters + * @param start The start location of the line + * @param end The end location of the line + * @param lineWidth The width of the line + * @param color The color of the line + * @param projectionMatrix The projection matrix of the camera + */ + public static void drawDebugLine(Vector2 start, Vector2 end, int lineWidth, Color color, Matrix4 projectionMatrix) { + Gdx.gl.glLineWidth(lineWidth); + debugRenderer.setProjectionMatrix(projectionMatrix); + debugRenderer.begin(ShapeRenderer.ShapeType.Line); + debugRenderer.setColor(color); + debugRenderer.line(start, end); + debugRenderer.end(); + Gdx.gl.glLineWidth(1); + } + + /** + * Used to draw a debug line with the specified parameters + * @param start The start location of the line + * @param end The end location of the line + * @param projectionMatrix The projection matrix of the camera + * @param color The color of the line + */ + public static void drawDebugLine(Vector2 start, Vector2 end, Matrix4 projectionMatrix, Color color) { + Gdx.gl.glLineWidth(5); + debugRenderer.setProjectionMatrix(projectionMatrix); + debugRenderer.begin(ShapeRenderer.ShapeType.Line); + debugRenderer.setColor(color); + debugRenderer.line(start, end); + debugRenderer.end(); + Gdx.gl.glLineWidth(1); + } + + /** + * Used to draw a debug dot (looks like a triangle for some reason) + * @param start The start location of the line + * @param projectionMatrix The end location of the line + * @param color The color of the line + */ + public static void drawDebugDot(Vector2 start, Matrix4 projectionMatrix, Color color) { + Gdx.gl.glLineWidth(5); + debugRenderer.setProjectionMatrix(projectionMatrix); + debugRenderer.begin(ShapeRenderer.ShapeType.Filled); + debugRenderer.setColor(color); + debugRenderer.circle(start.x, start.y, 0.25f); + debugRenderer.end(); + Gdx.gl.glLineWidth(1); + } + + // stop an instance being created of this class + private DebugUtils() { + + } + +} diff --git a/core/src/com/mygdx/pirategame/HealthBar.java b/core/src/main/java/com/mygdx/pirategame/HealthBar.java similarity index 95% rename from core/src/com/mygdx/pirategame/HealthBar.java rename to core/src/main/java/com/mygdx/pirategame/HealthBar.java index 33b9457f..594b2984 100644 --- a/core/src/com/mygdx/pirategame/HealthBar.java +++ b/core/src/main/java/com/mygdx/pirategame/HealthBar.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Sprite; +import com.mygdx.pirategame.gameobjects.enemy.Enemy; /** * Health Bar @@ -15,7 +16,7 @@ *@author Sam Pearson *@version 1.0 */ -class HealthBar { +public class HealthBar { private Sprite healthBar; private Texture image; diff --git a/core/src/com/mygdx/pirategame/Hud.java b/core/src/main/java/com/mygdx/pirategame/Hud.java similarity index 94% rename from core/src/com/mygdx/pirategame/Hud.java rename to core/src/main/java/com/mygdx/pirategame/Hud.java index 67620aa5..dd7f5f7f 100644 --- a/core/src/com/mygdx/pirategame/Hud.java +++ b/core/src/main/java/com/mygdx/pirategame/Hud.java @@ -5,10 +5,13 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.Viewport; +import com.mygdx.pirategame.screen.SkillTreeScreen; /** * Hud @@ -113,7 +116,7 @@ public void update(float dt) { timeCount = 0; //Check if a points boundary is met - SkillTree.pointsCheck(score); + SkillTreeScreen.pointsCheck(score); } } @@ -148,7 +151,7 @@ public static void changePoints(int value) { score += value; scoreLabel.setText(String.format("%03d", score)); //Check if a points boundary is met - SkillTree.pointsCheck(score); + SkillTreeScreen.pointsCheck(score); } /** @@ -189,6 +192,8 @@ public static Integer getCoins(){ return coins; } + public static Integer getPoints() { return score;} + /** * Disposes game data */ diff --git a/core/src/com/mygdx/pirategame/PirateGame.java b/core/src/main/java/com/mygdx/pirategame/PirateGame.java similarity index 64% rename from core/src/com/mygdx/pirategame/PirateGame.java rename to core/src/main/java/com/mygdx/pirategame/PirateGame.java index 2c6e32ed..13d5f1e5 100644 --- a/core/src/com/mygdx/pirategame/PirateGame.java +++ b/core/src/main/java/com/mygdx/pirategame/PirateGame.java @@ -3,13 +3,16 @@ import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.screen.*; /** - * The start of the program. Sets up the main back bone of the game. - * This includes most constants used throught for collision and changing screens - * Provides access for screens to interact with eachother and the options interface + * The start of the program. Sets up the main backbone of the game. + * This includes most constants used for collision and changing screens + * Provides access for screens to interact with each other and the options interface * @author Sam Pearson * @version 1.0 */ @@ -19,21 +22,26 @@ public class PirateGame extends Game { //Bits used in collisions public static final short DEFAULT_BIT = 1; public static final short PLAYER_BIT = 2; - public static final short COLLEGEFIRE_BIT = 4; + public static final short COLLEGE_FIRE_BIT = 4; public static final short COIN_BIT = 8; public static final short CANNON_BIT = 16; public static final short ENEMY_BIT = 32; public static final short COLLEGE_BIT = 64; - public static final short COLLEGESENSOR_BIT = 128; + public static final short COLLEGE_SENSOR_BIT = 128; + public static final short COIN_MAGNET_BIT = 256; + public static final short SPEED_BOOST_BIT = 512; + public static final short ABSORPTION_HEART_BIT = 1024; + public static final short FASTER_SHOOTING_BIT = 2048; + public static final short FREEZE_ENEMY_BIT = 4096; public SpriteBatch batch; //Variable for each screen private MainMenu menuScreen; private GameScreen gameScreen; - private SkillTree skillTreeScreen; + private SkillTreeScreen skillTreeScreen; private DeathScreen deathScreen; - private Help helpScreen; + private HelpScreen helpScreen; private VictoryScreen victoryScreen; private audioControls options; @@ -47,6 +55,7 @@ public class PirateGame extends Game { public final static int HELP = 4; public final static int VICTORY = 5; + /** * Creates the main body of the game. * Establises the batch for the whole game as well as sets the first screen @@ -62,7 +71,7 @@ public void create () { options = new audioControls(); //Set background music and play if valid - song = Gdx.audio.newMusic(Gdx.files.internal("pirate-music.mp3")); + song = Gdx.audio.newMusic(Gdx.files.internal("sfx_and_music/pirate-music.mp3")); song.setLooping(true); if(getPreferences().isMusicEnabled()){ song.play(); @@ -85,12 +94,13 @@ public void changeScreen(int screen) { case GAME: if (gameScreen == null) gameScreen = new GameScreen(this); - if (skillTreeScreen == null) skillTreeScreen = new SkillTree(this); + if (skillTreeScreen == null) skillTreeScreen = new SkillTreeScreen(this); + GameScreen.resetValues(); this.setScreen(gameScreen); break; case SKILL: - if (skillTreeScreen == null) skillTreeScreen = new SkillTree(this); + if (skillTreeScreen == null) skillTreeScreen = new SkillTreeScreen(this); this.setScreen(skillTreeScreen); break; @@ -100,7 +110,7 @@ public void changeScreen(int screen) { break; case HELP: - if (helpScreen == null) helpScreen = new Help(this); + if (helpScreen == null) helpScreen = new HelpScreen(this); this.setScreen(helpScreen); break; @@ -111,6 +121,29 @@ public void changeScreen(int screen) { }// } + /** + * Used to scale a location on the screen to a location within game coordinates + * + * @param point The point on the screen + * @param camera The camera that is in charge of scaling + * @return The point translated into in-game coordinates + */ + public static Vector2 getScaledLocation(Vector2 point, OrthographicCamera camera) { + return new Vector2(point.x * (camera.viewportWidth / Gdx.graphics.getWidth()), point.y * (camera.viewportHeight / Gdx.graphics.getHeight())); + } + + /** + * Used to get the in game coordinates of the mouse + * + * @param camera The camera that is in charge of scaling + * @return The location of the mouse pointer in in-game coordinates + */ + public static Vector2 getScaledMouseLocation(OrthographicCamera camera) { + int mouseX = Gdx.input.getX(); + int mouseY = Gdx.graphics.getHeight() - Gdx.input.getY(); + return getScaledLocation(new Vector2(mouseX, mouseY), camera); + } + /** * Allows the user to interact with the audio options * diff --git a/core/src/com/mygdx/pirategame/audioControls.java b/core/src/main/java/com/mygdx/pirategame/audioControls.java similarity index 100% rename from core/src/com/mygdx/pirategame/audioControls.java rename to core/src/main/java/com/mygdx/pirategame/audioControls.java diff --git a/core/src/com/mygdx/pirategame/CannonFire.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/CannonFire.java similarity index 60% rename from core/src/com/mygdx/pirategame/CannonFire.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/CannonFire.java index d86ddb3e..17f02276 100644 --- a/core/src/com/mygdx/pirategame/CannonFire.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/CannonFire.java @@ -1,12 +1,14 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Sprite; -import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.*; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * Cannon Fire @@ -19,15 +21,18 @@ */ public class CannonFire extends Sprite { private World world; - private Texture cannonBall; private float stateTime; private boolean destroyed; private boolean setToDestroy; private Body b2body; - private float angle; + private double angle; private float velocity; - private Vector2 bodyVel; private Sound fireNoise; + private final Texture texture; + private float sourceX, sourceY; + private float x, y; + private Vector2 mouse; + private float targetX, targetY; /** * Instantiates cannon fire @@ -35,33 +40,50 @@ public class CannonFire extends Sprite { * Determines firing sound * * @param screen visual data - * @param x x value of origin - * @param y y value of origin * @param body body of origin - * @param velocity velocity of the cannon ball + * @param camera game scaling camera + * @param velocity velocity of the cannonball */ - public CannonFire(GameScreen screen, float x, float y, Body body, float velocity) { + public CannonFire(GameScreen screen, Body body, OrthographicCamera camera, float velocity) { this.velocity = velocity; this.world = screen.getWorld(); - //sets the angle and velocity - bodyVel = body.getLinearVelocity(); - angle = body.getAngle(); + + // Get values of mouse location, scaled to size of screen + mouse = PirateGame.getScaledMouseLocation(camera); + targetX = mouse.x; + targetY = mouse.y; + + // Value of player source used to calculate angle + // Changed to fix issues with shooting and resize + //sourceX = Gdx.graphics.getWidth() / 2; + //sourceY = Gdx.graphics.getHeight() / 2; + + // Value of player source used to calculate angle + sourceX = camera.viewportWidth /2; + sourceY = camera.viewportHeight /2; + + // Value of player source used to set where the cannonball comes from + x = body.getPosition().x; + y = body.getPosition().y; + + // Uses a triangle to calculate the new trajectory + angle = Math.atan2(targetY - sourceY, targetX - sourceX); //set cannonBall dimensions for the texture - cannonBall = new Texture("cannonBall.png"); - setRegion(cannonBall); + this.texture = new Texture("cannonBall.png"); + setRegion(texture); setBounds(x, y, 10 / PirateGame.PPM, 10 / PirateGame.PPM); //set collision bounds defineCannonBall(); //set sound for fire and play if on - fireNoise = Gdx.audio.newSound(Gdx.files.internal("explosion.wav")); + fireNoise = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/explosion.wav")); if (screen.game.getPreferences().isEffectsEnabled()) { fireNoise.play(screen.game.getPreferences().getEffectsVolume()); } } /** - * Defines the existance, direction, shape and size of a cannonball + * Defines the existence, direction, shape and size of a cannonball */ public void defineCannonBall() { //sets the body definitions @@ -83,9 +105,9 @@ public void defineCannonBall() { fDef.isSensor = true; b2body.createFixture(fDef).setUserData(this); - //Velocity maths - float velX = MathUtils.cos(angle) * velocity + bodyVel.x; - float velY = MathUtils.sin(angle) * velocity + bodyVel.y; + float velX = (float) (Math.cos(angle) * velocity); + float velY = (float) (Math.sin(angle) * velocity); + b2body.applyLinearImpulse(new Vector2(velX, velY), b2body.getWorldCenter(), true); } @@ -93,14 +115,14 @@ public void defineCannonBall() { * Updates state with delta time * Defines range of cannon fire * - * @param dt Delta time (elapsed time since last game tick) + * @param delta Delta time (elapsed time since last game tick) */ - public void update(float dt){ - stateTime += dt; + public void update(float delta){ + stateTime += delta; //Update position of ball setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2); - //If ball is set to destroy and isnt, destroy it + //If ball is set to destroy and isn't, destroy it if((setToDestroy) && !destroyed) { world.destroyBody(b2body); destroyed = true; diff --git a/core/src/com/mygdx/pirategame/CollegeFire.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/CollegeFire.java similarity index 80% rename from core/src/com/mygdx/pirategame/CollegeFire.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/CollegeFire.java index 7c00fbb8..5b530b00 100644 --- a/core/src/com/mygdx/pirategame/CollegeFire.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/CollegeFire.java @@ -1,9 +1,14 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.*; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; + +import java.util.Random; + /** * College Fire * Defines college attack method @@ -32,7 +37,8 @@ public class CollegeFire extends Sprite { */ public CollegeFire(GameScreen screen, float x, float y) { this.world = screen.getWorld(); - playerPos = screen.getPlayerPos(); + playerPos = screen.getCenteredPlayerPos(); + cannonBall = new Texture("cannonBall.png"); //Set the position and size of the ball setRegion(cannonBall); @@ -50,12 +56,15 @@ public void defineCannonBall() { bDef.position.set(getX(), getY()); bDef.type = BodyDef.BodyType.DynamicBody; b2body = world.createBody(bDef); + MassData mass = new MassData(); + mass.mass = (float) 0.01; + b2body.setMassData(mass); //Sets collision boundaries FixtureDef fDef = new FixtureDef(); CircleShape shape = new CircleShape(); shape.setRadius(5 / PirateGame.PPM); // setting BIT identifier - fDef.filter.categoryBits = PirateGame.COLLEGEFIRE_BIT; + fDef.filter.categoryBits = PirateGame.COLLEGE_FIRE_BIT; // determining what this BIT can collide with fDef.filter.maskBits = PirateGame.PLAYER_BIT; @@ -64,6 +73,13 @@ public void defineCannonBall() { // Math for firing the cannonball at the player playerPos.sub(b2body.getPosition()); + + // adding randomness to cannon firing + Random rnd = new Random(); + float rndX = (float) (rnd.nextInt(2) - 1 + rnd.nextDouble()); + float rndY = (float) (rnd.nextInt(2) - 1 + rnd.nextDouble()); + playerPos.sub(rndX, rndY); + playerPos.nor(); float speed = 5f; b2body.setLinearVelocity(playerPos.scl(speed)); @@ -77,7 +93,7 @@ public void defineCannonBall() { */ public void update(float dt){ stateTime += dt; - //If college is set to destroy and isnt, destroy it + //If college is set to destroy and isn't, destroy it setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2); if((setToDestroy) && !destroyed) { world.destroyBody(b2body); diff --git a/core/src/com/mygdx/pirategame/Player.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/Player.java similarity index 63% rename from core/src/com/mygdx/pirategame/Player.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/Player.java index c02361c4..b25e6e6e 100644 --- a/core/src/com/mygdx/pirategame/Player.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/Player.java @@ -1,12 +1,15 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.physics.box2d.*; import com.badlogic.gdx.utils.Array; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * Creates the class of the player. Everything that involves actions coming from the player boat @@ -18,8 +21,9 @@ public class Player extends Sprite { private Texture ship; public World world; public Body b2body; - private Sound breakSound; + private Sound breakSound, cannonballHitSound; private Array cannonBalls; + private float timeFired = 0; /** * Instantiates a new Player. Constructor only called once per game @@ -29,7 +33,7 @@ public class Player extends Sprite { public Player(GameScreen screen) { // Retrieves world data and creates ship texture this.screen = screen; - ship = new Texture("player_ship.png"); + ship = new Texture("college/Ships/player_ship.png"); this.world = screen.getWorld(); // Defines a player, and the players position on screen and world @@ -38,15 +42,18 @@ public Player(GameScreen screen) { setRegion(ship); setOrigin(32 / PirateGame.PPM,55 / PirateGame.PPM); - // Sound effect for damage - breakSound = Gdx.audio.newSound(Gdx.files.internal("wood-bump.mp3")); + // Sound effect for terrain collision + breakSound = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/wood-bump.mp3")); + // Sound effect for cannonball hit + cannonballHitSound = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/ship-hit.wav")); + // Sets cannonball array - cannonBalls = new Array(); + cannonBalls = new Array<>(); } /** - * Update the position of the player. Also updates any cannon balls the player generates + * Update the position of the player. Also updates any cannonballs the player generates * * @param dt Delta Time */ @@ -63,18 +70,31 @@ public void update(float dt) { if(ball.isDestroyed()) cannonBalls.removeValue(ball, true); } + + // Add delay timer between shots + timeFired += dt; } /** * Plays the break sound when a boat takes damage */ public void playBreakSound() { - // Plays damage sound effect + // Plays terrain collision sound effect if (screen.game.getPreferences().isEffectsEnabled()) { breakSound.play(screen.game.getPreferences().getEffectsVolume()); } } + /** + * Plays the explosion sound when a boat is hit by a cannonball + */ + public void playCannonballHitSound() { + // Plays cannonball hit sound effect + if (screen.game.getPreferences().isEffectsEnabled()) { + cannonballHitSound.play(screen.game.getPreferences().getEffectsVolume()); + } + } + /** * Defines all the parts of the player's physical model. Sets it up for collisons */ @@ -83,6 +103,8 @@ private void definePlayer() { BodyDef bdef = new BodyDef(); bdef.position.set(1200 / PirateGame.PPM, 2500 / PirateGame.PPM); // Default Pos: 1800,2500 bdef.type = BodyDef.BodyType.DynamicBody; + // linear damping slows the player if no movement key is pressed + bdef.linearDamping = 1f; b2body = world.createBody(bdef); // Defines a player's shape and contact borders @@ -94,26 +116,28 @@ private void definePlayer() { fdef.filter.categoryBits = PirateGame.PLAYER_BIT; // determining what this BIT can collide with - fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.COIN_BIT | PirateGame.ENEMY_BIT | PirateGame.COLLEGE_BIT | PirateGame.COLLEGESENSOR_BIT | PirateGame.COLLEGEFIRE_BIT; + fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.COIN_BIT + | PirateGame.COIN_MAGNET_BIT | PirateGame.SPEED_BOOST_BIT + | PirateGame.ABSORPTION_HEART_BIT | PirateGame.FASTER_SHOOTING_BIT + | PirateGame.FREEZE_ENEMY_BIT | PirateGame.ENEMY_BIT + | PirateGame.COLLEGE_BIT | PirateGame.COLLEGE_SENSOR_BIT + | PirateGame.COLLEGE_FIRE_BIT; fdef.shape = shape; b2body.createFixture(fdef).setUserData(this); } /** - * Called when E is pushed. Causes 1 cannon ball to spawn on both sides of the ships wih their relative velocity + * Called when left button is pressed. + * One cannonball is launched towards the mouse position from the centre of the player. + * + * @param camera The camera that is in charge of scaling */ - public void fire() { - // Fires cannons - cannonBalls.add(new CannonFire(screen, b2body.getPosition().x, b2body.getPosition().y, b2body, 5)); - cannonBalls.add(new CannonFire(screen, b2body.getPosition().x, b2body.getPosition().y, b2body, -5)); - - // Cone fire below - /*cannonBalls.add(new CannonFire(screen, b2body.getPosition().x, b2body.getPosition().y, (float) (b2body.getAngle() - Math.PI / 6), -5, b2body.getLinearVelocity())); - cannonBalls.add(new CannonFire(screen, b2body.getPosition().x, b2body.getPosition().y, (float) (b2body.getAngle() - Math.PI / 6), 5, b2body.getLinearVelocity())); - cannonBalls.add(new CannonFire(screen, b2body.getPosition().x, b2body.getPosition().y, (float) (b2body.getAngle() + Math.PI / 6), -5, b2body.getLinearVelocity())); - cannonBalls.add(new CannonFire(screen, b2body.getPosition().x, b2body.getPosition().y, (float) (b2body.getAngle() + Math.PI / 6), 5, b2body.getLinearVelocity())); + public void fire(OrthographicCamera camera) { + // Fires cannon if specified delay time has passed + if (timeFired > GameScreen.getShootingDelay()) { + cannonBalls.add(new CannonFire(screen, b2body, camera, 5)); + timeFired = 0; } - */ } /** diff --git a/core/src/com/mygdx/pirategame/College.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/College.java similarity index 71% rename from core/src/com/mygdx/pirategame/College.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/College.java index 1764d4db..5653a38f 100644 --- a/core/src/com/mygdx/pirategame/College.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/College.java @@ -1,188 +1,211 @@ -package com.mygdx.pirategame; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.Batch; -import com.badlogic.gdx.physics.box2d.*; -import com.badlogic.gdx.utils.Array; - -import java.util.ArrayList; -import java.util.Random; - -/** - * College - * Class to generate the enemy entity college - * Instantiates colleges - * Instantiates college fleets - * - *@author Ethan Alabaster, Edward Poulter - *@version 1.0 - */ - -public class College extends Enemy{ - private Texture enemyCollege; - public Random rand = new Random(); - private String currentCollege; - private Array cannonBalls; - private AvailableSpawn noSpawn; - public ArrayList fleet = new ArrayList<>(); - - /** - * - * @param screen Visual data - * @param college College name i.e. "Alcuin" used for fleet assignment - * @param x College position on x-axis - * @param y College position on y-axis - * @param flag College flag sprite (image name) - * @param ship College ship sprite (image name) - * @param ship_no Number of college ships to produce - * @param invalidSpawn Spawn data to check spawn validity when generating ships - */ - public College(GameScreen screen, String college, float x, float y, String flag, String ship, int ship_no, AvailableSpawn invalidSpawn) { - super(screen, x, y); - this.screen = screen; - noSpawn = invalidSpawn; - currentCollege = flag; - enemyCollege = new Texture(flag); - //Set the position and size of the college - setBounds(0,0,64 / PirateGame.PPM, 110 / PirateGame.PPM); - setRegion(enemyCollege); - setOrigin(32 / PirateGame.PPM,55 / PirateGame.PPM); - damage = 10; - cannonBalls = new Array<>(); - int ranX = 0; - int ranY = 0; - boolean spawnIsValid; - - //Generates college fleet - for (int i = 0; i < ship_no; i++){ - spawnIsValid = false; - while (!spawnIsValid){ - ranX = rand.nextInt(2000) - 1000; - ranY = rand.nextInt(2000) - 1000; - ranX = (int)Math.floor(x + (ranX / PirateGame.PPM)); - ranY = (int)Math.floor(y + (ranY / PirateGame.PPM)); - spawnIsValid = getCoord(ranX, ranY); - } - fleet.add(new EnemyShip(screen, ranX, ranY, ship, college)); - } - } - - /** - * Checks ship spawning in at a valid location - * - * @param x x position to test - * @param y y position to test - * @return isValid : returns the validity of the proposed spawn point - */ - public boolean getCoord(int x, int y) { - if (x < noSpawn.xBase || x >= noSpawn.xCap || y < noSpawn.yBase || y >= noSpawn.yCap) { - return false; - }else if (noSpawn.tileBlocked.containsKey(x)) { - if (noSpawn.tileBlocked.get(x).contains(y)) { - return false; - } - } - return true; - } - - /** - * Updates the state of each object with delta time - * Checks for college destruction - * Checks for cannon fire - * - * @param dt Delta time (elapsed time since last game tick) - */ - public void update(float dt) { - //If college is set to destroy and isnt, destroy it - if(setToDestroy && !destroyed) { - world.destroyBody(b2body); - destroyed = true; - - //If it is the player ally college, end the game for the player - if (currentCollege.equals("alcuin_flag.png")){ - screen.gameOverCheck(); - } - //Award the player coins and points for destroying a college - if (!currentCollege.equals("alcuin_flag.png")){ - Hud.changePoints(100); - Hud.changeCoins(rand.nextInt(10)); - } - } - //If not destroyed, update the college position - else if(!destroyed) { - setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); - - } - if(health <= 0) { - setToDestroy = true; - } - bar.update(); - if(health <= 0) { - setToDestroy = true; - } - //Update cannon balls - for(CollegeFire ball : cannonBalls) { - ball.update(dt); - if(ball.isDestroyed()) - cannonBalls.removeValue(ball, true); - } - } - - /** - * Draws the batch of cannonballs - */ - public void draw(Batch batch) { - if(!destroyed) { - super.draw(batch); - //Render health bar - bar.render(batch); - //Render balls - for(CollegeFire ball : cannonBalls) - ball.draw(batch); - } - } - - /** - * Sets the data to define a college as an enemy - */ - @Override - protected void defineEnemy() { - //sets the body definitions - BodyDef bdef = new BodyDef(); - bdef.position.set(getX(), getY()); - bdef.type = BodyDef.BodyType.StaticBody; - b2body = world.createBody(bdef); - //Sets collision boundaries - FixtureDef fdef = new FixtureDef(); - CircleShape shape = new CircleShape(); - shape.setRadius(55 / PirateGame.PPM); - // setting BIT identifier - fdef.filter.categoryBits = PirateGame.COLLEGESENSOR_BIT; - // determining what this BIT can collide with - fdef.filter.maskBits = PirateGame.PLAYER_BIT; - fdef.shape = shape; - fdef.isSensor = true; - b2body.createFixture(fdef).setUserData(this); - } - - /** - * Contact detection - * Allows for the college to take damage - */ - @Override - public void onContact() { - //Damage the college and lower health bar - Gdx.app.log("enemy", "collision"); - health -= damage; - bar.changeHealth(damage); - } - - /** - * Fires cannonballs - */ - public void fire() { - cannonBalls.add(new CollegeFire(screen, b2body.getPosition().x, b2body.getPosition().y)); - } -} - +package com.mygdx.pirategame.gameobjects.enemy; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.CircleShape; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.badlogic.gdx.utils.Array; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.CollegeFire; +import com.mygdx.pirategame.screen.GameScreen; +import com.mygdx.pirategame.world.AvailableSpawn; +import java.util.ArrayList; +import java.util.Random; + +/** + * College + * Class to generate the enemy entity college + * Instantiates colleges + * Instantiates college fleets + * + *@author Ethan Alabaster, Edward Poulter + *@version 1.0 + */ + +public class College extends Enemy { + private Texture enemyCollege; + public Random rand = new Random(); + private Array cannonBalls; + private AvailableSpawn noSpawn; + public ArrayList fleet = new ArrayList<>(); + private Sound cannonballHitSound; + private CollegeMetadata collegeMeta; + private String flag; + private String ship; + + /** + * @param screen Visual data + * @param collegeMeta To identify college, used for fleet assignment + * @param ship_no Number of college ships to produce + * @param invalidSpawn Spawn data to check spawn validity when generating ships + */ + public College(GameScreen screen, CollegeMetadata collegeMeta, int ship_no, AvailableSpawn invalidSpawn) { + super(screen, collegeMeta.getX(), collegeMeta.getY()); + this.screen = screen; + this.collegeMeta = collegeMeta; + + String college = collegeMeta.getFilePath(); + flag = "college/Flags/" + college + "_flag.png"; + ship = "college/Ships/" + college + "_ship.png"; + + noSpawn = invalidSpawn; + enemyCollege = new Texture(flag); + //Set the position and size of the college + setBounds(0,0,64 / PirateGame.PPM, 110 / PirateGame.PPM); + setRegion(enemyCollege); + setOrigin(32 / PirateGame.PPM,55 / PirateGame.PPM); + damage = 10; + cannonBalls = new Array<>(); + int ranX = 0; + int ranY = 0; + boolean spawnIsValid; + + //Generates college fleet + for (int i = 0; i < ship_no; i++){ + spawnIsValid = false; + while (!spawnIsValid){ + ranX = rand.nextInt(2000) - 1000; + ranY = rand.nextInt(2000) - 1000; + ranX = (int)Math.floor(collegeMeta.getX() + (ranX / PirateGame.PPM)); + ranY = (int)Math.floor(collegeMeta.getY() + (ranY / PirateGame.PPM)); + spawnIsValid = getCoord(ranX, ranY); + } + fleet.add(new EnemyShip(screen, ranX, ranY, ship, collegeMeta)); + } + + // explosion sound effect + cannonballHitSound = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/explode.mp3")); + } + + /** + * Checks ship spawning in at a valid location + * + * @param x x position to test + * @param y y position to test + * @return isValid : returns the validity of the proposed spawn point + */ + public boolean getCoord(int x, int y) { + if (x < noSpawn.xBase || x >= noSpawn.xCap || y < noSpawn.yBase || y >= noSpawn.yCap) { + return false; + }else if (noSpawn.tileBlocked.containsKey(x)) { + if (noSpawn.tileBlocked.get(x).contains(y)) { + return false; + } + } + return true; + } + + /** + * Updates the state of each object with delta time + * Checks for college destruction + * Checks for cannon fire + * + * @param dt Delta time (elapsed time since last game tick) + */ + public void update(float dt) { + //If college is set to destroy and isn't, destroy it + if(setToDestroy && !destroyed) { + world.destroyBody(b2body); + destroyed = true; + + //If it is the player ally college, end the game for the player + if (collegeMeta == CollegeMetadata.ALCUIN){ + screen.gameOverCheck(); + } + else { + //Award the player coins and points for destroying a college + Hud.changePoints(100); + Hud.changeCoins(rand.nextInt(10)); + } + } + //If not destroyed, update the college position + else if(!destroyed) { + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + + } + if(health <= 0) { + setToDestroy = true; + } + bar.update(); + if(health <= 0) { + setToDestroy = true; + } + //Update cannon balls + for(CollegeFire ball : cannonBalls) { + ball.update(dt); + if(ball.isDestroyed()) + cannonBalls.removeValue(ball, true); + } + } + + /** + * Draws the batch of cannonballs + */ + public void draw(Batch batch) { + if(!destroyed) { + super.draw(batch); + //Render health bar + bar.render(batch); + //Render balls + for(CollegeFire ball : cannonBalls) + ball.draw(batch); + } + } + + /** + * Sets the data to define a college as an enemy + */ + @Override + protected void defineEnemy() { + //sets the body definitions + BodyDef bdef = new BodyDef(); + bdef.position.set(getX(), getY()); + bdef.type = BodyDef.BodyType.StaticBody; + b2body = world.createBody(bdef); + //Sets collision boundaries + FixtureDef fdef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(55 / PirateGame.PPM); + // setting BIT identifier + fdef.filter.categoryBits = PirateGame.COLLEGE_SENSOR_BIT; + // determining what this BIT can collide with + fdef.filter.maskBits = PirateGame.PLAYER_BIT; + fdef.shape = shape; + fdef.isSensor = true; + b2body.createFixture(fdef).setUserData(this); + } + + /** + * Contact detection + * Allows for the college to take damage + */ + @Override + public void onContact() { + //Damage the college and lower health bar + Gdx.app.log("enemy", "collision"); + health -= damage; + bar.changeHealth(damage); + + // Plays explosion sound effect + if (screen.game.getPreferences().isEffectsEnabled()) { + cannonballHitSound.play(screen.game.getPreferences().getEffectsVolume()); + } + } + + @Override + public void onEnemyShipContact() { + // nothing to do here + } + + /** + * Fires cannonballs + */ + public void fire() { + cannonBalls.add(new CollegeFire(screen, b2body.getPosition().x, b2body.getPosition().y)); + } +} + diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/CollegeMetadata.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/CollegeMetadata.java new file mode 100644 index 00000000..9ac3dfba --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/CollegeMetadata.java @@ -0,0 +1,93 @@ +package com.mygdx.pirategame.gameobjects.enemy; + +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.PirateGame; + +/** + * Enum used to store metadata about colleges + */ +public enum CollegeMetadata { + + ALCUIN(0, "alcuin", 1900 / PirateGame.PPM, 2100 / PirateGame.PPM), + ANNELISTER(1, "anne_lister", 6304 / PirateGame.PPM, 1199 / PirateGame.PPM), + CONSTANTINE(2, "constantine", 6240 / PirateGame.PPM, 6703 / PirateGame.PPM), + GOODRICKE(3, "goodricke", 1760 / PirateGame.PPM, 6767 / PirateGame.PPM); + + public static CollegeMetadata getCollegeMetaFromId(Integer id) { + System.out.println("college " + id); + switch (id) { + case 0: + return ALCUIN; + case 1: + return ANNELISTER; + case 2: + return CONSTANTINE; + case 3: + return GOODRICKE; + } + System.out.println("returning null"); + return null; + } + + private final int collegeID; + private final String filePath; + private final float x; + private final float y; + + /** + * @param collegeID The id of this college + * @param filePath college name as used in the file path + * @param x The x location of the college + * @param y The y location of the college + */ + CollegeMetadata(int collegeID, String filePath, float x, float y) { + this.collegeID = collegeID; + this.filePath = filePath; + this.x = x; + this.y = y; + } + + /** + * @return The ID of this college + */ + public int getCollegeID() { + return collegeID; + } + + /** + * @return college name as used in the file paths + */ + public String getFilePath() { + return filePath; + } + + /** + * @return The X locaiton of the college + */ + public float getX() { + return x; + } + + /** + * @return The Y location of the college + */ + public float getY() { + return y; + } + + /** + * @return The college location as a position vector + */ + public Vector2 getPosition(){ + return new Vector2(x, y); + } + + /** + * Used to check if this college is the college controlled by the player + * @return If this college is controlled by the player + */ + public boolean isPlayer() { + return this == ALCUIN; + } +} + diff --git a/core/src/com/mygdx/pirategame/Enemy.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/Enemy.java similarity index 88% rename from core/src/com/mygdx/pirategame/Enemy.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/Enemy.java index 9b6fdf02..941e15da 100644 --- a/core/src/com/mygdx/pirategame/Enemy.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/Enemy.java @@ -1,8 +1,10 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.enemy; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.World; +import com.mygdx.pirategame.HealthBar; +import com.mygdx.pirategame.screen.GameScreen; /** * Enemy @@ -50,6 +52,8 @@ public Enemy(GameScreen screen, float x, float y) { * Defines contact */ public abstract void onContact(); + + public abstract void onEnemyShipContact(); public abstract void update(float dt); /** diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/EnemyShip.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/EnemyShip.java new file mode 100644 index 00000000..606d9431 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/enemy/EnemyShip.java @@ -0,0 +1,336 @@ +package com.mygdx.pirategame.gameobjects.enemy; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.CircleShape; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.badlogic.gdx.utils.Array; +import com.mygdx.pirategame.DebugUtils; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.CollegeFire; +import com.mygdx.pirategame.pathfinding.Checkpoint; +import com.mygdx.pirategame.pathfinding.PathFinder; +import com.mygdx.pirategame.pathfinding.pathManager.AttackPath; +import com.mygdx.pirategame.pathfinding.pathManager.PathManager; +import com.mygdx.pirategame.pathfinding.pathManager.PatrolPath; +import com.mygdx.pirategame.pathfinding.pathManager.RandomPath; +import com.mygdx.pirategame.screen.GameScreen; + +import java.util.ArrayList; +import java.util.List; + +/** + * Enemy Ship + * Generates enemy ship data + * Instantiates an enemy ship + * + * @author Ethan Alabaster, Sam Pearson, Edward Poulter + * @version 1.0 + */ +public class EnemyShip extends Enemy { + + public static final int COLLISIONRADIUS = 55; + + private Texture enemyShip; + public CollegeMetadata collegeMeta; + private final Sound destroy; + private final Sound hit; + private Array cannonBalls; + + private PathManager pathManager; + + /** + * used to delay patfinding when the ship collides with something + */ + private int updateDelay = 0; + + private List path; + + /** + * Instantiates enemy ship + * + * @param screen Visual data + * @param x x coordinates of entity + * @param y y coordinates of entity + * @param path path of texture file + * @param collegeMeta College ship is assigned to + */ + public EnemyShip(GameScreen screen, float x, float y, String path, CollegeMetadata collegeMeta) { + super(screen, x, y); + enemyShip = new Texture(path); + //Assign college + this.collegeMeta = collegeMeta; + //Set audios + destroy = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/ship-explosion-2.wav")); + hit = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/ship-hit.wav")); + + cannonBalls = new Array<>(); + //Set the position and size of the college + setBounds(0, 0, 64 / PirateGame.PPM, 110 / PirateGame.PPM); + setRegion(enemyShip); + setOrigin(32 / PirateGame.PPM, COLLISIONRADIUS / PirateGame.PPM); + + damage = 20; + if (collegeMeta != null) { + this.pathManager = new PatrolPath(this, screen); + } else { + this.pathManager = new RandomPath(this, screen); + } + // give a seconds speed instead of a portin of it, then limit to a portion of the speed + generateNewPath(); + } + + /** + * Used to generate a new path from the current location to a random point on the map + */ + public void generateNewPath() { + + Vector2 destination = pathManager.generateDestination(); + if (destination == null) { + // destination will be regenerated next update + return; + } + int tilewidth = screen.getTileWidth(); + path = screen.getPathFinder().getPath((b2body.getPosition().x * PirateGame.PPM), (b2body.getPosition().y * PirateGame.PPM), destination.x, destination.y, COLLISIONRADIUS, COLLISIONRADIUS); + if (path != null && path.size() > 1) { + // removing the start node from the path as ship is already at it + path.remove(0); + + } + + } + + /** + * Updates the state of each object with delta time + * Checks for ship destruction + * + * @param dt Delta time (elapsed time since last game tick) + */ + public void update(float dt) { + + //Update cannon balls + for(CollegeFire ball : cannonBalls) { + ball.update(dt); + if(ball.isDestroyed()) + cannonBalls.removeValue(ball, true); + } + //If ship is set to destroy and isnt, destroy it + if (destroyed) { + return; + } + + + if (setToDestroy) { + //Play death noise + if (GameScreen.game.getPreferences().isEffectsEnabled()) { + destroy.play(GameScreen.game.getPreferences().getEffectsVolume()); + } + world.destroyBody(b2body); + destroyed = true; + //Change player coins and points + Hud.changePoints(20); + Hud.changeCoins(10); + } + + //Update position and angle of ship + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + float angle = (float) Math.atan2(b2body.getLinearVelocity().y, b2body.getLinearVelocity().x); + b2body.setTransform(b2body.getWorldCenter(), angle - ((float) Math.PI) / 2.0f); + setRotation((float) (b2body.getAngle() * 180 / Math.PI)); + //Update health bar + bar.update(); + + if (health <= 0) { + setToDestroy = true; + } + + if (updateDelay > 0) { + updateDelay--; + return; + } + + if (!inPlayerRange()) { + return; + } + + // updating the pathing manager + pathManager.update(dt); + + if (path == null || path.isEmpty()) { + generateNewPath(); + return; + } + + Checkpoint cp = path.get(0); + + if (cp.getVector2().dst(b2body.getPosition().scl(PirateGame.PPM)) < PirateGame.PPM / 2) { + path.remove(cp); + if (path.isEmpty()) { + generateNewPath(); + } + } + + final float speed = 100f * dt; + Vector2 v = travelToCheckpoint(speed, cp); + b2body.setLinearVelocity(v); + + // below code is to move the ship to a coordinate (target) + //Vector2 target = new Vector2(960 / PirateGame.PPM, 2432 / PirateGame.PPM); + //target.sub(b2body.getPosition()); + //target.nor(); + //float speed = 1.5f; + //b2body.setLinearVelocity(target.scl(speed)); + } + + /** + * Used + * + * @param maxDistance The max distance that can be travelled + * @param cp The checkpoint to travel towards + * @return The vector that needs to be applied to travel towards the checkpoint + */ + private Vector2 travelToCheckpoint(float maxDistance, Checkpoint cp) { + Vector2 v = new Vector2(cp.x - (b2body.getPosition().x * PirateGame.PPM) - getWidth() / 2, cp.y - (b2body.getPosition().y * PirateGame.PPM) - getHeight() / 2); + + return v.limit(maxDistance); + } + + /** + * Constructs the ship batch + * + * @param batch The batch of visual data of the ship + */ + public void draw(Batch batch) { + for(CollegeFire ball : cannonBalls) + ball.draw(batch); + + if (!destroyed) { + super.draw(batch); + //Render health bar + bar.render(batch); + // checking if pathfinding information should be displayed + if (PathFinder.PATHFINDERDEBUG && path != null && !path.isEmpty()) { + batch.end(); + + // setting the color for the debug output (so the current type of pathing can be identified) + Color dotColor; + if (pathManager instanceof PatrolPath) { + dotColor = Color.ORANGE; + } else if (pathManager instanceof AttackPath) { + dotColor = Color.RED; + } else { + dotColor = Color.GREEN; + } + + for (int i = 0; i < path.size() - 1; i++) { + + DebugUtils.drawDebugLine(path.get(i).getVector2().scl(1 / PirateGame.PPM), path.get(i + 1).getVector2().scl(1 / PirateGame.PPM), batch.getProjectionMatrix(), Color.RED); + DebugUtils.drawDebugDot(path.get(i).getVector2().scl(1 / PirateGame.PPM), batch.getProjectionMatrix(), dotColor); + } + batch.begin(); + } + } + } + + /** + * Defines the ship as an enemy + * Sets data to act as an enemy + */ + @Override + protected void defineEnemy() { + //sets the body definitions + BodyDef bdef = new BodyDef(); + bdef.position.set(getX(), getY()); + bdef.type = BodyDef.BodyType.DynamicBody; + b2body = world.createBody(bdef); + + //b2body.setLinearDamping(1); + //Sets collision boundaries + FixtureDef fdef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(COLLISIONRADIUS / PirateGame.PPM); + // setting BIT identifier + fdef.filter.categoryBits = PirateGame.ENEMY_BIT; + // determining what this BIT can collide with + fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT | PirateGame.CANNON_BIT; + fdef.shape = shape; + fdef.restitution = 0.7f; + b2body.createFixture(fdef).setUserData(this); + } + + /** + * Checks contact + * Changes health in accordance with contact and damage + */ + @Override + public void onContact() { + updateDelay = 50; + Gdx.app.log("enemy", "collision"); + //Play collision sound + if (GameScreen.game.getPreferences().isEffectsEnabled()) { + hit.play(GameScreen.game.getPreferences().getEffectsVolume()); + } + //Deal with the damage + health -= damage; + bar.changeHealth(damage); + Hud.changePoints(5); + } + + @Override + public void onEnemyShipContact() { + updateDelay = 50; + } + + /** + * Updates the ship image. Particuarly change texture on college destruction + * + * @param alignment Associated college + * @param path Path of new texture + */ + public void updateTexture(Integer alignment, String path) { + collegeMeta = CollegeMetadata.getCollegeMetaFromId(alignment); + enemyShip = new Texture(path); + setRegion(enemyShip); + } + + + /** + * Checks if the ship should pathfind or just sit still (used to reduce needless load) + * + * @return If the ship is in range of the player + */ + public boolean inPlayerRange() { + return screen.getPlayerPos().dst(b2body.getPosition()) < 30; + } + + /** + * Used to check if the set location is traversable by a ship of this size + * + * @param x The x location of the proposed location + * @param y The y location of the proposed location + * @return If the ship can go there + */ + public boolean isTraversable(float x, float y) { + return screen.getPathFinder().isTraversable(x, y, EnemyShip.COLLISIONRADIUS, EnemyShip.COLLISIONRADIUS); + } + + public void setPathManager(PathManager pathManager) { + this.pathManager = pathManager; + // dumping old path + path = new ArrayList<>(); + generateNewPath(); + } + + /** + * Fires cannonballs + */ + public void fire() { + cannonBalls.add(new CollegeFire(screen, b2body.getPosition().x, b2body.getPosition().y)); + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/AbsorptionHeart.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/AbsorptionHeart.java new file mode 100644 index 00000000..00a13518 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/AbsorptionHeart.java @@ -0,0 +1,101 @@ +package com.mygdx.pirategame.gameobjects.entity; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.CircleShape; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; + +/** + * Heals the player when picked up + */ +public class AbsorptionHeart extends PowerUp { + private Texture absorptionHeart; + + /** + * x + * Instantiates an entity + * Sets position in world + * + * @param screen Visual data + * @param x x position of entity + * @param y y position of entity + */ + public AbsorptionHeart(GameScreen screen, float x, float y) { + super(screen, x, y); + + // Set speed boost image + absorptionHeart = new Texture("cannonBall.png"); // CHANGE + //Set the position and size of the speed boost + setBounds(0,0,48 / PirateGame.PPM, 48 / PirateGame.PPM); + //Set the texture + setRegion(absorptionHeart); + //Sets origin of the speed boost + setOrigin(24 / PirateGame.PPM,24 / PirateGame.PPM); + } + + /** + * Updates the absorption heart state. If needed, deletes the absorption heart if picked up + */ + public void update() { + //If coin is set to destroy and isnt, destroy it + if(setToDestroyed && !destroyed) { + world.destroyBody(b2body); + destroyed = true; + } + //Update position of power up + else if(!destroyed) { + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + } + } + + @Override + public void endPowerUp() { + + } + + /** + * Defines all the parts of the speed boost physical model. Sets it up for collisions + */ + @Override + protected void defineEntity() { + // Sets the body definitions + BodyDef bdef = new BodyDef(); + bdef.position.set(getX(), getY()); + bdef.type = BodyDef.BodyType.DynamicBody; + b2body = world.createBody(bdef); + + // Sets collision boundaries + FixtureDef fdef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(24 / PirateGame.PPM); + + // Setting BIT identifier + fdef.filter.categoryBits = PirateGame.ABSORPTION_HEART_BIT; + + // Determining what this BIT can collide with + fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT; + fdef.shape = shape; + fdef.isSensor = true; + b2body.createFixture(fdef).setUserData(this); + } + + @Override + public void entityContact() { + if (!destroyed) { + // Heal player + Hud.changeHealth(10); + + // Set to destroy + setToDestroyed = true; + Gdx.app.log("absorptionHeart", "collision"); + // Play pickup sound + if (screen.game.getPreferences().isEffectsEnabled()) { + getSound().play(screen.game.getPreferences().getEffectsVolume()); + } + } + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/Coin.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/Coin.java new file mode 100644 index 00000000..57c1a316 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/Coin.java @@ -0,0 +1,179 @@ +package com.mygdx.pirategame.gameobjects.entity; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.*; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.Player; +import com.mygdx.pirategame.screen.GameScreen; + +/** + * Coin + * Creates an object for each coin + * Extends the entity class to define coin as an entity + * + *@author Joe Dickinson + *@version 1.0 + */ +public class Coin extends Entity { + private Texture coin; + private Sound coinPickup; + private Player player; + public boolean coinMagnetActive = false, inMagnetRange = false; + public Body b2bodyMagnet; + + /** + * Instantiates a new Coin. + * + * @param screen the screen its going onto + * @param x the x value to be placed at + * @param y the y value to be placed at + */ + public Coin(GameScreen screen, float x, float y) { + super(screen, x, y); + //Set coin image + coin = new Texture("coin.png"); + //Set the position and size of the coin + setBounds(0,0,48 / PirateGame.PPM, 48 / PirateGame.PPM); + //Set the texture + setRegion(coin); + //Sets origin of the coin + setOrigin(24 / PirateGame.PPM,24 / PirateGame.PPM); + coinPickup = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/coin-pickup.mp3")); + + // keep reference to the player object for coin magnet power up + player = screen.getPlayer(); + + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + } + + /** + * Updates the coins state. If needed, deletes the coin if picked up. + */ + public void update() { + // If coin is set to destroy and isnt, destroy it + if (setToDestroyed && !destroyed) { + world.destroyBody(b2body); + destroyed = true; + } + //Update position of coin + if (!destroyed) { + if (inMagnetRange) { + // move coin towards player if in range + + // position of player + float targetX = player.getX(); + float targetY = player.getY(); + // position of coin + float sourceX = b2body.getPosition().x; + float sourceY = b2body.getPosition().y; + + // If the coin is close to the player, collect it + double distance = Math.sqrt(Math.pow(targetX - b2body.getWorldCenter().x, 2) + Math.pow(targetY - b2body.getWorldCenter().y, 2)); + if (distance < 1) { + coinMagnetActive = false; + entityContact(); + } + // Uses a triangle to calculate the new trajectory + double angle = Math.atan2(targetY - sourceY, targetX - sourceX); + float velocity = 0.1f; + float velX = (float) (Math.cos(angle) * velocity); + float velY = (float) (Math.sin(angle) * velocity); + + // move the sprite then the collider + setPosition(sourceX + velX, sourceY + velY); + Vector2 newPos = new Vector2(sourceX, sourceY).add(new Vector2(velX, velY)); + b2body.setTransform(newPos, 0); + } + } + } + + /** + * Defines all the parts of the coins physical model. Sets it up for collisons + */ + @Override + protected void defineEntity() { + // set the body definition for the default body + BodyDef bodyDef = new BodyDef(); + bodyDef.position.set(getX(), getY()); + bodyDef.type = BodyDef.BodyType.DynamicBody; + b2body = world.createBody(bodyDef); + + //set the body definition for the coin magnet body + b2bodyMagnet = world.createBody(bodyDef); + + //Sets collision boundaries + FixtureDef fixtureDef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(24 / PirateGame.PPM); + // setting BIT identifier + fixtureDef.filter.categoryBits = PirateGame.COIN_BIT; + // determining what this BIT can collide with + fixtureDef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT; + fixtureDef.shape = shape; + fixtureDef.isSensor = true; + b2body.createFixture(fixtureDef).setUserData(this); + + // Create fixture for larger collision box whilst coin magnet is active + // Disabled until coin magnet power up is collected + fixtureDef.shape.setRadius(450 / PirateGame.PPM); + b2bodyMagnet.createFixture(fixtureDef).setUserData(this); + b2bodyMagnet.setActive(false); + } + + /** + * Enables and disables the larger collision circle for the coin magnet as well as some flags + */ + public void toggleCoinMagnet() { + // disabling/enabling the default collision circle at the same time crashes the game + if (b2bodyMagnet.isActive()) { + // disable coin magnet + b2bodyMagnet.setActive(false); + inMagnetRange = false; + coinMagnetActive = false; + } + else { + // enable coin magnet + b2bodyMagnet.setActive(true); + coinMagnetActive = true; + } + } + + /** + * What happens when an entity collides with the coin. The only entity that is able to do so is the player ship + */ + @Override + public void entityContact() { + // only attract coins if coin collides with the players larger hit box + if (coinMagnetActive) { + inMagnetRange = true; + } + // Move coin towards player if coin magnet is activated, otherwise collect instantly + else { + //Add a coin + Hud.changeCoins(1); + //Set to destroy + setToDestroyed = true; + Gdx.app.log("coin", "collision"); + //Play pickup sound + if (screen.game.getPreferences().isEffectsEnabled()) { + coinPickup.play(screen.game.getPreferences().getEffectsVolume()); + } + } + } + + /** + * Draws the coin using batch + * + * @param batch The batch of the program + */ + public void draw(Batch batch) { + if(!destroyed) { + super.draw(batch); + } + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/CoinMagnet.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/CoinMagnet.java new file mode 100644 index 00000000..31a08222 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/CoinMagnet.java @@ -0,0 +1,124 @@ +package com.mygdx.pirategame.gameobjects.entity; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.CircleShape; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; + +public class CoinMagnet extends PowerUp { + private Texture coinMagnet; + private boolean toggleCoinMagnet = false; + + /** + * x + * Instantiates an entity + * Sets position in world + * + * @param screen Visual data + * @param x x position of entity + * @param y y position of entity + */ + public CoinMagnet(GameScreen screen, float x, float y) { + super(screen, x, y); + + // Set speed boost image + coinMagnet = new Texture("cannonBall.png"); // CHANGE + //Set the position and size of the speed boost + setBounds(0,0,48 / PirateGame.PPM, 48 / PirateGame.PPM); + //Set the texture + setRegion(coinMagnet); + //Sets origin of the speed boost + setOrigin(24 / PirateGame.PPM,24 / PirateGame.PPM); + + // set duration of power up + duration = 10; + } + + /** + * Defines the properties of an entity + */ + @Override + protected void defineEntity() { + // Sets the body definitions + BodyDef bdef = new BodyDef(); + bdef.position.set(getX(), getY()); + bdef.type = BodyDef.BodyType.DynamicBody; + b2body = world.createBody(bdef); + + // Sets collision boundaries + FixtureDef fdef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(24 / PirateGame.PPM); + + // Setting BIT identifier + fdef.filter.categoryBits = PirateGame.COIN_MAGNET_BIT; + + // Determining what this BIT can collide with + fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT; + fdef.shape = shape; + fdef.isSensor = true; + b2body.createFixture(fdef).setUserData(this); + } + + /** + * Defines contact with other objects, The only entity that is able to do so is the player ship + */ + @Override + public void entityContact() { + if (!destroyed) { + toggleCoinMagnet = true; + active = true; + + // Set to destroy + setToDestroyed = true; + Gdx.app.log("coinmagnet", "collision"); + // Play pickup sound + if (screen.game.getPreferences().isEffectsEnabled()) { + getSound().play(screen.game.getPreferences().getEffectsVolume()); + } + } + } + + @Override + public void update() { + //If coin is set to destroy and isnt, destroy it + if(setToDestroyed && !destroyed) { + world.destroyBody(b2body); + destroyed = true; + } + //Update position of power up + else if(!destroyed) { + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + } + if (toggleCoinMagnet) { + toggleCoinMagnet(); + toggleCoinMagnet = false; + } + // ability lasts for a specified duration + if (timer > duration) { + endPowerUp(); + timer = 0; + } + else if (active) { + timer += Gdx.graphics.getDeltaTime(); + } + } + + /** + * Enables/disables the coin magnet power up + */ + private void toggleCoinMagnet() { + // collect coins in a larger radius around player + for (Coin coin : screen.getCoins()) coin.toggleCoinMagnet(); + } + + @Override + public void endPowerUp() { + toggleCoinMagnet(); + active = false; + Gdx.app.log("coinmagnet", "ended"); + } +} diff --git a/core/src/com/mygdx/pirategame/Entity.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/Entity.java similarity index 73% rename from core/src/com/mygdx/pirategame/Entity.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/entity/Entity.java index 59958b20..36df8f0d 100644 --- a/core/src/com/mygdx/pirategame/Entity.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/Entity.java @@ -1,8 +1,9 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.entity; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.World; +import com.mygdx.pirategame.screen.GameScreen; /** * Entity @@ -16,6 +17,8 @@ public abstract class Entity extends Sprite { protected World world; protected GameScreen screen; public Body b2body; + public boolean setToDestroyed = false; + public boolean destroyed = false; /** * Instantiates an entity @@ -33,12 +36,12 @@ public Entity(GameScreen screen, float x, float y) { } /** - * Defines an entity + * Defines the properties of an entity */ protected abstract void defineEntity(); /** - * Defines contact + * Defines contact with other objects, The only entity that is able to do so is the player ship */ public abstract void entityContact(); } diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/FasterShooting.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/FasterShooting.java new file mode 100644 index 00000000..c04cbf2a --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/FasterShooting.java @@ -0,0 +1,100 @@ +package com.mygdx.pirategame.gameobjects.entity; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.CircleShape; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; + +public class FasterShooting extends PowerUp { + private Texture fasterShooting; + + /** + * x + * Instantiates an entity + * Sets position in world + * + * @param screen Visual data + * @param x x position of entity + * @param y y position of entity + */ + public FasterShooting(GameScreen screen, float x, float y) { + super(screen, x, y); + + // Set speed boost image + fasterShooting = new Texture("cannonBall.png"); // CHANGE + //Set the position and size of the speed boost + setBounds(0,0,48 / PirateGame.PPM, 48 / PirateGame.PPM); + //Set the texture + setRegion(fasterShooting); + //Sets origin of the speed boost + setOrigin(24 / PirateGame.PPM,24 / PirateGame.PPM); + } + + /** + * Updates the speed boost state. If needed, deletes the speed boost if picked up + */ + public void update() { + //If coin is set to destroy and isnt, destroy it + if(setToDestroyed && !destroyed) { + world.destroyBody(b2body); + destroyed = true; + } + //Update position of coin + else if(!destroyed) { + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + } + } + + @Override + public void endPowerUp() { + + } + + /** + * Defines all the parts of the speed boost physical model. Sets it up for collisions + */ + @Override + protected void defineEntity() { + // Sets the body definitions + BodyDef bdef = new BodyDef(); + bdef.position.set(getX(), getY()); + bdef.type = BodyDef.BodyType.DynamicBody; + b2body = world.createBody(bdef); + + // Sets collision boundaries + FixtureDef fdef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(24 / PirateGame.PPM); + + // Setting BIT identifier + fdef.filter.categoryBits = PirateGame.SPEED_BOOST_BIT; + + // Determining what this BIT can collide with + fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT; + fdef.shape = shape; + fdef.isSensor = true; + b2body.createFixture(fdef).setUserData(this); + } + + /** + * What happens when an entity collides with the speed boost, only the player ship can + */ + @Override + public void entityContact() { + if (!destroyed) { + // Increase speed of shooting by decreasing shooting delay + GameScreen.changeShootingDelay((float) 10); + + // Set to destroy + setToDestroyed = true; + Gdx.app.log("fasterShooting", "collision"); + // Play pickup sound + if (screen.game.getPreferences().isEffectsEnabled()) { + getSound().play(screen.game.getPreferences().getEffectsVolume()); + } + } + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/PowerUp.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/PowerUp.java new file mode 100644 index 00000000..1fbae92f --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/PowerUp.java @@ -0,0 +1,54 @@ +package com.mygdx.pirategame.gameobjects.entity; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.mygdx.pirategame.screen.GameScreen; + +public abstract class PowerUp extends Entity { + private Sound pickupSound; + protected boolean active = false; + protected float timer = 0; + protected float duration; + + + /** + * x + * Instantiates an entity + * Sets position in world + * + * @param screen Visual data + * @param x x position of entity + * @param y y position of entity + */ + public PowerUp(GameScreen screen, float x, float y) { + super(screen, x, y); + this.world = screen.getWorld(); + this.screen = screen; + setPosition(x, y); + defineEntity(); + + // Sets pickup sound + pickupSound = Gdx.audio.newSound(Gdx.files.internal("sfx_and_music/coin-pickup.mp3")); + } + + public abstract void update(); + + public Sound getSound() { + return pickupSound; + } + + public abstract void endPowerUp(); + + /** + * Draws the coin using batch + * + * @param batch The batch of the program + */ + public void draw(Batch batch) { + if(!destroyed) { + super.draw(batch); + } + } +} + diff --git a/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/SpeedBoost.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/SpeedBoost.java new file mode 100644 index 00000000..d5aedeb8 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/entity/SpeedBoost.java @@ -0,0 +1,101 @@ +package com.mygdx.pirategame.gameobjects.entity; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.CircleShape; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; + +public class SpeedBoost extends PowerUp { + private Texture speedBoost; + + /** + * x + * Instantiates an entity + * Sets position in world + * + * @param screen Visual data + * @param x x position of entity + * @param y y position of entity + */ + public SpeedBoost(GameScreen screen, float x, float y) { + super(screen, x, y); + + // Set speed boost image + speedBoost = new Texture("cannonBall.png"); // CHANGE + //Set the position and size of the speed boost + setBounds(0,0,48 / PirateGame.PPM, 48 / PirateGame.PPM); + //Set the texture + setRegion(speedBoost); + //Sets origin of the speed boost + setOrigin(24 / PirateGame.PPM,24 / PirateGame.PPM); + } + + /** + * Updates the speed boost state. If needed, deletes the speed boost if picked up + */ + public void update() { + //If coin is set to destroy and isnt, destroy it + if(setToDestroyed && !destroyed) { + world.destroyBody(b2body); + destroyed = true; + } + //Update position of coin + else if(!destroyed) { + setPosition(b2body.getPosition().x - getWidth() / 2f, b2body.getPosition().y - getHeight() / 2f); + } + } + + @Override + public void endPowerUp() { + + } + + /** + * Defines all the parts of the speed boost physical model. Sets it up for collisions + */ + @Override + protected void defineEntity() { + // Sets the body definitions + BodyDef bdef = new BodyDef(); + bdef.position.set(getX(), getY()); + bdef.type = BodyDef.BodyType.DynamicBody; + b2body = world.createBody(bdef); + + // Sets collision boundaries + FixtureDef fdef = new FixtureDef(); + CircleShape shape = new CircleShape(); + shape.setRadius(24 / PirateGame.PPM); + + // Setting BIT identifier + fdef.filter.categoryBits = PirateGame.SPEED_BOOST_BIT; + + // Determining what this BIT can collide with + fdef.filter.maskBits = PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT | PirateGame.ENEMY_BIT; + fdef.shape = shape; + fdef.isSensor = true; + b2body.createFixture(fdef).setUserData(this); + } + + /** + * What happens when an entity collides with the speed boost, only the player ship can + */ + @Override + public void entityContact() { + if (!destroyed) { + // Increase speed and acceleration variables (by percentage) + GameScreen.changeMaxSpeed((float) 5); + GameScreen.changeAcceleration((float) 10); + + // Set to destroy + setToDestroyed = true; + Gdx.app.log("speedBoost", "collision"); + // Play pickup sound + if (screen.game.getPreferences().isEffectsEnabled()) { + getSound().play(screen.game.getPreferences().getEffectsVolume()); + } + } + } +} diff --git a/core/src/com/mygdx/pirategame/CollegeWalls.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls.java similarity index 77% rename from core/src/com/mygdx/pirategame/CollegeWalls.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls.java index eae1804d..b6d554b0 100644 --- a/core/src/com/mygdx/pirategame/CollegeWalls.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls.java @@ -1,6 +1,8 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.tileobject; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * College Walls (Alcuin) @@ -32,7 +34,7 @@ public CollegeWalls(GameScreen screen, Rectangle bounds) { @Override public void onContact() { Gdx.app.log("wall", "collision"); - //Deal damage to the assigned college - screen.getCollege("Alcuin").onContact(); + //Deal damage to the assigned college (Alcuin) + screen.getCollege(0).onContact(); } } diff --git a/core/src/com/mygdx/pirategame/CollegeWalls2.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls2.java similarity index 77% rename from core/src/com/mygdx/pirategame/CollegeWalls2.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls2.java index d041bfc7..d100b57e 100644 --- a/core/src/com/mygdx/pirategame/CollegeWalls2.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls2.java @@ -1,6 +1,8 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.tileobject; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * College Walls (Goodricke) @@ -32,7 +34,7 @@ public CollegeWalls2(GameScreen screen, Rectangle bounds) { @Override public void onContact() { Gdx.app.log("wall", "collision"); - //Deal damage to the assigned college - screen.getCollege("Goodricke").onContact(); + //Deal damage to the assigned college (Goodricke) + screen.getCollege(3).onContact(); } } diff --git a/core/src/com/mygdx/pirategame/CollegeWalls3.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls3.java similarity index 77% rename from core/src/com/mygdx/pirategame/CollegeWalls3.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls3.java index 5cfbcc98..7629f32d 100644 --- a/core/src/com/mygdx/pirategame/CollegeWalls3.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls3.java @@ -1,6 +1,8 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.tileobject; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * College Walls (Constantine) @@ -32,7 +34,7 @@ public CollegeWalls3(GameScreen screen, Rectangle bounds) { @Override public void onContact() { Gdx.app.log("wall", "collision"); - //Deal damage to the assigned college - screen.getCollege("Constantine").onContact(); + //Deal damage to the assigned college (Constantine) + screen.getCollege(2).onContact(); } } diff --git a/core/src/com/mygdx/pirategame/CollegeWalls4.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls4.java similarity index 77% rename from core/src/com/mygdx/pirategame/CollegeWalls4.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls4.java index 141c2adf..9891e9a4 100644 --- a/core/src/com/mygdx/pirategame/CollegeWalls4.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/CollegeWalls4.java @@ -1,6 +1,8 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.tileobject; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * College Walls (Anne Lister) @@ -32,8 +34,8 @@ public CollegeWalls4(GameScreen screen, Rectangle bounds) { @Override public void onContact() { Gdx.app.log("wall", "collision"); - //Deal damage to the assigned college - screen.getCollege("Anne Lister").onContact(); + //Deal damage to the assigned college (Anne Lister) + screen.getCollege(1).onContact(); } } diff --git a/core/src/com/mygdx/pirategame/InteractiveTileObject.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/InteractiveTileObject.java similarity index 92% rename from core/src/com/mygdx/pirategame/InteractiveTileObject.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/InteractiveTileObject.java index a5fca6ac..edd92bd9 100644 --- a/core/src/com/mygdx/pirategame/InteractiveTileObject.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/InteractiveTileObject.java @@ -1,8 +1,10 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.tileobject; import com.badlogic.gdx.maps.tiled.TiledMapTile; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.physics.box2d.*; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * Interactive Tile Object diff --git a/core/src/com/mygdx/pirategame/Islands.java b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/Islands.java similarity index 83% rename from core/src/com/mygdx/pirategame/Islands.java rename to core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/Islands.java index bda49a46..617d6c26 100644 --- a/core/src/com/mygdx/pirategame/Islands.java +++ b/core/src/main/java/com/mygdx/pirategame/gameobjects/tileobject/Islands.java @@ -1,6 +1,9 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.gameobjects.tileobject; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.Rectangle; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.screen.GameScreen; /** * Sets up the class for all the Islands. Deals with what happens on collision and its properties diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/Checkpoint.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/Checkpoint.java new file mode 100644 index 00000000..76e3310d --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/Checkpoint.java @@ -0,0 +1,67 @@ +package com.mygdx.pirategame.pathfinding; + +import com.badlogic.gdx.math.Vector2; + +public class Checkpoint { + /** + * Used to create a checkpoint from a tilemap grid position. The location of the checkpoint will be the centre of the grid + * + * @param x The x coord + * @param y The y coord + * @param gradient The gradient of the tilemap + * @return The created checkpoint + */ + public static Checkpoint createCheckpointFromTilemap(int x, int y, int gradient) { + return new Checkpoint((float) (x * gradient) + gradient / 2, (float) (y * gradient) + gradient / 2, gradient); + } + + public float x, y; + + public final float gradient; + + /** + * @param x the x coord of the checkpoint in game space + * @param y the y coord of the checkpoint in game space + */ + public Checkpoint(float x, float y, float gradient) { + this.x = x; + this.y = y; + + this.gradient = gradient; + } + + /** + * @return the tilemap X locaiton + */ + public int getTileX() { + return (int) (x / gradient); + } + + /** + * @return The tilemap Y location + */ + public int getTileY() { + return (int) (y / gradient); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Checkpoint that = (Checkpoint) o; + return Float.compare(that.getTileX(), getTileX()) == 0 && Float.compare(that.getTileY(), getTileY()) == 0; + } + + @Override + public String toString() { + return "Checkpoint{" + + "x=" + x + + ", y=" + y + + ", gradient=" + gradient + + '}'; + } + + public Vector2 getVector2(){ + return new Vector2(x, y); + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/PathFinder.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/PathFinder.java new file mode 100644 index 00000000..6867d457 --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/PathFinder.java @@ -0,0 +1,254 @@ +package com.mygdx.pirategame.pathfinding; + +import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.screen.GameScreen; + +import java.util.*; + +public class PathFinder { + + /** + * Used to determine if debug information about the pathfinder should be displayed + */ + public static final boolean PATHFINDERDEBUG = false; + + private final GameScreen gameScreen; + private final float tileSize; + + /** + * NOTE: the greater the gradient, the less accurate the result is to the true result but results will be generated faster + * + * @param gameScreen The gameScreen for the world + * @param tileSize How small each tile in the tilemap should be (ie 5 game units large tiles) + */ + public PathFinder(GameScreen gameScreen, float tileSize) { + this.gameScreen = gameScreen; + this.tileSize = tileSize; + + } + + /** + * @param sourceX the x source location + * @param sourceY the y source location + * @param destinationX the x destination + * @param destinationY the y destination + * @return the path as a list of checkpoint, or null if no path could be found + */ + public List getPath(float sourceX, float sourceY, float destinationX, float destinationY, float width, float height) { + + // checking if the start or finish location is an invalid + if (!isTraversable(sourceX, sourceY, width, height) || !isTraversable(destinationX, destinationY, width, height)) { + return null; + } + + destinationX = destinationX - (destinationX % tileSize); + destinationY = destinationY - (destinationY % tileSize); + sourceX = sourceX - (sourceX % tileSize); + sourceY = sourceY - (sourceY % tileSize); + + // converting locations into tilemap equivalents + Checkpoint source = new Checkpoint(sourceX, sourceY, tileSize); + Checkpoint dest = new Checkpoint(destinationX, destinationY, tileSize); + + PriorityQueue open = new PriorityQueue<>(); + + List close = new ArrayList<>(); + + open.add(new PathNode(source, 0, dest, null)); + int count = 0; + PathNode solutionNode = null; + while (!open.isEmpty()) { + count++; + if (count > 1000) { + break; + } + PathNode currentNode = open.poll(); + if (currentNode.checkpoint.equals(dest)) { + // if we have found the solution + solutionNode = currentNode; + break; + } + + // looping through successor nodes + for (PathNode successorNode : successor(currentNode, width, height)) { + if (open.contains(successorNode)) { + // already in the fringe + continue; + } else if (close.contains(successorNode)) { + // already visited + continue; + } else { + // path cost is too great, limiting scope + if (successorNode.fx > 10000) { + continue; + } + open.add(successorNode); + } + + } + + } + + if (solutionNode == null) { + return null; + } + + List checkpoints = new ArrayList<>(); + checkpoints.add(dest); + PathNode nextNode = solutionNode; + + while (nextNode.parent != null) { + checkpoints.add(nextNode.parent.checkpoint); + nextNode = nextNode.parent; + } + + Collections.reverse(checkpoints); + return checkpoints; + } + + /** + * Used to lookup a location in the tilemap to check if the location is traversable + * + * @param xb the x coord in game space + * @param yb the y coord in game space + * @param width the width of the object + * @param height the height of the object + * @return if the location is traversable + */ + public boolean isTraversable(float xb, float yb, float width, float height) { + + float hw = width; + float hh = height; + Vector2[] vlst = new Vector2[8]; + vlst[0] = new Vector2(xb - hw, yb - hh); + vlst[1] = new Vector2(xb + hw, yb - hh); + vlst[2] = new Vector2(xb - hw, yb + hh); + vlst[3] = new Vector2(xb + hw, yb + hh); + vlst[4] = new Vector2(xb, yb + hh); + vlst[5] = new Vector2(xb, yb - hh); + vlst[6] = new Vector2(xb + hw, yb); + vlst[7] = new Vector2(xb - hw, yb); + for (Vector2 v : vlst) { + int x = (int) (v.x / tileSize); + int y = (int) (v.y / tileSize); + TiledMapTileLayer islands = (TiledMapTileLayer) gameScreen.getMap().getLayers().get("islands"); + if (isColliding(islands, x, y)) { + return false; + } + + + TiledMapTileLayer rocks = (TiledMapTileLayer) gameScreen.getMap().getLayers().get("rocks + leaves"); + + if (isColliding(rocks, x, y)) { + return false; + } + + } + + return true; + } + + private boolean isColliding(TiledMapTileLayer layer, int x, int y) { + TiledMapTileLayer.Cell cell = layer.getCell(x, y); + if (cell == null) { + return false; + } + + return cell.getTile().getId() != 0; + } + + /** + * Used to get a list of all successor nodes of the provided node + * + * @param node The node to get the successors of + * @return The list of successors + */ + private List successor(PathNode node, float width, float height) { + List toReturn = new ArrayList<>(); + int mapWidth = gameScreen.getTileMapWidth(); + int mapHeight = gameScreen.getTileMapHeight(); + + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + + if (x == 0 && y == 0) { + // cannot travel to itself as a successor + continue; + } + + float calcX = node.checkpoint.x + (x * tileSize); + float calcY = node.checkpoint.y + (y * tileSize); + + if (calcX >= mapWidth * tileSize) { + continue; + } + if (calcY >= mapHeight * tileSize) { + continue; + } + + if (isTraversable(calcX, calcY, width, height)) { + toReturn.add(new PathNode(new Checkpoint(calcX, calcY, tileSize), (float) Math.sqrt(Math.abs(x * tileSize) + Math.abs(y * tileSize)), node.dest, node)); + } + } + } + return toReturn; + } + + /** + * Used as to avoid repeated calculations and to store the checkpoint within the priority list + */ + private class PathNode implements Comparable { + float fx; + float gx; + Checkpoint checkpoint; + Checkpoint dest; + PathNode parent; + + public PathNode(Checkpoint checkpoint, float gx, Checkpoint dest, PathNode parent) { + this.checkpoint = checkpoint; + this.dest = dest; + this.parent = parent; + if (parent == null) { + this.gx = gx; + } else { + this.gx = gx + parent.gx; + } + fx = hx(dest) + this.gx; + } + + private float hx(Checkpoint dest) { + return (float) Math.sqrt(Math.pow(checkpoint.x - dest.x, 2) + Math.pow(checkpoint.y - dest.y, 2)); + } + + /** + * comparator for the priority list + * + * @param o the other PathNode to compare it to + * @return The comparison of fx + */ + @Override + public int compareTo(PathNode o) { + return (int) (fx - o.fx); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PathNode pathNode = (PathNode) o; + return checkpoint.equals(pathNode.checkpoint); + } + + @Override + public String toString() { + return "PathNode{" + + "fx=" + fx + + ", gx=" + gx + + ", checkpoint=" + checkpoint + + ", dest=" + dest + + ", parent=" + parent + + '}'; + } + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/AttackPath.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/AttackPath.java new file mode 100644 index 00000000..3540b80e --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/AttackPath.java @@ -0,0 +1,86 @@ +package com.mygdx.pirategame.pathfinding.pathManager; + +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.enemy.EnemyShip; +import com.mygdx.pirategame.screen.GameScreen; + +import java.util.Random; + +/** + * Class used for pathing an AI ship to attack a target + */ +public class AttackPath implements PathManager { + + // the path that the ship used to be on + private final PathManager previousPath; + private final EnemyShip ship; + private final GameScreen screen; + + public AttackPath(PathManager previousPath, EnemyShip ship, GameScreen screen){ + this.previousPath = previousPath; + this.ship = ship; + this.screen = screen; + } + + @Override + public Vector2 generateDestination() { + Random rnd = new Random(); + + int tileWidth = (int) PirateGame.PPM; + + // limiting attempts at finding a valid attack path + for (int i = 0; i < 10; i++) { + // generate random position for ship to go around the college + // making the player position the origin + Vector2 diff = ship.b2body.getPosition().sub(screen.getPlayerPos()); + // limiting the distance of the player to 2 tiles + diff = diff.limit(200 / tileWidth); + diff.add(screen.getPlayerPos()); + + int x = rnd.nextInt(200) + (int) (diff.x * tileWidth); + int y = rnd.nextInt(200) + (int) (diff.y * tileWidth); + + // bounding the location + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x > screen.getTileMapWidth()) { + x = screen.getTileMapWidth(); + } + if (y > screen.getTileMapHeight()) { + y = screen.getTileMapHeight(); + } + + // checking if the location is valid + if (ship.isTraversable(x, y)) { + // going to that location + return new Vector2(x, y); + } + } + + // attack path could not be found, reverting to passive + ship.setPathManager(previousPath); + return null; + } + + int fireDelay = 0; + + @Override + public void update(float dt) { + // if the ship out of range of the player + if (ship.b2body.getPosition().dst(screen.getPlayerPos()) > 6 || (ship.collegeMeta != null && !ship.collegeMeta.isPlayer() && ship.collegeMeta.getPosition().dst(ship.b2body.getPosition()) > 40)) { + ship.setPathManager(previousPath); + return; + } + + fireDelay++; + if(fireDelay > 50){ + ship.fire(); + fireDelay = 0; + } + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/PathManager.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/PathManager.java new file mode 100644 index 00000000..d50ec88b --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/PathManager.java @@ -0,0 +1,22 @@ +package com.mygdx.pirategame.pathfinding.pathManager; + +import com.badlogic.gdx.math.Vector2; + +/** + * Used to manage a type of pathing that a ship can have + */ +public interface PathManager { + + /** + * Generates a destination (called when a the current path fails or is completed) + * @return + */ + public abstract Vector2 generateDestination(); + + /** + * Called once a tick in case this type of path finding requires remapping during a path + * @param dt The Delta time of this update + */ + public abstract void update(float dt); + +} diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/PatrolPath.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/PatrolPath.java new file mode 100644 index 00000000..2d9f938c --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/PatrolPath.java @@ -0,0 +1,68 @@ +package com.mygdx.pirategame.pathfinding.pathManager; + +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.enemy.College; +import com.mygdx.pirategame.gameobjects.enemy.EnemyShip; +import com.mygdx.pirategame.screen.GameScreen; + +import java.util.Random; + +/** + * This class is used to manage the pathing of a ship while it is not targeting a specific entity + */ +public class PatrolPath extends WaitingPath{ + + + /** + * Create a new PatrolPath, The ship must be assigned to a valid college else this will throw an error + * + * @param ship The ship + * @param screen The GameScreen managing the game + */ + public PatrolPath(EnemyShip ship, GameScreen screen) { + super(ship, screen); + + if (ship.collegeMeta == null) { + throw new IllegalArgumentException("Ship cannot patrol a college when it is not assigned to a valid college"); + } + } + + @Override + public Vector2 generateDestination() { + Random rnd = new Random(); + + int tileWidth = (int) PirateGame.PPM; + + while (true) { + // generate random position for ship to go around the college + int x = rnd.nextInt(3000) - 1500 + (int) (ship.collegeMeta.getX() * tileWidth); + int y = rnd.nextInt(3000) - 1500 + (int) (ship.collegeMeta.getY() * tileWidth); + + // bounding the location + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x > screen.getTileMapWidth()) { + x = screen.getTileMapWidth(); + } + if (y > screen.getTileMapHeight()) { + y = screen.getTileMapHeight(); + } + + // checking if the location is valid + if (ship.isTraversable(x, y)) { + // going to that location + return new Vector2(x, y); + } + } + } + + @Override + public void update(float dt) { + super.update(dt); + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/RandomPath.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/RandomPath.java new file mode 100644 index 00000000..743f061a --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/RandomPath.java @@ -0,0 +1,61 @@ +package com.mygdx.pirategame.pathfinding.pathManager; + +import com.badlogic.gdx.math.Path; +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.enemy.Enemy; +import com.mygdx.pirategame.gameobjects.enemy.EnemyShip; +import com.mygdx.pirategame.screen.GameScreen; + +import java.util.Random; + +/** + * Generates random paths for ships and randomly paths between them + * Used for ships without an assigned college + */ +public class RandomPath extends WaitingPath { + + + public RandomPath (EnemyShip ship, GameScreen screen) { + super(ship, screen); + } + + @Override + public Vector2 generateDestination() { + Random rnd = new Random(); + + int tileWidth = (int) PirateGame.PPM; + + while (true) { + // generate random position for ship to go + int x = rnd.nextInt(2000) - 1000 + (int) (ship.b2body.getPosition().x * tileWidth); + int y = rnd.nextInt(2000) - 1000 + (int) (ship.b2body.getPosition().y * tileWidth); + + // bounding the location + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x > screen.getTileMapWidth()) { + x = screen.getTileMapWidth(); + } + if (y > screen.getTileMapHeight()) { + y = screen.getTileMapHeight(); + } + + // checking if the location is valid + if (ship.isTraversable(x, y)) { + // going to that location + return new Vector2(x, y); + } + } + } + + @Override + public void update(float dt) { + super.update(dt); + // nothing to do here + } +} diff --git a/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/WaitingPath.java b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/WaitingPath.java new file mode 100644 index 00000000..9caf349b --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/pathfinding/pathManager/WaitingPath.java @@ -0,0 +1,35 @@ +package com.mygdx.pirategame.pathfinding.pathManager; + +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.gameobjects.enemy.EnemyShip; +import com.mygdx.pirategame.screen.GameScreen; + +/** + * Superclass used for all pathing managers which are in a passive state waiting for a ship to come into range to attack + * This class will switch to an attacking pathing manager if within range of an enemy + */ +public abstract class WaitingPath implements PathManager { + + protected final EnemyShip ship; + protected final GameScreen screen; + + /** + * Used for all passive pathing managers that can start an attack + * @param ship The ship that is being pathed + * @param screen The gameScreen controlling the level + */ + public WaitingPath(EnemyShip ship, GameScreen screen) { + this.ship = ship; + this.screen = screen; + } + + @Override + public void update(float dt) { + // if the ship is in range of the player + if ((ship.collegeMeta == null || !ship.collegeMeta.isPlayer()) && ship.b2body.getPosition().dst(screen.getPlayerPos()) < 3) { + ship.setPathManager(new AttackPath(this, ship, screen)); + } + + } + +} diff --git a/core/src/com/mygdx/pirategame/DeathScreen.java b/core/src/main/java/com/mygdx/pirategame/screen/DeathScreen.java similarity index 95% rename from core/src/com/mygdx/pirategame/DeathScreen.java rename to core/src/main/java/com/mygdx/pirategame/screen/DeathScreen.java index 9a99a0fa..11126e3a 100644 --- a/core/src/com/mygdx/pirategame/DeathScreen.java +++ b/core/src/main/java/com/mygdx/pirategame/screen/DeathScreen.java @@ -1,4 +1,4 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; @@ -13,6 +13,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.mygdx.pirategame.PirateGame; /** * Death Screen @@ -41,7 +42,7 @@ public DeathScreen(PirateGame pirateGame){ */ @Override public void show() { - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); Gdx.input.setInputProcessor(stage); // Create tables for the text and button diff --git a/core/src/main/java/com/mygdx/pirategame/screen/GameScreen.java b/core/src/main/java/com/mygdx/pirategame/screen/GameScreen.java new file mode 100644 index 00000000..fa701b6f --- /dev/null +++ b/core/src/main/java/com/mygdx/pirategame/screen/GameScreen.java @@ -0,0 +1,807 @@ +package com.mygdx.pirategame.screen; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.maps.MapProperties; +import com.badlogic.gdx.maps.tiled.TiledMap; +import com.badlogic.gdx.maps.tiled.TmxMapLoader; +import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.viewport.FitViewport; +import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.Player; +import com.mygdx.pirategame.gameobjects.enemy.College; +import com.mygdx.pirategame.gameobjects.enemy.CollegeMetadata; +import com.mygdx.pirategame.gameobjects.enemy.EnemyShip; +import com.mygdx.pirategame.gameobjects.entity.Coin; +import com.mygdx.pirategame.pathfinding.PathFinder; + +import com.mygdx.pirategame.gameobjects.entity.*; + +import com.mygdx.pirategame.world.AvailableSpawn; +import com.mygdx.pirategame.world.WorldContactListener; +import com.mygdx.pirategame.world.WorldCreator; + +import java.util.*; + + +/** + * Game Screen + * Class to generate the various screens used to play the game. + * Instantiates all screen types and displays current screen. + * + * @author Ethan Alabaster, Adam Crook, Joe Dickinson, Sam Pearson, Tom Perry, Edward Poulter + * @version 1.0 + */ +public class GameScreen implements Screen { + private static float maxSpeed = 4f; + private static float accel = 0.1f; + private static float shootingDelay = 1f; + private float stateTime; + + public static PirateGame game; + private final OrthographicCamera camera; + private final FitViewport viewport; + private final Stage stage; + + private final TmxMapLoader maploader; + private final TiledMap map; + private final OrthogonalTiledMapRenderer renderer; + + private final World world; + private final Box2DDebugRenderer b2dr; + + private final Player player; + private static HashMap colleges = new HashMap<>(); + private static ArrayList ships = new ArrayList<>(); + private static ArrayList Coins = new ArrayList<>(); + + private static ArrayList PowerUps = new ArrayList<>(); + private final AvailableSpawn invalidSpawn = new AvailableSpawn(); + private final Hud hud; + + + public static final int GAME_RUNNING = 0; + public static final int GAME_PAUSED = 1; + private static int gameStatus; + + private Texture tutorialTexture; + private Sprite tutorials; + + private final PathFinder pathFinder; + + private Table pauseTable; + private Table table; + + public Random rand = new Random(); + + private Integer attackingCollege; + private final List collegesLeft = new LinkedList(Arrays.asList(1, 2, 3)); + private final Random collegeRand = new Random(); + + /** + * Initialises the Game Screen, + * generates the world data and data for entities that exist upon it, + * + * @param game passes game data to current class, + */ + public GameScreen(PirateGame game) { + gameStatus = GAME_RUNNING; + GameScreen.game = game; + // Initialising camera and extendable viewport for viewing game + camera = new OrthographicCamera(); + camera.zoom = 0.0155f; + viewport = new FitViewport(1280, 720, camera); + camera.position.set(viewport.getWorldWidth() / 3, viewport.getWorldHeight() / 3, 0); + + // Initialize a hud + hud = new Hud(game.batch); + + // Initialising box2d physics + world = new World(new Vector2(0, 0), true); + b2dr = new Box2DDebugRenderer(); + player = new Player(this); + + // making the Tiled tmx file render as a map + maploader = new TmxMapLoader(); + map = maploader.load("map/map.tmx"); + renderer = new OrthogonalTiledMapRenderer(map, getUnitScale()); + pathFinder = new PathFinder(this, 64); + + new WorldCreator(this); + + // stores tutorial texture + tutorialTexture = new Texture("Tutorial.png"); + tutorials = new Sprite(tutorialTexture); + + // Setting up contact listener for collisions + world.setContactListener(new WorldContactListener()); + + // Spawning enemy ship and coin. x and y is spawn location + colleges = new HashMap<>(); + + // Alcuin college + colleges.put(CollegeMetadata.ALCUIN, new College(this, CollegeMetadata.ALCUIN, 6, invalidSpawn)); + // Anne Lister college + colleges.put(CollegeMetadata.ANNELISTER, new College(this, CollegeMetadata.ANNELISTER, 8, invalidSpawn)); + // Constantine college + colleges.put(CollegeMetadata.CONSTANTINE, new College(this, CollegeMetadata.CONSTANTINE, 8, invalidSpawn)); + // Goodricke college + colleges.put(CollegeMetadata.GOODRICKE, new College(this, CollegeMetadata.GOODRICKE, 8, invalidSpawn)); + + ships = new ArrayList<>(); + + for (CollegeMetadata college : CollegeMetadata.values()) { + ships.addAll(getCollege(college).fleet); + } + + //Random ships + for (int i = 0; i < 20; i++) { + int[] loc = getRandomLocation(); + //Add a ship at the random coords + ships.add(new EnemyShip(this, loc[0], loc[1], "college/Ships/unaligned_ship.png", null)); + } + + //Random coins + Coins = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + int[] loc = getRandomLocation(); + //Add a coins at the random coords + Coins.add(new Coin(this, loc[0], loc[1])); + } + + addPowerUps(); + + //Setting stage + stage = new Stage(new ScreenViewport()); + + //Setting the college that can currently be attacked + nextCollege(); + } + + /** + * Randomly generates x and y and checks if they are valid + * + * @return x, y + */ + public int[] getRandomLocation() { + Boolean validLoc = false; + int x = 0, y = 0; + while (!validLoc) { + //Get random x and y coords + x = rand.nextInt(AvailableSpawn.xCap - AvailableSpawn.xBase) + AvailableSpawn.xBase; + y = rand.nextInt(AvailableSpawn.yCap - AvailableSpawn.yBase) + AvailableSpawn.yBase; + validLoc = checkGenPos(x, y); + } + return new int[]{x, y}; + } + + /** + * Randomly positions power ups around the sea + */ + public void addPowerUps() { + //Random powerups + PowerUps = new ArrayList<>(); + // Add Speedboosts + for (int i = 0; i < 100; i++) { + int[] loc = getRandomLocation(); + + //Add a powerup at the random coords + //PowerUps.add(new AbsorptionHeart(this, loc[0], loc[1])); + //PowerUps.add(new SpeedBoost(this, loc[0], loc[1])); + //PowerUps.add(new FasterShooting(this, loc[0], loc[1])); + PowerUps.add(new CoinMagnet(this, loc[0], loc[1])); + } + } + + /** + * Returns the player object + * @return player object + */ + public Player getPlayer() { + return player; + } + + /** + * Returns the array of coins in the level + * @return coin array + */ + public ArrayList getCoins() { + return Coins; + } + + /** + * Makes this the current screen for the game. + * Generates the buttons to be able to interact with what screen is being displayed. + * Creates the escape menu and pause button + */ + @Override + public void show() { + Gdx.input.setInputProcessor(stage); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); + + //GAME BUTTONS + final TextButton pauseButton = new TextButton("Pause", skin); + final TextButton skill = new TextButton("Skill Tree", skin); + + //PAUSE MENU BUTTONS + final TextButton start = new TextButton("Resume", skin); + final TextButton options = new TextButton("Options", skin); + TextButton exit = new TextButton("Exit", skin); + + //Create main table and pause tables + table = new Table(); + table.setFillParent(true); + stage.addActor(table); + + pauseTable = new Table(); + pauseTable.setFillParent(true); + stage.addActor(pauseTable); + + //Set the visibility of the tables. Particularly used when coming back from options or skillTree + if (gameStatus == GAME_PAUSED) { + table.setVisible(false); + pauseTable.setVisible(true); + } else { + pauseTable.setVisible(false); + table.setVisible(true); + } + + //ADD TO TABLES + table.add(pauseButton); + table.row().pad(10, 0, 10, 0); + table.left().top(); + + pauseTable.add(start).fillX().uniformX(); + pauseTable.row().pad(20, 0, 10, 0); + pauseTable.add(skill).fillX().uniformX(); + pauseTable.row().pad(20, 0, 10, 0); + pauseTable.add(options).fillX().uniformX(); + pauseTable.row().pad(20, 0, 10, 0); + pauseTable.add(exit).fillX().uniformX(); + pauseTable.center(); + + + pauseButton.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + table.setVisible(false); + pauseTable.setVisible(true); + pause(); + + } + }); + skill.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + pauseTable.setVisible(false); + game.changeScreen(PirateGame.SKILL); + } + }); + start.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + pauseTable.setVisible(false); + table.setVisible(true); + resume(); + } + }); + options.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + pauseTable.setVisible(false); + game.setScreen(new OptionsScreen(game, game.getScreen())); + } + } + ); + exit.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + Gdx.app.exit(); + } + }); + } + + /** + * Checks for input and performs an action + * Applies to key "W" "A" "S" "D" "E" "Esc" "Left" "Right" "Up" "Down" + *

+ * Caps player velocity + * + * @param dt Delta time (elapsed time since last game tick) + */ + public void handleInput(float dt) { + if (gameStatus == GAME_RUNNING) { + // Left physics impulse on 'A' + if (Gdx.input.isKeyPressed(Input.Keys.A) || Gdx.input.isKeyPressed(Input.Keys.LEFT)) { + player.b2body.applyLinearImpulse(new Vector2(-accel, 0), player.b2body.getWorldCenter(), true); + } + // Right physics impulse on 'D' + if (Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { + player.b2body.applyLinearImpulse(new Vector2(accel, 0), player.b2body.getWorldCenter(), true); + } + // Up physics impulse on 'W' + if (Gdx.input.isKeyPressed(Input.Keys.W) || Gdx.input.isKeyPressed(Input.Keys.UP)) { + player.b2body.applyLinearImpulse(new Vector2(0, accel), player.b2body.getWorldCenter(), true); + } + // Down physics impulse on 'S' + if (Gdx.input.isKeyPressed(Input.Keys.S) || Gdx.input.isKeyPressed(Input.Keys.DOWN)) { + player.b2body.applyLinearImpulse(new Vector2(0, -accel), player.b2body.getWorldCenter(), true); + } + // Checking if player at max velocity, and keeping them below max + if (player.b2body.getLinearVelocity().x >= maxSpeed) { + player.b2body.applyLinearImpulse(new Vector2(-accel, 0), player.b2body.getWorldCenter(), true); + } + if (player.b2body.getLinearVelocity().x <= -maxSpeed) { + player.b2body.applyLinearImpulse(new Vector2(accel, 0), player.b2body.getWorldCenter(), true); + } + if (player.b2body.getLinearVelocity().y >= maxSpeed) { + player.b2body.applyLinearImpulse(new Vector2(0, -accel), player.b2body.getWorldCenter(), true); + } + if (player.b2body.getLinearVelocity().y <= -maxSpeed) { + player.b2body.applyLinearImpulse(new Vector2(0, accel), player.b2body.getWorldCenter(), true); + } + // Firing Code, when left mouse is pressed + if (Gdx.input.isButtonJustPressed(Input.Buttons.LEFT)) { + player.fire(camera); + } + } + if (Gdx.input.isKeyJustPressed(Input.Keys.ESCAPE)) { + if (gameStatus == GAME_PAUSED) { + resume(); + table.setVisible(true); + pauseTable.setVisible(false); + } else { + table.setVisible(false); + pauseTable.setVisible(true); + pause(); + } + } + } + + /** + * Updates the state of each object with delta time + * + * @param dt Delta time (elapsed time since last game tick) + */ + public void update(float dt) { + stateTime += dt; + handleInput(dt); + // Stepping the physics engine by time of 1 frame + world.step(1 / 60f, 6, 2); + + // Update all players and entities + player.update(dt); + + for (CollegeMetadata college : CollegeMetadata.values()) { + getCollege(college).update(dt); + } + + // space bar removes tutorial screen + if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE)) { + tutorialTexture.dispose(); + } + + // centers tutorial screen + tutorials.setPosition(camera.position.x - (tutorials.getWidth() / 2), camera.position.y - (tutorials.getHeight() / 2)); + // scales the sprite depending on window size divided by a constant + tutorials.setSize(camera.viewportWidth / 100f, camera.viewportHeight / 100f); + + //Update ships + for (int i = 0; i < ships.size(); i++) { + ships.get(i).update(dt); + } + + //Updates coin + for (int i = 0; i < Coins.size(); i++) { + Coins.get(i).update(); + } + //Updates powerups + for (int i = 0; i < PowerUps.size(); i++) { + PowerUps.get(i).update(); + } + //After a delay check if a college is destroyed. If not, if can fire + if (stateTime > 1) { + for (CollegeMetadata college : CollegeMetadata.values()) { + if (!college.isPlayer() && !getCollege(college).destroyed) { + getCollege(college).fire(); + } + } + stateTime = 0; + } + + hud.update(dt); + + // Centre camera on player boat + camera.position.x = player.b2body.getPosition().x; + camera.position.y = player.b2body.getPosition().y; + camera.update(); + renderer.setView(camera); + } + + /** + * Renders the visual data for all objects + * Changes and renders new visual data for ships + * + * @param dt Delta time (elapsed time since last game tick) + */ + @Override + public void render(float dt) { + if (gameStatus == GAME_RUNNING) { + update(dt); + } else { + handleInput(dt); + } + + Gdx.gl.glClearColor(46 / 255f, 204 / 255f, 113 / 255f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + renderer.render(); + // b2dr is the hitbox shapes, can be commented out to hide + //b2dr.render(world, camera.combined); + + game.batch.setProjectionMatrix(camera.combined); + game.batch.begin(); + // Order determines layering + + //Renders coins + for (int i = 0; i < Coins.size(); i++) { + Coins.get(i).draw(game.batch); + } + + //Renders powerups + for (int i = 0; i < PowerUps.size(); i++) { + PowerUps.get(i).draw(game.batch); + } + + //Renders colleges + player.draw(game.batch); + for (Map.Entry college : colleges.entrySet()) { + college.getValue().draw(game.batch); + } + + //Updates all ships + for (int i = 0; i < ships.size(); i++) { + // if the ship is in a college + if (ships.get(i).collegeMeta != null) { + //Flips a colleges allegiance if their college is destroyed + if (getCollege(ships.get(i).collegeMeta).destroyed) { + + ships.get(i).updateTexture(0, "college/Ships/alcuin_ship.png"); + } + } + ships.get(i).draw(game.batch); + } + + // show tutorial screen + tutorials.draw(game.batch); + + game.batch.end(); + Hud.stage.draw(); + stage.act(); + stage.draw(); + //Checks game over conditions + gameOverCheck(); + + } + + /** + * Changes the camera size, Scales the hud to match the camera + * + * @param width the width of the viewable area + * @param height the height of the viewable area + */ + @Override + public void resize(int width, int height) { + viewport.update(width, height); + stage.getViewport().update(width, height, true); + Hud.resize(width, height); + camera.update(); + renderer.setView(camera); + } + + /** + * Returns the map + * + * @return map : returns the world map + */ + public TiledMap getMap() { + return map; + } + + /** + * @return The tile map width in in-game pixels + */ + public int getTileMapWidth() { + MapProperties prop = getMap().getProperties(); + int mapWidth = prop.get("width", Integer.class); + int tilePixelWidth = prop.get("tilewidth", Integer.class); + + return mapWidth * tilePixelWidth; + } + + /** + * @return the width of a single tile on the tilemap + */ + public int getTileWidth() { + MapProperties prop = getMap().getProperties(); + int tilePixelWidth = prop.get("tilewidth", Integer.class); + + return tilePixelWidth; + } + + /** + * @return The tile map height in in-game pixels + */ + public int getTileMapHeight() { + MapProperties prop = getMap().getProperties(); + int mapHeight = prop.get("height", Integer.class); + int tilePixelHeight = prop.get("tileheight", Integer.class); + + return mapHeight * tilePixelHeight; + } + + /** + * Returns the world (map and objects) + * + * @return world : returns the world + */ + public World getWorld() { + return world; + } + + /** + * Returns the college from the colleges hashmap + * + * @param collegeID uses a collegeID as an index + * @return college : returns the college fetched from colleges + * @deprecated use CollegeMetadata instead of collegeID + */ + @Deprecated + public College getCollege(Integer collegeID) { + return getCollege(CollegeMetadata.getCollegeMetaFromId(collegeID)); + } + + /** + * Returns the college from the colleges hashmap + * + * @param college uses the collegeMetadata to find the college + * @return returns the college fetched from colleges + */ + public College getCollege(CollegeMetadata college) { + return colleges.get(college); + } + + /** + * When called, finds the next college that the player can attack + */ + public void nextCollege() { + // Selects, at random, an index from length of collegeLeft list + Integer collegeIndex = collegeRand.nextInt(collegesLeft.size()); + // Gets the collegeID from the collegeLeft list + attackingCollege = collegesLeft.get(collegeIndex); + // Removes the college selected from the collegeLeft list + collegesLeft.remove(collegeIndex); + } + + /** + * Returns the college which can currently be attacked + * + * @return integer : returns CollegeID + */ + public Integer getAttackingCollege() { + return attackingCollege; + } + + /** + * Checks if the game is over + * i.e. goal reached (all colleges bar 0 are destroyed) + */ + public void gameOverCheck() { + //Lose game if ship on 0 health or Alcuin is destroyed + if (Hud.getHealth() <= 0 || getCollege(CollegeMetadata.ALCUIN).destroyed) { + game.changeScreen(PirateGame.DEATH); + game.killGame(); + } + //Win game if all colleges destroyed + else if (getCollege(CollegeMetadata.ANNELISTER).destroyed && getCollege(CollegeMetadata.CONSTANTINE).destroyed && getCollege(CollegeMetadata.GOODRICKE).destroyed) { + game.changeScreen(PirateGame.VICTORY); + game.killGame(); + } + } + + /** + * Fetches the player's current position + * + * @return position vector : returns the position of the player + */ + public Vector2 getPlayerPos() { + return new Vector2(player.b2body.getPosition().x, player.b2body.getPosition().y); + } + + /** + * Calculates the players position centered in the middle of the player + * + * @return The centered position of the player + */ + public Vector2 getCenteredPlayerPos() { + return getPlayerPos().add(player.getWidth(), player.getHeight()); + } + + /** + * Updates acceleration by a given percentage. Accessed by skill tree and power ups + * + * @param percentage percentage increase + */ + public static void changeAcceleration(Float percentage) { + accel = accel * (1 + (percentage / 100)); + } + + /** + * Sets acceleration to a given value + * + * @param value new acceleration value + */ + public static void setAcceleration(Float value) { + accel = value; + } + + /** + * Updates max speed by a given percentage. Accessed by skill tree + * + * @param percentage percentage increase + */ + public static void changeMaxSpeed(Float percentage) { + maxSpeed = maxSpeed * (1 + (percentage / 100)); + } + + /** + * Sets max speed to a given value + * + * @param value new max speed value + */ + public static void setMaxSpeed(Float value) { + maxSpeed = value; + } + + /** + * Resets game values to default, used on game restart + */ + public static void resetValues() { + setMaxSpeed(4f); + setAcceleration(0.1f); + setShootingDelay(1f); + } + + /** + * Fetches the current shooting delay + * + * @return shooting delay : returns the current shooting delay value + */ + public static float getShootingDelay() { + return shootingDelay; + } + + /** + * Sets shooting delay to a given value + * + * @param value new shooting delay value + */ + public static void setShootingDelay(Float value) { + shootingDelay = value; + } + + /** + * Updates shooting delay by a given percentage. Accessed by power ups + * + * @param percentage percentage decrease + */ + public static void changeShootingDelay(Float percentage) { + shootingDelay = shootingDelay * (1 - (percentage / 100)); + } + + /** + * Changes the amount of damage done by each hit. Accessed by skill tree + * + * @param value damage dealt + */ + public static void changeDamage(int value) { + + for (int i = 0; i < ships.size(); i++) { + ships.get(i).changeDamageReceived(value); + } + + for(Map.Entry college : colleges.entrySet()){ + college.getValue().changeDamageReceived(value); + } + + } + + /** + * Tests validity of randomly generated position + * + * @param x random x value + * @param y random y value + */ + private Boolean checkGenPos(int x, int y) { + if (invalidSpawn.tileBlocked.containsKey(x)) { + ArrayList yTest = invalidSpawn.tileBlocked.get(x); + return !yTest.contains(y); + } + return true; + } + + /** + * Pauses game + */ + @Override + public void pause() { + gameStatus = GAME_PAUSED; + } + + /** + * Resumes game + */ + @Override + public void resume() { + gameStatus = GAME_RUNNING; + } + + /** + * (Not Used) + * Hides game + */ + @Override + public void hide() { + + } + + /** + * Disposes game data + */ + @Override + public void dispose() { + map.dispose(); + renderer.dispose(); + world.dispose(); + b2dr.dispose(); + hud.dispose(); + stage.dispose(); + } + + + public OrthogonalTiledMapRenderer getRenderer() { + return renderer; + } + + public float getUnitScale() { + return 1 / PirateGame.PPM; + } + + public PathFinder getPathFinder() { + return pathFinder; + } + + public AvailableSpawn getInvalidSpawn() { + return invalidSpawn; + } + + public HashMap getColleges() { + return colleges; + + } +} diff --git a/core/src/com/mygdx/pirategame/Help.java b/core/src/main/java/com/mygdx/pirategame/screen/HelpScreen.java similarity index 95% rename from core/src/com/mygdx/pirategame/Help.java rename to core/src/main/java/com/mygdx/pirategame/screen/HelpScreen.java index 9a77b61a..10f847be 100644 --- a/core/src/com/mygdx/pirategame/Help.java +++ b/core/src/main/java/com/mygdx/pirategame/screen/HelpScreen.java @@ -1,4 +1,4 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; @@ -13,15 +13,14 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.mygdx.pirategame.PirateGame; -import java.util.ArrayList; -import java.util.List; /** * Screen with instructions for the user * @author Sam Pearson * @version 1.0 */ -public class Help implements Screen { +public class HelpScreen implements Screen { private final PirateGame parent; private final Stage stage; @@ -30,7 +29,7 @@ public class Help implements Screen { * * @param pirateGame Game data */ - public Help(PirateGame pirateGame){ + public HelpScreen(PirateGame pirateGame){ parent = pirateGame; stage = new Stage(new ScreenViewport()); } @@ -53,7 +52,7 @@ public void show() { stage.addActor(Other); //The skin for the actors - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); //Text Label Controls1 = new Label("WASD to move", new Label.LabelStyle(new BitmapFont(), Color.WHITE)); diff --git a/core/src/com/mygdx/pirategame/MainMenu.java b/core/src/main/java/com/mygdx/pirategame/screen/MainMenu.java similarity index 82% rename from core/src/com/mygdx/pirategame/MainMenu.java rename to core/src/main/java/com/mygdx/pirategame/screen/MainMenu.java index 4d45db78..9461b1ab 100644 --- a/core/src/com/mygdx/pirategame/MainMenu.java +++ b/core/src/main/java/com/mygdx/pirategame/screen/MainMenu.java @@ -1,15 +1,19 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; -import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.badlogic.gdx.utils.Scaling; +import com.mygdx.pirategame.PirateGame; /** * Main menu is the first screen the player sees. Allows them to navigate where they want to go to @@ -20,6 +24,8 @@ public class MainMenu implements Screen { private final PirateGame parent; private final Stage stage; + private Texture backgroundTexture; + private Image backgroundImage; /** * Instantiates a new Main menu. @@ -37,6 +43,12 @@ public MainMenu(PirateGame PirateGame){ */ @Override public void show() { + backgroundTexture = new Texture("map_blurred.png"); + + backgroundImage = new Image(backgroundTexture); + backgroundImage.setScaling(Scaling.stretch); + stage.addActor(backgroundImage); + //Set the input processor Gdx.input.setInputProcessor(stage); // Create a table for the buttons @@ -45,7 +57,7 @@ public void show() { stage.addActor(table); //The skin for the actors - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); //create buttons TextButton newGame = new TextButton("New Game", skin); @@ -83,7 +95,7 @@ public void changed(ChangeEvent event, Actor actor){ options.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor){ - parent.setScreen(new Options(parent,parent.getScreen())); + parent.setScreen(new OptionsScreen(parent,parent.getScreen())); } }); @@ -103,9 +115,8 @@ public void changed(ChangeEvent event, Actor actor) { */ @Override public void render(float delta) { - Gdx.gl.glClearColor(0f, 0f, 0f, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f)); + backgroundImage.setSize(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); stage.draw(); } @@ -150,6 +161,7 @@ public void hide() { @Override public void dispose() { stage.dispose(); + backgroundTexture.dispose(); } } diff --git a/core/src/com/mygdx/pirategame/Options.java b/core/src/main/java/com/mygdx/pirategame/screen/OptionsScreen.java similarity index 95% rename from core/src/com/mygdx/pirategame/Options.java rename to core/src/main/java/com/mygdx/pirategame/screen/OptionsScreen.java index 8d1c7023..5aee0f96 100644 --- a/core/src/com/mygdx/pirategame/Options.java +++ b/core/src/main/java/com/mygdx/pirategame/screen/OptionsScreen.java @@ -1,4 +1,4 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; @@ -10,15 +10,16 @@ import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.mygdx.pirategame.PirateGame; /** * Provides a UI for the user to interact with the audioControls interface * @author Sam Pearson * @version 1.0 */ -public class Options implements Screen { +public class OptionsScreen implements Screen { - private final PirateGame PirateGame; + private final com.mygdx.pirategame.PirateGame PirateGame; private final Screen parent; private final Stage stage; @@ -28,7 +29,7 @@ public class Options implements Screen { * @param pirateGame the main starting body of the game. Where screen swapping is carried out. * @param parent the screen that called the options screen. Allows for easy return */ - public Options(PirateGame pirateGame, Screen parent){ + public OptionsScreen(PirateGame pirateGame, Screen parent){ this.PirateGame = pirateGame; this.parent = parent; stage = new Stage(new ScreenViewport()); @@ -49,7 +50,7 @@ public void show() { stage.addActor(table); //The skin for the actors - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); //Music Sliders and Check boxes final Slider volumeMusicSlider = new Slider( 0f, 1f, 0.1f,false, skin ); diff --git a/core/src/com/mygdx/pirategame/SkillTree.java b/core/src/main/java/com/mygdx/pirategame/screen/SkillTreeScreen.java similarity index 95% rename from core/src/com/mygdx/pirategame/SkillTree.java rename to core/src/main/java/com/mygdx/pirategame/screen/SkillTreeScreen.java index 67d1ffc7..dde8dd8b 100644 --- a/core/src/com/mygdx/pirategame/SkillTree.java +++ b/core/src/main/java/com/mygdx/pirategame/screen/SkillTreeScreen.java @@ -1,4 +1,4 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; @@ -9,8 +9,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; + import java.util.ArrayList; import java.util.List; @@ -22,7 +25,7 @@ * @author Sam Pearson * @version 1.0 */ -public class SkillTree implements Screen { +public class SkillTreeScreen implements Screen { private final PirateGame parent; private final Stage stage; @@ -41,7 +44,7 @@ public class SkillTree implements Screen { * @param pirateGame the main starting body of the game. Where screen swapping is carried out. */ //In the constructor, the parent and stage are set. Also the states list is set - public SkillTree(PirateGame pirateGame){ + public SkillTreeScreen(PirateGame pirateGame){ parent = pirateGame; stage = new Stage(new ScreenViewport()); @@ -72,7 +75,7 @@ public void show() { //The skin for the actors - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); //create skill tree buttons movement1 = new TextButton("Movement Speed + 20%", skin); diff --git a/core/src/com/mygdx/pirategame/VictoryScreen.java b/core/src/main/java/com/mygdx/pirategame/screen/VictoryScreen.java similarity index 96% rename from core/src/com/mygdx/pirategame/VictoryScreen.java rename to core/src/main/java/com/mygdx/pirategame/screen/VictoryScreen.java index b396918e..f91c5a1c 100644 --- a/core/src/com/mygdx/pirategame/VictoryScreen.java +++ b/core/src/main/java/com/mygdx/pirategame/screen/VictoryScreen.java @@ -1,4 +1,4 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.screen; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; @@ -13,6 +13,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.mygdx.pirategame.PirateGame; /** * The type for the victory screen @@ -42,7 +43,7 @@ public VictoryScreen(PirateGame pirateGame) { @Override public void show() { //Creates the skin for the buttons and labels to use - Skin skin = new Skin(Gdx.files.internal("skin\\uiskin.json")); + Skin skin = new Skin(Gdx.files.internal("skin/uiskin.json")); //Sets stage to be the input processor Gdx.input.setInputProcessor(stage); diff --git a/core/src/com/mygdx/pirategame/AvailableSpawn.java b/core/src/main/java/com/mygdx/pirategame/world/AvailableSpawn.java similarity index 98% rename from core/src/com/mygdx/pirategame/AvailableSpawn.java rename to core/src/main/java/com/mygdx/pirategame/world/AvailableSpawn.java index 3e036d5c..434d4eb9 100644 --- a/core/src/com/mygdx/pirategame/AvailableSpawn.java +++ b/core/src/main/java/com/mygdx/pirategame/world/AvailableSpawn.java @@ -1,4 +1,4 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.world; import java.util.ArrayList; import java.util.HashMap; diff --git a/core/src/com/mygdx/pirategame/WorldContactListener.java b/core/src/main/java/com/mygdx/pirategame/world/WorldContactListener.java similarity index 61% rename from core/src/com/mygdx/pirategame/WorldContactListener.java rename to core/src/main/java/com/mygdx/pirategame/world/WorldContactListener.java index a4d5d05d..c16b2c89 100644 --- a/core/src/com/mygdx/pirategame/WorldContactListener.java +++ b/core/src/main/java/com/mygdx/pirategame/world/WorldContactListener.java @@ -1,7 +1,16 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.world; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.physics.box2d.*; +import com.mygdx.pirategame.Hud; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.gameobjects.CannonFire; +import com.mygdx.pirategame.gameobjects.CollegeFire; +import com.mygdx.pirategame.gameobjects.Player; +import com.mygdx.pirategame.gameobjects.enemy.Enemy; +import com.mygdx.pirategame.gameobjects.entity.Entity; +import com.mygdx.pirategame.gameobjects.tileobject.InteractiveTileObject; + /** * Tells the game what to do when certain entities come into contact with each other @@ -13,20 +22,53 @@ public class WorldContactListener implements ContactListener { /** * The start of the collision. Tells the game what should happen when the contact begins + * * @param contact The object that contains information about the collision */ @Override public void beginContact(Contact contact) { - // Finds contact + // Finds contact, fixA and fixB are the two entities causing collision Fixture fixA = contact.getFixtureA(); Fixture fixB = contact.getFixtureB(); int cDef = fixA.getFilterData().categoryBits | fixB.getFilterData().categoryBits; // Fixes contact to an entity - switch (cDef){ + switch (cDef) { case PirateGame.COIN_BIT | PirateGame.PLAYER_BIT: - if(fixA.getFilterData().categoryBits == PirateGame.COIN_BIT) { + if (fixA.getFilterData().categoryBits == PirateGame.COIN_BIT) { + ((Entity) fixA.getUserData()).entityContact(); + } else { + ((Entity) fixB.getUserData()).entityContact(); + } + break; + // TODO: ABSORPTION_HEART_BIT collides twice ?????? + case PirateGame.ABSORPTION_HEART_BIT | PirateGame.PLAYER_BIT: + if(fixA.getFilterData().categoryBits == PirateGame.ABSORPTION_HEART_BIT) { + ((Entity) fixA.getUserData()).entityContact(); + } + else { + ((Entity) fixB.getUserData()).entityContact(); + } + break; + case PirateGame.SPEED_BOOST_BIT | PirateGame.PLAYER_BIT: + if(fixA.getFilterData().categoryBits == PirateGame.SPEED_BOOST_BIT) { + ((Entity) fixA.getUserData()).entityContact(); + } + else { + ((Entity) fixB.getUserData()).entityContact(); + } + break; + case PirateGame.FASTER_SHOOTING_BIT | PirateGame.PLAYER_BIT: + if(fixA.getFilterData().categoryBits == PirateGame.FASTER_SHOOTING_BIT) { + ((Entity) fixA.getUserData()).entityContact(); + } + else { + ((Entity) fixB.getUserData()).entityContact(); + } + break; + case PirateGame.COIN_MAGNET_BIT | PirateGame.PLAYER_BIT: + if(fixA.getFilterData().categoryBits == PirateGame.COIN_MAGNET_BIT) { ((Entity) fixA.getUserData()).entityContact(); } else { @@ -34,34 +76,31 @@ public void beginContact(Contact contact) { } break; case PirateGame.DEFAULT_BIT | PirateGame.PLAYER_BIT: - if(fixA.getFilterData().categoryBits == PirateGame.DEFAULT_BIT) { + if (fixA.getFilterData().categoryBits == PirateGame.DEFAULT_BIT) { if (fixA.getUserData() != null && InteractiveTileObject.class.isAssignableFrom(fixA.getUserData().getClass())) { ((InteractiveTileObject) fixA.getUserData()).onContact(); ((Player) fixB.getUserData()).playBreakSound(); } - } - else { + } else { if (fixB.getUserData() != null && InteractiveTileObject.class.isAssignableFrom(fixB.getUserData().getClass())) { ((InteractiveTileObject) fixB.getUserData()).onContact(); } } break; case PirateGame.ENEMY_BIT | PirateGame.PLAYER_BIT: - if(fixA.getFilterData().categoryBits == PirateGame.ENEMY_BIT) { + if (fixA.getFilterData().categoryBits == PirateGame.ENEMY_BIT) { ((Enemy) fixA.getUserData()).onContact(); - } - else { + } else { ((Enemy) fixB.getUserData()).onContact(); } break; case PirateGame.COLLEGE_BIT | PirateGame.CANNON_BIT: - if(fixA.getFilterData().categoryBits == PirateGame.COLLEGE_BIT) { + if (fixA.getFilterData().categoryBits == PirateGame.COLLEGE_BIT) { if (fixA.getUserData() != null && InteractiveTileObject.class.isAssignableFrom(fixA.getUserData().getClass())) { ((InteractiveTileObject) fixA.getUserData()).onContact(); ((CannonFire) fixB.getUserData()).setToDestroy(); } - } - else { + } else { if (fixB.getUserData() != null && InteractiveTileObject.class.isAssignableFrom(fixB.getUserData().getClass())) { ((InteractiveTileObject) fixB.getUserData()).onContact(); ((CannonFire) fixA.getUserData()).setToDestroy(); @@ -69,42 +108,51 @@ public void beginContact(Contact contact) { } break; case PirateGame.ENEMY_BIT | PirateGame.CANNON_BIT: - if(fixA.getFilterData().categoryBits == PirateGame.ENEMY_BIT) { + if (fixA.getFilterData().categoryBits == PirateGame.ENEMY_BIT) { ((Enemy) fixA.getUserData()).onContact(); ((CannonFire) fixB.getUserData()).setToDestroy(); - } - else { + } else { ((Enemy) fixB.getUserData()).onContact(); ((CannonFire) fixA.getUserData()).setToDestroy(); } break; - case PirateGame.COLLEGEFIRE_BIT | PirateGame.PLAYER_BIT: - if(fixA.getFilterData().categoryBits == PirateGame.COLLEGEFIRE_BIT) { + // Player collision with college cannonball + case PirateGame.COLLEGE_FIRE_BIT | PirateGame.PLAYER_BIT: + if (fixA.getFilterData().categoryBits == PirateGame.COLLEGE_FIRE_BIT) { Hud.changeHealth(-15); ((CollegeFire) fixA.getUserData()).setToDestroy(); - } - else { + } else { Hud.changeHealth(-15); ((CollegeFire) fixB.getUserData()).setToDestroy(); + ((Player) fixA.getUserData()).playCannonballHitSound(); + } break; + // enemy collides with enemy + case PirateGame.ENEMY_BIT | PirateGame.ENEMY_BIT: + // notifying a single ship so it can pause + ((Enemy) fixB.getUserData()).onEnemyShipContact(); + break; + } } /** * Run when contact is ended. Nearly empty since nothing special needs to happen when a contact is ended + * * @param contact The object that contains information about the collision */ @Override public void endContact(Contact contact) { // Displays contact message - Gdx.app.log("End Contact", ""); + //Gdx.app.log("End Contact", ""); } /** * (Not Used) * Can be called before beginContact to pre emptively solve it - * @param contact The object that contains information about the collision + * + * @param contact The object that contains information about the collision * @param oldManifold Predicted impulse based on old data */ @Override @@ -115,6 +163,7 @@ public void preSolve(Contact contact, Manifold oldManifold) { /** * (Not Used) * Can be called before beginContact to post emptively solve it + * * @param contact The object that contains information about the collision * @param impulse The signal recieved */ diff --git a/core/src/com/mygdx/pirategame/WorldCreator.java b/core/src/main/java/com/mygdx/pirategame/world/WorldCreator.java similarity index 92% rename from core/src/com/mygdx/pirategame/WorldCreator.java rename to core/src/main/java/com/mygdx/pirategame/world/WorldCreator.java index 3cdf0c69..4a2e3ead 100644 --- a/core/src/com/mygdx/pirategame/WorldCreator.java +++ b/core/src/main/java/com/mygdx/pirategame/world/WorldCreator.java @@ -1,10 +1,11 @@ -package com.mygdx.pirategame; +package com.mygdx.pirategame.world; import com.badlogic.gdx.maps.MapObject; import com.badlogic.gdx.maps.objects.RectangleMapObject; import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.math.Rectangle; -import com.badlogic.gdx.physics.box2d.*; +import com.mygdx.pirategame.gameobjects.tileobject.*; +import com.mygdx.pirategame.screen.GameScreen; /** * This is the class where all boundaries and collisions are created for the map. @@ -35,7 +36,7 @@ public WorldCreator(GameScreen screen) { Rectangle rect = ((RectangleMapObject) object).getRectangle(); new CollegeWalls2(screen, rect); - } + } for(MapObject object : map.getLayers().get(7).getObjects().getByType(RectangleMapObject.class)) { Rectangle rect = ((RectangleMapObject) object).getRectangle(); diff --git a/core/src/test/java/com/mygdx/pirategame/PirateGameTest.java b/core/src/test/java/com/mygdx/pirategame/PirateGameTest.java new file mode 100644 index 00000000..289b3b7d --- /dev/null +++ b/core/src/test/java/com/mygdx/pirategame/PirateGameTest.java @@ -0,0 +1,99 @@ +package com.mygdx.pirategame; + +import com.badlogic.gdx.ApplicationListener; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.backends.headless.HeadlessApplicationConfiguration; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; + +import java.util.HashMap; +import java.util.Map; + +public class PirateGameTest extends BlockJUnit4ClassRunner implements ApplicationListener { + + private final Map test_instance = new HashMap(); + + /** + * @param klass refers to the class of the test being tested if @RunWith is used + * + * @throws InitializationError if the file isn't able to run + */ + public PirateGameTest(Class klass) throws InitializationError { + super(klass); + + /* + * this refers to the test + * conf defines how many updates per second (60 by default) + * and the maximum number of threads for requests + */ + HeadlessApplicationConfiguration conf = new HeadlessApplicationConfiguration(); + new HeadlessApplication(this, conf); + } + + @Override + public void create() { + + } + + @Override + public void resize(int width, int height) { + + } + + + @Override + public void render() { + /* + * Runs the function runChild for each test + * val.getKey() represents the specific test + * val.getValue() represents whether the specific test has passed or not + */ + for (Map.Entry val : test_instance.entrySet()) { + super.runChild(val.getKey(), val.getValue()); + } + // Clears the HashMap + test_instance.clear(); + } + + @Override + public void pause() { + + } + + @Override + public void resume() { + + } + + @Override + public void dispose() { + + } + + /** + * @param method refers to the test + * @param notifier refers to whether it passes the tests or not + */ + @Override + protected void runChild(FrameworkMethod method, RunNotifier notifier) { + + /* + * the synchronized function prevents thread interference + * Adds every instance being tested to the HashMap + */ + synchronized(test_instance){ + test_instance.put(method, notifier); + } + + //wait until that test is invoked and continues only if the execution was successful + try { + Thread.sleep(100); + } catch(InterruptedException e) { + e.printStackTrace(); + } + + } + +} \ No newline at end of file diff --git a/core/src/test/java/com/mygdx/pirategame/tests/PirateGameTestScaling.java b/core/src/test/java/com/mygdx/pirategame/tests/PirateGameTestScaling.java new file mode 100644 index 00000000..13522c38 --- /dev/null +++ b/core/src/test/java/com/mygdx/pirategame/tests/PirateGameTestScaling.java @@ -0,0 +1,58 @@ +package com.mygdx.pirategame.tests; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Graphics; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.math.Vector2; +import com.mygdx.pirategame.PirateGame; +import com.mygdx.pirategame.PirateGameTest; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +/** + * This class is used to target the class pirategame with scaling tests + */ +@RunWith(PirateGameTest.class) +public class PirateGameTestScaling { + + /** + * Setting up before running this test class + */ + @BeforeClass + public static void init() { + // Use Mockito to mock the OpenGL methods since we are running headlessly + Gdx.gl20 = Mockito.mock(GL20.class); + Gdx.gl = Gdx.gl20; + + // Mock the graphics class. + Gdx.graphics = Mockito.mock(Graphics.class); + when(Gdx.graphics.getWidth()).thenReturn(500); + when(Gdx.graphics.getHeight()).thenReturn(500); + } + + /** + * Used to test if the pirategame.getScaledLocaiton provides correct results + */ + @Test + public void testScaling() { + + OrthographicCamera camera = new OrthographicCamera(); + camera.viewportWidth = 500; + camera.viewportHeight = 500; + + // checking on static location + assertEquals(PirateGame.getScaledLocation(new Vector2(50.1f, 50.1f), camera), new Vector2(50.1f, 50.1f)); + + camera.viewportWidth = 100; + camera.viewportHeight = 100; + // checking when scaling is required + assertEquals(PirateGame.getScaledLocation(new Vector2(50, 50), camera), new Vector2(10, 10)); + } + +} \ No newline at end of file diff --git a/core/src/test/java/com/mygdx/pirategame/tests/fileExistance.java b/core/src/test/java/com/mygdx/pirategame/tests/fileExistance.java new file mode 100644 index 00000000..fc9ced6c --- /dev/null +++ b/core/src/test/java/com/mygdx/pirategame/tests/fileExistance.java @@ -0,0 +1,476 @@ +package com.mygdx.pirategame.tests; + +import com.badlogic.gdx.Gdx; +import com.mygdx.pirategame.PirateGameTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertTrue; + +/** + * This class is used to target the class pirategame with file assertion tests + */ +@RunWith(PirateGameTest.class) +public class fileExistance { + + /** + * mapbase.txt is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void mapbasetxt() { + assertTrue("This test will pass if mapbase.txt exists", Gdx.files + .internal("../core/assets/mapBase.txt").exists()); + } + + /** + * map_blurred.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void map_blurred() { + assertTrue("This test will pass if map_blurred.png exists", Gdx.files + .internal("../core/assets/map_blurred.png").exists()); + } + + /** + * hudBG.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void hudBG() { + assertTrue("This test will pass if hudBG.png exists", Gdx.files + .internal("../core/assets/hudBG.png").exists()); + } + + /** + * mapbase.txt is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void hp() { + assertTrue("This test will pass if hp.png exists", Gdx.files + .internal("../core/assets/hp.png").exists()); + } + + /** + * HealthBar.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void HealthBar() { + assertTrue("This test will pass if mapbase.txt exists", Gdx.files + .internal("../core/assets/HealthBar.png").exists()); + } + + /** + * default.fnt is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void defaultfnt() { + assertTrue("This test will pass if default.fnt exists", Gdx.files + .internal("../core/assets/default.fnt").exists()); + } + + /** + * coin.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void coin() { + assertTrue("This test will pass if coin.png exists", Gdx.files + .internal("../core/assets/coin.png").exists()); + } + + /** + * cannonBall.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void cannonBall() { + assertTrue("This test will pass if cannonBall.png exists", Gdx.files + .internal("../core/assets/cannonBall.png").exists()); + } + + //assets in /skin/ + + /** + * skin/default.fnt is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void skindefault() { + assertTrue("This test will pass if skin/default.fnt exists", Gdx.files + .internal("../core/assets/skin/default.fnt").exists()); + } + + /** + * skin/uiskin.atlas is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void skinuiskinatlas() { + assertTrue("This test will pass if skin/uiskin.atlas exists", Gdx.files + .internal("../core/assets/skin/uiskin.atlas").exists()); + } + + /** + * skin/uiskin.json is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void skinuiskinjson() { + assertTrue("This test will pass if skin/uiskin.json exists", Gdx.files + .internal("../core/assets/skin/uiskin.json").exists()); + } + + /** + * skin/uiskin.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void skinuiskinpng() { + assertTrue("This test will pass if skin/uiskin.png exists", Gdx.files + .internal("../core/assets/skin/uiskin.png").exists()); + } + + //assets in sfx_and_music + + /** + * sfx_and_music/coin-pickup.mp3 is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void coinpickup() { + assertTrue("This test will pass if /sfx_and_music/coin-pickup.mp3 exists", Gdx.files + .internal("../core/assets/sfx_and_music/coin-pickup.mp3").exists()); + } + + /** + * sfx_and_music/explode.mp3 is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void explodemp3() { + assertTrue("This test will pass if /sfx_and_music/explode.mp3 exists", Gdx.files + .internal("../core/assets/sfx_and_music/explode.mp3").exists()); + } + + /** + * sfx_and_music/explosion.wav is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void explodewav() { + assertTrue("This test will pass /sfx_and_music/explosion.wav exists", Gdx.files + .internal("../core/assets/sfx_and_music/explosion.wav").exists()); + } + + /** + * sfx_and_music/pirate-music.mp3 is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void piratemusicmp3() { + assertTrue("This test will pass /sfx_and_music/pirate-music.mp3", Gdx.files + .internal("../core/assets/sfx_and_music/pirate-music.mp3").exists()); + } + + /** + * sfx_and_music/ship-explosion-2.wav is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void shipexplosion2wav() { + assertTrue("This test will pass /sfx_and_music/ship-explosion-2.wav", Gdx.files + .internal("../core/assets/sfx_and_music/ship-explosion-2.wav").exists()); + } + + /** + * sfx_and_music/ship-hit.wav is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void shiphit() { + assertTrue("This test will pass /sfx_and_music/ship-hit.wav", Gdx.files + .internal("../core/assets/sfx_and_music/ship-hit.wav").exists()); + } + + /** + * sfx_and_music/wood-bump.mp3 is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void woodbumpmp3() { + assertTrue("This test will pass /sfx_and_music/wood-bump.mp3", Gdx.files + .internal("../core/assets/sfx_and_music/wood-bump.mp3").exists()); + } + + //Map rendering + + /** + * Will check that every asset for the map renders properly + * Note: for loop used up to 88 but since tiles 89, 90, 91 and 92 don't exist originally, + * the specific tiles after that are tested + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void maprender() { + assertTrue("This test will pass /map/islands.tsx", Gdx.files + .internal("../core/assets/map/islands.tsx").exists()); + assertTrue("This test will pass /map/map.tmx", Gdx.files + .internal("../core/assets/map/map.tmx").exists()); + assertTrue("This test will pass /map/rocks.tsx", Gdx.files + .internal("../core/assets/map/rocks.tsx").exists()); + assertTrue("This test will pass /map/water.tsx", Gdx.files + .internal("../core/assets/map/water.tsx").exists()); + for (int i=1; i<=88; i++) { + if (Integer.toString(i).length() == 1) { + assertTrue("This test will pass /map/tile_0" + i + ".png", Gdx.files + .internal("../core/assets/map/tile_0" + i + ".png").exists()); + } else { + assertTrue("This test will pass /map/tile_" + i + ".png", Gdx.files + .internal("../core/assets/map/tile_" + i + ".png").exists()); + } + } + assertTrue("This test will pass /map/tile_93.png", Gdx.files + .internal("../core/assets/map/tile_93.png").exists()); + assertTrue("This test will pass /map/tile_94.png", Gdx.files + .internal("../core/assets/map/tile_94.png").exists()); + } + + //assets in /college/ + + //assets in /college/Flags + /** + * college/Flags/alcuin_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void alcuinflag() { + assertTrue("This test will pass /college/Flags/alcuin_flag.png", Gdx.files + .internal("../core/assets/college/Flags/alcuin_flag.png").exists()); + } + + /** + * college/Flags/anne_lister_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void annelisterflag() { + assertTrue("This test will pass /college/Flags/anne_lister_flag.png", Gdx.files + .internal("../core/assets/college/Flags/anne_lister_flag.png").exists()); + } + + /** + * college/Flags/constantine_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void constantineflag() { + assertTrue("This test will pass /college/Flags/constantine_flag.png", Gdx.files + .internal("../core/assets/college/Flags/constantine_flag.png").exists()); + } + + /** + * college/Flags/derwent_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void derwentflag() { + assertTrue("This test will pass /college/Flags/derwent_flag.png", Gdx.files + .internal("../core/assets/college/Flags/derwent_flag.png").exists()); + } + + /** + * college/Flags/goodricke_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void goodrickeflag() { + assertTrue("This test will pass /college/Flags/goodricke_flag.png", Gdx.files + .internal("../core/assets/college/Flags/goodricke_flag.png").exists()); + } + + /** + * college/Flags/halifax_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void halifaxflag() { + assertTrue("This test will pass /college/Flags/halifax_flag.png", Gdx.files + .internal("../core/assets/college/Flags/halifax_flag.png").exists()); + } + + /** + * college/Flags/james_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void jamesflag() { + assertTrue("This test will pass /college/Flags/james_flag.png", Gdx.files + .internal("../core/assets/college/Flags/james_flag.png").exists()); + } + + /** + * college/Flags/langwith_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void langwithflag() { + assertTrue("This test will pass /college/Flags/langwith_flag.png", Gdx.files + .internal("../core/assets/college/Flags/langwith_flag.png").exists()); + } + + /** + * college/Flags/vanbrugh_flag.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void vanbrughflag() { + assertTrue("This test will pass /college/Flags/vanbrugh_flag.png", Gdx.files + .internal("../core/assets/college/Flags/vanbrugh_flag.png").exists()); + } + + //assets in /college/Ships + + /** + * college/Ships/alcuin_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void alcuinship() { + assertTrue("This test will pass /college/Ships/alcuin_ship.png", Gdx.files + .internal("../core/assets/college/Ships/alcuin_ship.png").exists()); + } + + /** + * college/Ships/anne_lister_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void annelistership() { + assertTrue("This test will pass /college/Ships/anne_lister_ship.png", Gdx.files + .internal("../core/assets/college/Ships/anne_lister_ship.png").exists()); + } + + /** + * college/Ships/constantine_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void constantineship() { + assertTrue("This test will pass /college/Ships/constantine_ship.png", Gdx.files + .internal("../core/assets/college/Ships/constantine_ship.png").exists()); + } + + /** + * college/Ships/derwent_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void derwentship() { + assertTrue("This test will pass /college/Ships/derwent_ship.png", Gdx.files + .internal("../core/assets/college/Ships/derwent_ship.png").exists()); + } + + /** + * college/Ships/enemyShip1.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void enemyShip1() { + assertTrue("This test will pass /college/Ships/enemyShip1.png", Gdx.files + .internal("../core/assets/college/Ships/enemyShip1.png").exists()); + } + + /** + * college/Ships/goodricke_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void goodrickeship() { + assertTrue("This test will pass /college/Ships/goodricke_ship.png", Gdx.files + .internal("../core/assets/college/Ships/goodricke_ship.png").exists()); + } + + /** + * college/Ships/player_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void playership() { + assertTrue("This test will pass /college/Ships/player_ship.png", Gdx.files + .internal("../core/assets/college/Ships/player_ship.png").exists()); + } + + /** + * college/Ships/ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void ship1() { + assertTrue("This test will pass /college/Ships/ship.png", Gdx.files + .internal("../core/assets/college/Ships/ship.png").exists()); + } + + /** + * college/Ships/ship1.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void ship2() { + assertTrue("This test will pass /college/Ships/ship1.png", Gdx.files + .internal("../core/assets/college/Ships/ship1.png").exists()); + } + + /** + * college/Ships/unaligned_ship.png is an asset file + * + * @throws AssertionError passes the message for specific test that didn't pass and raises an error + */ + @Test + public void unalignedship() { + assertTrue("This test will pass /college/Ships/unaligned_ship.png", Gdx.files + .internal("../core/assets/college/Ships/unaligned_ship.png").exists()); + } +} diff --git a/core/src/test/java/com/mygdx/pirategame/tests/pathfinding/PathFinderTest.java b/core/src/test/java/com/mygdx/pirategame/tests/pathfinding/PathFinderTest.java new file mode 100644 index 00000000..41c65afb --- /dev/null +++ b/core/src/test/java/com/mygdx/pirategame/tests/pathfinding/PathFinderTest.java @@ -0,0 +1,16 @@ +package com.mygdx.pirategame.tests.pathfinding; + +import com.mygdx.pirategame.pathfinding.PathFinder; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; + +public class PathFinderTest { + + @Test + public void checkDebug(){ + // checking if the debug tools for pathfinding are disabled + assertFalse("PathFinder debug tools must be disabled", PathFinder.PATHFINDERDEBUG); + } + +} diff --git a/desktop/src/com/mygdx/pirategame/desktop/DesktopLauncher.java b/desktop/src/com/mygdx/pirategame/desktop/DesktopLauncher.java index 73489a36..cae6ecf0 100644 --- a/desktop/src/com/mygdx/pirategame/desktop/DesktopLauncher.java +++ b/desktop/src/com/mygdx/pirategame/desktop/DesktopLauncher.java @@ -7,6 +7,8 @@ public class DesktopLauncher { public static void main (String[] arg) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); + config.height=720; + config.width=1280; new LwjglApplication(new PirateGame(), config); } } diff --git a/settings.gradle b/settings.gradle index 74fc6522..a51bf4af 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include 'desktop', 'core' \ No newline at end of file +include 'desktop', 'core', 'test' \ No newline at end of file