diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a8ef0bd --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "tabWidth": 2, + "useTabs": false, + "arrowParens": "always", + "singleQuote": true, + "semi": true, + "trailingComma": "all", + "bracketSpacing": true +} diff --git a/.todo b/.todo index 8e9ab6e..675c30f 100644 --- a/.todo +++ b/.todo @@ -1,39 +1,43 @@ Setup: ✔ make game canvas @done(22-01-28 20:23) ✔ add a block to canvas movable with keyboard @done(22-01-28 20:53) - ☐ create basic socket.io server - ☐ connect players to the server - ☐ draw other players on canvas - ☐ update player position on canvas + ✔ create basic socket.io server @done(22-01-28 22:43) + ✔ connect players to the server @done(22-01-29 00:51) + ✔ draw other players on canvas @done(22-01-29 00:51) + ✔ update player position on canvas @done(22-01-29 00:51) Game: - ☐ add physics for player to fall down - ☐ add interaction with blocks (and ground) - ☐ implement jump - ☐ add plyer collision? + ✔ add physics for player to fall down @done(22-01-29 02:02) + ✔ add interaction with blocks (and ground) @done(22-01-29 11:17) + ✔ implement jump @done(22-01-29 02:02) + ✘ add plyer collision? @cancelled(22-01-29 11:18) ☐ allow player to enter a name before starting the game ☐ show players names above their heads - ☐ restrict some words and name length + ☐ add name length limit Server: - ☐ do the same calculations for game logic (maybe use the same code base) + ✘ do the same calculations for game logic (maybe use the same code base) @cancelled(22-01-29 11:18) ☐ set player name - ☐ IMPLEMENT BANNING PEOPLE + ✘ IMPLEMENT BANNING PEOPLE @cancelled(22-01-29 11:18) Win condition?: ☐ reach some specific height? (premade map) ☐ when time runs out player at the highest point wins? (randomy generated map) last one standing: - ☐ player that is too far back from leading one looses? + ✘ player that is too far back from leading one looses? @cancelled(22-01-29 11:19) ☐ last player after specific time is eliminated? Game art: - ☐ randomly generated from assets? - ☐ choosing one of preset characters? - ☐ character builder? + ✘ randomly generated from assets? @cancelled(22-01-29 11:19) + ✘ choosing one of preset characters? @cancelled(22-01-29 11:19) + ✘ character builder? @cancelled(22-01-29 11:19) misc: - ☐ user accounts to track their score and save their chacaters? - ☐ game ratio 9x16? - ☐ game ratio 16x9? \ No newline at end of file + ✘ user accounts to track their score and save their chacaters? @cancelled(22-01-29 11:18) + ✔ game ratio 9x16? @done(22-01-29 11:17) + ✘ game ratio 16x9? @cancelled(22-01-29 11:17) + + +ideas: + ✘ block fall off platform if they are 1/3 off it @cancelled(22-01-29 11:18) diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..63c86fe --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,96 @@ +# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling +*.hprof + +# Cordova plugins for Capacitor +capacitor-cordova-android-plugins + +# Copied web assets +app/src/main/assets/public diff --git a/android/.idea/.gitignore b/android/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/android/.idea/compiler.xml b/android/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/android/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/.idea/jarRepositories.xml b/android/.idea/jarRepositories.xml new file mode 100644 index 0000000..e34606c --- /dev/null +++ b/android/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml new file mode 100644 index 0000000..2a4d5b5 --- /dev/null +++ b/android/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/.gitignore b/android/app/.gitignore new file mode 100644 index 0000000..043df80 --- /dev/null +++ b/android/app/.gitignore @@ -0,0 +1,2 @@ +/build/* +!/build/.npmkeep diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..ced7d59 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,51 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { + applicationId "lt.rdarius.kawaiijumper" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + aaptOptions { + // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. + // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +repositories { + flatDir{ + dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation project(':capacitor-cordova-android-plugins') +} + +apply from: 'capacitor.build.gradle' + +try { + def servicesJSON = file('google-services.json') + if (servicesJSON.text) { + apply plugin: 'com.google.gms.google-services' + } +} catch(Exception e) { + logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") +} diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle new file mode 100644 index 0000000..8c6c4e9 --- /dev/null +++ b/android/app/capacitor.build.gradle @@ -0,0 +1,22 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { + implementation project(':capacitor-app') + implementation project(':capacitor-haptics') + implementation project(':capacitor-keyboard') + implementation project(':capacitor-status-bar') + +} + + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# 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 *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java new file mode 100644 index 0000000..f2c2217 --- /dev/null +++ b/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.app", appContext.getPackageName()); + } +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..e6b2c70 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/assets/capacitor.config.json b/android/app/src/main/assets/capacitor.config.json new file mode 100644 index 0000000..a2f50fa --- /dev/null +++ b/android/app/src/main/assets/capacitor.config.json @@ -0,0 +1,6 @@ +{ + "appId": "io.ionic.starter", + "appName": "Kawaii-Jumper", + "webDir": "www", + "bundledWebRuntime": false +} diff --git a/android/app/src/main/assets/capacitor.plugins.json b/android/app/src/main/assets/capacitor.plugins.json new file mode 100644 index 0000000..101dda7 --- /dev/null +++ b/android/app/src/main/assets/capacitor.plugins.json @@ -0,0 +1,18 @@ +[ + { + "pkg": "@capacitor/app", + "classpath": "com.capacitorjs.plugins.app.AppPlugin" + }, + { + "pkg": "@capacitor/haptics", + "classpath": "com.capacitorjs.plugins.haptics.HapticsPlugin" + }, + { + "pkg": "@capacitor/keyboard", + "classpath": "com.capacitorjs.plugins.keyboard.KeyboardPlugin" + }, + { + "pkg": "@capacitor/status-bar", + "classpath": "com.capacitorjs.plugins.statusbar.StatusBarPlugin" + } +] diff --git a/android/app/src/main/java/lt/rdarius/kawaiijumper/MainActivity.java b/android/app/src/main/java/lt/rdarius/kawaiijumper/MainActivity.java new file mode 100644 index 0000000..e813f5a --- /dev/null +++ b/android/app/src/main/java/lt/rdarius/kawaiijumper/MainActivity.java @@ -0,0 +1,5 @@ +package lt.rdarius.kawaiijumper; + +import com.getcapacitor.BridgeActivity; + +public class MainActivity extends BridgeActivity {} diff --git a/android/app/src/main/res/drawable-land-hdpi/splash.png b/android/app/src/main/res/drawable-land-hdpi/splash.png new file mode 100644 index 0000000..e31573b Binary files /dev/null and b/android/app/src/main/res/drawable-land-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-mdpi/splash.png b/android/app/src/main/res/drawable-land-mdpi/splash.png new file mode 100644 index 0000000..f7a6492 Binary files /dev/null and b/android/app/src/main/res/drawable-land-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-xhdpi/splash.png b/android/app/src/main/res/drawable-land-xhdpi/splash.png new file mode 100644 index 0000000..8077255 Binary files /dev/null and b/android/app/src/main/res/drawable-land-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-xxhdpi/splash.png b/android/app/src/main/res/drawable-land-xxhdpi/splash.png new file mode 100644 index 0000000..14c6c8f Binary files /dev/null and b/android/app/src/main/res/drawable-land-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-xxxhdpi/splash.png b/android/app/src/main/res/drawable-land-xxxhdpi/splash.png new file mode 100644 index 0000000..244ca25 Binary files /dev/null and b/android/app/src/main/res/drawable-land-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-hdpi/splash.png b/android/app/src/main/res/drawable-port-hdpi/splash.png new file mode 100644 index 0000000..74faaa5 Binary files /dev/null and b/android/app/src/main/res/drawable-port-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-mdpi/splash.png b/android/app/src/main/res/drawable-port-mdpi/splash.png new file mode 100644 index 0000000..e944f4a Binary files /dev/null and b/android/app/src/main/res/drawable-port-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-xhdpi/splash.png b/android/app/src/main/res/drawable-port-xhdpi/splash.png new file mode 100644 index 0000000..564a82f Binary files /dev/null and b/android/app/src/main/res/drawable-port-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-xxhdpi/splash.png b/android/app/src/main/res/drawable-port-xxhdpi/splash.png new file mode 100644 index 0000000..bfabe68 Binary files /dev/null and b/android/app/src/main/res/drawable-port-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-xxxhdpi/splash.png b/android/app/src/main/res/drawable-port-xxxhdpi/splash.png new file mode 100644 index 0000000..6929071 Binary files /dev/null and b/android/app/src/main/res/drawable-port-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/splash.png b/android/app/src/main/res/drawable/splash.png new file mode 100644 index 0000000..f7a6492 Binary files /dev/null and b/android/app/src/main/res/drawable/splash.png differ diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..b5ad138 --- /dev/null +++ b/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..036d09b --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..c023e50 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2127973 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..b441f37 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..72905b8 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..8ed0605 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..9502e47 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..4d1e077 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..df0f158 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..853db04 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..6cdf97c Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2960cbb Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..8e3093a Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..46de6e2 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..d2ea9ab Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..a40d73e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/android/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..423bd0b --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + Kawaii-Jumper + Kawaii-Jumper + io.ionic.starter + io.ionic.starter + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..bb45498 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/config.xml b/android/app/src/main/res/xml/config.xml new file mode 100644 index 0000000..1b1b0e0 --- /dev/null +++ b/android/app/src/main/res/xml/config.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/file_paths.xml b/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000..bd0c4d8 --- /dev/null +++ b/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java new file mode 100644 index 0000000..0297327 --- /dev/null +++ b/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..ad085c3 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,29 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.google.gms:google-services:4.3.5' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply from: "variables.gradle" + +allprojects { + repositories { + google() + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle new file mode 100644 index 0000000..bd35873 --- /dev/null +++ b/android/capacitor.settings.gradle @@ -0,0 +1,15 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') + +include ':capacitor-app' +project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') + +include ':capacitor-haptics' +project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android') + +include ':capacitor-keyboard' +project(':capacitor-keyboard').projectDir = new File('../node_modules/@capacitor/keyboard/android') + +include ':capacitor-status-bar' +project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android') diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..0566c22 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3c4101c --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or 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 UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$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 "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# 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 + ;; + 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" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,89 @@ +@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%" == "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%"=="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! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..3b4431d --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +include ':capacitor-cordova-android-plugins' +project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') + +apply from: 'capacitor.settings.gradle' \ No newline at end of file diff --git a/android/variables.gradle b/android/variables.gradle new file mode 100644 index 0000000..967549c --- /dev/null +++ b/android/variables.gradle @@ -0,0 +1,14 @@ +ext { + minSdkVersion = 21 + compileSdkVersion = 30 + targetSdkVersion = 30 + androidxActivityVersion = '1.2.0' + androidxAppCompatVersion = '1.2.0' + androidxCoordinatorLayoutVersion = '1.1.0' + androidxCoreVersion = '1.3.2' + androidxFragmentVersion = '1.3.0' + junitVersion = '4.13.1' + androidxJunitVersion = '1.1.2' + androidxEspressoCoreVersion = '3.3.0' + cordovaAndroidVersion = '7.0.0' +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 19a11ce..c53b559 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2426,6 +2426,11 @@ "to-fast-properties": "^2.0.0" } }, + "@capacitor/android": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.4.0.tgz", + "integrity": "sha512-O2hHGVzdTH2Lsmz58EI8zHY5byEFIWl9KrW60WSrO/tV6u9DpfaUq56FaejvfU27GFXDZkmoQNa33EvDYWp4wA==" + }, "@capacitor/app": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@capacitor/app/-/app-1.1.0.tgz", @@ -5112,6 +5117,11 @@ "resolved": "https://registry.npmjs.org/@socket.io/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "integrity": "sha512-dOlCBKnDw4iShaIsH/bxujKTM18+2TOAsYz+KSc11Am38H4q5Xw8Bbz97ZYdrVNM+um3p7w86Bvvmcn9q+5+eQ==" }, + "@socket.io/component-emitter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", + "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==" + }, "@stencil/core": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.12.1.tgz", @@ -6186,6 +6196,11 @@ "@babel/helper-define-polyfill-provider": "^0.2.4" } }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -7090,8 +7105,7 @@ "core-js": { "version": "3.20.3", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", - "dev": true + "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==" }, "core-js-compat": { "version": "3.20.3", @@ -7998,6 +8012,29 @@ } } }, + "engine.io-client": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.1.1.tgz", + "integrity": "sha512-V05mmDo4gjimYW+FGujoGmmmxRaDsrVr7AXA3ZIfa04MWM1jOfZfUwou0oNqhNwy/votUDvGDt4JA4QF4e0b4g==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.0", + "has-cors": "1.1.0", + "parseqs": "0.0.6", + "parseuri": "0.0.6", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" + } + } + }, "engine.io-parser": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.3.tgz", @@ -9478,6 +9515,11 @@ "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", "dev": true }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -11894,6 +11936,31 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "ngrx": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/ngrx/-/ngrx-0.0.1-security.tgz", + "integrity": "sha512-3hYh1th9Arjoh7mA3KvOt7NB/ZGynOwibYUYftovFRAojsqtI+WZpa51JZ0u+INv3Lcvbi5qkJYupar17aLGdg==" + }, + "ngx-socket-io": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ngx-socket-io/-/ngx-socket-io-4.1.0.tgz", + "integrity": "sha512-p/IxD/hdpF/3+Xu6FFoo1OMIi9+rbqN55smJKE1RSFHAhS0UmRno2soHd1RTG3QXm6hCntp2vvfPE4tn60P5mw==", + "requires": { + "core-js": "^3.0.0", + "reflect-metadata": "^0.1.10", + "socket.io": "^4.0.0", + "socket.io-client": "^4.0.0", + "tslib": "^2.0.0", + "zone.js": "^0.10.1" + }, + "dependencies": { + "zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==" + } + } + }, "nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", @@ -12637,6 +12704,16 @@ "parse5": "^6.0.1" } }, + "parseqs": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" + }, + "parseuri": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -14851,8 +14928,7 @@ "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "regenerate": { "version": "1.4.2", @@ -15811,6 +15887,30 @@ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz", "integrity": "sha512-Qd/iwn3VskrpNO60BeRyCyr8ZWw9CPZyitW4AQwmRZ8zCiyDiL+znRnWX6tDHXnWn1sJrM1+b6Mn6wEDJJ4aYQ==" }, + "socket.io-client": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.4.1.tgz", + "integrity": "sha512-N5C/L5fLNha5Ojd7Yeb/puKcPWWcoB/A09fEjjNsg91EDVr5twk/OEyO6VT9dlLSUNY85NpW6KBhVMvaLKQ3vQ==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "backo2": "~1.0.2", + "debug": "~4.3.2", + "engine.io-client": "~6.1.1", + "parseuri": "0.0.6", + "socket.io-parser": "~4.1.1" + }, + "dependencies": { + "socket.io-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.1.tgz", + "integrity": "sha512-USQVLSkDWE5nbcY760ExdKaJxCE65kcsG/8k5FDGZVVxpD1pA7hABYXYkCUvxUuYYh/+uQw0N/fvBzfT8o07KA==", + "requires": { + "@socket.io/component-emitter": "~3.0.0", + "debug": "~4.3.1" + } + } + } + }, "socket.io-parser": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.4.tgz", @@ -17389,6 +17489,11 @@ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", "dev": true }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -17452,6 +17557,11 @@ "fd-slicer": "~1.1.0" } }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index a08d6f6..7b5d826 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,16 @@ "@angular/platform-browser": "~13.0.0", "@angular/platform-browser-dynamic": "~13.0.0", "@angular/router": "~13.0.0", + "@capacitor/android": "^3.4.0", "@capacitor/app": "1.1.0", "@capacitor/core": "3.4.0", "@capacitor/haptics": "1.1.4", "@capacitor/keyboard": "1.2.1", "@capacitor/status-bar": "1.0.7", "@ionic/angular": "^6.0.0", - "rxjs": "~6.6.0", + "ngrx": "0.0.1-security", + "ngx-socket-io": "^4.1.0", + "rxjs": "^6.6.7", "socket.io": "^4.4.1", "tslib": "^2.2.0", "zone.js": "~0.11.4" diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index e7b0d5a..5712c96 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -2,15 +2,10 @@ import { NgModule } from '@angular/core'; import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; const routes: Routes = [ - { - path: 'home', - loadChildren: () => import('./home/home.module').then( m => m.HomePageModule) - }, { path: '', - redirectTo: 'home', - pathMatch: 'full' - }, + loadChildren: () => import('./home/home.module').then( m => m.HomePageModule) + } ]; @NgModule({ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f8b75ac..323dff4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,16 +1,20 @@ import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; - + import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; +import { SocketIoConfig, SocketIoModule } from 'ngx-socket-io'; + +const config: SocketIoConfig = { url: 'http://localhost:3000', options: {} }; +// const config: SocketIoConfig = { url: 'https://ggj2022.rapalis.lt', options: {} }; @NgModule({ declarations: [AppComponent], entryComponents: [], - imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule], + imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, SocketIoModule.forRoot(config)], providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }], bootstrap: [AppComponent], }) diff --git a/src/app/home/applyGravity.ts b/src/app/home/applyGravity.ts new file mode 100644 index 0000000..739cd86 --- /dev/null +++ b/src/app/home/applyGravity.ts @@ -0,0 +1,10 @@ +import { Vector } from './types.dto'; + +export const applyGravity = ( + currentVelocity: Vector, + deltaTime: number, +): Vector => { + currentVelocity.y += 0.003 * deltaTime; + currentVelocity.y = currentVelocity.y > 0.9 ? 0.9 : currentVelocity.y; + return { ...currentVelocity }; +}; diff --git a/src/app/home/deltaTime.ts b/src/app/home/deltaTime.ts new file mode 100644 index 0000000..ae427ee --- /dev/null +++ b/src/app/home/deltaTime.ts @@ -0,0 +1,27 @@ +export class DeltaTime { + private lastTick: number; + private static instance: DeltaTime; + private deltaTime: number; + + private constructor() { + this.lastTick = Date.now(); + } + + public static getInstance() { + if (!this.instance) { + this.instance = new DeltaTime(); + } + return this.instance; + } + + public updateDeltaTime() { + const time = Date.now(); + this.deltaTime = time - this.lastTick; + this.lastTick = time; + } + + public getDeltaTime(): number { + return this.deltaTime; + } + +} \ No newline at end of file diff --git a/src/app/home/drawMap.ts b/src/app/home/drawMap.ts new file mode 100644 index 0000000..13aa863 --- /dev/null +++ b/src/app/home/drawMap.ts @@ -0,0 +1,11 @@ +import { MapTile } from '../../../../Kawaii-Jumper-server/src/mapTile'; + +export const drawMap = ( + mapTiles: MapTile[], + context: CanvasRenderingContext2D, + images: HTMLImageElement[], +) => { + for (let tile of mapTiles) { + context.drawImage(images[tile.color], tile.x, tile.y, tile.w, tile.h); + } +}; diff --git a/src/app/home/getAngleBetweenTwoPoints.ts b/src/app/home/getAngleBetweenTwoPoints.ts new file mode 100644 index 0000000..85304d7 --- /dev/null +++ b/src/app/home/getAngleBetweenTwoPoints.ts @@ -0,0 +1,5 @@ +import { Vector } from './types.dto'; + +export const getAngleBetweenTwoPoints = (p1: Vector, p2: Vector): number => { + return Math.atan2(p2.y - p1.y, p2.x - p1.x); +}; diff --git a/src/app/home/getXFromAngle.ts b/src/app/home/getXFromAngle.ts new file mode 100644 index 0000000..fe1eb24 --- /dev/null +++ b/src/app/home/getXFromAngle.ts @@ -0,0 +1,3 @@ +export const getXFromAngle = (angle: number) => { + return Math.cos(angle); +}; diff --git a/src/app/home/getYFromAngle.ts b/src/app/home/getYFromAngle.ts new file mode 100644 index 0000000..d2e3ea1 --- /dev/null +++ b/src/app/home/getYFromAngle.ts @@ -0,0 +1,3 @@ +export const getYFromAngle = (angle: number) => { + return Math.sin(angle); +}; diff --git a/src/app/home/globals.ts b/src/app/home/globals.ts new file mode 100644 index 0000000..027a819 --- /dev/null +++ b/src/app/home/globals.ts @@ -0,0 +1,68 @@ +import { Socket } from 'ngx-socket-io'; +import { MapTile } from '../../../../Kawaii-Jumper-server/src/mapTile'; +import { makeHTMLAudioElements } from './makeHTMLAudioElements'; +import { makeHTMLImageElements } from './makeHTMLImageObjects'; +import { scaleScreen } from './scaleScreen'; +import { Vector } from './types.dto'; + +export class Globals { + public width: number = 0; + public height: number = 0; + public canvasScale: number = 0; + public pageWidth: number = 0; + public pageHeight: number = 0; + public canvas: HTMLCanvasElement; + public context: CanvasRenderingContext2D; + public playerImages: HTMLImageElement[] = []; + public platformImages: HTMLImageElement[] = []; + public socket: Socket; + public socketId: string; + public colors: string[] = ['#FF63C8', '#79e7ff']; + public sounds: HTMLAudioElement[] = []; + public playerSize: Vector = { x: 50, y: 34 }; + public map: MapTile[] = []; + public backgroudnImage: HTMLImageElement; + + private readonly playerImageFiles: string[] = [ + '/assets/slime-1-left.png', + '/assets/slime-1-right.png', + '/assets/slime-2-left.png', + '/assets/slime-2-right.png', + ]; + private readonly platformImageFiles: string[] = [ + '/assets/platform-1.png', + '/assets/platform-2.png', + ]; + private readonly soundFiles: string[] = [ + '/assets/jump.wav', + '/assets/land.wav', + ]; + private static instance: Globals; + + private constructor() { + this.setupImages(); + this.setupSounds(); + } + + private setupImages(): void { + this.playerImages = makeHTMLImageElements(this.playerImageFiles); + this.platformImages = makeHTMLImageElements(this.platformImageFiles); + this.backgroudnImage = makeHTMLImageElements(['/assets/bg.png'])[0]; + } + private setupSounds(): void { + this.sounds = makeHTMLAudioElements(this.soundFiles); + } + + public static getInstance(): Globals { + if (!this.instance) { + this.instance = new Globals(); + } + return this.instance; + } + + public setupCanvas() { + this.canvas = document.getElementById('game') as HTMLCanvasElement; + this.context = this.canvas.getContext('2d'); + scaleScreen(); + } +} diff --git a/src/app/home/home.page.html b/src/app/home/home.page.html index 3e47db2..93ea3ac 100644 --- a/src/app/home/home.page.html +++ b/src/app/home/home.page.html @@ -1 +1,4 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/src/app/home/home.page.ts b/src/app/home/home.page.ts index 45a0b27..66fcd3c 100644 --- a/src/app/home/home.page.ts +++ b/src/app/home/home.page.ts @@ -1,4 +1,28 @@ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; +import { Socket } from 'ngx-socket-io'; + +import { Position } from '../../../../Kawaii-Jumper-server/src/position'; +import { + PlayerDTO, + PlayerDTOList, + PlayerList, + StringNumber, + StringVector, + Vector, +} from './types.dto'; + +import { MapTile } from '../../../../Kawaii-Jumper-server/src/mapTile'; +import { getXFromAngle } from './getXFromAngle'; +import { getAngleBetweenTwoPoints } from './getAngleBetweenTwoPoints'; +import { getYFromAngle } from './getYFromAngle'; +import { applyGravity } from './applyGravity'; +import { IsIntersecting } from './isIntersecting'; +import { drawMap } from './drawMap'; + +import { Globals } from './globals'; +import { Players } from './players'; +import { MySocket } from './mySocket'; +import { DeltaTime } from './deltaTime'; @Component({ selector: 'app-home', @@ -6,50 +30,505 @@ import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { + globals: Globals; + players: Players; + mySocket: MySocket; + deltaTime: DeltaTime; - canvas: HTMLCanvasElement; - context: CanvasRenderingContext2D; + myLastPosition: Position = { x: 0, y: 0 }; - pageHeight = window.innerHeight; - pageWidth = window.innerWidth; + jumpPower = Date.now(); - constructor() { + lastPointerPosition: Position = { x: 0, y: 0 }; + + keysDown: { [key: number]: boolean } = {}; + + mapBuilder = false; + + builtMap: MapTile[] = []; + + constructor(private socket: Socket) { + this.globals = Globals.getInstance(); + this.players = Players.getInstance(); + this.deltaTime = DeltaTime.getInstance(); + this.globals.socket = socket; + this.mySocket = MySocket.getInstance(); + this.globals.pageHeight = window.innerHeight; + this.globals.pageWidth = window.innerWidth; + + this.setupSocketListeners(); } ngOnInit(): void { - this.canvas = document.getElementById('game') as HTMLCanvasElement; - this.context = this.canvas.getContext('2d'); - this.scaleScreen(); + this.globals.setupCanvas(); + this.setListeners(); this.gameLoop(); } - gameLoop() { - - this.drawPlayer(); - - requestAnimationFrame(() => {this.gameLoop();}); + setupSocketListeners() { + this.mySocket.onId((id: string) => (this.globals.socketId = id)); + this.mySocket.onMap((map: MapTile[]) => (this.globals.map = map)); + this.mySocket.onPlayerConnected((players: PlayerDTOList) => + this.players.addMultiplaPlayers(players), + ); + this.mySocket.onNewPlayerConnected((player: PlayerDTO) => + this.players.addPlayer(player), + ); + this.mySocket.onPlayerDisconnected((id: string) => + this.players.removePlayer(id), + ); + this.mySocket.onUpdatedPlayerColor((playersColor: StringNumber) => + this.players.updatePlayerColor(playersColor), + ); + this.mySocket.onUpdatedPlayerPosition((playersPosition: StringVector) => + this.players.updatePlayerPosition(playersPosition), + ); + this.mySocket.onUpdatedPlayerDirection((playersDirection: StringNumber) => + this.players.updatePlayerDirection(playersDirection), + ); } - drawPlayer() { - this.context.fillStyle = 'white'; - this.context.fillRect(50, 50, 50, 50); + getJumpPower(): number { + let power = Date.now() - this.jumpPower; + return Math.abs(getXFromAngle(power / 1000) * 1.4); } - - setCanvasSize(w: number, h: number) { - this.canvas.style.height = h + 'px'; - this.canvas.style.width = w + 'px'; - this.canvas.height = h; - this.canvas.width = w; + getJumpDirection(x: number, y: number) { + return getAngleBetweenTwoPoints( + { + x: + this.players.getMyself().getPosition().x + + this.globals.playerSize.x / 2, + y: + this.players.getMyself().getPosition().y + + this.globals.playerSize.y / 2, + }, + { + x: x * this.globals.canvasScale, + y: y * this.globals.canvasScale, + }, + ); } - scaleScreen() { - const scaleX = this.pageWidth / 9; - const scaleY = this.pageHeight / 16; - if (scaleX > scaleY) { // width is longer, calculate based on height - return this.setCanvasSize(this.pageHeight / 16 * 9, this.pageHeight); + clickEndListener($event): Position { + console.log('click'); + if (!this.players.getMyself()) return; + console.log('I found myself'); + if (!this.players.getMyself().isGrounded()) return; + console.log('I am grounded'); + + this.players.getMyself().swapColor(); + this.socket.emit('updatedColor', this.players.getMyself().getColor()); + this.players.getMyself().setGrounded(false); + const angle = this.getJumpDirection($event.offsetX, $event.offsetY); + this.players.getMyself().jump(angle, this.getJumpPower()); + + this.socket.emit( + 'updatedDirection', + this.players.getMyself().getDirection(), + ); + this.globals.sounds[0].play(); + return this.players.getMyself().getMovingVelocity(); + } + + mapClickListenerEnd($event) { + this.builtMap.push({ + color: 0, + x: $event.offsetX * this.globals.canvasScale, + y: $event.offsetY * this.globals.canvasScale, + w: 130, + h: 30, + }); + console.log(this.builtMap); + } + + moveListener($event): void { + if (!this.globals.socketId) return; + this.lastPointerPosition = { + x: $event.offsetX * this.globals.canvasScale, + y: $event.offsetY * this.globals.canvasScale, + }; + } + + setListeners() { + window.addEventListener('keydown', (e) => this.keyListener(e, true)); + window.addEventListener('keyup', (e) => this.keyListener(e, false)); + window.addEventListener('mouseup', (e) => this.mapBuilder ? this.mapClickListenerEnd(e) : this.clickEndListener(e)); + window.addEventListener('touchend', (e) => this.clickEndListener(e)); + window.addEventListener('mousemove', (e) => this.moveListener(e)); + } + + keyListener($event, state) { + this.keysDown[$event.keyCode] = state; + } + + detectCollisions() { + const player = this.players.getMyself(); + for (let block of this.globals.map) { + if (block.color !== this.players.getMyself().getColor()) continue; + + const playerWidth = this.globals.playerSize.x; + const playerHeight = this.globals.playerSize.y; + const myPosition = player.getPosition(); + + const playerTopLeft: Position = myPosition; + const playerTopRight: Position = { + x: myPosition.x + playerWidth, + y: myPosition.y, + }; + const playerBottomLeft: Position = { + x: myPosition.x, + y: myPosition.y + playerHeight, + }; + const playerBottomRight: Position = { + x: myPosition.x + playerWidth, + y: myPosition.y + playerHeight, + }; + + const blockTopLeft: Position = { x: block.x, y: block.y }; + const blockTopRight: Position = { x: block.x + block.w, y: block.y }; + const blockBottomLeft: Position = { x: block.x, y: block.y + block.h }; + const blockBottomRight: Position = { + x: block.x + block.w, + y: block.y + block.h, + }; + + if ( + IsIntersecting( + playerTopRight, + playerBottomRight, + blockTopLeft, + blockTopRight, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + const dx = this.getDistanceX(playerBottomRight, blockTopLeft); + const dy = this.getDistanceY(playerBottomRight, blockTopLeft); + console.log('collision on top left corner of platform'); + + return dx < dy + ? this.players.getMyself().touchRight(blockTopLeft.x) + : this.players.getMyself().touchBottom(blockTopLeft.y); + } + + if ( + IsIntersecting( + playerTopRight, + playerBottomRight, + blockBottomLeft, + blockBottomRight, + ) && + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + const dx = this.getDistanceX(playerTopRight, blockBottomLeft); + const dy = this.getDistanceY(playerTopRight, blockBottomLeft); + console.log('collision on bottom left corner of platform'); + + return dx < dy + ? this.players.getMyself().touchRight(blockBottomLeft.x) + : this.players.getMyself().touchTop(blockBottomLeft.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockTopLeft, + blockTopRight, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopRight, + blockBottomRight, + ) + ) { + const dx = this.getDistanceX(playerBottomLeft, blockTopRight); + const dy = this.getDistanceY(playerBottomLeft, blockTopRight); + console.log('collision on top right corner of platform'); + + return dx < dy + ? this.players.getMyself().touchLeft(blockTopRight.x) + : this.players.getMyself().touchBottom(blockTopRight.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockBottomLeft, + blockBottomRight, + ) && + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopRight, + blockBottomRight, + ) + ) { + const dx = this.getDistanceX(playerTopLeft, blockBottomRight); + const dy = this.getDistanceY(playerTopLeft, blockBottomRight); + console.log('collision on bottom right corner of platform'); + + return dx < dy + ? this.players.getMyself().touchLeft(blockBottomRight.x) + : this.players.getMyself().touchTop(blockBottomRight.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopLeft, + blockBottomLeft, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + console.log( + 'collision on left side of platform (platform bigger than player)', + ); + return this.players.getMyself().touchRight(blockBottomLeft.x); + } + + if ( + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopRight, + blockBottomRight, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopRight, + blockBottomRight, + ) + ) { + console.log( + 'collision on right side of platform (platform bigger than player)', + ); + return this.players.getMyself().touchLeft(blockBottomRight.x); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockBottomLeft, + blockBottomRight, + ) && + IsIntersecting( + playerTopRight, + playerBottomRight, + blockBottomLeft, + blockBottomRight, + ) + ) { + console.log( + 'collision on bottom side of platform (platform bigger than player)', + ); + return this.players.getMyself().touchTop(blockBottomLeft.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockTopLeft, + blockTopRight, + ) && + IsIntersecting( + playerTopRight, + playerBottomRight, + blockTopLeft, + blockTopRight, + ) + ) { + console.log( + 'collision on top side of platform (platform bigger than player)', + ); + return this.players.getMyself().touchBottom(blockTopLeft.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockTopLeft, + blockTopRight, + ) + ) { + console.log( + 'collision on right side of platform (platform smaller than player)', + ); + return this.players.getMyself().touchLeft(blockTopRight.x); + } + + if ( + IsIntersecting( + playerTopRight, + playerBottomRight, + blockTopLeft, + blockTopRight, + ) + ) { + console.log( + 'collision on left side of platform (platform smaller than player)', + ); + return this.players.getMyself().touchRight(blockTopLeft.x); + } + + if ( + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + console.log( + 'collision on bottom side of platform (platform smaller than player)', + ); + return this.players.getMyself().touchTop(blockBottomLeft.y); + } + + if ( + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + console.log( + 'collision on top side of platform (platform smaller than player)', + ); + return this.players.getMyself().touchBottom(blockTopLeft.y); + } + } + + /* MAP BOUNDS */ + if ( + this.players.getMyself().getPosition().y > + this.globals.height - this.globals.playerSize.y + ) { + this.players.getMyself().touchBottom(this.globals.height); + } + + if (this.players.getMyself().getPosition().x < 0) { + this.players.getMyself().touchLeft(0); + } + + if ( + this.players.getMyself().getPosition().x > + this.globals.width - this.globals.playerSize.x + ) { + this.players.getMyself().touchRight(this.globals.width); } - this.setCanvasSize(this.pageWidth, this.pageWidth / 9 * 16) // height is longer, calculate based on width } + updatePlayerPosition() { + if (!this.players.getMyself()) return; + this.detectCollisions(); + if ( + this.players.getMyself().getPosition().x !== this.myLastPosition.x || + this.players.getMyself().getPosition().y !== this.myLastPosition.y + ) { + this.socket.emit( + 'updatedPosition', + this.players.getMyself().getPosition(), + ); + this.myLastPosition = { ...this.players.getMyself().getPosition() }; + } + } + + getDistanceX(p1: Position, p2: Position): number { + return Math.abs(p1.x - p2.x); + } + + getDistanceY(p1: Position, p2: Position): number { + return Math.abs(p1.y - p2.y); + } + + drawPointer() { + if (!this.globals.socketId) return; + this.globals.context.strokeStyle = '#00ff0066'; + this.globals.context.lineWidth = 5; + const angle = getAngleBetweenTwoPoints( + { + x: + this.players.getMyself().getPosition().x + + this.globals.playerSize.x / 2, + y: + this.players.getMyself().getPosition().y + + this.globals.playerSize.y / 2, + }, + this.lastPointerPosition, + ); + this.globals.context.beginPath(); + this.globals.context.moveTo( + this.players.getMyself().getPosition().x + this.globals.playerSize.x / 2, + this.players.getMyself().getPosition().y + this.globals.playerSize.y / 2, + ); + this.globals.context.lineTo( + this.players.getMyself().getPosition().x + + this.globals.playerSize.x / 2 + + getXFromAngle(angle) * this.getJumpPower() * 50, + this.players.getMyself().getPosition().y + + this.globals.playerSize.y / 2 + + getYFromAngle(angle) * this.getJumpPower() * 50, + ); + this.globals.context.stroke(); + } + + gameLoop() { + this.globals.context.fillStyle = 'gray'; + this.globals.context.drawImage( + this.globals.backgroudnImage, + 0, + 0, + this.globals.width, + this.globals.height, + ); + + drawMap( + this.globals.map, + this.globals.context, + this.globals.platformImages, + ); + if (this.mapBuilder) { + drawMap( + this.builtMap, + this.globals.context, + this.globals.platformImages, + ); + } + + this.deltaTime.updateDeltaTime(); + + this.players.tick(); + this.players.draw(); + + this.updatePlayerPosition(); + this.drawPointer(); + + requestAnimationFrame(() => { + this.gameLoop(); + }); + } } diff --git a/src/app/home/isIntersecting.ts b/src/app/home/isIntersecting.ts new file mode 100644 index 0000000..9ab14df --- /dev/null +++ b/src/app/home/isIntersecting.ts @@ -0,0 +1,25 @@ +import { Vector } from './types.dto'; + +export const IsIntersecting = ( + l1p1: Vector, // line 1 point 1 + l1p2: Vector, // line 1 point 2 + l2p1: Vector, // line 2 point 1 + l2p2: Vector, // line 2 point 2 +): boolean => { + const denominator = + (l1p2.x - l1p1.x) * (l2p2.y - l2p1.y) - + (l1p2.y - l1p1.y) * (l2p2.x - l2p1.x); + const numerator1 = + (l1p1.y - l2p1.y) * (l2p2.x - l2p1.x) - + (l1p1.x - l2p1.x) * (l2p2.y - l2p1.y); + const numerator2 = + (l1p1.y - l2p1.y) * (l1p2.x - l1p1.x) - + (l1p1.x - l2p1.x) * (l1p2.y - l1p1.y); + + if (denominator == 0) return numerator1 == 0 && numerator2 == 0; + + const r = numerator1 / denominator; + const s = numerator2 / denominator; + + return r >= 0 && r <= 1 && s >= 0 && s <= 1; +}; diff --git a/src/app/home/makeHTMLAudioElements.ts b/src/app/home/makeHTMLAudioElements.ts new file mode 100644 index 0000000..779bd74 --- /dev/null +++ b/src/app/home/makeHTMLAudioElements.ts @@ -0,0 +1,11 @@ +export const makeHTMLAudioElements = ( + fileList: string[], +): HTMLAudioElement[] => { + const sounds: HTMLAudioElement[] = []; + + for (let file of fileList) { + sounds.push(new Audio(file)); + } + + return sounds; +}; diff --git a/src/app/home/makeHTMLImageObjects.ts b/src/app/home/makeHTMLImageObjects.ts new file mode 100644 index 0000000..35471c8 --- /dev/null +++ b/src/app/home/makeHTMLImageObjects.ts @@ -0,0 +1,13 @@ +export const makeHTMLImageElements = ( + fileList: string[], +): HTMLImageElement[] => { + const images: HTMLImageElement[] = []; + + for (let file of fileList) { + const image = new Image(); + image.src = file; + images.push(image); + } + + return images; +}; diff --git a/src/app/home/mySocket.ts b/src/app/home/mySocket.ts new file mode 100644 index 0000000..7dd1dad --- /dev/null +++ b/src/app/home/mySocket.ts @@ -0,0 +1,49 @@ +import { Globals } from './globals'; + +export class MySocket { + private static instance: MySocket; + private globals: Globals; + + private constructor() { + this.globals = Globals.getInstance(); + } + + public static getInstance(): MySocket { + if (!this.instance) { + this.instance = new MySocket(); + } + return this.instance; + } + + public onId(callback: CallableFunction): void { + this.globals.socket.on('takeYourIdAndLeaveMeAlone', callback); + } + + public onPlayerConnected(callback: CallableFunction): void { + this.globals.socket.on('connectedPlayers', callback); + } + + public onNewPlayerConnected(callback: CallableFunction): void { + this.globals.socket.on('newPlayer', callback); + } + + public onPlayerDisconnected(callback: CallableFunction): void { + this.globals.socket.on('playerDisconnected', callback); + } + + public onUpdatedPlayerPosition(callback: CallableFunction): void { + this.globals.socket.on('updatedPlayerPositions', callback); + } + + public onUpdatedPlayerColor(callback: CallableFunction): void { + this.globals.socket.on('updatedPlayerColor', callback); + } + + public onUpdatedPlayerDirection(callback: CallableFunction): void { + this.globals.socket.on('updatedPlayerDirection', callback); + } + + public onMap(callback: CallableFunction): void { + this.globals.socket.on('takeTheMapAndBeQuiet', callback); + } +} diff --git a/src/app/home/player.ts b/src/app/home/player.ts new file mode 100644 index 0000000..2f72fd3 --- /dev/null +++ b/src/app/home/player.ts @@ -0,0 +1,146 @@ +import { Position } from '../../../../Kawaii-Jumper-server/src/position'; +import { applyGravity } from './applyGravity'; +import { DeltaTime } from './deltaTime'; +import { getXFromAngle } from './getXFromAngle'; +import { getYFromAngle } from './getYFromAngle'; +import { Globals } from './globals'; +import { PlayerDTO, Vector } from './types.dto'; + +export class Player { + private readonly globals: Globals; + private readonly deltaTime: DeltaTime; + private id: string; + private position: Vector; + private name: string; + private movingVelocity: Vector; + private color: number; + private direction: number; + private grounded: boolean; + + public constructor(id: string, data: PlayerDTO) { + this.globals = Globals.getInstance(); + this.deltaTime = DeltaTime.getInstance(); + this.id = id; + this.position = data.position; + this.name = data.name; + this.movingVelocity = data.movingVelocity; + this.color = data.color; + this.direction = data.direction; + this.grounded = true; + } + + public applyGravity() { + this.movingVelocity = { + ...applyGravity(this.movingVelocity, this.deltaTime.getDeltaTime()), + }; + } + + public resetVelocity() { + this.movingVelocity = { x: 0, y: 0 }; + } + + public updatePosition(position: Vector): void { + this.position = { ...position }; + } + + public updateDirection(direction: number): void { + this.direction = direction; + } + + public updateColor(color: number): void { + this.color = color; + } + + public getId(): string { + return this.id; + } + + public getPosition(): Vector { + return { ...this.position }; + } + + public getName(): string { + return this.name; + } + + public getColor(): number { + return this.color; + } + + public getDirection(): number { + return this.direction; + } + + public isGrounded(): boolean { + return this.grounded; + } + + public setGrounded(grounded: boolean): void { + this.grounded = grounded; + } + + public getMovingVelocity(): Vector { + return { ...this.movingVelocity }; + } + + public swapColor(): void { + this.color = this.color === 0 ? 1 : 0; + } + + public jump(angle: number, jumpPower: number): void { + this.movingVelocity.x = getXFromAngle(angle) * jumpPower; + this.movingVelocity.y = getYFromAngle(angle) * jumpPower; + this.direction = this.movingVelocity.x > 0 ? 1 : 0; + } + + public move(): void { + this.position.x += this.movingVelocity.x * this.deltaTime.getDeltaTime(); + this.position.y += this.movingVelocity.y * this.deltaTime.getDeltaTime(); + } + + public touchBottom(resetPoint: number) { + this.position.y = resetPoint - this.globals.playerSize.y - 1; + this.grounded = true; + if (this.id === this.globals.socketId) { + this.globals.sounds[1].play(); + } + this.resetVelocity(); + } + + public touchTop(resetPoint: number) { + this.position.y = resetPoint + 1; + this.resetVelocity(); + } + + public touchLeft(resetPoint: number) { + this.position.x = resetPoint + 1; + this.resetVelocity(); + } + + public touchRight(resetPoint: number) { + this.position.x = resetPoint - this.globals.playerSize.x - 1; + this.resetVelocity(); + } + + public isMyself(): boolean { + return this.id === this.globals.socketId; + } + + public draw() { + this.globals.context.drawImage( + this.globals.playerImages[this.color * 2 + this.direction], + this.position.x, + this.position.y, + this.globals.playerSize.x, + this.globals.playerSize.y, + ); + this.globals.context.fillStyle = 'black'; + this.globals.context.textAlign = 'center'; + this.globals.context.font = '25px Arial'; + this.globals.context.fillText( + this.name, + this.position.x + this.globals.playerSize.x / 2, + this.position.y - 30, + ); + } +} diff --git a/src/app/home/players.ts b/src/app/home/players.ts new file mode 100644 index 0000000..dc0101c --- /dev/null +++ b/src/app/home/players.ts @@ -0,0 +1,98 @@ +import { applyGravity } from './applyGravity'; +import { Globals } from './globals'; +import { Player } from './player'; +import { + PlayerDTO, + PlayerDTOList, + PlayerList, + StringNumber, + StringVector, + Vector, +} from './types.dto'; + +export class Players { + private globals: Globals; + private players: PlayerList = {}; + private static instance: Players; + + private constructor() { + this.globals = Globals.getInstance(); + } + + public static getInstance(): Players { + if (!this.instance) { + this.instance = new Players(); + } + return this.instance; + } + + public tick(): void { + for (let id of this.getPlayerIds()) { + if (this.getPlayer(id).isGrounded()) { + continue; + } + this.getPlayer(id).applyGravity(); + this.getPlayer(id).move(); + } + } + + public resetVelocity(id: string): void { + this.getPlayer(id).resetVelocity(); + } + + public resetMyVelocity(): void { + this.resetVelocity(this.globals.socketId); + } + + public getPlayerIds(): string[] { + return Object.keys(this.players); + } + + public getPlayer(id: string): Player { + return this.players[id]; + } + + public addMultiplaPlayers(players: PlayerDTOList): void { + for (let player of Object.keys(players)) { + this.addPlayer(players[player]); + } + } + + public addPlayer(player: PlayerDTO): Players { + this.players[player.id] = new Player(player.id, player); + return this; + } + + public removePlayer(id: string): Players { + delete this.players[id]; + return this; + } + + public updatePlayerPosition(playersPosition: StringVector): void { + for (let id of Object.keys(playersPosition)) { + this.getPlayer(id).updatePosition(playersPosition[id]); + } + } + + public updatePlayerDirection(playersDirection: StringNumber): void { + for (let id of Object.keys(playersDirection)) { + this.getPlayer(id).updateDirection(playersDirection[id]); + } + } + + public updatePlayerColor(playersColor: { [key: string]: number }): void { + for (let id of Object.keys(playersColor)) { + this.getPlayer(id).updateColor(playersColor[id]); + } + } + + public getMyself(): Player { + return this.getPlayer(Globals.getInstance().socketId); + } + + public draw(): void { + for (let id of this.getPlayerIds()) { + this.players[id].draw(); + } + } +} diff --git a/src/app/home/scaleScreen.ts b/src/app/home/scaleScreen.ts new file mode 100644 index 0000000..2bfcc6f --- /dev/null +++ b/src/app/home/scaleScreen.ts @@ -0,0 +1,11 @@ +import { Globals } from "./globals"; +import { setCanvasSize } from "./setCanvasSize"; + +export const scaleScreen = () => { + const scaleX = Globals.getInstance().pageWidth / 9; + const scaleY = Globals.getInstance().pageHeight / 16; + if (scaleX > scaleY) { // width is longer, calculate based on height + return setCanvasSize((Globals.getInstance().pageHeight / 16) * 9, Globals.getInstance().pageHeight); + } + setCanvasSize(Globals.getInstance().pageWidth, (Globals.getInstance().pageWidth / 9) * 16); // height is longer, calculate based on width + } \ No newline at end of file diff --git a/src/app/home/setCanvasSize.ts b/src/app/home/setCanvasSize.ts new file mode 100644 index 0000000..38b67c6 --- /dev/null +++ b/src/app/home/setCanvasSize.ts @@ -0,0 +1,11 @@ +import { Globals } from "./globals"; + +export const setCanvasSize = (w: number, h: number) => { + Globals.getInstance().canvasScale = 1920 / h; + Globals.getInstance().width = w * Globals.getInstance().canvasScale; + Globals.getInstance().height = h * Globals.getInstance().canvasScale; + Globals.getInstance().canvas.style.height = h + 'px'; + Globals.getInstance().canvas.style.width = w + 'px'; + Globals.getInstance().canvas.height = Globals.getInstance().height; + Globals.getInstance().canvas.width = Globals.getInstance().width; + } \ No newline at end of file diff --git a/src/app/home/types.dto.ts b/src/app/home/types.dto.ts new file mode 100644 index 0000000..3820482 --- /dev/null +++ b/src/app/home/types.dto.ts @@ -0,0 +1,21 @@ +import { Position } from '../../../../Kawaii-Jumper-server/src/position'; +import { Player } from './player'; + +export type PlayerDTO = { + id: string; + position: Position; + name: string; + movingVelocity: Position; + color: number; + direction: number; +}; + +export type PlayerList = { [key: string]: Player }; +export type PlayerDTOList = { [key: string]: PlayerDTO }; + +export type Vector = { x: number; y: number }; + +export type StringString = { [key: string]: string }; +export type StringNumber = { [key: string]: number }; +export type StringVector = { [key: string]: Vector }; +export type StringBoolean = { [key: string]: boolean }; diff --git a/src/assets/bg.png b/src/assets/bg.png new file mode 100644 index 0000000..c025ccb Binary files /dev/null and b/src/assets/bg.png differ diff --git a/src/assets/jump.wav b/src/assets/jump.wav new file mode 100644 index 0000000..90312f8 Binary files /dev/null and b/src/assets/jump.wav differ diff --git a/src/assets/land.wav b/src/assets/land.wav new file mode 100644 index 0000000..67022dc Binary files /dev/null and b/src/assets/land.wav differ diff --git a/src/assets/platform-1.png b/src/assets/platform-1.png new file mode 100644 index 0000000..8ec790e Binary files /dev/null and b/src/assets/platform-1.png differ diff --git a/src/assets/platform-2.png b/src/assets/platform-2.png new file mode 100644 index 0000000..841b529 Binary files /dev/null and b/src/assets/platform-2.png differ diff --git a/src/assets/slime-1-left.png b/src/assets/slime-1-left.png new file mode 100644 index 0000000..d762ba7 Binary files /dev/null and b/src/assets/slime-1-left.png differ diff --git a/src/assets/slime-1-right.png b/src/assets/slime-1-right.png new file mode 100644 index 0000000..13cd8f7 Binary files /dev/null and b/src/assets/slime-1-right.png differ diff --git a/src/assets/slime-2-left.png b/src/assets/slime-2-left.png new file mode 100644 index 0000000..0b25bf2 Binary files /dev/null and b/src/assets/slime-2-left.png differ diff --git a/src/assets/slime-2-right.png b/src/assets/slime-2-right.png new file mode 100644 index 0000000..bc096e3 Binary files /dev/null and b/src/assets/slime-2-right.png differ diff --git a/src/index.html b/src/index.html index 3b0aae1..897f0dd 100644 --- a/src/index.html +++ b/src/index.html @@ -11,6 +11,9 @@ + + +