[WIP] multiple servers

This commit is contained in:
2022-01-30 14:13:05 +02:00
parent e11a283b2c
commit 805ae22f3b
37 changed files with 1183 additions and 554 deletions

21
.todo
View File

@@ -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)

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\RDarius\.android\avd\Pixel_4_API_29.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2022-01-30T00:49:19.859590700Z" />
</component>
</project>

View File

@@ -21,7 +21,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider

View File

@@ -2,5 +2,9 @@
<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<access origin="*" />
<feature name="NativeAudio">
<param name="android-package" value="com.rjfun.cordova.plugin.nativeaudio.NativeAudio"/>
</feature>
</widget>

View File

@@ -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

View File

@@ -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

136
package-lock.json generated
View File

@@ -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",

View File

@@ -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"

1
readme.md Normal file
View File

@@ -0,0 +1 @@
Server repository can be found [here](https://github.com/rdarius/kawaii-jumper-server)

View File

@@ -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({

View File

@@ -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 {}

View File

@@ -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');
}
}

View File

@@ -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();
}

41
src/app/home/gameLoop.ts Normal file
View File

@@ -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();
});
}

View File

@@ -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);
};

View File

@@ -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',

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -6,11 +6,11 @@ const routes: Routes = [
{
path: '',
component: HomePage,
}
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
exports: [RouterModule],
})
export class HomePageRoutingModule {}

View File

@@ -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();
});
}
}

View File

@@ -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));
};

View File

@@ -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);
}
}

View File

@@ -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,
);

View File

@@ -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]);

View File

@@ -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),
);
}

View File

@@ -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() };
}
};

View File

@@ -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 {}

View File

@@ -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 {}

View File

@@ -0,0 +1,21 @@
<ion-header>
<ion-toolbar>
<ion-title>Kawaii Jumper</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form (ngSubmit)="setName()">
<label for="name">{{ username ? 'Username: ' + username : 'Set your username' }}</label>
<input if="name" type="text" [(ngModel)]="user.username" name="username" />
<button type="submit">Change Username</button>
</form>
<a class="server-button" [routerLink]="['/game/1']">Server #1</a>
<a class="server-button" [routerLink]="['/game/2']">Server #2 (no-map)</a>
<a class="server-button" [routerLink]="['/game/3']">Server #3 (no-map)</a>
<a class="server-button" [routerLink]="['/game/4']">Server #4 (no-map)</a>
<a class="server-button" [routerLink]="['/game/5']">Server #5 (no-map)</a>
<a class="server-button" [routerLink]="['/game/6']">Server #6 (no-map)</a>
</ion-content>

View File

@@ -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;
}
}

View File

@@ -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<LobbyPage>;
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();
});
});

View File

@@ -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);
}
}

View File

@@ -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;
}