commit 68aba39dc1ff15331b4cba8cfc1a448b2a7fdb98 Author: Andrey Limasov Date: Tue Jun 16 11:03:12 2026 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d9d087 --- /dev/null +++ b/.gitignore @@ -0,0 +1,114 @@ +## Java + +*.class +*.war +*.ear +hs_err_pid* + +## Robovm +/ios/robovm-build/ + +## GWT +/html/war/ +/html/gwt-unitCache/ +.apt_generated/ +.gwt/ +gwt-unitCache/ +www-test/ +.gwt-tmp/ + +## Android Studio and Intellij and Android in general +/android/libs/armeabi-v7a/ +/android/libs/arm64-v8a/ +/android/libs/x86/ +/android/libs/x86_64/ +/android/gen/ +.idea/ +*.ipr +*.iws +*.iml +/android/out/ +com_crashlytics_export_strings.xml + +## Eclipse + +.classpath +.project +.metadata/ +/android/bin/ +/core/bin/ +/desktop/bin/ +/html/bin/ +/ios/bin/ +*.tmp +*.bak +*.swp +*~.nib +.settings/ +.loadpath +.externalToolBuilders/ +*.launch + +## NetBeans + +/nbproject/private/ +/android/nbproject/private/ +/core/nbproject/private/ +/desktop/nbproject/private/ +/html/nbproject/private/ +/ios/nbproject/private/ + +/build/ +/android/build/ +/core/build/ +/desktop/build/ +/html/build/ +/ios/build/ + +/nbbuild/ +/android/nbbuild/ +/core/nbbuild/ +/desktop/nbbuild/ +/html/nbbuild/ +/ios/nbbuild/ + +/dist/ +/android/dist/ +/core/dist/ +/desktop/dist/ +/html/dist/ +/ios/dist/ + +/nbdist/ +/android/nbdist/ +/core/nbdist/ +/desktop/nbdist/ +/html/nbdist/ +/ios/nbdist/ + +nbactions.xml +nb-configuration.xml + +## Gradle + +/local.properties +.gradle/ +gradle-app.setting +/build/ +/android/build/ +/core/build/ +/desktop/build/ +/html/build/ +/ios/build/ + +## OS Specific +.DS_Store +Thumbs.db + +## iOS +/ios/xcode/*.xcodeproj/* +!/ios/xcode/*.xcodeproj/xcshareddata +!/ios/xcode/*.xcodeproj/project.pbxproj +/ios/xcode/native/ +/ios/IOSLauncher.app +/ios/IOSLauncher.app.dSYM diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000..1d1fc81 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..d108238 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,89 @@ +android { + namespace "com.mygdx.game" + buildToolsVersion "33.0.2" + compileSdkVersion 32 + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['../assets'] + jniLibs.srcDirs = ['libs'] + } + + } + packagingOptions { + exclude 'META-INF/robovm/ios/robovm.xml' + } + defaultConfig { + applicationId "com.mygdx.game" + minSdkVersion 14 + targetSdkVersion 35 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + + +// called every time gradle gets executed, takes the native dependencies of +// the natives configuration, and extracts them to the proper libs/ folders +// so they get packed with the APK. +tasks.register('copyAndroidNatives') { + doFirst { + file("libs/armeabi-v7a/").mkdirs() + file("libs/arm64-v8a/").mkdirs() + file("libs/x86_64/").mkdirs() + file("libs/x86/").mkdirs() + + configurations.natives.copy().files.each { jar -> + def outputDir = null + if (jar.name.endsWith("natives-arm64-v8a.jar")) outputDir = file("libs/arm64-v8a") + if (jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a") + if (jar.name.endsWith("natives-x86_64.jar")) outputDir = file("libs/x86_64") + if (jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86") + if (outputDir != null) { + copy { + from zipTree(jar) + into outputDir + include "*.so" + } + } + } + } +} + +tasks.matching { it.name.contains("merge") && it.name.contains("JniLibFolders") }.configureEach { packageTask -> + packageTask.dependsOn 'copyAndroidNatives' +} + +tasks.register('run', Exec) { + def path + def localProperties = project.file("../local.properties") + if (localProperties.exists()) { + Properties properties = new Properties() + localProperties.withInputStream { instr -> + properties.load(instr) + } + def sdkDir = properties.getProperty('sdk.dir') + if (sdkDir) { + path = sdkDir + } else { + path = "$System.env.ANDROID_HOME" + } + } else { + path = "$System.env.ANDROID_HOME" + } + + def adb = path + "/platform-tools/adb" + commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.mygdx.game/com.mygdx.game.AndroidLauncher' +} + +eclipse.project.name = appName + "-android" diff --git a/android/ic_launcher-web.png b/android/ic_launcher-web.png new file mode 100644 index 0000000..8f0110d Binary files /dev/null and b/android/ic_launcher-web.png differ diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro new file mode 100644 index 0000000..63c1adb --- /dev/null +++ b/android/proguard-rules.pro @@ -0,0 +1,38 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +-verbose + +-dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication + +# Required if using Gdx-Controllers extension +-keep class com.badlogic.gdx.controllers.android.AndroidControllers + +# Required if using Box2D extension +-keepclassmembers class com.badlogic.gdx.physics.box2d.World { + boolean contactFilter(long, long); + void beginContact(long); + void endContact(long); + void preSolve(long, long); + void postSolve(long, long); + boolean reportFixture(long); + float reportRayFixture(long, float, float, float, float, float); +} diff --git a/android/project.properties b/android/project.properties new file mode 100644 index 0000000..3fefa92 --- /dev/null +++ b/android/project.properties @@ -0,0 +1,9 @@ +# This file is used by the Eclipse ADT plugin. It is unnecessary for IDEA and Android Studio projects, which +# configure Proguard and the Android target via the build.gradle file. + +# To enable ProGuard to work with Eclipse ADT, uncomment this (available properties: sdk.dir, user.home) +# and ensure proguard.jar in the Android SDK is up to date (or alternately reduce the android target to 23 or lower): +# proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-rules.pro + +# Project target. +target=android-19 diff --git a/android/res/drawable-anydpi-v26/ic_launcher.xml b/android/res/drawable-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6c7313a --- /dev/null +++ b/android/res/drawable-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/drawable-anydpi-v26/ic_launcher_foreground.xml b/android/res/drawable-anydpi-v26/ic_launcher_foreground.xml new file mode 100644 index 0000000..5916ee8 --- /dev/null +++ b/android/res/drawable-anydpi-v26/ic_launcher_foreground.xml @@ -0,0 +1,40 @@ + + + + + + + + + diff --git a/android/res/drawable-hdpi/ic_launcher.png b/android/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..91f696b Binary files /dev/null and b/android/res/drawable-hdpi/ic_launcher.png differ diff --git a/android/res/drawable-mdpi/ic_launcher.png b/android/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..c1ab239 Binary files /dev/null and b/android/res/drawable-mdpi/ic_launcher.png differ diff --git a/android/res/drawable-xhdpi/ic_launcher.png b/android/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..2011cc0 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_launcher.png differ diff --git a/android/res/drawable-xxhdpi/ic_launcher.png b/android/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..25fcef0 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/android/res/drawable-xxxhdpi/ic_launcher.png b/android/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..d109946 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/android/res/values-v21/styles.xml b/android/res/values-v21/styles.xml new file mode 100644 index 0000000..fcc6217 --- /dev/null +++ b/android/res/values-v21/styles.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/values/color.xml b/android/res/values/color.xml new file mode 100644 index 0000000..933353e --- /dev/null +++ b/android/res/values/color.xml @@ -0,0 +1,4 @@ + + + #FFFFFFFF + diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml new file mode 100644 index 0000000..889c244 --- /dev/null +++ b/android/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + My GDX Game + + diff --git a/android/res/values/styles.xml b/android/res/values/styles.xml new file mode 100644 index 0000000..77377af --- /dev/null +++ b/android/res/values/styles.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/src/com/mygdx/game/AndroidLauncher.java b/android/src/com/mygdx/game/AndroidLauncher.java new file mode 100644 index 0000000..1425b35 --- /dev/null +++ b/android/src/com/mygdx/game/AndroidLauncher.java @@ -0,0 +1,16 @@ +package com.mygdx.game; + +import android.os.Bundle; + +import com.badlogic.gdx.backends.android.AndroidApplication; +import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; +import com.mygdx.game.MyGdxGame; + +public class AndroidLauncher extends AndroidApplication { + @Override + protected void onCreate (Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); + initialize(new MyGdxGame(), config); + } +} diff --git a/assets/badlogic.jpg b/assets/badlogic.jpg new file mode 100644 index 0000000..4390da6 Binary files /dev/null and b/assets/badlogic.jpg differ diff --git a/assets/fonts/Montserrat-Bold.ttf b/assets/fonts/Montserrat-Bold.ttf new file mode 100644 index 0000000..9a425b9 Binary files /dev/null and b/assets/fonts/Montserrat-Bold.ttf differ diff --git a/assets/fonts/arial.ttf b/assets/fonts/arial.ttf new file mode 100644 index 0000000..a882d32 Binary files /dev/null and b/assets/fonts/arial.ttf differ diff --git a/assets/sounds/background.mp3 b/assets/sounds/background.mp3 new file mode 100644 index 0000000..3d45d50 Binary files /dev/null and b/assets/sounds/background.mp3 differ diff --git a/assets/sounds/button_click.mp3 b/assets/sounds/button_click.mp3 new file mode 100644 index 0000000..458ba46 Binary files /dev/null and b/assets/sounds/button_click.mp3 differ diff --git a/assets/sounds/explosion.mp3 b/assets/sounds/explosion.mp3 new file mode 100644 index 0000000..458ba46 Binary files /dev/null and b/assets/sounds/explosion.mp3 differ diff --git a/assets/sounds/rocket.mp3 b/assets/sounds/rocket.mp3 new file mode 100644 index 0000000..96596ae Binary files /dev/null and b/assets/sounds/rocket.mp3 differ diff --git a/assets/sounds/select.mp3 b/assets/sounds/select.mp3 new file mode 100644 index 0000000..8f7d5d2 Binary files /dev/null and b/assets/sounds/select.mp3 differ diff --git a/assets/sounds/shoot.mp3 b/assets/sounds/shoot.mp3 new file mode 100644 index 0000000..458ba46 Binary files /dev/null and b/assets/sounds/shoot.mp3 differ diff --git a/assets/textures/Air/Speed.png b/assets/textures/Air/Speed.png new file mode 100644 index 0000000..afe535b Binary files /dev/null and b/assets/textures/Air/Speed.png differ diff --git a/assets/textures/Air/basic.png b/assets/textures/Air/basic.png new file mode 100644 index 0000000..3ff3d08 Binary files /dev/null and b/assets/textures/Air/basic.png differ diff --git a/assets/textures/Air/enemy.png b/assets/textures/Air/enemy.png new file mode 100644 index 0000000..9976ae6 Binary files /dev/null and b/assets/textures/Air/enemy.png differ diff --git a/assets/textures/Air/enemy_basic.png b/assets/textures/Air/enemy_basic.png new file mode 100644 index 0000000..9976ae6 Binary files /dev/null and b/assets/textures/Air/enemy_basic.png differ diff --git a/assets/textures/Air/enemy_boss.png b/assets/textures/Air/enemy_boss.png new file mode 100644 index 0000000..be09177 Binary files /dev/null and b/assets/textures/Air/enemy_boss.png differ diff --git a/assets/textures/Air/enemy_boss_falling1.png b/assets/textures/Air/enemy_boss_falling1.png new file mode 100644 index 0000000..fec24f0 Binary files /dev/null and b/assets/textures/Air/enemy_boss_falling1.png differ diff --git a/assets/textures/Air/enemy_boss_falling2.png b/assets/textures/Air/enemy_boss_falling2.png new file mode 100644 index 0000000..cb68750 Binary files /dev/null and b/assets/textures/Air/enemy_boss_falling2.png differ diff --git a/assets/textures/Air/enemy_falling1.png b/assets/textures/Air/enemy_falling1.png new file mode 100644 index 0000000..d887e78 Binary files /dev/null and b/assets/textures/Air/enemy_falling1.png differ diff --git a/assets/textures/Air/enemy_falling2.png b/assets/textures/Air/enemy_falling2.png new file mode 100644 index 0000000..a9595db Binary files /dev/null and b/assets/textures/Air/enemy_falling2.png differ diff --git a/assets/textures/Air/enemy_fast.png b/assets/textures/Air/enemy_fast.png new file mode 100644 index 0000000..a0f3f4d Binary files /dev/null and b/assets/textures/Air/enemy_fast.png differ diff --git a/assets/textures/Air/enemy_fast_falling1.png b/assets/textures/Air/enemy_fast_falling1.png new file mode 100644 index 0000000..51730cb Binary files /dev/null and b/assets/textures/Air/enemy_fast_falling1.png differ diff --git a/assets/textures/Air/enemy_fast_falling2.png b/assets/textures/Air/enemy_fast_falling2.png new file mode 100644 index 0000000..fc03d45 Binary files /dev/null and b/assets/textures/Air/enemy_fast_falling2.png differ diff --git a/assets/textures/Air/enemy_tank.png b/assets/textures/Air/enemy_tank.png new file mode 100644 index 0000000..cf5dae5 Binary files /dev/null and b/assets/textures/Air/enemy_tank.png differ diff --git a/assets/textures/Air/enemy_tank_falling1.png b/assets/textures/Air/enemy_tank_falling1.png new file mode 100644 index 0000000..fec24f0 Binary files /dev/null and b/assets/textures/Air/enemy_tank_falling1.png differ diff --git a/assets/textures/Air/enemy_tank_falling2.png b/assets/textures/Air/enemy_tank_falling2.png new file mode 100644 index 0000000..cb68750 Binary files /dev/null and b/assets/textures/Air/enemy_tank_falling2.png differ diff --git a/assets/textures/Air/player_basic.png b/assets/textures/Air/player_basic.png new file mode 100644 index 0000000..12ec6ce Binary files /dev/null and b/assets/textures/Air/player_basic.png differ diff --git a/assets/textures/Air/player_fast.png b/assets/textures/Air/player_fast.png new file mode 100644 index 0000000..a0f3f4d Binary files /dev/null and b/assets/textures/Air/player_fast.png differ diff --git a/assets/textures/Air/player_tank.png b/assets/textures/Air/player_tank.png new file mode 100644 index 0000000..cf5dae5 Binary files /dev/null and b/assets/textures/Air/player_tank.png differ diff --git a/assets/textures/Air/tanks.png b/assets/textures/Air/tanks.png new file mode 100644 index 0000000..3dfdcc1 Binary files /dev/null and b/assets/textures/Air/tanks.png differ diff --git a/assets/textures/background/background.png b/assets/textures/background/background.png new file mode 100644 index 0000000..864c4ce Binary files /dev/null and b/assets/textures/background/background.png differ diff --git a/assets/textures/background/background1.png b/assets/textures/background/background1.png new file mode 100644 index 0000000..2d16f9e Binary files /dev/null and b/assets/textures/background/background1.png differ diff --git a/assets/textures/background/game_over_bg.png b/assets/textures/background/game_over_bg.png new file mode 100644 index 0000000..a6e6296 Binary files /dev/null and b/assets/textures/background/game_over_bg.png differ diff --git a/assets/textures/background/level1_bg.jpg b/assets/textures/background/level1_bg.jpg new file mode 100644 index 0000000..d94d078 Binary files /dev/null and b/assets/textures/background/level1_bg.jpg differ diff --git a/assets/textures/background/level2_bg.jpg b/assets/textures/background/level2_bg.jpg new file mode 100644 index 0000000..39647fb Binary files /dev/null and b/assets/textures/background/level2_bg.jpg differ diff --git a/assets/textures/background/level3_bg.png b/assets/textures/background/level3_bg.png new file mode 100644 index 0000000..c089a1c Binary files /dev/null and b/assets/textures/background/level3_bg.png differ diff --git a/assets/textures/background/level_select_bg.png b/assets/textures/background/level_select_bg.png new file mode 100644 index 0000000..e20d176 Binary files /dev/null and b/assets/textures/background/level_select_bg.png differ diff --git a/assets/textures/background/menu_bg.png b/assets/textures/background/menu_bg.png new file mode 100644 index 0000000..a6e6296 Binary files /dev/null and b/assets/textures/background/menu_bg.png differ diff --git a/assets/textures/background/menu_bg1.png b/assets/textures/background/menu_bg1.png new file mode 100644 index 0000000..3ab2bf0 Binary files /dev/null and b/assets/textures/background/menu_bg1.png differ diff --git a/assets/textures/background/player_select_bg.png b/assets/textures/background/player_select_bg.png new file mode 100644 index 0000000..d8e366e Binary files /dev/null and b/assets/textures/background/player_select_bg.png differ diff --git a/assets/textures/bullet.png b/assets/textures/bullet.png new file mode 100644 index 0000000..3a07265 Binary files /dev/null and b/assets/textures/bullet.png differ diff --git a/assets/textures/bullet_basic.png b/assets/textures/bullet_basic.png new file mode 100644 index 0000000..3a07265 Binary files /dev/null and b/assets/textures/bullet_basic.png differ diff --git a/assets/textures/bullet_rocket.png b/assets/textures/bullet_rocket.png new file mode 100644 index 0000000..3a07265 Binary files /dev/null and b/assets/textures/bullet_rocket.png differ diff --git a/assets/textures/button/button.png b/assets/textures/button/button.png new file mode 100644 index 0000000..a702731 Binary files /dev/null and b/assets/textures/button/button.png differ diff --git a/assets/textures/button/button_attack.png b/assets/textures/button/button_attack.png new file mode 100644 index 0000000..d8384e7 Binary files /dev/null and b/assets/textures/button/button_attack.png differ diff --git a/assets/textures/button/button_bg1.png b/assets/textures/button/button_bg1.png new file mode 100644 index 0000000..1100b33 Binary files /dev/null and b/assets/textures/button/button_bg1.png differ diff --git a/assets/textures/button/button_left.png b/assets/textures/button/button_left.png new file mode 100644 index 0000000..5aea106 Binary files /dev/null and b/assets/textures/button/button_left.png differ diff --git a/assets/textures/button/button_pause.png b/assets/textures/button/button_pause.png new file mode 100644 index 0000000..e9ad403 Binary files /dev/null and b/assets/textures/button/button_pause.png differ diff --git a/assets/textures/button/button_right.png b/assets/textures/button/button_right.png new file mode 100644 index 0000000..d1f9cd0 Binary files /dev/null and b/assets/textures/button/button_right.png differ diff --git a/assets/textures/button/button_speed.png b/assets/textures/button/button_speed.png new file mode 100644 index 0000000..21f4354 Binary files /dev/null and b/assets/textures/button/button_speed.png differ diff --git a/assets/textures/button/button_speed100.png b/assets/textures/button/button_speed100.png new file mode 100644 index 0000000..badf46e Binary files /dev/null and b/assets/textures/button/button_speed100.png differ diff --git a/assets/textures/button/button_speed60.png b/assets/textures/button/button_speed60.png new file mode 100644 index 0000000..571a255 Binary files /dev/null and b/assets/textures/button/button_speed60.png differ diff --git a/assets/textures/button/button_speed80.png b/assets/textures/button/button_speed80.png new file mode 100644 index 0000000..7144c91 Binary files /dev/null and b/assets/textures/button/button_speed80.png differ diff --git a/assets/textures/button/button_weapon.png b/assets/textures/button/button_weapon.png new file mode 100644 index 0000000..b1d1e12 Binary files /dev/null and b/assets/textures/button/button_weapon.png differ diff --git a/assets/textures/explosion.png b/assets/textures/explosion.png new file mode 100644 index 0000000..826adc8 Binary files /dev/null and b/assets/textures/explosion.png differ diff --git a/assets/textures/health_bar.png b/assets/textures/health_bar.png new file mode 100644 index 0000000..a744450 Binary files /dev/null and b/assets/textures/health_bar.png differ diff --git a/assets/textures/health_bg.png b/assets/textures/health_bg.png new file mode 100644 index 0000000..3a39003 Binary files /dev/null and b/assets/textures/health_bg.png differ diff --git a/assets/textures/health_fill.png b/assets/textures/health_fill.png new file mode 100644 index 0000000..4b3acf2 Binary files /dev/null and b/assets/textures/health_fill.png differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..77fc9ae --- /dev/null +++ b/build.gradle @@ -0,0 +1,93 @@ +buildscript { + + + repositories { + mavenLocal() + mavenCentral() + gradlePluginPortal() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + google() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.2.2' + + + } +} + +allprojects { + apply plugin: "eclipse" + + version = '1.0' + ext { + appName = "Воздушный бой" + gdxVersion = '1.12.0' + roboVMVersion = '2.3.19' + box2DLightsVersion = '1.5' + ashleyVersion = '1.7.4' + aiVersion = '1.8.2' + gdxControllersVersion = '2.2.1' + } + + repositories { + mavenLocal() + mavenCentral() + google() + gradlePluginPortal() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + maven { url "https://oss.sonatype.org/content/repositories/releases/" } + maven { url "https://jitpack.io" } + } +} + +project(":desktop") { + apply plugin: "java-library" + + + dependencies { + implementation project(":core") + api "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion" + api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + api "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" + api "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop" + + } +} + +project(":android") { + apply plugin: "com.android.application" + + configurations { natives } + + dependencies { + implementation project(":core") + api "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64" + api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" + natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a" + natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a" + natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86" + natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-x86_64" + api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi-v7a" + natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-arm64-v8a" + natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86" + natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86_64" + + } +} + +project(":core") { + apply plugin: "java-library" + + + dependencies { + api "com.badlogicgames.gdx:gdx:$gdxVersion" + api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" + api "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + + } +} diff --git a/core/build.gradle b/core/build.gradle new file mode 100644 index 0000000..d192d04 --- /dev/null +++ b/core/build.gradle @@ -0,0 +1,6 @@ +sourceCompatibility = 1.7 +[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' + +sourceSets.main.java.srcDirs = [ "src/" ] + +eclipse.project.name = appName + "-core" diff --git a/core/src/com/mygdx/game/FontBuilder.java b/core/src/com/mygdx/game/FontBuilder.java new file mode 100644 index 0000000..51c2714 --- /dev/null +++ b/core/src/com/mygdx/game/FontBuilder.java @@ -0,0 +1,30 @@ +package com.mygdx.game; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; + +public class FontBuilder { + + public static BitmapFont generate(int size, Color color, String fontPath) { + try { + FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal(fontPath)); + FreeTypeFontParameter parameter = new FreeTypeFontParameter(); + parameter.size = size; + parameter.color = color; + + parameter.characters = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 .,!?-"; + BitmapFont font = generator.generateFont(parameter); + generator.dispose(); + return font; + } catch (Exception e) { + + BitmapFont font = new BitmapFont(); + font.getData().setScale(size / 24f); + font.setColor(color); + return font; + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/GameResources.java b/core/src/com/mygdx/game/GameResources.java new file mode 100644 index 0000000..4785772 --- /dev/null +++ b/core/src/com/mygdx/game/GameResources.java @@ -0,0 +1,72 @@ +package com.mygdx.game; + +public class GameResources { + + // ангар + public static final String BASIC_PATH = "textures/Air/basic.png"; + public static final String FAST_PATH = "textures/Air/Speed.png"; + public static final String TANK_PATH = "textures/Air/tanks.png"; + + // Текстуры для кнопок + + public static final String BUTTON_PATH = "textures/button/button.png"; + + public static final String BUTTON_PAUSE_PATH = "textures/button/button_pause.png"; + + public static final String BUTTON_ATTACK_PATH = "textures/button/button_attack.png"; + public static final String BUTTON_WEAPON_PATH = "textures/button/button_weapon.png"; + public static final String BUTTON_LEFT_PATH = "textures/button/button_left.png"; + public static final String BUTTON_RIGHT_PATH = "textures/button/button_right.png"; + public static final String BUTTON_SPEED_PATH = "textures/button/button_speed.png"; + + + // Фоны экранов + public static final String LEVEL_SELECT_BG_PATH = "textures/background/level_select_bg.png"; + public static final String PLAYER_SELECT_BG_PATH = "textures/background/player_select_bg.png"; + public static final String GAME_OVER_BG_PATH = "textures/background/game_over_bg.png"; + public static final String MENU_BG_IMG_PATH = "textures/background/menu_bg.png"; + // Фоны уровней + public static final String LEVEL1_BG_PATH = "textures/background/level1_bg.jpg"; + public static final String LEVEL2_BG_PATH = "textures/background/level2_bg.jpg"; + public static final String LEVEL3_BG_PATH = "textures/background/level3_bg.png"; + // Игрок + public static final String PLAYER_BASIC_PATH = "textures/Air/player_basic.png"; + public static final String PLAYER_FAST_PATH = "textures/Air/player_fast.png"; + public static final String PLAYER_TANK_PATH = "textures/Air/player_tank.png"; + + // Враги + public static final String ENEMY_BASIC_PATH = "textures/Air/enemy_basic.png"; + public static final String ENEMY_FAST_PATH = "textures/Air/enemy_fast.png"; + public static final String ENEMY_TANK_PATH = "textures/Air/enemy_tank.png"; + public static final String ENEMY_BOSS_PATH = "textures/Air/enemy_boss.png"; + + // Обычный враг + public static final String ENEMY_FALLING1_PATH = "textures/Air/enemy_falling1.png"; + public static final String ENEMY_FALLING2_PATH = "textures/Air/enemy_falling2.png"; + // Быстрый враг + public static final String ENEMY_FAST_FALLING1_PATH = "textures/Air/enemy_fast_falling1.png"; + public static final String ENEMY_FAST_FALLING2_PATH = "textures/Air/enemy_fast_falling2.png"; + // Танк + public static final String ENEMY_TANK_FALLING1_PATH = "textures/Air/enemy_tank_falling1.png"; + public static final String ENEMY_TANK_FALLING2_PATH = "textures/Air/enemy_tank_falling2.png"; + // Босс + public static final String ENEMY_BOSS_FALLING1_PATH = "textures/Air/enemy_boss_falling1.png"; + public static final String ENEMY_BOSS_FALLING2_PATH = "textures/Air/enemy_boss_falling2.png"; + // Боеприпасы + public static final String BULLET_BASIC_PATH = "textures/bullet_basic.png"; + public static final String BULLET_ROCKET_PATH = "textures/bullet_rocket.png"; + // + public static final String HEALTH_BG_PATH = "textures/health_bg.png"; + public static final String HEALTH_FILL_PATH = "textures/health_fill.png"; + public static final String EXPLOSION_PATH = "textures/explosion.png"; + + // Звуки + public static final String BACKGROUND_MUSIC_PATH = "sounds/background.mp3"; + public static final String SHOOT_SOUND_PATH = "sounds/shoot.mp3"; + public static final String ROCKET_SOUND_PATH = "sounds/rocket.mp3"; + public static final String EXPLOSION_SOUND_PATH = "sounds/explosion.mp3"; + public static final String SELECT_SOUND_PATH = "sounds/select.mp3"; + + // Шрифты + public static final String FONT_PATH = "fonts/arial.ttf"; +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/GameSettings.java b/core/src/com/mygdx/game/GameSettings.java new file mode 100644 index 0000000..6795726 --- /dev/null +++ b/core/src/com/mygdx/game/GameSettings.java @@ -0,0 +1,135 @@ +package com.mygdx.game; + +import com.badlogic.gdx.graphics.Color; + +public class GameSettings { + public static final int SCREEN_WIDTH = 1280; + public static final int SCREEN_HEIGHT = 720; + + //Игрок + + public static final float[] SPEED_LEVELS = {0.5f, 0.8f, 1.0f}; + + public static class PlayerConfig { + public String texturePath; + public float speed; + public int health; + public float rotationSpeed; + public String name; + public String description; + + public PlayerConfig(String texture, float speed, int health, + float rotation, String name, String desc) { + this.texturePath = texture; + this.speed = speed; + this.health = health; + this.rotationSpeed = rotation; + this.name = name; + this.description = desc; + } + } + + public static final PlayerConfig[] PLAYERS = { + new PlayerConfig( + GameResources.PLAYER_BASIC_PATH, + 300, 100, 180, + "БАЗОВЫЙ", + "Баланс скорости и защиты" + ), + new PlayerConfig( + GameResources.PLAYER_FAST_PATH, + 450, 70, 220, + "СКОРОСТНОЙ", + "Высокая скорость, низкая защита" + ), + new PlayerConfig( + GameResources.PLAYER_TANK_PATH, + 200, 150, 160, + "ТАНК", + "Высокая защита, низкая скорость" + ) + }; + + //Уровень + + public static class LevelConfig { + public String name; + public String backgroundPath; + public int enemyCount; + public String description; + + public LevelConfig(String name, String bgPath, int count, String desc) { + this.name = name; + this.backgroundPath = bgPath; + this.enemyCount = count; + this.description = desc; + } + } + + public static final LevelConfig[] LEVELS = { + new LevelConfig("ЛЕС", GameResources.LEVEL1_BG_PATH, 10, "Лесной уровень"), + new LevelConfig("ПУСТЫНЯ", GameResources.LEVEL2_BG_PATH, 10, "Пустынный уровень"), + new LevelConfig("КОСМОС", GameResources.LEVEL3_BG_PATH, 10, "Космический уровень") + }; + + //стрельба + + public static final float BULLET_SPEED = 1500f; + public static final float ROCKET_SPEED = 1200f; + + public static final int ROCKET_DAMAGE = 30; + public static final int BULLET_DAMAGE = 10; + + public static final float BULLET_COOLDOWN = 0.2f; + public static final float ROCKET_COOLDOWN = 0.5f; + + //враги + + public static final float ENEMY_SHOOT_PROBABILITY = 0.003f; + public static final float ENEMY_SPAWN_RATE = 3f; + public static final float BOSS_CHANCE = 0.1f; + + //механика + + public static final int PLAYER_COLLISION_DAMAGE = 10; + public static final int BULLET_COLLISION_DAMAGE = 5; + + + public static final float BULLET_DESPAWN_DISTANCE = 3000f; + public static final int SCORE_PER_ENEMY = 100; + + //текст + + public static final Color TEXT_COLOR_WHITE = Color.WHITE; + public static final Color TEXT_COLOR_YELLOW = Color.YELLOW; + + public static final int FONT_SIZE_TITLE = 72; + public static final int FONT_SIZE_BUTTON = 36; + public static final int FONT_SIZE_SMALL = 24; + + public enum Difficulty { + EASY, + NORMAL, + HARD + } + + public static Difficulty currentDifficulty = Difficulty.NORMAL; + + public static float getDifficultyMultiplier() { + switch (currentDifficulty) { + case EASY: return 0.7f; + case NORMAL: return 1.0f; + case HARD: return 1.5f; + default: return 1.0f; + } + } + + public static int getEnemyCountForLevel(int baseCount) { + switch (currentDifficulty) { + case EASY: return baseCount; + case NORMAL: return (int)(baseCount * 1.3f); + case HARD: return (int)(baseCount * 1.6f); + default: return baseCount; + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/MyGdxGame.java b/core/src/com/mygdx/game/MyGdxGame.java new file mode 100644 index 0000000..a470829 --- /dev/null +++ b/core/src/com/mygdx/game/MyGdxGame.java @@ -0,0 +1,240 @@ +package com.mygdx.game; + +import com.badlogic.gdx.Game; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.managers.SoundManager; +import com.mygdx.game.screens.GameOverScreen; +import com.mygdx.game.screens.GameScreen; +import com.mygdx.game.screens.LevelSelectScreen; +import com.mygdx.game.screens.MenuScreen; +import com.mygdx.game.screens.PlayerSelectScreen; +import com.mygdx.game.screens.SettingsScreen; + +public class MyGdxGame extends Game { + public SpriteBatch batch; + public OrthographicCamera camera; + public Vector3 touch; + public SoundManager soundManager; + + public BitmapFont titleFont; + public BitmapFont buttonFont; + public BitmapFont smallFont; + + public MenuScreen menuScreen; + public PlayerSelectScreen playerSelectScreen; + public LevelSelectScreen levelSelectScreen; + public SettingsScreen settingsScreen; + public GameScreen gameScreen; + public GameOverScreen gameOverScreen; + + public int selectedPlayer = 0; + public int selectedLevel = 0; + + public boolean isFromGame = false; + + @Override + public void create() { + Gdx.graphics.setForegroundFPS(60); + System.out.println("MyGdxGame: create() начат"); + + try { + camera = new OrthographicCamera(); + camera.setToOrtho(false, GameSettings.SCREEN_WIDTH, GameSettings.SCREEN_HEIGHT); + + batch = new SpriteBatch(); + touch = new Vector3(); + + System.out.println("MyGdxGame: Основные компоненты созданы"); + + soundManager = new SoundManager(); + System.out.println("MyGdxGame: SoundManager создан"); + + createFonts(); + System.out.println("MyGdxGame: Шрифты созданы"); + + createScreens(); + System.out.println("MyGdxGame: Экраны созданы"); + + if (soundManager != null) { + soundManager.playBackgroundMusic(); + System.out.println("MyGdxGame: Музыка включена"); + } + + setScreen(menuScreen); + System.out.println("MyGdxGame: Экран меню показан"); + + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в create(): " + e.getMessage()); + e.printStackTrace(); + } + } + + private void createFonts() { + try { + titleFont = FontBuilder.generate(GameSettings.FONT_SIZE_TITLE, GameSettings.TEXT_COLOR_YELLOW, GameResources.FONT_PATH); + buttonFont = FontBuilder.generate(GameSettings.FONT_SIZE_BUTTON, GameSettings.TEXT_COLOR_WHITE, GameResources.FONT_PATH); + smallFont = FontBuilder.generate(GameSettings.FONT_SIZE_SMALL, GameSettings.TEXT_COLOR_WHITE, GameResources.FONT_PATH); + System.out.println("MyGdxGame: Шрифты успешно созданы"); + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка создания шрифтов: " + e.getMessage()); + titleFont = new BitmapFont(); + buttonFont = new BitmapFont(); + smallFont = new BitmapFont(); + System.out.println("MyGdxGame: Используются стандартные шрифты"); + } + } + + private void createScreens() { + try { + menuScreen = new MenuScreen(this); + System.out.println("MyGdxGame: MenuScreen создан"); + + playerSelectScreen = new PlayerSelectScreen(this); + System.out.println("MyGdxGame: PlayerSelectScreen создан"); + + levelSelectScreen = new LevelSelectScreen(this); + System.out.println("MyGdxGame: LevelSelectScreen создан"); + + settingsScreen = new SettingsScreen(this); + System.out.println("MyGdxGame: SettingsScreen создан"); + + gameOverScreen = new GameOverScreen(this); + System.out.println("MyGdxGame: GameOverScreen создан"); + + gameScreen = null; + + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка создания экранов: " + e.getMessage()); + e.printStackTrace(); + } + } + + public void startNewGame() { + System.out.println("MyGdxGame: startNewGame() вызван"); + + try { + if (gameScreen != null) { + gameScreen.dispose(); + System.out.println("MyGdxGame: Старый GameScreen удален"); + } + + gameScreen = new GameScreen(this); + System.out.println("MyGdxGame: Новый GameScreen создан"); + + setScreen(gameScreen); + System.out.println("MyGdxGame: GameScreen показан"); + + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в startNewGame(): " + e.getMessage()); + e.printStackTrace(); + setScreen(menuScreen); + } + } + + @Override + public void render() { + try { + super.render(); + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в render(): " + e.getMessage()); + e.printStackTrace(); + } + } + + @Override + public void resize(int width, int height) { + try { + super.resize(width, height); + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в resize(): " + e.getMessage()); + } + } + + @Override + public void pause() { + try { + super.pause(); + if (soundManager != null) { + soundManager.pauseBackgroundMusic(); + } + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в pause(): " + e.getMessage()); + } + } + + @Override + public void resume() { + try { + super.resume(); + if (soundManager != null) { + soundManager.resumeBackgroundMusic(); + } + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в resume(): " + e.getMessage()); + } + } + + @Override + public void dispose() { + System.out.println("MyGdxGame: dispose() начат"); + + try { + if (menuScreen != null) { + menuScreen.dispose(); + menuScreen = null; + } + if (playerSelectScreen != null) { + playerSelectScreen.dispose(); + playerSelectScreen = null; + } + if (levelSelectScreen != null) { + levelSelectScreen.dispose(); + levelSelectScreen = null; + } + if (settingsScreen != null) { + settingsScreen.dispose(); + settingsScreen = null; + } + if (gameScreen != null) { + gameScreen.dispose(); + gameScreen = null; + } + if (gameOverScreen != null) { + gameOverScreen.dispose(); + gameOverScreen = null; + } + + if (titleFont != null) { + titleFont.dispose(); + titleFont = null; + } + if (buttonFont != null) { + buttonFont.dispose(); + buttonFont = null; + } + if (smallFont != null) { + smallFont.dispose(); + smallFont = null; + } + + if (soundManager != null) { + soundManager.dispose(); + soundManager = null; + } + + if (batch != null) { + batch.dispose(); + batch = null; + } + + System.out.println("MyGdxGame: Все ресурсы освобождены"); + + } catch (Exception e) { + System.err.println("MyGdxGame: Ошибка в dispose(): " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/components/ButtonView.java b/core/src/com/mygdx/game/components/ButtonView.java new file mode 100644 index 0000000..f42ce72 --- /dev/null +++ b/core/src/com/mygdx/game/components/ButtonView.java @@ -0,0 +1,68 @@ +package com.mygdx.game.components; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.GlyphLayout; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; + +public class ButtonView extends View { + + Texture texture; + BitmapFont bitmapFont; + String text; + float textX; + float textY; + Color textColor; + + public ButtonView(float x, float y, float width, float height, + BitmapFont font, String texturePath, String text) { + super(x, y, width, height); + this.text = text; + this.bitmapFont = font; + this.texture = new Texture(texturePath); + this.textColor = Color.BLACK; + + GlyphLayout glyphLayout = new GlyphLayout(bitmapFont, text); + float textWidth = glyphLayout.width; + float textHeight = glyphLayout.height; + + textX = x + (width - textWidth) / 2; + textY = y + (height + textHeight) / 2; + } + + public ButtonView(float x, float y, float width, float height, String texturePath) { + super(x, y, width, height); + this.texture = new Texture(texturePath); + this.bitmapFont = null; + } + + public void setTextColor(Color color) { + this.textColor = color; + } + + @Override + public void draw(SpriteBatch batch) { + batch.draw(texture, x, y, width, height); + if (bitmapFont != null && text != null) { + Color oldColor = bitmapFont.getColor(); + bitmapFont.setColor(textColor); + bitmapFont.draw(batch, text, textX, textY); + bitmapFont.setColor(oldColor); + } + } + + public boolean isHit(float touchX, float touchY) { + return touchX >= x && touchX <= x + width && + touchY >= y && touchY <= y + height; + } + + @Override + public void dispose() { + if (texture != null) { + texture.dispose(); + texture = null; + } + bitmapFont = null; + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/components/ImageView.java b/core/src/com/mygdx/game/components/ImageView.java new file mode 100644 index 0000000..ca0708f --- /dev/null +++ b/core/src/com/mygdx/game/components/ImageView.java @@ -0,0 +1,27 @@ +package com.mygdx.game.components; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; + +public class ImageView extends View { + + Texture texture; + + public ImageView(float x, float y, float width, float height, String imagePath) { + super(x, y, width, height); + texture = new Texture(imagePath); + } + + @Override + public void draw(SpriteBatch batch) { + batch.draw(texture, x, y, width, height); + } + + @Override + public void dispose() { + if (texture != null) { + texture.dispose(); + texture = null; + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/components/TextView.java b/core/src/com/mygdx/game/components/TextView.java new file mode 100644 index 0000000..fc37217 --- /dev/null +++ b/core/src/com/mygdx/game/components/TextView.java @@ -0,0 +1,42 @@ +package com.mygdx.game.components; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.GlyphLayout; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; + +public class TextView extends View { + private BitmapFont font; + private String text; + private Color color; + + public TextView(BitmapFont font, float x, float y, String text) { + super(x, y); + this.font = font; + this.text = text; + this.color = Color.WHITE; + + GlyphLayout layout = new GlyphLayout(font, text); + width = layout.width; + height = layout.height; + } + + public void setText(String text) { + this.text = text; + GlyphLayout layout = new GlyphLayout(font, text); + width = layout.width; + height = layout.height; + } + + public void setColor(Color color) { + this.color = color; + } + + @Override + public void draw(SpriteBatch batch) { + Color oldColor = font.getColor(); + font.setColor(color); + font.draw(batch, text, x, y); + font.setColor(oldColor); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/components/View.java b/core/src/com/mygdx/game/components/View.java new file mode 100644 index 0000000..2d52ccb --- /dev/null +++ b/core/src/com/mygdx/game/components/View.java @@ -0,0 +1,32 @@ +package com.mygdx.game.components; + +import com.badlogic.gdx.graphics.g2d.SpriteBatch; + +public abstract class View { + protected float x, y; + protected float width, height; + + public View(float x, float y) { + this.x = x; + this.y = y; + this.width = 0; + this.height = 0; + } + + public View(float x, float y, float width, float height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public abstract void draw(SpriteBatch batch); + + public void dispose() { + } + + public float getX() { return x; } + public float getY() { return y; } + + +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/managers/MemoryManager.java b/core/src/com/mygdx/game/managers/MemoryManager.java new file mode 100644 index 0000000..3a89b25 --- /dev/null +++ b/core/src/com/mygdx/game/managers/MemoryManager.java @@ -0,0 +1,85 @@ +package com.mygdx.game.managers; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.utils.Json; + +import java.util.ArrayList; + +public class MemoryManager { + + private static final Preferences preferences = Gdx.app.getPreferences("User saves"); + + public static void saveSoundSettings(boolean isOn) { + preferences.putBoolean("isSoundOn", isOn); + preferences.flush(); + } + + public static boolean loadIsSoundOn() { + return preferences.getBoolean("isSoundOn", true); + } + + public static void saveMusicSettings(boolean isOn) { + preferences.putBoolean("isMusicOn", isOn); + preferences.flush(); + } + + public static boolean loadIsMusicOn() { + return preferences.getBoolean("isMusicOn", true); + } + + public static void saveTableOfRecords(ArrayList table) { + Json json = new Json(); + String tableInString = json.toJson(table); + preferences.putString("recordTable", tableInString); + preferences.flush(); + } + + public static ArrayList loadRecordsTable() { + if (!preferences.contains("recordTable")) + return null; + + String scores = preferences.getString("recordTable"); + Json json = new Json(); + ArrayList table = json.fromJson(ArrayList.class, scores); + return table; + } + + public static void saveHighScore(int score) { + System.out.println("saveHighScore вызван, score = " + score); + + ArrayList records = loadRecordsTable(); + if (records == null) { + records = new ArrayList(); + System.out.println("Создан новый список рекордов"); + } + records.add(score); + System.out.println("Добавлен рекорд. Список: " + records.toString()); + + for (int i = 0; i < records.size() - 1; i++) { + for (int j = i + 1; j < records.size(); j++) { + if (records.get(i) < records.get(j)) { + int temp = records.get(i); + records.set(i, records.get(j)); + records.set(j, temp); + } + } + } + System.out.println("После сортировки: " + records.toString()); + + while (records.size() > 10) { + records.remove(records.size() - 1); + } + + saveTableOfRecords(records); + System.out.println("Рекорд сохранён. getHighScore = " + getHighScore()); + } + + public static int getHighScore() { + ArrayList records = loadRecordsTable(); + if (records == null || records.size() == 0) { + return 0; + } + return records.get(0); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/managers/SoundManager.java b/core/src/com/mygdx/game/managers/SoundManager.java new file mode 100644 index 0000000..d629ae5 --- /dev/null +++ b/core/src/com/mygdx/game/managers/SoundManager.java @@ -0,0 +1,122 @@ +package com.mygdx.game.managers; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.audio.Sound; +import com.mygdx.game.GameResources; + +public class SoundManager { + private Music backgroundMusic; + private Sound shootSound; + private Sound rocketSound; + private Sound explosionSound; + private Sound selectSound; + + private float musicVolume = 0.5f; + private float soundVolume = 0.7f; + + private boolean musicEnabled; + private boolean soundEnabled; + + public SoundManager() { + musicEnabled = MemoryManager.loadIsMusicOn(); + soundEnabled = MemoryManager.loadIsSoundOn(); + loadSounds(); + } + + private void loadSounds() { + try { + backgroundMusic = Gdx.audio.newMusic(Gdx.files.internal(GameResources.BACKGROUND_MUSIC_PATH)); + backgroundMusic.setLooping(true); + backgroundMusic.setVolume(musicVolume); + + shootSound = Gdx.audio.newSound(Gdx.files.internal(GameResources.SHOOT_SOUND_PATH)); + rocketSound = Gdx.audio.newSound(Gdx.files.internal(GameResources.ROCKET_SOUND_PATH)); + explosionSound = Gdx.audio.newSound(Gdx.files.internal(GameResources.EXPLOSION_SOUND_PATH)); + selectSound = Gdx.audio.newSound(Gdx.files.internal(GameResources.SELECT_SOUND_PATH)); + } catch (Exception e) { + System.err.println("Не удалось загрузить звуки: " + e.getMessage()); + } + } + + public void playBackgroundMusic() { + if (backgroundMusic != null && musicEnabled && !backgroundMusic.isPlaying()) { + backgroundMusic.play(); + } + } + + public void pauseBackgroundMusic() { + if (backgroundMusic != null && backgroundMusic.isPlaying()) { + backgroundMusic.pause(); + } + } + + public void resumeBackgroundMusic() { + if (backgroundMusic != null && musicEnabled && !backgroundMusic.isPlaying()) { + backgroundMusic.play(); + } + } + + public void playShootSound() { + if (shootSound != null && soundEnabled) { + shootSound.play(soundVolume); + } + } + + public void playRocketSound() { + if (rocketSound != null && soundEnabled) { + rocketSound.play(soundVolume); + } + } + + public void playExplosionSound() { + if (explosionSound != null && soundEnabled) { + explosionSound.play(soundVolume); + } + } + + public void playSelectSound() { + if (selectSound != null && soundEnabled) { + selectSound.play(soundVolume); + } + } + + public boolean isMusicEnabled() { + return musicEnabled; + } + + public void setMusicEnabled(boolean enabled) { + musicEnabled = enabled; + MemoryManager.saveMusicSettings(musicEnabled); + if (musicEnabled) { + playBackgroundMusic(); + } else { + pauseBackgroundMusic(); + } + } + + public boolean isSoundEnabled() { + return soundEnabled; + } + + public void setSoundEnabled(boolean enabled) { + soundEnabled = enabled; + MemoryManager.saveSoundSettings(soundEnabled); + } + + public void toggleMusic() { + setMusicEnabled(!musicEnabled); + } + + public void toggleSound() { + setSoundEnabled(!soundEnabled); + } + + public void dispose() { + if (backgroundMusic != null) backgroundMusic.dispose(); + if (shootSound != null) shootSound.dispose(); + if (rocketSound != null) rocketSound.dispose(); + if (explosionSound != null) explosionSound.dispose(); + if (selectSound != null) selectSound.dispose(); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/objects/Bullet.java b/core/src/com/mygdx/game/objects/Bullet.java new file mode 100644 index 0000000..633c2ac --- /dev/null +++ b/core/src/com/mygdx/game/objects/Bullet.java @@ -0,0 +1,78 @@ +package com.mygdx.game.objects; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.MathUtils; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; + +public class Bullet { + private float x, y; + private float width = 10, height = 20; + private Texture texture; + private float speed; + private float angle; + private int damage; + private boolean isPlayer; + private boolean isRocket; + private boolean active = true; + + public Bullet() { + + } + + public void init(float x, float y, float angle, boolean isPlayer, boolean isRocket) { + this.x = x; + this.y = y; + this.angle = angle; + this.isPlayer = isPlayer; + this.isRocket = isRocket; + + if (isRocket) { + texture = new Texture(GameResources.BULLET_ROCKET_PATH); + width = 15; + height = 30; + speed = GameSettings.ROCKET_SPEED; + damage = GameSettings.ROCKET_DAMAGE; + } else { + texture = new Texture(GameResources.BULLET_BASIC_PATH); + width = 8; + height = 16; + speed = GameSettings.BULLET_SPEED; + damage = GameSettings.BULLET_DAMAGE; + } + } + + public void update(float delta) { + x += MathUtils.cos(angle) * speed * delta; + y += MathUtils.sin(angle) * speed * delta; + } + + public void draw(SpriteBatch batch) { + if (active && texture != null) { + batch.draw(texture, x - width/2, y - height/2, width, height); + } + } + + public float getX() { + return x; + } + + public float getY() { + return y; + } + + public float getWidth() { + return width; + } + + public int getDamage() { + return damage; + } + + public void dispose() { + if (texture != null) { + texture.dispose(); + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/objects/EnemyPlane.java b/core/src/com/mygdx/game/objects/EnemyPlane.java new file mode 100644 index 0000000..ef5f7df --- /dev/null +++ b/core/src/com/mygdx/game/objects/EnemyPlane.java @@ -0,0 +1,173 @@ +package com.mygdx.game.objects; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.MathUtils; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; + +public class EnemyPlane { + public float x, y; + private float width, height; + private Texture texture; + private float speed; + private float rotation; + private float moveAngle; + private int health; + private int maxHealth; + private int level; + private int enemyType; + + private boolean isDead = false; + private float deadTimer = 0; + private int deadFrame = 0; + private Texture[] deadTextures; + + + + public EnemyPlane(float startX, float startY, int level, float multiplier) { + this.x = startX; + this.y = startY; + this.level = level; + + enemyType = (int)(Math.random() * 3); + + if (enemyType == 0) { + texture = new Texture(GameResources.ENEMY_BASIC_PATH); + health = (int)(30 * multiplier); + speed = 150 * multiplier; + width = 60; + height = 60; + // Анимация + deadTextures = new Texture[3]; + deadTextures[0] = new Texture(GameResources.EXPLOSION_PATH); + deadTextures[1] = new Texture(GameResources.ENEMY_FALLING1_PATH); + deadTextures[2] = new Texture(GameResources.ENEMY_FALLING2_PATH); + } else if (enemyType == 1) { // Быстрый + texture = new Texture(GameResources.ENEMY_FAST_PATH); + health = (int)(20 * multiplier); + speed = 250 * multiplier; + width = 50; + height = 50; + deadTextures = new Texture[3]; + deadTextures[0] = new Texture(GameResources.EXPLOSION_PATH); + deadTextures[1] = new Texture(GameResources.ENEMY_FAST_FALLING1_PATH); + deadTextures[2] = new Texture(GameResources.ENEMY_FAST_FALLING2_PATH); + } else { + texture = new Texture(GameResources.ENEMY_TANK_PATH); + health = (int)(80 * multiplier); + speed = 100 * multiplier; + width = 80; + height = 80; + deadTextures = new Texture[3]; + deadTextures[0] = new Texture(GameResources.EXPLOSION_PATH); + deadTextures[1] = new Texture(GameResources.ENEMY_TANK_FALLING1_PATH); + deadTextures[2] = new Texture(GameResources.ENEMY_TANK_FALLING2_PATH); + } + + if (Math.random() < GameSettings.BOSS_CHANCE) { + enemyType = 3; + texture = new Texture(GameResources.ENEMY_BOSS_PATH); + health = (int)(150 * multiplier); + speed = 80 * multiplier; + width = 120; + height = 120; + deadTextures = new Texture[3]; + deadTextures[0] = new Texture(GameResources.EXPLOSION_PATH); + deadTextures[1] = new Texture(GameResources.ENEMY_BOSS_FALLING1_PATH); + deadTextures[2] = new Texture(GameResources.ENEMY_BOSS_FALLING2_PATH); + } + + this.maxHealth = health; + + moveAngle = (float)(Math.random() * Math.PI * 2); + rotation = moveAngle * 180 / (float)Math.PI - 90; + } + + public void update(float delta, float playerX, float playerY) { + if (isDead) { + deadTimer += delta; + + if (deadTimer >= 0.15f) { + deadTimer = 0; + deadFrame++; + } + return; + } + + x += MathUtils.cos(moveAngle) * speed * delta; + y += MathUtils.sin(moveAngle) * speed * delta; + + if (Math.random() < 0.005f) { + moveAngle = (float)(Math.random() * Math.PI * 2); + rotation = moveAngle * 180 / (float)Math.PI - 90; + } + } + + public void draw(SpriteBatch batch) { + if (isDead) { + int frame = deadFrame; + if (frame >= deadTextures.length) { + frame = deadTextures.length - 1; + } + + if (frame == 0) { + batch.draw(deadTextures[frame], x - width, y - height, width * 2, height * 2); + } else { + batch.draw(deadTextures[frame], x - width/2, y - height/2, width, height); + } + } else { + batch.draw(texture, x - width/2, y - height/2, width, height); + } + } + + public void kill() { + if (!isDead) { + isDead = true; + deadTimer = 0; + deadFrame = 0; + } + } + + public boolean isDead() { + return isDead; + } + + public boolean isAnimationFinished() { + return deadFrame >= deadTextures.length; + } + + + + public float getX() { return x; } + public float getY() { return y; } + public float getWidth() { return width; } + + + public boolean takeDamage(int damage) { + health -= damage; + if (health <= 0) { + kill(); + return true; + } + return false; + } + + + public boolean collidesWith(float bulletX, float bulletY, float bulletRadius) { + if (isDead) return false; + float dx = x - bulletX; + float dy = y - bulletY; + float distance = (float) Math.sqrt(dx * dx + dy * dy); + return distance < (width/2 + bulletRadius); + } + + public void dispose() { + if (texture != null) texture.dispose(); + if (deadTextures != null) { + for (Texture t : deadTextures) { + if (t != null) t.dispose(); + } + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/objects/PlayerPlane.java b/core/src/com/mygdx/game/objects/PlayerPlane.java new file mode 100644 index 0000000..626df52 --- /dev/null +++ b/core/src/com/mygdx/game/objects/PlayerPlane.java @@ -0,0 +1,168 @@ +package com.mygdx.game.objects; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.MathUtils; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; + +public class PlayerPlane { + public float x, y; + private float width = 80, height = 80; + private Texture texture; + + private float speed; + private float speedMultiplier = 1.0f; + private float rotation = 90f; + private float rotationSpeed = 180f; + + private int health; + private int maxHealth; + private int playerType; + + private boolean isRocket = false; + + public PlayerPlane(float startX, float startY, int playerType) { + this.x = startX; + this.y = startY; + this.playerType = playerType; + + System.out.println("PlayerPlane: Конструктор вызван"); + System.out.println("StartX = " + startX + " StartY = " + startY); + + GameSettings.PlayerConfig config = GameSettings.PLAYERS[playerType]; + + switch (playerType) { + case 0: + texture = new Texture(GameResources.PLAYER_BASIC_PATH); + break; + case 1: + texture = new Texture(GameResources.PLAYER_FAST_PATH); + break; + case 2: + texture = new Texture(GameResources.PLAYER_TANK_PATH); + break; + default: + texture = new Texture(GameResources.PLAYER_BASIC_PATH); + } + + this.speed = config.speed; + this.rotationSpeed = config.rotationSpeed; + this.health = config.health; + this.maxHealth = config.health; + + System.out.println("Speed = " + speed); + System.out.println("RotationSpeed = " + rotationSpeed); + System.out.println("Health = " + health); + } + + public void update(float delta) { + float angleRad = rotation * MathUtils.degreesToRadians; + float dx = MathUtils.cos(angleRad) * speed * speedMultiplier * delta; + float dy = MathUtils.sin(angleRad) * speed * speedMultiplier * delta; + + x += dx; + y += dy; + + + } + + public void draw(SpriteBatch batch) { + + batch.draw(texture, + x - width/2, y - height/2, + width/2, height/2, + width, height, + 1, 1, + rotation, + 0, 0, + texture.getWidth(), + texture.getHeight(), + false, false); + } + + public void rotateLeft(float delta) { + rotation += rotationSpeed * delta; + + } + + public void rotateRight(float delta) { + rotation -= rotationSpeed * delta; + + } + + public void switchWeapon() { + isRocket = !isRocket; + System.out.println("switchWeapon: isRocket=" + isRocket); + } + + public boolean isRocket() { + return isRocket; + } + + public float getShootAngle() { + return rotation * MathUtils.degreesToRadians; + } + + public float[] getGunPosition() { + float angleRad = rotation * MathUtils.degreesToRadians; + float gunX = x + MathUtils.cos(angleRad) * 50; + float gunY = y + MathUtils.sin(angleRad) * 50; + return new float[]{gunX, gunY}; + } + + public float getX() { + return x; + } + + public float getY() { + return y; + } + + + + public void setSpeedMultiplier(float multiplier) { + this.speedMultiplier = multiplier; + System.out.println("setSpeedMultiplier: " + multiplier); + } + + public int getHealth() { + return health; + } + + public int getMaxHealth() { + return maxHealth; + } + + + + public void takeDamage(int damage) { + health -= damage; + if (health < 0) { + health = 0; + } + System.out.println("takeDamage: damage=" + damage + " health=" + health); + } + + public boolean isAlive() { + return health > 0; + } + + public boolean collidesWith(float otherX, float otherY, float radius) { + float dx = x - otherX; + float dy = y - otherY; + float distance = (float) Math.sqrt(dx * dx + dy * dy); + boolean collision = distance < (width/2 + radius); + if (collision) { + System.out.println("COLLISION: distance=" + distance); + } + return collision; + } + + public void dispose() { + System.out.println("PlayerPlane: dispose"); + if (texture != null) { + texture.dispose(); + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/screens/GameOverScreen.java b/core/src/com/mygdx/game/screens/GameOverScreen.java new file mode 100644 index 0000000..a1b6425 --- /dev/null +++ b/core/src/com/mygdx/game/screens/GameOverScreen.java @@ -0,0 +1,143 @@ +package com.mygdx.game.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; +import com.mygdx.game.MyGdxGame; +import com.mygdx.game.components.ButtonView; +import com.mygdx.game.components.ImageView; +import com.mygdx.game.components.TextView; +import com.mygdx.game.managers.MemoryManager; + +public class GameOverScreen extends ScreenAdapter { + private MyGdxGame game; + private SpriteBatch batch; + private ImageView background; + + private TextView titleTextView; + private TextView scoreTextView; + private TextView highScoreTextView; + private ButtonView restartButton; + private ButtonView menuButton; + + private int finalScore; + + public GameOverScreen(MyGdxGame game) { + this.game = game; + this.batch = game.batch; + } + + public void setScore(int score) { + this.finalScore = score; + MemoryManager.saveHighScore(score); + } + + @Override + public void render(float delta) { + Gdx.gl.glClearColor(0.3f, 0.1f, 0.1f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + game.camera.update(); + batch.setProjectionMatrix(game.camera.combined); + + handleInput(); + + batch.begin(); + + if (background == null) { + background = new ImageView(0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.GAME_OVER_BG_PATH); + } + background.draw(batch); + + titleTextView.draw(batch); + scoreTextView.draw(batch); + highScoreTextView.draw(batch); + restartButton.draw(batch); + menuButton.draw(batch); + + batch.end(); + } + + private void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + game.camera.unproject(touchPos); + + if (restartButton.isHit(touchPos.x, touchPos.y)) { + game.startNewGame(); + if (game.soundManager != null) { + game.soundManager.playSelectSound(); + } + return; + } + + if (menuButton.isHit(touchPos.x, touchPos.y)) { + game.setScreen(game.menuScreen); + if (game.soundManager != null) { + game.soundManager.playSelectSound(); + } + return; + } + } + } + + @Override + public void show() { + float centerX = GameSettings.SCREEN_WIDTH / 2f; + + if (background == null) { + background = new ImageView(0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.GAME_OVER_BG_PATH); + } + + titleTextView = new TextView(game.titleFont, + centerX - 150, + GameSettings.SCREEN_HEIGHT - 200, + "ИГРА ОКОНЧЕНА"); + + scoreTextView = new TextView(game.buttonFont, + centerX - 100, + GameSettings.SCREEN_HEIGHT - 300, + "УНИЧТОЖЕНО: " + finalScore); + + int bestRecord = MemoryManager.getHighScore(); + highScoreTextView = new TextView(game.buttonFont, + centerX - 150, + GameSettings.SCREEN_HEIGHT - 350, + "ЛУЧШИЙ РЕЗУЛЬТАТ: " + bestRecord); + + restartButton = new ButtonView( + centerX - 150, 300, 300, 80, + game.buttonFont, + GameResources.BUTTON_PATH, + "ЗАНОВО" + ); + + menuButton = new ButtonView( + centerX - 150, 200, 300, 80, + game.buttonFont, + GameResources.BUTTON_PATH, + "МЕНЮ" + ); + + if (game.soundManager != null) { + game.soundManager.playBackgroundMusic(); + } + } + + @Override + public void dispose() { + if (background != null) background.dispose(); + if (restartButton != null) restartButton.dispose(); + if (menuButton != null) menuButton.dispose(); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/screens/GameScreen.java b/core/src/com/mygdx/game/screens/GameScreen.java new file mode 100644 index 0000000..4d0d3e8 --- /dev/null +++ b/core/src/com/mygdx/game/screens/GameScreen.java @@ -0,0 +1,704 @@ +package com.mygdx.game.screens; + +import static com.mygdx.game.GameSettings.*; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.*; +import com.mygdx.game.components.*; +import com.mygdx.game.objects.*; + +import java.util.ArrayList; +import java.util.Iterator; + +public class GameScreen extends ScreenAdapter { + + private MyGdxGame game; + private SpriteBatch batch; + + private OrthographicCamera gameCamera; + + private PlayerPlane player; + private ArrayList enemies; + private ArrayList playerBullets; + private ArrayList enemyBullets; + private ArrayList explosions; + + private Texture backgroundTexture; + private Texture healthBarBg; + private Texture healthBarFill; + private Texture explosionTexture; + + private ButtonView pauseButton; + private ButtonView weaponButton; + private ButtonView rotateLeftButton; + private ButtonView rotateRightButton; + private ButtonView attackButton; + private ButtonView speed50Button; + private ButtonView speed80Button; + private ButtonView speed100Button; + + private ButtonView resumeButton; + private ButtonView settingsButton; + private ButtonView menuButton; + + private TextView scoreText; + private TextView levelText; + private TextView enemiesText; + private TextView speedText; + private TextView weaponIndicator; + + private int currentLevel; + private float enemySpawnTimer; + private int currentSpeedLevel; + private boolean isPaused; + private boolean rotatingLeft; + private boolean rotatingRight; + private boolean isAttacking; + private float autoShootTimer; + private int score; + private float shootCooldown; + private int enemiesToDefeat; + private int defeatedEnemies; + + public GameScreen(MyGdxGame game) { + this.game = game; + this.batch = game.batch; + this.currentLevel = game.selectedLevel; + + System.out.println("=== GameScreen создан ==="); + System.out.println("Выбран уровень: " + currentLevel); + + startNewGame(); + } + + private void startNewGame() { + System.out.println("Запуск новой игры"); + + gameCamera = new OrthographicCamera(); + gameCamera.setToOrtho(false, SCREEN_WIDTH, SCREEN_HEIGHT); + + LevelConfig levelConfig = LEVELS[currentLevel]; + backgroundTexture = new Texture(Gdx.files.internal(levelConfig.backgroundPath)); + + healthBarBg = new Texture(Gdx.files.internal(GameResources.HEALTH_BG_PATH)); + healthBarFill = new Texture(Gdx.files.internal(GameResources.HEALTH_FILL_PATH)); + explosionTexture = new Texture(Gdx.files.internal(GameResources.EXPLOSION_PATH)); + + enemiesToDefeat = GameSettings.getEnemyCountForLevel(levelConfig.enemyCount); + System.out.println("Врагов нужно убить: " + enemiesToDefeat); + + player = new PlayerPlane(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, game.selectedPlayer); + player.setSpeedMultiplier(SPEED_LEVELS[currentSpeedLevel]); + + enemies = new ArrayList<>(); + playerBullets = new ArrayList<>(); + enemyBullets = new ArrayList<>(); + explosions = new ArrayList<>(); + + createButtons(); + createText(); + resetGameVariables(); + } + + private void createButtons() { + float btnSize = 80; + float bigW = 300; + float bigH = 100; + + pauseButton = new ButtonView( + SCREEN_WIDTH / 2 - btnSize / 2, + SCREEN_HEIGHT - btnSize - 20, + btnSize, btnSize, + GameResources.BUTTON_PAUSE_PATH + ); + + weaponButton = new ButtonView( + 20, 20, + btnSize, btnSize, + GameResources.BUTTON_WEAPON_PATH + ); + + float rotY = 20; + float rotSpacing = 10; + + rotateLeftButton = new ButtonView( + SCREEN_WIDTH - 1000 - btnSize - rotSpacing, + rotY, + btnSize, btnSize, + GameResources.BUTTON_LEFT_PATH + ); + + rotateRightButton = new ButtonView( + SCREEN_WIDTH - 1000 + rotSpacing, + rotY, + btnSize, btnSize, + GameResources.BUTTON_RIGHT_PATH + ); + + attackButton = new ButtonView( + SCREEN_WIDTH - btnSize - 20, + 20, + btnSize, btnSize, + GameResources.BUTTON_ATTACK_PATH + ); + + float speedY = 150; + float speedSize = 70; + float speedSpacing = 10; + + speed50Button = new ButtonView( + SCREEN_WIDTH - speedSize - 20, + speedY, + speedSize, speedSize, + GameResources.BUTTON_SPEED_PATH + ); + + speed80Button = new ButtonView( + SCREEN_WIDTH - speedSize - 20, + speedY + speedSize + speedSpacing, + speedSize, speedSize, + GameResources.BUTTON_SPEED_PATH + ); + + speed100Button = new ButtonView( + SCREEN_WIDTH - speedSize - 20, + speedY + (speedSize + speedSpacing) * 2, + speedSize, speedSize, + GameResources.BUTTON_SPEED_PATH + ); + + float centerX = SCREEN_WIDTH / 2 - bigW / 2; + float centerY = SCREEN_HEIGHT / 2; + + resumeButton = new ButtonView( + centerX, centerY + 120, + bigW, bigH, + game.buttonFont, + GameResources.BUTTON_PATH, + "ПРОДОЛЖИТЬ" + ); + resumeButton.setTextColor(Color.BLACK); + + settingsButton = new ButtonView( + centerX, centerY, + bigW, bigH, + game.buttonFont, + GameResources.BUTTON_PATH, + "НАСТРОЙКИ" + ); + settingsButton.setTextColor(Color.BLACK); + + menuButton = new ButtonView( + centerX, centerY - 120, + bigW, bigH, + game.buttonFont, + GameResources.BUTTON_PATH, + "ГЛАВНОЕ МЕНЮ" + ); + menuButton.setTextColor(Color.BLACK); + } + + private void createText() { + float leftX = 20; + + levelText = new TextView( + game.smallFont, + leftX, SCREEN_HEIGHT - 40, + "Уровень: " + LEVELS[currentLevel].name + ); + levelText.setColor(Color.WHITE); + + scoreText = new TextView( + game.smallFont, + leftX, SCREEN_HEIGHT - 70, + "Очки: 0" + ); + scoreText.setColor(Color.WHITE); + + enemiesText = new TextView( + game.smallFont, + leftX, SCREEN_HEIGHT - 100, + "Враги: 0/" + enemiesToDefeat + ); + enemiesText.setColor(Color.WHITE); + + speedText = new TextView( + game.smallFont, + SCREEN_WIDTH - 200, 130, + "Скорость: 100%" + ); + speedText.setColor(Color.WHITE); + + weaponIndicator = new TextView( + game.buttonFont, + 20, 200, + "ОРУЖИЕ: ПУЛИ" + ); + weaponIndicator.setColor(Color.WHITE); + } + + private void resetGameVariables() { + enemySpawnTimer = 0; + currentSpeedLevel = 2; + isPaused = false; + rotatingLeft = false; + rotatingRight = false; + isAttacking = false; + autoShootTimer = 0; + score = 0; + shootCooldown = 0; + defeatedEnemies = 0; + } + + @Override + public void render(float delta) { + Gdx.gl.glClearColor(0.1f, 0.1f, 0.2f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + if (!isPaused) { + updateGame(delta); + } + + updateCamera(); + drawGame(); + drawInterface(); + handleInput(); + } + //------------------------------- + private void updateGame(float delta) { + player.update(delta); + + if (rotatingLeft) { + player.rotateLeft(delta); + } + if (rotatingRight) { + player.rotateRight(delta); + } + + if (isAttacking) { + if (autoShootTimer <= 0) { + playerShoot(); + if (player.isRocket()) { + autoShootTimer = ROCKET_COOLDOWN; + } else { + autoShootTimer = BULLET_COOLDOWN; + } + } else { + autoShootTimer -= delta; + } + } + + updateText(); + + if (shootCooldown > 0) { + shootCooldown -= delta; + } + + updateEnemies(delta); + updatePlayerBullets(delta); + updateEnemyBullets(delta); + updateEnemySpawn(delta); + updateExplosions(delta); + + if (!player.isAlive()) { + gameOver(); + } + } + + private void updateEnemies(float delta) { + Iterator it = enemies.iterator(); + while (it.hasNext()) { + EnemyPlane enemy = it.next(); + + if (enemy.isDead()) { + enemy.update(delta, player.getX(), player.getY()); + if (enemy.isAnimationFinished()) { + it.remove(); + } + continue; + } + + enemy.update(delta, player.getX(), player.getY()); + + if (Math.random() < ENEMY_SHOOT_PROBABILITY) { + shootFromEnemy(enemy); + } + + if (player.collidesWith(enemy.getX(), enemy.getY(), enemy.getWidth()/2)) { + player.takeDamage(PLAYER_COLLISION_DAMAGE); + it.remove(); + } + } + } + + private void updatePlayerBullets(float delta) { + Iterator it = playerBullets.iterator(); + while (it.hasNext()) { + Bullet bullet = it.next(); + bullet.update(delta); + + float dx = bullet.getX() - player.getX(); + float dy = bullet.getY() - player.getY(); + if (dx * dx + dy * dy > BULLET_DESPAWN_DISTANCE * BULLET_DESPAWN_DISTANCE) { + it.remove(); + continue; + } + + Iterator enemyIt = enemies.iterator(); + while (enemyIt.hasNext()) { + EnemyPlane enemy = enemyIt.next(); + if (enemy.collidesWith(bullet.getX(), bullet.getY(), bullet.getWidth()/2)) { + if (enemy.takeDamage(bullet.getDamage())) { + score += SCORE_PER_ENEMY; + defeatedEnemies++; + game.soundManager.playExplosionSound(); + System.out.println("Враг уничтожен! " + defeatedEnemies + "/" + enemiesToDefeat); + + if (defeatedEnemies >= enemiesToDefeat) { + levelComplete(); + return; + } + } + it.remove(); + break; + } + } + } + } + + private void updateEnemyBullets(float delta) { + Iterator it = enemyBullets.iterator(); + while (it.hasNext()) { + Bullet bullet = it.next(); + bullet.update(delta); + + if (player.collidesWith(bullet.getX(), bullet.getY(), bullet.getWidth()/2)) { + player.takeDamage(BULLET_COLLISION_DAMAGE); + it.remove(); + continue; + } + + float dx = bullet.getX() - player.getX(); + float dy = bullet.getY() - player.getY(); + if (dx * dx + dy * dy > BULLET_DESPAWN_DISTANCE * BULLET_DESPAWN_DISTANCE) { + it.remove(); + } + } + } + + private void updateEnemySpawn(float delta) { + enemySpawnTimer += delta; + if (enemySpawnTimer >= ENEMY_SPAWN_RATE) { + int maxSpawn = enemiesToDefeat * 2; + if (enemies.size() < maxSpawn) { + spawnEnemy(); + } + enemySpawnTimer = 0; + } + } + + + + private void updateExplosions(float delta) { + for (int i = 0; i < explosions.size(); i++) { + float[] exp = explosions.get(i); + exp[2] -= delta; + if (exp[2] <= 0) { + explosions.remove(i); + i--; + } + } + } +//---------------------- + private void drawExplosions() { + for (float[] exp : explosions) { + float alpha = exp[2] / 0.3f; + batch.setColor(1, 1, 1, alpha); + batch.draw(explosionTexture, exp[0] - 40, exp[1] - 40, 80, 80); + batch.setColor(1, 1, 1, 1); + } + } + + private void spawnEnemy() { + float angle = (float) (Math.random() * Math.PI * 2); + float distance = 600 + (float) (Math.random() * 300); + + float x = player.getX() + (float) Math.cos(angle) * distance; + float y = player.getY() + (float) Math.sin(angle) * distance; + + float multiplier = getDifficultyMultiplier(); + enemies.add(new EnemyPlane(x, y, currentLevel, multiplier)); + } + + private void shootFromEnemy(EnemyPlane enemy) { + float dx = player.getX() - enemy.getX(); + float dy = player.getY() - enemy.getY(); + float angle = (float) Math.atan2(dy, dx); + + Bullet bullet = new Bullet(); + bullet.init(enemy.getX(), enemy.getY(), angle, false, false); + enemyBullets.add(bullet); + } + + private void playerShoot() { + if (shootCooldown > 0) { + return; + } + + float[] gunPos = player.getGunPosition(); + Bullet bullet = new Bullet(); + bullet.init(gunPos[0], gunPos[1], player.getShootAngle(), true, player.isRocket()); + playerBullets.add(bullet); + + if (player.isRocket()) { + game.soundManager.playRocketSound(); + shootCooldown = ROCKET_COOLDOWN; + } else { + game.soundManager.playShootSound(); + shootCooldown = BULLET_COOLDOWN; + } + } + + private void updateText() { + scoreText.setText("Очки: " + score); + enemiesText.setText("Враги: " + defeatedEnemies + "/" + enemiesToDefeat); + } + + private void updateCamera() { + gameCamera.position.set(player.getX(), player.getY(), 0); + gameCamera.update(); + } + + private void drawGame() { + batch.setProjectionMatrix(gameCamera.combined); + batch.begin(); + + float w = backgroundTexture.getWidth(); + float h = backgroundTexture.getHeight(); + + float left = gameCamera.position.x - SCREEN_WIDTH; + float right = gameCamera.position.x + SCREEN_WIDTH; + float bottom = gameCamera.position.y - SCREEN_HEIGHT; + float top = gameCamera.position.y + SCREEN_HEIGHT; + + int startCol = (int)Math.floor(left / w); + int endCol = (int)Math.ceil(right / w); + int startRow = (int)Math.floor(bottom / h); + int endRow = (int)Math.ceil(top / h); + + for (int col = startCol; col <= endCol; col++) { + for (int row = startRow; row <= endRow; row++) { + float x = col * w; + float y = row * h; + batch.draw(backgroundTexture, x, y, w, h); + } + } + + player.draw(batch); + + for (EnemyPlane enemy : enemies) { + enemy.draw(batch); + } + + for (Bullet bullet : playerBullets) { + bullet.draw(batch); + } + + for (Bullet bullet : enemyBullets) { + bullet.draw(batch); + } + + drawExplosions(); + + batch.end(); + } + + private void drawInterface() { + batch.setProjectionMatrix(game.camera.combined); + batch.begin(); + + pauseButton.draw(batch); + weaponButton.draw(batch); + rotateLeftButton.draw(batch); + rotateRightButton.draw(batch); + attackButton.draw(batch); + speed50Button.draw(batch); + speed80Button.draw(batch); + speed100Button.draw(batch); + + levelText.draw(batch); + scoreText.draw(batch); + enemiesText.draw(batch); + speedText.draw(batch); + weaponIndicator.draw(batch); + + float healthPercent = (float)player.getHealth() / player.getMaxHealth(); + batch.draw(healthBarBg, SCREEN_WIDTH - 220, SCREEN_HEIGHT - 60, 200, 20); + batch.draw(healthBarFill, SCREEN_WIDTH - 220, SCREEN_HEIGHT - 60, 200 * healthPercent, 20); + + if (isPaused) { + batch.setColor(0, 0, 0, 0.7f); + Texture black = new Texture(Gdx.files.internal(GameResources.BUTTON_PATH)); + batch.draw(black, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + black.dispose(); + batch.setColor(Color.WHITE); + + game.titleFont.draw(batch, "ПАУЗА", SCREEN_WIDTH/2 - 100, SCREEN_HEIGHT - 100); + + resumeButton.draw(batch); + settingsButton.draw(batch); + menuButton.draw(batch); + } + + batch.end(); + } + + private void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touch = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + game.camera.unproject(touch); + + if (isPaused) { + if (resumeButton.isHit(touch.x, touch.y)) { + isPaused = false; + game.soundManager.playSelectSound(); + } + else if (settingsButton.isHit(touch.x, touch.y)) { + game.isFromGame = true; + game.setScreen(game.settingsScreen); + game.soundManager.playSelectSound(); + } + else if (menuButton.isHit(touch.x, touch.y)) { + returnToMenu(); + } + } else { + if (pauseButton.isHit(touch.x, touch.y)) { + isPaused = true; + game.soundManager.playSelectSound(); + } + else if (weaponButton.isHit(touch.x, touch.y)) { + player.switchWeapon(); + if (player.isRocket()) { + weaponIndicator.setText("ОРУЖИЕ: РАКЕТЫ"); + } else { + weaponIndicator.setText("ОРУЖИЕ: ПУЛИ"); + } + game.soundManager.playSelectSound(); + } + else if (speed50Button.isHit(touch.x, touch.y)) { + setSpeedLevel(0); + } + else if (speed80Button.isHit(touch.x, touch.y)) { + setSpeedLevel(1); + } + else if (speed100Button.isHit(touch.x, touch.y)) { + setSpeedLevel(2); + } + else if (rotateLeftButton.isHit(touch.x, touch.y)) { + rotatingLeft = true; + rotatingRight = false; + } + else if (rotateRightButton.isHit(touch.x, touch.y)) { + rotatingRight = true; + rotatingLeft = false; + } + else if (attackButton.isHit(touch.x, touch.y)) { + isAttacking = true; + } + } + } + + if (!Gdx.input.isTouched()) { + isAttacking = false; + rotatingLeft = false; + rotatingRight = false; + } + } + + private void setSpeedLevel(int level) { + currentSpeedLevel = level; + player.setSpeedMultiplier(SPEED_LEVELS[level]); + + if (level == 0) { + speedText.setText("Скорость: 50%"); + } else if (level == 1) { + speedText.setText("Скорость: 80%"); + } else { + speedText.setText("Скорость: 100%"); + } + + game.soundManager.playSelectSound(); + } + + private void gameOver() { + game.gameOverScreen.setScore(score); + game.setScreen(game.gameOverScreen); + game.soundManager.playExplosionSound(); + } + + private void levelComplete() { + game.gameOverScreen.setScore(score); + game.setScreen(game.gameOverScreen); + } + + private void returnToMenu() { + disposeGameObjects(); + game.setScreen(game.menuScreen); + game.soundManager.playSelectSound(); + } + + private void disposeGameObjects() { + if (player != null) player.dispose(); + for (EnemyPlane e : enemies) e.dispose(); + for (Bullet b : playerBullets) b.dispose(); + for (Bullet b : enemyBullets) b.dispose(); + + enemies.clear(); + playerBullets.clear(); + enemyBullets.clear(); + explosions.clear(); + } + + @Override + public void show() { + if (game.soundManager != null) { + game.soundManager.playBackgroundMusic(); + } + } + + @Override + public void hide() { + if (game.soundManager != null) { + game.soundManager.pauseBackgroundMusic(); + } + } + + @Override + public void dispose() { + disposeGameObjects(); + + if (backgroundTexture != null) backgroundTexture.dispose(); + if (healthBarBg != null) healthBarBg.dispose(); + if (healthBarFill != null) healthBarFill.dispose(); + if (explosionTexture != null) explosionTexture.dispose(); + + if (pauseButton != null) pauseButton.dispose(); + if (weaponButton != null) weaponButton.dispose(); + if (rotateLeftButton != null) rotateLeftButton.dispose(); + if (rotateRightButton != null) rotateRightButton.dispose(); + if (attackButton != null) attackButton.dispose(); + if (speed50Button != null) speed50Button.dispose(); + if (speed80Button != null) speed80Button.dispose(); + if (speed100Button != null) speed100Button.dispose(); + if (resumeButton != null) resumeButton.dispose(); + if (settingsButton != null) settingsButton.dispose(); + if (menuButton != null) menuButton.dispose(); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/screens/LevelSelectScreen.java b/core/src/com/mygdx/game/screens/LevelSelectScreen.java new file mode 100644 index 0000000..4014b65 --- /dev/null +++ b/core/src/com/mygdx/game/screens/LevelSelectScreen.java @@ -0,0 +1,178 @@ +package com.mygdx.game.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; +import com.mygdx.game.MyGdxGame; +import com.mygdx.game.components.ButtonView; +import com.mygdx.game.components.ImageView; +import com.mygdx.game.components.TextView; + +public class LevelSelectScreen extends ScreenAdapter { + private MyGdxGame game; + private SpriteBatch batch; + private ImageView background; + + private TextView titleTextView; + private ButtonView[] levelButtons; + private ButtonView backButton; + + public LevelSelectScreen(MyGdxGame game) { + this.game = game; + this.batch = game.batch; + this.background = null; + this.levelButtons = null; + this.backButton = null; + + init(); + } + + private void init() { + // Фон + try { + background = new ImageView(0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.LEVEL_SELECT_BG_PATH); + } catch (Exception e) { + background = new ImageView(0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.MENU_BG_IMG_PATH); + } + + float centerX = GameSettings.SCREEN_WIDTH / 2f; + + titleTextView = new TextView(game.titleFont, + centerX - 200, + GameSettings.SCREEN_HEIGHT - 150, + "ВЫБОР УРОВНЯ"); + + levelButtons = new ButtonView[GameSettings.LEVELS.length]; + + for (int i = 0; i < GameSettings.LEVELS.length; i++) { + int levelNum = i + 1; + String levelName = GameSettings.LEVELS[i].name; + String buttonText = levelNum + ". " + levelName; + + levelButtons[i] = new ButtonView( + centerX - 150, + 400 - i * 100, + 300, 80, + game.buttonFont, + GameResources.BUTTON_PATH, + buttonText + ); + } + + backButton = new ButtonView( + centerX - 150, 100, 300, 80, + game.buttonFont, + GameResources.BUTTON_PATH, + "НАЗАД" + ); + } + + @Override + public void render(float delta) { + Gdx.gl.glClearColor(0.1f, 0.2f, 0.3f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + game.camera.update(); + batch.setProjectionMatrix(game.camera.combined); + + handleInput(); + + batch.begin(); + + if (background != null) { + background.draw(batch); + } + + titleTextView.draw(batch); + + if (levelButtons != null) { + for (ButtonView button : levelButtons) { + if (button != null) { + button.draw(batch); + } + } + } + + if (backButton != null) { + backButton.draw(batch); + } + + batch.end(); + } + + private void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + game.camera.unproject(touchPos); + + if (levelButtons != null) { + for (int i = 0; i < levelButtons.length; i++) { + if (levelButtons[i] != null && levelButtons[i].isHit(touchPos.x, touchPos.y)) { + game.selectedLevel = i; + System.out.println("Выбран уровень: " + (i + 1) + " - " + GameSettings.LEVELS[i].name); + + if (game.gameScreen != null) { + game.gameScreen.dispose(); + game.gameScreen = null; + } + game.gameScreen = new GameScreen(game); + game.setScreen(game.gameScreen); + + if (game.soundManager != null) game.soundManager.playSelectSound(); + return; + } + } + } + + if (backButton != null && backButton.isHit(touchPos.x, touchPos.y)) { + System.out.println("Возврат в меню"); + game.setScreen(game.menuScreen); + if (game.soundManager != null) game.soundManager.playSelectSound(); + } + } + } + + @Override + public void show() { + System.out.println("Показан экран выбора уровня"); + System.out.println("Доступно уровней: " + GameSettings.LEVELS.length); + + if (game.soundManager != null) { + game.soundManager.playBackgroundMusic(); + } + } + + @Override + public void dispose() { + System.out.println("Освобождение ресурсов LevelSelectScreen"); + + if (background != null) { + background.dispose(); + background = null; + } + + if (levelButtons != null) { + for (ButtonView button : levelButtons) { + if (button != null) { + button.dispose(); + } + } + levelButtons = null; + } + + if (backButton != null) { + backButton.dispose(); + backButton = null; + } + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/screens/MenuScreen.java b/core/src/com/mygdx/game/screens/MenuScreen.java new file mode 100644 index 0000000..d36841a --- /dev/null +++ b/core/src/com/mygdx/game/screens/MenuScreen.java @@ -0,0 +1,146 @@ +package com.mygdx.game.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; +import com.mygdx.game.MyGdxGame; +import com.mygdx.game.components.ButtonView; +import com.mygdx.game.components.ImageView; +import com.mygdx.game.components.TextView; + +public class MenuScreen extends ScreenAdapter { + + private MyGdxGame game; + private SpriteBatch batch; + + private ImageView background; + private TextView titleTextView; + private ButtonView playButton; + private ButtonView settingsButton; + private ButtonView exitButton; + + public MenuScreen(MyGdxGame game) { + this.game = game; + this.batch = game.batch; + + background = new ImageView( + 0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.MENU_BG_IMG_PATH + ); + + float centerX = GameSettings.SCREEN_WIDTH / 2f; + + titleTextView = new TextView( + game.titleFont, + centerX - 200, + GameSettings.SCREEN_HEIGHT - 150, + "ВОЗДУШНЫЙ БОЙ" + ); + + float buttonWidth = 300; + float buttonHeight = 100; + float buttonSpacing = 30; + float startY = 350; + + playButton = new ButtonView( + centerX - buttonWidth / 2, + startY, + buttonWidth, buttonHeight, + game.buttonFont, + GameResources.BUTTON_PATH, + "Играть" + ); + + settingsButton = new ButtonView( + centerX - buttonWidth / 2, + startY - buttonHeight - buttonSpacing, + buttonWidth, buttonHeight, + game.buttonFont, + GameResources.BUTTON_PATH, + "Настройки" + ); + + exitButton = new ButtonView( + centerX - buttonWidth / 2, + startY - (buttonHeight + buttonSpacing) * 2, + buttonWidth, buttonHeight, + game.buttonFont, + GameResources.BUTTON_PATH, + "Выход" + ); + } + + @Override + public void render(float delta) { + Gdx.gl.glClearColor(0, 0, 0, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + game.camera.update(); + batch.setProjectionMatrix(game.camera.combined); + + handleInput(); + + batch.begin(); + + if (background != null) background.draw(batch); + if (titleTextView != null) titleTextView.draw(batch); + if (playButton != null) playButton.draw(batch); + if (settingsButton != null) settingsButton.draw(batch); + if (exitButton != null) exitButton.draw(batch); + + batch.end(); + } + + private void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + game.camera.unproject(touchPos); + + if (playButton != null && playButton.isHit(touchPos.x, touchPos.y)) { + if (game.soundManager != null) { + game.soundManager.playSelectSound(); + } + if (game.playerSelectScreen == null) { + game.playerSelectScreen = new PlayerSelectScreen(game); + } + game.setScreen(game.playerSelectScreen); + } + else if (settingsButton != null && settingsButton.isHit(touchPos.x, touchPos.y)) { + if (game.soundManager != null) { + game.soundManager.playSelectSound(); + } + if (game.settingsScreen == null) { + game.settingsScreen = new SettingsScreen(game); + } + game.setScreen(game.settingsScreen); + } + else if (exitButton != null && exitButton.isHit(touchPos.x, touchPos.y)) { + Gdx.app.exit(); + } + } + } + + @Override + public void show() { + if (game.soundManager != null) { + game.soundManager.playBackgroundMusic(); + } + } + + @Override + public void hide() {} + + @Override + public void dispose() { + if (background != null) background.dispose(); + if (playButton != null) playButton.dispose(); + if (settingsButton != null) settingsButton.dispose(); + if (exitButton != null) exitButton.dispose(); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/screens/PlayerSelectScreen.java b/core/src/com/mygdx/game/screens/PlayerSelectScreen.java new file mode 100644 index 0000000..73caea1 --- /dev/null +++ b/core/src/com/mygdx/game/screens/PlayerSelectScreen.java @@ -0,0 +1,210 @@ +package com.mygdx.game.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; +import com.mygdx.game.MyGdxGame; +import com.mygdx.game.components.ButtonView; +import com.mygdx.game.components.ImageView; +import com.mygdx.game.components.TextView; + +public class PlayerSelectScreen extends ScreenAdapter { + private MyGdxGame game; + private SpriteBatch batch; + private ImageView background; + + private ButtonView leftButton; + private ButtonView rightButton; + private ButtonView selectButton; + private ButtonView backButton; + private TextView titleTextView; + private TextView playerNameTextView; + private TextView playerDescTextView; + + private int selectedPlayer = 0; + private String[] playerNames = {"БАЗОВЫЙ", "СКОРОСТНОЙ", "ТАНК"}; + private String[] playerDescs = { + "Баланс скорости и защиты", + "Высокая скорость, низкая защита", + "Высокая защита, низкая скорость" + }; + + private String[] playerTextures = { + GameResources.BASIC_PATH, + GameResources.FAST_PATH, + GameResources.TANK_PATH + }; + + private Texture currentPlayerTexture; + + public PlayerSelectScreen(MyGdxGame game) { + this.game = game; + this.batch = game.batch; + + background = new ImageView(0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.PLAYER_SELECT_BG_PATH); + + float centerX = GameSettings.SCREEN_WIDTH / 2f; + + titleTextView = new TextView(game.titleFont, + centerX - 200, + GameSettings.SCREEN_HEIGHT - 150, + "ВЫБОР САМОЛЕТА"); + + float buttonSize = 100; + leftButton = new ButtonView( + 100, + GameSettings.SCREEN_HEIGHT / 2 - buttonSize/2, + buttonSize, buttonSize, + GameResources.BUTTON_LEFT_PATH + ); + + rightButton = new ButtonView( + GameSettings.SCREEN_WIDTH - 100 - buttonSize, + GameSettings.SCREEN_HEIGHT / 2 - buttonSize/2, + buttonSize, buttonSize, + GameResources.BUTTON_RIGHT_PATH + ); + + float bigButtonWidth = 300; + float bigButtonHeight = 100; + + selectButton = new ButtonView( + centerX - bigButtonWidth/2, + 200, + bigButtonWidth, bigButtonHeight, + game.buttonFont, + GameResources.BUTTON_PATH, + "ВЫБРАТЬ" + ); + selectButton.setTextColor(Color.BLACK); + + backButton = new ButtonView( + 50, + 50, + bigButtonWidth, bigButtonHeight, + game.buttonFont, + GameResources.BUTTON_PATH, + "НАЗАД" + ); + backButton.setTextColor(Color.BLACK); + + currentPlayerTexture = new Texture(Gdx.files.internal(playerTextures[selectedPlayer])); + updateText(); + } + + private void updateText() { + float centerX = GameSettings.SCREEN_WIDTH / 2f; + + if (playerNameTextView != null) { + playerNameTextView.setText(playerNames[selectedPlayer]); + playerDescTextView.setText(playerDescs[selectedPlayer]); + } else { + playerNameTextView = new TextView(game.buttonFont, + centerX - 100, + 400, + playerNames[selectedPlayer]); + + playerDescTextView = new TextView(game.smallFont, + centerX - 200, + 350, + playerDescs[selectedPlayer]); + } + } + + private void updatePlayerTexture() { + if (currentPlayerTexture != null) { + currentPlayerTexture.dispose(); + } + currentPlayerTexture = new Texture(Gdx.files.internal(playerTextures[selectedPlayer])); + } + + @Override + public void render(float delta) { + Gdx.gl.glClearColor(0.2f, 0.1f, 0.3f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + game.camera.update(); + batch.setProjectionMatrix(game.camera.combined); + handleInput(); + + batch.begin(); + + if (background != null) background.draw(batch); + + titleTextView.draw(batch); + leftButton.draw(batch); + rightButton.draw(batch); + selectButton.draw(batch); + backButton.draw(batch); + playerNameTextView.draw(batch); + playerDescTextView.draw(batch); + + float planeSize = 200; + float planeX = GameSettings.SCREEN_WIDTH / 2 - planeSize/2; + float planeY = GameSettings.SCREEN_HEIGHT / 2 - planeSize/2 + 100; + batch.draw(currentPlayerTexture, planeX, planeY, planeSize, planeSize); + + batch.end(); + } + + private void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + game.camera.unproject(touchPos); + + if (leftButton.isHit(touchPos.x, touchPos.y)) { + selectedPlayer--; + if (selectedPlayer < 0) { + selectedPlayer = playerNames.length - 1; + } + updateText(); + updatePlayerTexture(); + if (game.soundManager != null) game.soundManager.playSelectSound(); + } + else if (rightButton.isHit(touchPos.x, touchPos.y)) { + selectedPlayer++; + if (selectedPlayer >= playerNames.length) { + selectedPlayer = 0; + } + updateText(); + updatePlayerTexture(); + if (game.soundManager != null) game.soundManager.playSelectSound(); + } + else if (selectButton.isHit(touchPos.x, touchPos.y)) { + game.selectedPlayer = selectedPlayer; + game.setScreen(game.levelSelectScreen); + if (game.soundManager != null) game.soundManager.playSelectSound(); + } + else if (backButton.isHit(touchPos.x, touchPos.y)) { + game.setScreen(game.menuScreen); + if (game.soundManager != null) game.soundManager.playSelectSound(); + } + } + } + + @Override + public void show() { + if (game.soundManager != null) { + game.soundManager.playBackgroundMusic(); + } + } + + @Override + public void dispose() { + if (background != null) background.dispose(); + if (currentPlayerTexture != null) currentPlayerTexture.dispose(); + if (leftButton != null) leftButton.dispose(); + if (rightButton != null) rightButton.dispose(); + if (selectButton != null) selectButton.dispose(); + if (backButton != null) backButton.dispose(); + } +} \ No newline at end of file diff --git a/core/src/com/mygdx/game/screens/SettingsScreen.java b/core/src/com/mygdx/game/screens/SettingsScreen.java new file mode 100644 index 0000000..b42da7f --- /dev/null +++ b/core/src/com/mygdx/game/screens/SettingsScreen.java @@ -0,0 +1,189 @@ +package com.mygdx.game.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector3; +import com.mygdx.game.GameResources; +import com.mygdx.game.GameSettings; +import com.mygdx.game.MyGdxGame; +import com.mygdx.game.components.ButtonView; +import com.mygdx.game.components.ImageView; +import com.mygdx.game.components.TextView; + +public class SettingsScreen extends ScreenAdapter { + private MyGdxGame game; + private SpriteBatch batch; + private ImageView background; + + private TextView titleTextView; + private ButtonView musicButton; + private ButtonView soundButton; + private ButtonView easyButton; + private ButtonView normalButton; + private ButtonView hardButton; + private ButtonView backButton; + + public SettingsScreen(MyGdxGame game) { + this.game = game; + this.batch = game.batch; + + background = new ImageView(0, 0, + GameSettings.SCREEN_WIDTH, + GameSettings.SCREEN_HEIGHT, + GameResources.MENU_BG_IMG_PATH); + + float centerX = GameSettings.SCREEN_WIDTH / 2f; + float buttonY = 500; + float buttonSpacing = 80; + + titleTextView = new TextView(game.titleFont, + centerX - 200, + GameSettings.SCREEN_HEIGHT - 150, + "НАСТРОЙКИ"); + + musicButton = new ButtonView( + centerX - 150, buttonY, 300, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "МУЗЫКА: " + (game.soundManager.isMusicEnabled() ? "ВКЛ" : "ВЫКЛ") + ); + + soundButton = new ButtonView( + centerX - 150, buttonY - buttonSpacing, 300, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "ЗВУКИ: " + (game.soundManager.isSoundEnabled() ? "ВКЛ" : "ВЫКЛ") + ); + + easyButton = new ButtonView( + centerX - 350, buttonY - buttonSpacing * 2, 200, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "ЛЕГКИЙ" + ); + + normalButton = new ButtonView( + centerX - 100, buttonY - buttonSpacing * 2, 200, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "СРЕДНИЙ" + ); + + hardButton = new ButtonView( + centerX + 150, buttonY - buttonSpacing * 2, 200, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "СЛОЖНЫЙ" + ); + + backButton = new ButtonView( + centerX - 150, 100, 300, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "НАЗАД" + ); + } + + @Override + public void render(float delta) { + Gdx.gl.glClearColor(0.3f, 0.3f, 0.4f, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + game.camera.update(); + batch.setProjectionMatrix(game.camera.combined); + handleInput(); + + batch.begin(); + + if (background != null) background.draw(batch); + + titleTextView.draw(batch); + musicButton.draw(batch); + soundButton.draw(batch); + easyButton.draw(batch); + normalButton.draw(batch); + hardButton.draw(batch); + backButton.draw(batch); + + batch.end(); + } + + private void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + game.camera.unproject(touchPos); + + if (musicButton.isHit(touchPos.x, touchPos.y)) { + if (game.soundManager != null) { + game.soundManager.toggleMusic(); + float x = musicButton.getX(); + float y = musicButton.getY(); + musicButton.dispose(); + musicButton = new ButtonView( + x, y, 300, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "МУЗЫКА: " + (game.soundManager.isMusicEnabled() ? "ВКЛ" : "ВЫКЛ") + ); + game.soundManager.playSelectSound(); + } + } + else if (soundButton.isHit(touchPos.x, touchPos.y)) { + if (game.soundManager != null) { + game.soundManager.toggleSound(); + float x = soundButton.getX(); + float y = soundButton.getY(); + soundButton.dispose(); + soundButton = new ButtonView( + x, y, 300, 60, + game.buttonFont, + GameResources.BUTTON_PATH, + "ЗВУКИ: " + (game.soundManager.isSoundEnabled() ? "ВКЛ" : "ВЫКЛ") + ); + game.soundManager.playSelectSound(); + } + } + else if (easyButton.isHit(touchPos.x, touchPos.y)) { + GameSettings.currentDifficulty = GameSettings.Difficulty.EASY; + game.soundManager.playSelectSound(); + } + else if (normalButton.isHit(touchPos.x, touchPos.y)) { + GameSettings.currentDifficulty = GameSettings.Difficulty.NORMAL; + game.soundManager.playSelectSound(); + } + else if (hardButton.isHit(touchPos.x, touchPos.y)) { + GameSettings.currentDifficulty = GameSettings.Difficulty.HARD; + game.soundManager.playSelectSound(); + } + else if (backButton.isHit(touchPos.x, touchPos.y)) { + if (game.isFromGame) { + game.isFromGame = false; + game.setScreen(game.gameScreen); + } else { + game.setScreen(game.menuScreen); + } + game.soundManager.playSelectSound(); + } + } + } + + @Override + public void show() { + if (game.soundManager != null) { + game.soundManager.playBackgroundMusic(); + } + } + + @Override + public void dispose() { + if (background != null) background.dispose(); + if (musicButton != null) musicButton.dispose(); + if (soundButton != null) soundButton.dispose(); + if (easyButton != null) easyButton.dispose(); + if (normalButton != null) normalButton.dispose(); + if (hardButton != null) hardButton.dispose(); + if (backButton != null) backButton.dispose(); + } +} \ No newline at end of file diff --git a/desktop/build.gradle b/desktop/build.gradle new file mode 100644 index 0000000..a7f0abe --- /dev/null +++ b/desktop/build.gradle @@ -0,0 +1,49 @@ +sourceCompatibility = 1.8 +sourceSets.main.java.srcDirs = [ "src/" ] +sourceSets.main.resources.srcDirs = ["../assets"] + +project.ext.mainClassName = "com.mygdx.game.DesktopLauncher" +project.ext.assetsDir = new File("../assets") + +import org.gradle.internal.os.OperatingSystem + +tasks.register('run', JavaExec) { + dependsOn classes + mainClass = project.mainClassName + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = project.assetsDir + ignoreExitValue = true + + if (OperatingSystem.current() == OperatingSystem.MAC_OS) { + // Required to run on macOS + jvmArgs += "-XstartOnFirstThread" + } +} + +tasks.register('debug', JavaExec) { + dependsOn classes + mainClass = project.mainClassName + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = project.assetsDir + ignoreExitValue = true + debug = true +} + +tasks.register('dist', Jar) { + duplicatesStrategy(DuplicatesStrategy.EXCLUDE) + manifest { + attributes 'Main-Class': project.mainClassName + } + dependsOn configurations.runtimeClasspath + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + with jar +} + + +dist.dependsOn classes + +eclipse.project.name = appName + "-desktop" diff --git a/desktop/src/com/mygdx/game/DesktopLauncher.java b/desktop/src/com/mygdx/game/DesktopLauncher.java new file mode 100644 index 0000000..10b154b --- /dev/null +++ b/desktop/src/com/mygdx/game/DesktopLauncher.java @@ -0,0 +1,15 @@ +package com.mygdx.game; + +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; +import com.mygdx.game.MyGdxGame; + +// Please note that on macOS your application needs to be started with the -XstartOnFirstThread JVM argument +public class DesktopLauncher { + public static void main (String[] arg) { + Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); + config.setForegroundFPS(60); + config.setTitle("My GDX Game"); + new Lwjgl3Application(new MyGdxGame(), config); + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..92e8269 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,5 @@ +org.gradle.daemon=true +org.gradle.jvmargs=-Xms128m -Xmx1500m +org.gradle.configureondemand=false +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..249e583 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ae04661 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..a69d9cb --- /dev/null +++ b/gradlew @@ -0,0 +1,240 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f127cfd --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..77ae463 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include 'desktop', 'android', 'core' \ No newline at end of file