diff --git a/.todo b/.todo index 675c30f..196d0d9 100644 --- a/.todo +++ b/.todo @@ -11,21 +11,21 @@ Game: ✔ 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 - ☐ add name length limit + ✔ allow player to enter a name before starting the game @done(22-01-30 03:32) + ✔ show players names above their heads @done(22-01-29 16:13) + ✔ add name length limit @done(22-01-30 03:39) Server: ✘ do the same calculations for game logic (maybe use the same code base) @cancelled(22-01-29 11:18) - ☐ set player name + ✔ set player name @done(22-01-29 16:13) ✘ 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) + ✔ reach some specific height? (premade map) @done(22-01-30 03:39) + ✘ when time runs out player at the highest point wins? (randomy generated endless map) @cancelled(22-01-30 03:39) last one standing: ✘ player that is too far back from leading one looses? @cancelled(22-01-29 11:19) - ☐ last player after specific time is eliminated? + ✘ last player after specific time is eliminated? @cancelled(22-01-30 03:39) Game art: @@ -36,8 +36,13 @@ Game art: misc: ✘ 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) + +if I have time left: + ☐ once player reached the top, show winner's name to all players in that server and save their name in leaderboards next to button of that server + ☐ kawaii girl congatulates you when you reach the top + ☐ upgrade slimes to bigger and cuter creatures (maybe shrimps) + ☐ add background music from GDrive? (https://drive.google.com/drive/folders/1ZT_PQ4y0_KFQoQ34KN0AFEyaZ40WPX7L) \ No newline at end of file diff --git a/android/.idea/deploymentTargetDropDown.xml b/android/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..fa1ce43 --- /dev/null +++ b/android/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e6b2c70..760b450 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -21,7 +21,6 @@ - + + + + \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index ad085c3..8b15a09 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,13 +1,13 @@ // 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.android.tools.build:gradle:7.0.4' classpath 'com.google.gms:google-services:4.3.5' // NOTE: Do not place your application dependencies here; they belong diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 3c4101c..2475c50 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +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 +#Sun Jan 30 00:21:02 EET 2022 +//=DO NOT EDIT THIS FILE\! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include='\:capacitor-status-bar' +project('=capacitor-status-bar').projectDir \= new File('../node_modules/@capacitor/status-bar/android') +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip diff --git a/package-lock.json b/package-lock.json index c53b559..71fed7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1038,6 +1038,14 @@ "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", "dev": true }, + "@awesome-cordova-plugins/core": { + "version": "5.38.0", + "resolved": "https://registry.npmjs.org/@awesome-cordova-plugins/core/-/core-5.38.0.tgz", + "integrity": "sha512-mXMsQLTkJ/BBA0a44KutxpZK9jvC7vY7b8XuuiemPhC/1KxKQ9NKUQrQpDKanpHMoiiGRpLqoCFxLS2ShOzC3w==", + "requires": { + "@types/cordova": "^0.0.34" + } + }, "@babel/code-frame": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", @@ -2591,6 +2599,29 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@ionic-native/core": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/core/-/core-5.36.0.tgz", + "integrity": "sha512-lOrkktadlKYbYf1LrDyAtsu1JnQ0oCCdkOU7iHQ8oXnNOkMwobFfD2m62F1CoOr0u9LIkpYnZSPjng8lZbmbNw==", + "requires": { + "@types/cordova": "^0.0.34" + } + }, + "@ionic-native/native-audio": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/@ionic-native/native-audio/-/native-audio-5.36.0.tgz", + "integrity": "sha512-abE7G1dtvZAhSRj2B2tPZYDYtK5oHIUQHfu6JRLTMu8sj1FhK5prKm9B1mcrvK75PVIzPnp7m2q2jlFov4KfaQ==", + "requires": { + "@types/cordova": "^0.0.34" + }, + "dependencies": { + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + } + } + }, "@ionic/angular": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-6.0.4.tgz", @@ -5196,6 +5227,11 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, + "@types/cordova": { + "version": "0.0.34", + "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", + "integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=" + }, "@types/cors": { "version": "2.8.12", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", @@ -5671,6 +5707,27 @@ "@xtuc/long": "4.2.2" } }, + "@webpack-cli/configtest": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", + "dev": true + }, + "@webpack-cli/info": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", + "dev": true + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -7102,6 +7159,11 @@ } } }, + "cordova-plugin-nativeaudio": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/cordova-plugin-nativeaudio/-/cordova-plugin-nativeaudio-3.0.9.tgz", + "integrity": "sha1-Fs6/2u4kvrI8BfSXE8uHc7x4U2w=" + }, "core-js": { "version": "3.20.3", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", @@ -8080,6 +8142,12 @@ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, "err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", @@ -9063,6 +9131,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -10038,6 +10112,12 @@ "side-channel": "^1.0.4" } }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, "ionicons": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-6.0.1.tgz", @@ -14925,6 +15005,15 @@ "picomatch": "^2.2.1" } }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, "reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", @@ -17166,6 +17255,53 @@ } } }, + "webpack-cli": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + } + } + }, "webpack-dev-middleware": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz", diff --git a/package.json b/package.json index 7b5d826..b68a219 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,17 @@ "@angular/platform-browser": "~13.0.0", "@angular/platform-browser-dynamic": "~13.0.0", "@angular/router": "~13.0.0", + "@awesome-cordova-plugins/core": "^5.38.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-native/core": "^5.36.0", + "@ionic-native/native-audio": "^5.36.0", "@ionic/angular": "^6.0.0", + "cordova-plugin-nativeaudio": "^3.0.9", "ngrx": "0.0.1-security", "ngx-socket-io": "^4.1.0", "rxjs": "^6.6.7", @@ -64,6 +68,7 @@ "karma-jasmine": "~4.0.0", "karma-jasmine-html-reporter": "^1.5.0", "protractor": "~7.0.0", + "socket.io-client": "^4.4.1", "ts-node": "~8.3.0", "ts-node-dev": "^1.1.8", "typescript": "~4.4.4" diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..b695222 --- /dev/null +++ b/readme.md @@ -0,0 +1 @@ +Server repository can be found [here](https://github.com/rdarius/kawaii-jumper-server) \ No newline at end of file diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 5712c96..0e7db1d 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -2,10 +2,39 @@ import { NgModule } from '@angular/core'; import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; const routes: Routes = [ + { + path: 'game/1', + loadChildren: () => import('./home/home-1.module').then( m => m.HomePageModule1) + }, + { + path: 'game/2', + loadChildren: () => import('./home/home-2.module').then( m => m.HomePageModule2) + }, + { + path: 'game/3', + loadChildren: () => import('./home/home-3.module').then( m => m.HomePageModule3) + }, + { + path: 'game/4', + loadChildren: () => import('./home/home-4.module').then( m => m.HomePageModule4) + }, + { + path: 'game/5', + loadChildren: () => import('./home/home-5.module').then( m => m.HomePageModule5) + }, + { + path: 'game/6', + loadChildren: () => import('./home/home-6.module').then( m => m.HomePageModule6) + }, { path: '', - loadChildren: () => import('./home/home.module').then( m => m.HomePageModule) - } + redirectTo: 'lobby', + pathMatch: 'full' + }, + { + path: 'lobby', + loadChildren: () => import('./lobby/lobby.module').then( m => m.LobbyPageModule) + }, ]; @NgModule({ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 323dff4..9bb112e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,21 +1,75 @@ -import { NgModule } from '@angular/core'; +import { Injectable, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; -import { RouteReuseStrategy } from '@angular/router'; - +import { RouteReuseStrategy, RouterModule } 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'; +import { Socket, SocketIoConfig, SocketIoModule } from 'ngx-socket-io'; +import { NativeAudio } from '@ionic-native/native-audio/ngx'; + + +@Injectable() +export class SocketOne extends Socket { + constructor() { + super({ url: 'https://ggj2022-s1.rapalis.lt', options: {} }); + } +} + +@Injectable() +export class SocketTwo extends Socket { + constructor() { + super({ url: 'https://ggj2022-s2.rapalis.lt', options: {} }); + } +} + +@Injectable() +export class SocketThree extends Socket { + constructor() { + super({ url: 'https://ggj2022-s3.rapalis.lt', options: {} }); + } +} + +@Injectable() +export class SocketFour extends Socket { + constructor() { + super({ url: 'https://ggj2022-s4.rapalis.lt', options: {} }); + } +} + +@Injectable() +export class SocketFive extends Socket { + constructor() { + super({ url: 'https://ggj2022-s5.rapalis.lt', options: {} }); + } +} + +@Injectable() +export class SocketSix extends Socket { + constructor() { + super({ url: 'https://ggj2022-s6.rapalis.lt', options: {} }); + } +} 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, SocketIoModule.forRoot(config)], - providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }], + imports: [ + BrowserModule, + IonicModule.forRoot(), + AppRoutingModule, + RouterModule, + SocketIoModule.forRoot(config), + ], + providers: [ + { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, + NativeAudio, + SocketOne, + SocketTwo, + ], bootstrap: [AppComponent], }) export class AppModule {} diff --git a/src/app/home/detectCollision.ts b/src/app/home/detectCollision.ts new file mode 100644 index 0000000..54fcccb --- /dev/null +++ b/src/app/home/detectCollision.ts @@ -0,0 +1,311 @@ +import { getDistanceX, getDistanceY } from "./getDistance"; +import { Globals } from "./globals"; +import { IsIntersecting } from "./isIntersecting"; +import { Players } from "./players"; +import { Vector } from "./types.dto"; + +export const detectCollisions = () => { + const players = Players.getInstance(); + const player = players.getMyself(); + const globals = Globals.getInstance(); + + /* WIN CONDITION */ + if (player.getPosition().y < 160) { + alert('Congratulations, you raeched the top!'); + } + + for (let block of globals.map) { + if (block.color !== player.getColor()) continue; + + const playerWidth = globals.playerSize.x; + const playerHeight = globals.playerSize.y; + const myPosition = player.getPosition(); + + const playerTopLeft: Vector = myPosition; + const playerTopRight: Vector = { + x: myPosition.x + playerWidth, + y: myPosition.y, + }; + const playerBottomLeft: Vector = { + x: myPosition.x, + y: myPosition.y + playerHeight, + }; + const playerBottomRight: Vector = { + x: myPosition.x + playerWidth, + y: myPosition.y + playerHeight, + }; + + const blockTopLeft: Vector = { x: block.x, y: block.y }; + const blockTopRight: Vector = { x: block.x + block.w, y: block.y }; + const blockBottomLeft: Vector = { x: block.x, y: block.y + block.h }; + const blockBottomRight: Vector = { + x: block.x + block.w, + y: block.y + block.h, + }; + + if ( + IsIntersecting( + playerTopRight, + playerBottomRight, + blockTopLeft, + blockTopRight, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + const dx = getDistanceX(playerBottomRight, blockTopLeft); + const dy = getDistanceY(playerBottomRight, blockTopLeft); + if (globals.collisionLogging) + console.log('collision on top left corner of platform'); + + return dx < dy + ? player.touchRight(blockTopLeft.x) + : player.touchBottom(blockTopLeft.y); + } + + if ( + IsIntersecting( + playerTopRight, + playerBottomRight, + blockBottomLeft, + blockBottomRight, + ) && + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + const dx = getDistanceX(playerTopRight, blockBottomLeft); + const dy = getDistanceY(playerTopRight, blockBottomLeft); + if (globals.collisionLogging) + console.log('collision on bottom left corner of platform'); + + return dx < dy + ? player.touchRight(blockBottomLeft.x) + : player.touchTop(blockBottomLeft.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockTopLeft, + blockTopRight, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopRight, + blockBottomRight, + ) + ) { + const dx = getDistanceX(playerBottomLeft, blockTopRight); + const dy = getDistanceY(playerBottomLeft, blockTopRight); + if (globals.collisionLogging) + console.log('collision on top right corner of platform'); + + return dx < dy + ? player.touchLeft(blockTopRight.x) + : player.touchBottom(blockTopRight.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockBottomLeft, + blockBottomRight, + ) && + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopRight, + blockBottomRight, + ) + ) { + const dx = getDistanceX(playerTopLeft, blockBottomRight); + const dy = getDistanceY(playerTopLeft, blockBottomRight); + if (globals.collisionLogging) + console.log('collision on bottom right corner of platform'); + + return dx < dy + ? player.touchLeft(blockBottomRight.x) + : player.touchTop(blockBottomRight.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopLeft, + blockBottomLeft, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on left side of platform (platform bigger than player)', + ); + return player.touchRight(blockBottomLeft.x); + } + + if ( + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopRight, + blockBottomRight, + ) && + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopRight, + blockBottomRight, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on right side of platform (platform bigger than player)', + ); + return player.touchLeft(blockBottomRight.x); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockBottomLeft, + blockBottomRight, + ) && + IsIntersecting( + playerTopRight, + playerBottomRight, + blockBottomLeft, + blockBottomRight, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on bottom side of platform (platform bigger than player)', + ); + return player.touchTop(blockBottomLeft.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockTopLeft, + blockTopRight, + ) && + IsIntersecting( + playerTopRight, + playerBottomRight, + blockTopLeft, + blockTopRight, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on top side of platform (platform bigger than player)', + ); + return player.touchBottom(blockTopLeft.y); + } + + if ( + IsIntersecting( + playerTopLeft, + playerBottomLeft, + blockTopLeft, + blockTopRight, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on right side of platform (platform smaller than player)', + ); + return player.touchLeft(blockTopRight.x); + } + + if ( + IsIntersecting( + playerTopRight, + playerBottomRight, + blockTopLeft, + blockTopRight, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on left side of platform (platform smaller than player)', + ); + return player.touchRight(blockTopLeft.x); + } + + if ( + IsIntersecting( + playerTopLeft, + playerTopRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on bottom side of platform (platform smaller than player)', + ); + return player.touchTop(blockBottomLeft.y); + } + + if ( + IsIntersecting( + playerBottomLeft, + playerBottomRight, + blockTopLeft, + blockBottomLeft, + ) + ) { + if (globals.collisionLogging) + console.log( + 'collision on top side of platform (platform smaller than player)', + ); + return player.touchBottom(blockTopLeft.y); + } + } + + /* MAP BOUNDS */ + if ( + player.getPosition().y > + globals.height - globals.playerSize.y + ) { + player.touchBottom(globals.height); + if (globals.collisionLogging) + console.log('collision on the ground'); + } + + if (player.getPosition().x < 0) { + player.touchLeft(0); + if (globals.collisionLogging) + console.log('collision on left wall'); + } + + if ( + player.getPosition().x > + globals.width - globals.playerSize.x + ) { + player.touchRight(globals.width); + if (globals.collisionLogging) + console.log('collision on right wall'); + } + } \ No newline at end of file diff --git a/src/app/home/drawPointer.ts b/src/app/home/drawPointer.ts new file mode 100644 index 0000000..ec3382c --- /dev/null +++ b/src/app/home/drawPointer.ts @@ -0,0 +1,40 @@ +import { getAngleBetweenTwoPoints } from "./getAngleBetweenTwoPoints"; +import { getXFromAngle } from "./getXFromAngle"; +import { getYFromAngle } from "./getYFromAngle"; +import { Globals } from "./globals"; +import { Players } from "./players"; +import { Vector } from "./types.dto"; + +export const drawPointer = () => { + const globals = Globals.getInstance(); + const players = Players.getInstance(); + if (!globals.socketId) return; + if (!players.getMyself()) return; + globals.context.strokeStyle = '#00ff0066'; + globals.context.lineWidth = 15; + const angle = getAngleBetweenTwoPoints( + { + x: + players.getMyself().getPosition().x + + globals.playerSize.x / 2, + y: + players.getMyself().getPosition().y + + globals.playerSize.y / 2, + }, + globals.lastPointerPosition, + ); + globals.context.beginPath(); + globals.context.moveTo( + players.getMyself().getPosition().x + globals.playerSize.x / 2, + players.getMyself().getPosition().y + globals.playerSize.y / 2, + ); + globals.context.lineTo( + players.getMyself().getPosition().x + + globals.playerSize.x / 2 + + getXFromAngle(angle) * players.getMyself().getJumpPower() * 50, + players.getMyself().getPosition().y + + globals.playerSize.y / 2 + + getYFromAngle(angle) * players.getMyself().getJumpPower() * 50, + ); + globals.context.stroke(); + } \ No newline at end of file diff --git a/src/app/home/gameLoop.ts b/src/app/home/gameLoop.ts new file mode 100644 index 0000000..0b97d3e --- /dev/null +++ b/src/app/home/gameLoop.ts @@ -0,0 +1,41 @@ +import { DeltaTime } from "./deltaTime"; +import { drawMap } from "./drawMap"; +import { drawPointer } from "./drawPointer"; +import { Globals } from "./globals"; +import { Players } from "./players"; +import { updatePlayerPosition } from "./updatePlayerPosition"; + +export const gameLoop = () => { + const globals = Globals.getInstance(); + const deltaTime = DeltaTime.getInstance(); + const players = Players.getInstance(); + globals.context.fillStyle = 'gray'; + globals.context.drawImage( + globals.backgroudnImage, + 0, + 0, + globals.width, + globals.height, + ); + + drawMap( + globals.map, + globals.context, + globals.platformImages, + ); + if (globals.mapBuilder) { + drawMap(globals.builtMap, globals.context, globals.platformImages); + } + + deltaTime.updateDeltaTime(); + + players.tick(); + players.draw(); + + updatePlayerPosition(); + drawPointer(); + + requestAnimationFrame(() => { + gameLoop(); + }); + } \ No newline at end of file diff --git a/src/app/home/getDistance.ts b/src/app/home/getDistance.ts new file mode 100644 index 0000000..174ef63 --- /dev/null +++ b/src/app/home/getDistance.ts @@ -0,0 +1,9 @@ +import { Vector } from './types.dto'; + +export const getDistanceX = (p1: Vector, p2: Vector): number => { + return Math.abs(p1.x - p2.x); +}; + +export const getDistanceY = (p1: Vector, p2: Vector): number => { + return Math.abs(p1.y - p2.y); +}; diff --git a/src/app/home/globals.ts b/src/app/home/globals.ts index 027a819..fc80fd7 100644 --- a/src/app/home/globals.ts +++ b/src/app/home/globals.ts @@ -1,7 +1,10 @@ +import { NativeAudio } from '@ionic-native/native-audio/ngx'; +import { Platform } from '@ionic/angular'; import { Socket } from 'ngx-socket-io'; import { MapTile } from '../../../../Kawaii-Jumper-server/src/mapTile'; import { makeHTMLAudioElements } from './makeHTMLAudioElements'; import { makeHTMLImageElements } from './makeHTMLImageObjects'; +import { Players } from './players'; import { scaleScreen } from './scaleScreen'; import { Vector } from './types.dto'; @@ -9,8 +12,8 @@ export class Globals { public width: number = 0; public height: number = 0; public canvasScale: number = 0; - public pageWidth: number = 0; - public pageHeight: number = 0; + public pageWidth: number = window.innerWidth; + public pageHeight: number = window.innerHeight; public canvas: HTMLCanvasElement; public context: CanvasRenderingContext2D; public playerImages: HTMLImageElement[] = []; @@ -22,6 +25,16 @@ export class Globals { public playerSize: Vector = { x: 50, y: 34 }; public map: MapTile[] = []; public backgroudnImage: HTMLImageElement; + public nativeAudio: NativeAudio; + public platform: Platform; + public collisionLogging: boolean = false; + public mapBuilder: boolean = false; + public lastPointerPosition: Vector = { x: 0, y: 0 }; + public builtMap: MapTile[] = []; + public myLastPosition: Vector = { x: 0, y: 0 }; + public mapBuilderTile: number = 0; + public canvasOffset: Vector = { x: 0, y: 0 }; + public keysDown: boolean[] = []; private readonly playerImageFiles: string[] = [ '/assets/slime-1-left.png', diff --git a/src/app/home/home-1.module.ts b/src/app/home/home-1.module.ts new file mode 100644 index 0000000..fdc1597 --- /dev/null +++ b/src/app/home/home-1.module.ts @@ -0,0 +1,15 @@ +import { Injectable, NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { Socket } from 'ngx-socket-io'; +import { SocketOne } from '../app.module'; + +@NgModule({ + imports: [CommonModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], + providers: [{provide: Socket, useClass: SocketOne}] +}) +export class HomePageModule1 {} diff --git a/src/app/home/home-2.module.ts b/src/app/home/home-2.module.ts new file mode 100644 index 0000000..c182b29 --- /dev/null +++ b/src/app/home/home-2.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { Socket } from 'ngx-socket-io'; +import { SocketTwo } from '../app.module'; + +@NgModule({ + imports: [CommonModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], + providers: [{provide: Socket, useClass: SocketTwo}] +}) +export class HomePageModule2 {} diff --git a/src/app/home/home-3.module.ts b/src/app/home/home-3.module.ts new file mode 100644 index 0000000..a0f2a80 --- /dev/null +++ b/src/app/home/home-3.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { Socket } from 'ngx-socket-io'; +import { SocketThree } from '../app.module'; + +@NgModule({ + imports: [CommonModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], + providers: [{provide: Socket, useClass: SocketThree}] +}) +export class HomePageModule3 {} + diff --git a/src/app/home/home-4.module.ts b/src/app/home/home-4.module.ts new file mode 100644 index 0000000..1b4174d --- /dev/null +++ b/src/app/home/home-4.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { Socket } from 'ngx-socket-io'; +import { SocketFour } from '../app.module'; + +@NgModule({ + imports: [CommonModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], + providers: [{provide: Socket, useClass: SocketFour}] +}) +export class HomePageModule4 {} + diff --git a/src/app/home/home-5.module.ts b/src/app/home/home-5.module.ts new file mode 100644 index 0000000..d39b179 --- /dev/null +++ b/src/app/home/home-5.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { Socket } from 'ngx-socket-io'; +import { SocketFive } from '../app.module'; + +@NgModule({ + imports: [CommonModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], + providers: [{provide: Socket, useClass: SocketFive}] +}) +export class HomePageModule5 {} + diff --git a/src/app/home/home-6.module.ts b/src/app/home/home-6.module.ts new file mode 100644 index 0000000..8b3a3f4 --- /dev/null +++ b/src/app/home/home-6.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { IonicModule } from '@ionic/angular'; +import { HomePage } from './home.page'; + +import { HomePageRoutingModule } from './home-routing.module'; +import { Socket } from 'ngx-socket-io'; +import { SocketSix } from '../app.module'; + +@NgModule({ + imports: [CommonModule, IonicModule, HomePageRoutingModule], + declarations: [HomePage], + providers: [{provide: Socket, useClass: SocketSix}] +}) +export class HomePageModule6 {} diff --git a/src/app/home/home-routing.module.ts b/src/app/home/home-routing.module.ts index 29c3f60..dcf3102 100644 --- a/src/app/home/home-routing.module.ts +++ b/src/app/home/home-routing.module.ts @@ -6,11 +6,11 @@ const routes: Routes = [ { path: '', component: HomePage, - } + }, ]; @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule] + exports: [RouterModule], }) export class HomePageRoutingModule {} diff --git a/src/app/home/home.page.ts b/src/app/home/home.page.ts index 66fcd3c..8411890 100644 --- a/src/app/home/home.page.ts +++ b/src/app/home/home.page.ts @@ -1,534 +1,58 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, 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 { NativeAudio } from '@ionic-native/native-audio/ngx'; import { Globals } from './globals'; +import { Platform } from '@ionic/angular'; +import { setupSocketListeners } from './setupSocketListeners'; +import { gameLoop } from './gameLoop'; +import { setListeners } from './listenerEvents'; import { Players } from './players'; -import { MySocket } from './mySocket'; -import { DeltaTime } from './deltaTime'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) -export class HomePage implements OnInit { +export class HomePage { globals: Globals; players: Players; - mySocket: MySocket; - deltaTime: DeltaTime; - myLastPosition: Position = { x: 0, y: 0 }; + constructor( + private readonly socket: Socket, + private readonly nativeAudio: NativeAudio, + private readonly platform: Platform, + ) { + } - jumpPower = Date.now(); - - lastPointerPosition: Position = { x: 0, y: 0 }; - - keysDown: { [key: number]: boolean } = {}; - - mapBuilder = false; - - builtMap: MapTile[] = []; - - constructor(private socket: Socket) { + ionViewDidLeave() { + this.globals.socket.removeAllListeners(); + this.globals.socket.disconnect(); + } + + ionViewWillEnter() { 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(); + this.globals.socket = this.socket; + setupSocketListeners(); } - ngOnInit(): void { + ionViewDidEnter() { + this.players.removeAllPlayers(); + this.globals.map = []; + + this.globals.nativeAudio = this.nativeAudio; + this.globals.platform = this.platform; this.globals.setupCanvas(); - this.setListeners(); - this.gameLoop(); + this.socket.connect(); + setListeners(); + gameLoop(); + + this.nativeAudio.preloadSimple('jump', 'assets/jump.wav'); + this.nativeAudio.preloadSimple('land', 'assets/land.wav'); + this.globals.canvasOffset.y = + (window.innerHeight - parseInt(this.globals.canvas.style.height)) / 2; + this.globals.canvasOffset.x = + (window.innerWidth - parseInt(this.globals.canvas.style.width)) / 2; } - 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), - ); - } - - getJumpPower(): number { - let power = Date.now() - this.jumpPower; - return Math.abs(getXFromAngle(power / 1000) * 1.4); - } - - 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, - }, - ); - } - - 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); - } - } - - 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/listenerEvents.ts b/src/app/home/listenerEvents.ts new file mode 100644 index 0000000..a64c8c0 --- /dev/null +++ b/src/app/home/listenerEvents.ts @@ -0,0 +1,95 @@ +import { Globals } from './globals'; +import { MySocket } from './mySocket'; +import { Players } from './players'; +import { Vector } from './types.dto'; + +export const touchEndListener = ($event): void => { + const globals = Globals.getInstance(); + if (!$event.changedTouches.length) return; + clickEvent({ + x: $event.changedTouches[0].pageX - globals.canvasOffset.x, + y: $event.changedTouches[0].pageY - globals.canvasOffset.y, + }); +}; + +export const clickEndListener = ($event): void => { + if ($event.button !== 0) return; + clickEvent({ x: $event.offsetX, y: $event.offsetY }); +}; + +export const clickEvent = (position: Vector) => { + const globals = Globals.getInstance(); + const players = Players.getInstance(); + const mySocket = MySocket.getInstance(); + if (!players.getMyself()) return; + if (!players.getMyself().isGrounded()) return; + const player = players.getMyself(); + + player.swapColor(); + player.setGrounded(false); + player.jump(position); + + mySocket.sendUpdatedColor(player.getColor()); + mySocket.sendUpdatedDirection(player.getDirection()); + if (globals.platform.is('cordova')) { + globals.nativeAudio.play('jump').then(console.log, console.error); + } else { + globals.sounds[0].play(); + } +}; + +export const mapClickListenerEnd = ($event) => { + if ($event.button !== 0) return; + const globals = Globals.getInstance(); + globals.builtMap.push({ + color: globals.mapBuilderTile, + x: Math.floor($event.offsetX * globals.canvasScale), + y: Math.floor($event.offsetY * globals.canvasScale), + w: 130, + h: 30, + }); + console.log(globals.builtMap); +}; + +export const touchMoveListener = ($event: TouchEvent): void => { + const globals = Globals.getInstance(); + if (!$event.touches.length) return; + globals.lastPointerPosition = { + x: ($event.touches[0].pageX - globals.canvasOffset.x) * globals.canvasScale, + y: ($event.touches[0].pageY - globals.canvasOffset.y) * globals.canvasScale, + }; +}; + +export const moveListener = ($event): void => { + const globals = Globals.getInstance(); + if (!globals.socketId) return; + globals.lastPointerPosition = { + x: $event.offsetX * globals.canvasScale, + y: $event.offsetY * globals.canvasScale, + }; +}; + +export const keyListener = ($event, state) => { + const globals = Globals.getInstance(); + globals.keysDown[$event.keyCode] = state; + switch ($event.keyCode) { + case 49: + globals.mapBuilderTile = 0; + break; + case 50: + globals.mapBuilderTile = 1; + break; + } +}; + +export const setListeners = () => { + const globals = Globals.getInstance(); + window.addEventListener('keydown', (e) => keyListener(e, true)); + window.addEventListener('keyup', (e) => keyListener(e, false)); + globals.canvas.addEventListener('mouseup', (e) => + globals.mapBuilder ? mapClickListenerEnd(e) : clickEndListener(e), + ); + globals.canvas.addEventListener('touchend', (e) => touchEndListener(e)); + globals.canvas.addEventListener('mousemove', (e) => moveListener(e)); + globals.canvas.addEventListener('touchmove', (e) => touchMoveListener(e)); +}; diff --git a/src/app/home/mySocket.ts b/src/app/home/mySocket.ts index 7dd1dad..17b2fce 100644 --- a/src/app/home/mySocket.ts +++ b/src/app/home/mySocket.ts @@ -1,9 +1,12 @@ import { Globals } from './globals'; +import { Vector } from './types.dto'; export class MySocket { private static instance: MySocket; private globals: Globals; + private readonly debug = true; + private constructor() { this.globals = Globals.getInstance(); } @@ -16,34 +19,65 @@ export class MySocket { } public onId(callback: CallableFunction): void { + if (this.debug) console.log('socket >> takeYourIdAndLeaveMeAlone'); this.globals.socket.on('takeYourIdAndLeaveMeAlone', callback); + if (this.debug) console.log('socket << setMyUsername'); + this.globals.socket.emit('setMyUsername', localStorage.getItem('username')); } public onPlayerConnected(callback: CallableFunction): void { + if (this.debug) console.log('socket >> connectedPlayers'); this.globals.socket.on('connectedPlayers', callback); } + public onNameChanged(callback: CallableFunction): void { + if (this.debug) console.log('socket >> nameChanged'); + this.globals.socket.on('nameChanged', callback); + } + public onNewPlayerConnected(callback: CallableFunction): void { + if (this.debug) console.log('socket >> newPlayer'); this.globals.socket.on('newPlayer', callback); } public onPlayerDisconnected(callback: CallableFunction): void { + if (this.debug) console.log('socket >> playerDisconnected'); this.globals.socket.on('playerDisconnected', callback); } public onUpdatedPlayerPosition(callback: CallableFunction): void { + if (this.debug) console.log('socket >> updatedPlayerPositions'); this.globals.socket.on('updatedPlayerPositions', callback); } public onUpdatedPlayerColor(callback: CallableFunction): void { + if (this.debug) console.log('socket >> updatedPlayerColor'); this.globals.socket.on('updatedPlayerColor', callback); } public onUpdatedPlayerDirection(callback: CallableFunction): void { + if (this.debug) console.log('socket >> updatedPlayerDirection'); this.globals.socket.on('updatedPlayerDirection', callback); } public onMap(callback: CallableFunction): void { + if (this.debug) console.log('socket >> takeTheMapAndBeQuiet'); this.globals.socket.on('takeTheMapAndBeQuiet', callback); } + + public sendUpdatedColor(color: number): void { + if (this.debug) console.log('socket << updatedColor'); + this.globals.socket.emit('updatedColor', color); + } + + public sendUpdatedPosition(position: Vector): void { + if (this.debug) console.log('socket << updatedPosition'); + this.globals.socket.emit('updatedPosition', position); + } + + public sendUpdatedDirection(direction: number): void { + if (this.debug) console.log('socket << updatedDirection'); + this.globals.socket.emit('updatedDirection', direction); + } + } diff --git a/src/app/home/player.ts b/src/app/home/player.ts index 2f72fd3..7b10882 100644 --- a/src/app/home/player.ts +++ b/src/app/home/player.ts @@ -1,14 +1,15 @@ import { Position } from '../../../../Kawaii-Jumper-server/src/position'; import { applyGravity } from './applyGravity'; import { DeltaTime } from './deltaTime'; +import { getAngleBetweenTwoPoints } from './getAngleBetweenTwoPoints'; 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 readonly globals: Globals; + private readonly deltaTime: DeltaTime; private id: string; private position: Vector; private name: string; @@ -33,6 +34,7 @@ export class Player { this.movingVelocity = { ...applyGravity(this.movingVelocity, this.deltaTime.getDeltaTime()), }; + console.log(this.movingVelocity); } public resetVelocity() { @@ -60,9 +62,16 @@ export class Player { } public getName(): string { + if (this.isMyself() && localStorage.getItem('username')) { + return localStorage.getItem('username'); + } return this.name; } + public setName(name: string): void { + this.name = name; + } + public getColor(): number { return this.color; } @@ -87,10 +96,30 @@ export class Player { this.color = this.color === 0 ? 1 : 0; } - public jump(angle: number, jumpPower: number): void { + public getJumpPower(): number { + return Math.abs(getXFromAngle(Date.now() / 1000) * 1.4); + } + + private _getJumpDirection(x: number, y: number) { + return getAngleBetweenTwoPoints( + { + x: this.position.x + this.globals.playerSize.x / 2, + y: this.position.y + this.globals.playerSize.y / 2, + }, + { + x: x * this.globals.canvasScale, + y: y * this.globals.canvasScale, + }, + ); + } + + public jump(click: Vector): void { + const jumpPower = this.getJumpPower(); + const angle = this._getJumpDirection(click.x, click.y); this.movingVelocity.x = getXFromAngle(angle) * jumpPower; this.movingVelocity.y = getYFromAngle(angle) * jumpPower; this.direction = this.movingVelocity.x > 0 ? 1 : 0; + console.log(this.movingVelocity, this.direction); } public move(): void { @@ -101,8 +130,12 @@ export class Player { 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(); + if (this.isMyself()) { + if(this.globals.platform.is('cordova')) { + this.globals.nativeAudio.play('land').then(console.log, console.error); + } else { + this.globals.sounds[1].play(); + } } this.resetVelocity(); } @@ -138,7 +171,7 @@ export class Player { this.globals.context.textAlign = 'center'; this.globals.context.font = '25px Arial'; this.globals.context.fillText( - this.name, + this.getName(), 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 index dc0101c..4589c9d 100644 --- a/src/app/home/players.ts +++ b/src/app/home/players.ts @@ -6,6 +6,7 @@ import { PlayerDTOList, PlayerList, StringNumber, + StringString, StringVector, Vector, } from './types.dto'; @@ -36,6 +37,10 @@ export class Players { } } + public removeAllPlayers(): void { + this.players = {}; + } + public resetVelocity(id: string): void { this.getPlayer(id).resetVelocity(); } @@ -53,6 +58,7 @@ export class Players { } public addMultiplaPlayers(players: PlayerDTOList): void { + this.players = {}; for (let player of Object.keys(players)) { this.addPlayer(players[player]); } @@ -80,6 +86,12 @@ export class Players { } } + public updatePlayerNames(playersName: StringString): void { + for (let id of Object.keys(playersName)) { + this.getPlayer(id).setName(playersName[id]); + } + } + public updatePlayerColor(playersColor: { [key: string]: number }): void { for (let id of Object.keys(playersColor)) { this.getPlayer(id).updateColor(playersColor[id]); diff --git a/src/app/home/setupSocketListeners.ts b/src/app/home/setupSocketListeners.ts new file mode 100644 index 0000000..9d0fce9 --- /dev/null +++ b/src/app/home/setupSocketListeners.ts @@ -0,0 +1,34 @@ +import { MapTile } from "../../../../Kawaii-Jumper-server/src/mapTile"; +import { Globals } from "./globals"; +import { MySocket } from "./mySocket"; +import { Players } from "./players"; +import { PlayerDTO, PlayerDTOList, StringNumber, StringString, StringVector } from "./types.dto"; + +export const setupSocketListeners = () => { + const mySocket = MySocket.getInstance(); + const players = Players.getInstance(); + const globals = Globals.getInstance(); + mySocket.onId((id: string) => (globals.socketId = id)); + mySocket.onMap((map: MapTile[]) => (globals.map = map)); + mySocket.onPlayerConnected((playersList: PlayerDTOList) => + players.addMultiplaPlayers(playersList), + ); + mySocket.onNewPlayerConnected((player: PlayerDTO) => + players.addPlayer(player), + ); + mySocket.onPlayerDisconnected((id: string) => + players.removePlayer(id), + ); + mySocket.onUpdatedPlayerColor((playersColor: StringNumber) => + players.updatePlayerColor(playersColor), + ); + mySocket.onUpdatedPlayerPosition((playersPosition: StringVector) => + players.updatePlayerPosition(playersPosition), + ); + mySocket.onUpdatedPlayerDirection((playersDirection: StringNumber) => + players.updatePlayerDirection(playersDirection), + ); + mySocket.onNameChanged((playersName: StringString) => + players.updatePlayerNames(playersName), + ); + } \ No newline at end of file diff --git a/src/app/home/updatePlayerPosition.ts b/src/app/home/updatePlayerPosition.ts new file mode 100644 index 0000000..e2fe122 --- /dev/null +++ b/src/app/home/updatePlayerPosition.ts @@ -0,0 +1,19 @@ +import { detectCollisions } from './detectCollision'; +import { Globals } from './globals'; +import { MySocket } from './mySocket'; +import { Players } from './players'; + +export const updatePlayerPosition = () => { + const players = Players.getInstance(); + const globals = Globals.getInstance(); + const mySocket = MySocket.getInstance(); + if (!players.getMyself()) return; + detectCollisions(); + if ( + players.getMyself().getPosition().x !== globals.myLastPosition.x || + players.getMyself().getPosition().y !== globals.myLastPosition.y + ) { + mySocket.sendUpdatedPosition(players.getMyself().getPosition()); + globals.myLastPosition = { ...players.getMyself().getPosition() }; + } +}; diff --git a/src/app/lobby/lobby-routing.module.ts b/src/app/lobby/lobby-routing.module.ts new file mode 100644 index 0000000..6990853 --- /dev/null +++ b/src/app/lobby/lobby-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { LobbyPage } from './lobby.page'; + +const routes: Routes = [ + { + path: '', + component: LobbyPage + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class LobbyPageRoutingModule {} diff --git a/src/app/home/home.module.ts b/src/app/lobby/lobby.module.ts similarity index 58% rename from src/app/home/home.module.ts rename to src/app/lobby/lobby.module.ts index a554f01..27a44b5 100644 --- a/src/app/home/home.module.ts +++ b/src/app/lobby/lobby.module.ts @@ -1,19 +1,20 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { IonicModule } from '@ionic/angular'; import { FormsModule } from '@angular/forms'; -import { HomePage } from './home.page'; -import { HomePageRoutingModule } from './home-routing.module'; +import { IonicModule } from '@ionic/angular'; +import { LobbyPageRoutingModule } from './lobby-routing.module'; + +import { LobbyPage } from './lobby.page'; @NgModule({ imports: [ CommonModule, FormsModule, IonicModule, - HomePageRoutingModule + LobbyPageRoutingModule ], - declarations: [HomePage] + declarations: [LobbyPage] }) -export class HomePageModule {} +export class LobbyPageModule {} diff --git a/src/app/lobby/lobby.page.html b/src/app/lobby/lobby.page.html new file mode 100644 index 0000000..2040a77 --- /dev/null +++ b/src/app/lobby/lobby.page.html @@ -0,0 +1,21 @@ + + + Kawaii Jumper + + + + + +
+ + + +
+ + Server #1 + Server #2 (no-map) + Server #3 (no-map) + Server #4 (no-map) + Server #5 (no-map) + Server #6 (no-map) +
diff --git a/src/app/lobby/lobby.page.scss b/src/app/lobby/lobby.page.scss new file mode 100644 index 0000000..80049ea --- /dev/null +++ b/src/app/lobby/lobby.page.scss @@ -0,0 +1,24 @@ +.server-button { + padding: 24px; + font-size: 24px; + margin: 12px; + background: #FF63C8; + &:nth-child(odd) { + background: #79e7ff; + } + color: black; + display: inline-block; + text-decoration: none; +} + +form { + display: flex; + flex-direction: column; + padding: 24px; + + input, label, button { + padding: 8px; + margin: 8px; + } + +} \ No newline at end of file diff --git a/src/app/lobby/lobby.page.spec.ts b/src/app/lobby/lobby.page.spec.ts new file mode 100644 index 0000000..5e54a11 --- /dev/null +++ b/src/app/lobby/lobby.page.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { IonicModule } from '@ionic/angular'; + +import { LobbyPage } from './lobby.page'; + +describe('LobbyPage', () => { + let component: LobbyPage; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ LobbyPage ], + imports: [IonicModule.forRoot()] + }).compileComponents(); + + fixture = TestBed.createComponent(LobbyPage); + component = fixture.componentInstance; + fixture.detectChanges(); + })); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/lobby/lobby.page.ts b/src/app/lobby/lobby.page.ts new file mode 100644 index 0000000..98e5db2 --- /dev/null +++ b/src/app/lobby/lobby.page.ts @@ -0,0 +1,30 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-lobby', + templateUrl: './lobby.page.html', + styleUrls: ['./lobby.page.scss'], +}) +export class LobbyPage implements OnInit { + + username = ''; + + user = { + username: '' + } + + constructor() {} + + ngOnInit() { + this.username = localStorage.getItem('username'); + } + + setName() { + this.username = this.user.username; + if (this.username.length > 16) { + this.username = this.username.substring(0, 16); + } + localStorage.setItem('username', this.username); + } + +} diff --git a/src/global.scss b/src/global.scss index d854de8..62f5815 100644 --- a/src/global.scss +++ b/src/global.scss @@ -24,3 +24,7 @@ @import "~@ionic/angular/css/text-alignment.css"; @import "~@ionic/angular/css/text-transformation.css"; @import "~@ionic/angular/css/flex-utils.css"; + +body { + background: black!important; +} \ No newline at end of file