Merge branch 'master' into feature/back-players-proximity
# Conflicts: # back/src/Model/Websocket/MessageUserPosition.ts
This commit is contained in:
commit
9730df2295
1
.env.template
Normal file
1
.env.template
Normal file
@ -0,0 +1 @@
|
|||||||
|
DEBUG_MODE=false
|
102
.github/workflows/build-and-deploy.yml
vendored
Normal file
102
.github/workflows/build-and-deploy.yml
vendored
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
name: Build, push and deploy Docker image
|
||||||
|
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
|
||||||
|
# Enables BuildKit
|
||||||
|
env:
|
||||||
|
DOCKER_BUILDKIT: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build-front:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
|
||||||
|
# Create a slugified value of the branch
|
||||||
|
- uses: rlespinasse/github-slug-action@master
|
||||||
|
|
||||||
|
- name: "Build and push front image"
|
||||||
|
uses: docker/build-push-action@v1
|
||||||
|
with:
|
||||||
|
dockerfile: front/Dockerfile
|
||||||
|
path: front/
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
repository: thecodingmachine/workadventure-front
|
||||||
|
tags: ${{ env.GITHUB_REF_SLUG }}
|
||||||
|
add_git_labels: true
|
||||||
|
|
||||||
|
build-back:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Create a slugified value of the branch
|
||||||
|
- uses: rlespinasse/github-slug-action@master
|
||||||
|
|
||||||
|
- name: "Build and push back image"
|
||||||
|
uses: docker/build-push-action@v1
|
||||||
|
with:
|
||||||
|
dockerfile: back/Dockerfile
|
||||||
|
path: back/
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
repository: thecodingmachine/workadventure-back
|
||||||
|
tags: ${{ env.GITHUB_REF_SLUG }}
|
||||||
|
add_git_labels: true
|
||||||
|
|
||||||
|
deeploy:
|
||||||
|
needs:
|
||||||
|
- build-front
|
||||||
|
- build-back
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Create a slugified value of the branch
|
||||||
|
- uses: rlespinasse/github-slug-action@1.1.0
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: thecodingmachine/deeployer@master
|
||||||
|
env:
|
||||||
|
KUBE_CONFIG_FILE: ${{ secrets.KUBE_CONFIG_FILE }}
|
||||||
|
with:
|
||||||
|
namespace: workadventure-${{ env.GITHUB_REF_SLUG }}
|
||||||
|
|
||||||
|
- name: Add a comment in PR
|
||||||
|
uses: unsplash/comment-on-pr@v1.2.0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
msg: Environment deployed at https://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
|
||||||
|
check_for_duplicate_msg: true
|
||||||
|
|
||||||
|
- name: Run Cypress tests
|
||||||
|
uses: cypress-io/github-action@v1
|
||||||
|
env:
|
||||||
|
CYPRESS_BASE_URL: https://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
|
||||||
|
with:
|
||||||
|
env: host=${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com,port=80
|
||||||
|
spec: cypress/integration/spec.js
|
||||||
|
wait-on: https://${{ env.GITHUB_REF_SLUG }}.workadventure.test.thecodingmachine.com
|
||||||
|
working-directory: e2e
|
||||||
|
|
||||||
|
- name: "Upload the screenshot on test failure"
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
name: "screenshot"
|
||||||
|
path: "./e2e/cypress/screenshots/spec.js/WorkAdventureGame -- loads (failed).png"
|
1
.github/workflows/continuous_integration.yml
vendored
1
.github/workflows/continuous_integration.yml
vendored
@ -65,3 +65,4 @@ jobs:
|
|||||||
- name: "Jasmine"
|
- name: "Jasmine"
|
||||||
run: yarn test
|
run: yarn test
|
||||||
working-directory: "back"
|
working-directory: "back"
|
||||||
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.env
|
||||||
.idea
|
.idea
|
||||||
.vagrant
|
.vagrant
|
||||||
Vagrantfile
|
Vagrantfile
|
15
README.md
15
README.md
@ -32,6 +32,19 @@ Note: on some OSes, you will need to add this line to your `/etc/hosts` file:
|
|||||||
workadventure.localhost 127.0.0.1
|
workadventure.localhost 127.0.0.1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Designing a map
|
||||||
|
|
||||||
|
If you want to design your own map, you can use [Tiled](https://www.mapeditor.org/).
|
||||||
|
|
||||||
|
A few things to notice:
|
||||||
|
|
||||||
|
- your map can have as many layers as your want
|
||||||
|
- your map MUST contain a layer named "floorLayer" of type "objectgroup" that represents the layer on which characters will be drawn.
|
||||||
|
- the tilesets in your map MUST be embedded. You can refer to an external typeset in a TSX file. Click the "embed tileset" button in the tileset tab to embed tileset data.
|
||||||
|
- your map MUST be exported in JSON format. You need to use a recent version of Tiled to get JSON format export (1.3+)
|
||||||
|
|
||||||
|
![](doc/images/tiled_screenshot_1.png)
|
||||||
|
|
||||||
### MacOS developers, your environment with Vagrant
|
### MacOS developers, your environment with Vagrant
|
||||||
|
|
||||||
If you are using MacOS, you can increase Docker performance using Vagrant. If you want more explanations, you can read [this medium article](https://medium.com/better-programming/vagrant-to-increase-docker-performance-with-macos-25b354b0c65c).
|
If you are using MacOS, you can increase Docker performance using Vagrant. If you want more explanations, you can read [this medium article](https://medium.com/better-programming/vagrant-to-increase-docker-performance-with-macos-25b354b0c65c).
|
||||||
@ -98,4 +111,4 @@ Vagrant destroy
|
|||||||
* `Vagrant destroy`: delete your VM Vagrant.
|
* `Vagrant destroy`: delete your VM Vagrant.
|
||||||
|
|
||||||
## Features developed
|
## Features developed
|
||||||
You have more details of features developed in back [README.md](./back/README.md).
|
You have more details of features developed in back [README.md](./back/README.md).
|
||||||
|
5
back/.dockerignore
Normal file
5
back/.dockerignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/dist/
|
||||||
|
/node_modules/
|
||||||
|
/dist/bundle.js
|
||||||
|
/yarn-error.log
|
||||||
|
/Dockerfile
|
9
back/Dockerfile
Normal file
9
back/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
FROM thecodingmachine/nodejs:12
|
||||||
|
|
||||||
|
COPY --chown=docker:docker . .
|
||||||
|
RUN yarn install
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
CMD ["yarn", "run", "prod"]
|
||||||
|
|
@ -25,13 +25,15 @@
|
|||||||
"@types/http-status-codes": "^1.2.0",
|
"@types/http-status-codes": "^1.2.0",
|
||||||
"@types/jsonwebtoken": "^8.3.8",
|
"@types/jsonwebtoken": "^8.3.8",
|
||||||
"@types/socket.io": "^2.1.4",
|
"@types/socket.io": "^2.1.4",
|
||||||
|
"@types/uuidv4": "^5.0.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"http-status-codes": "^1.4.0",
|
"http-status-codes": "^1.4.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"socket.io": "^2.3.0",
|
"socket.io": "^2.3.0",
|
||||||
"ts-node-dev": "^1.0.0-pre.44",
|
"ts-node-dev": "^1.0.0-pre.44",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3",
|
||||||
|
"uuidv4": "^6.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jasmine": "^3.5.10",
|
"@types/jasmine": "^3.5.10",
|
||||||
|
@ -2,6 +2,7 @@ import {Application, Request, Response} from "express";
|
|||||||
import Jwt from "jsonwebtoken";
|
import Jwt from "jsonwebtoken";
|
||||||
import {BAD_REQUEST, OK} from "http-status-codes";
|
import {BAD_REQUEST, OK} from "http-status-codes";
|
||||||
import {SECRET_KEY, ROOM} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
import {SECRET_KEY, ROOM} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..."
|
||||||
|
import { uuid } from 'uuidv4';
|
||||||
|
|
||||||
export class AuthenticateController{
|
export class AuthenticateController{
|
||||||
App : Application;
|
App : Application;
|
||||||
@ -21,8 +22,13 @@ export class AuthenticateController{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
//TODO check user email for The Coding Machine game
|
//TODO check user email for The Coding Machine game
|
||||||
let token = Jwt.sign({email: param.email, roomId: ROOM}, SECRET_KEY, {expiresIn: '24h'});
|
let userId = uuid();
|
||||||
return res.status(OK).send({token: token, roomId: ROOM});
|
let token = Jwt.sign({email: param.email, roomId: ROOM, userId: userId}, SECRET_KEY, {expiresIn: '24h'});
|
||||||
|
return res.status(OK).send({
|
||||||
|
token: token,
|
||||||
|
roomId: ROOM,
|
||||||
|
userId: userId
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -104,7 +104,8 @@ export class IoSocketController{
|
|||||||
roomId: <string>,
|
roomId: <string>,
|
||||||
position: {
|
position: {
|
||||||
x : <number>,
|
x : <number>,
|
||||||
y : <number>
|
y : <number>,
|
||||||
|
direction: <string>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
@ -125,8 +126,7 @@ export class IoSocketController{
|
|||||||
}
|
}
|
||||||
arrayMap.forEach((value : any) => {
|
arrayMap.forEach((value : any) => {
|
||||||
let roomId = value[0];
|
let roomId = value[0];
|
||||||
let data = value[1];
|
this.Io.in(roomId).emit('user-position', JSON.stringify(arrayMap));
|
||||||
this.Io.in(roomId).emit('user-position', JSON.stringify(data));
|
|
||||||
});
|
});
|
||||||
this.seTimeOutInProgress = setTimeout(() => {
|
this.seTimeOutInProgress = setTimeout(() => {
|
||||||
this.shareUsersPosition();
|
this.shareUsersPosition();
|
||||||
|
@ -4,19 +4,22 @@ import {PointInterface} from "./PointInterface";
|
|||||||
export class Point implements PointInterface{
|
export class Point implements PointInterface{
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
direction: string;
|
||||||
|
|
||||||
constructor(x : number, y : number) {
|
constructor(x : number, y : number, direction : string = "none") {
|
||||||
if(x === null || y === null){
|
if(x === null || y === null){
|
||||||
throw Error("position x and y cannot be null");
|
throw Error("position x and y cannot be null");
|
||||||
}
|
}
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
this.direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson(){
|
toJson(){
|
||||||
return {
|
return {
|
||||||
x : this.x,
|
x : this.x,
|
||||||
y: this.y
|
y: this.y,
|
||||||
|
direction: this.direction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,9 +27,10 @@ export class Point implements PointInterface{
|
|||||||
export class MessageUserPosition extends Message{
|
export class MessageUserPosition extends Message{
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
|
|
||||||
constructor(data: any) {
|
constructor(message: string) {
|
||||||
super(data);
|
super(message);
|
||||||
this.position = new Point(data.position.x, data.position.y);
|
let data = JSON.parse(message);
|
||||||
|
this.position = new Point(data.position.x, data.position.y, data.position.direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export interface PointInterface {
|
export interface PointInterface {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
direction: string;
|
||||||
toJson() : object;
|
toJson() : object;
|
||||||
}
|
}
|
@ -135,6 +135,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
|
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
|
||||||
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
|
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
|
||||||
|
|
||||||
|
"@types/uuidv4@^5.0.0":
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/uuidv4/-/uuidv4-5.0.0.tgz#2c94e67b0c06d5adb28fb7ced1a1b5f0866ecd50"
|
||||||
|
integrity sha512-xUrhYSJnkTq9CP79cU3svoKTLPCIbMMnu9Twf/tMpHATYSHCAAeDNeb2a/29YORhk5p4atHhCTMsIBU/tvdh6A==
|
||||||
|
dependencies:
|
||||||
|
uuidv4 "*"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^2.26.0":
|
"@typescript-eslint/eslint-plugin@^2.26.0":
|
||||||
version "2.26.0"
|
version "2.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.26.0.tgz#04c96560c8981421e5a9caad8394192363cc423f"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.26.0.tgz#04c96560c8981421e5a9caad8394192363cc423f"
|
||||||
@ -2094,6 +2101,18 @@ utils-merge@1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||||
|
|
||||||
|
uuid@7.0.3:
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
|
||||||
|
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
|
||||||
|
|
||||||
|
uuidv4@*, uuidv4@^6.0.7:
|
||||||
|
version "6.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/uuidv4/-/uuidv4-6.0.7.tgz#15e920848e1afbbd97b4919bc50f4f2f2278f880"
|
||||||
|
integrity sha512-4mpYRFNqO22EckzxPSJ/+xjn9GgO6SAqEJ33yt23Y+HZZoZOt/6l4U4iIjc86ZfxSN2fSCGGmHNb3kiACFNd1g==
|
||||||
|
dependencies:
|
||||||
|
uuid "7.0.3"
|
||||||
|
|
||||||
v8-compile-cache@^2.0.3:
|
v8-compile-cache@^2.0.3:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
|
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
|
||||||
|
35
deeployer.libsonnet
Normal file
35
deeployer.libsonnet
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
local env = std.extVar("env"),
|
||||||
|
local namespace = env.GITHUB_REF_SLUG,
|
||||||
|
local tag = if namespace == "master" then "latest" else namespace,
|
||||||
|
"$schema": "https://raw.githubusercontent.com/thecodingmachine/deeployer/master/deeployer.schema.json",
|
||||||
|
"containers": {
|
||||||
|
"back": {
|
||||||
|
"image": "thecodingmachine/workadventure-back:"+tag,
|
||||||
|
"host": {
|
||||||
|
"url": "api."+namespace+".workadventure.test.thecodingmachine.com",
|
||||||
|
"https": "enable"
|
||||||
|
},
|
||||||
|
"ports": [8080],
|
||||||
|
"env": {
|
||||||
|
"SECRET_KEY": "tempSecretKeyNeedsToChange"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"front": {
|
||||||
|
"image": "thecodingmachine/workadventure-front:"+tag,
|
||||||
|
"host": {
|
||||||
|
"url": namespace+".workadventure.test.thecodingmachine.com",
|
||||||
|
"https": "enable"
|
||||||
|
},
|
||||||
|
"ports": [80],
|
||||||
|
"env": {
|
||||||
|
"API_URL": "https://api."+namespace+".workadventure.test.thecodingmachine.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"https": {
|
||||||
|
"mail": "d.negrier@thecodingmachine.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
doc/images/tiled_screenshot_1.png
Normal file
BIN
doc/images/tiled_screenshot_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
20
docker-compose.ci.yml
Normal file
20
docker-compose.ci.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
wait_app:
|
||||||
|
image: dadarek/wait-for-dependencies
|
||||||
|
depends_on:
|
||||||
|
- reverse-proxy
|
||||||
|
command: front:8080
|
||||||
|
cypress:
|
||||||
|
# the Docker image to use from https://github.com/cypress-io/cypress-docker-images
|
||||||
|
image: "cypress/included:3.8.3"
|
||||||
|
depends_on:
|
||||||
|
- reverse-proxy
|
||||||
|
environment:
|
||||||
|
# pass base url to test pointing at the web application
|
||||||
|
- CYPRESS_baseUrl=http://front:8080
|
||||||
|
working_dir: /e2e
|
||||||
|
volumes:
|
||||||
|
- ./e2e/:/e2e
|
@ -7,12 +7,16 @@ services:
|
|||||||
- "80:80"
|
- "80:80"
|
||||||
# The Web UI (enabled by --api.insecure=true)
|
# The Web UI (enabled by --api.insecure=true)
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
|
depends_on:
|
||||||
|
- back
|
||||||
|
- front
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
|
||||||
front:
|
front:
|
||||||
image: thecodingmachine/nodejs:12
|
image: thecodingmachine/nodejs:12
|
||||||
environment:
|
environment:
|
||||||
|
DEBUG_MODE: "$DEBUG_MODE"
|
||||||
HOST: "0.0.0.0"
|
HOST: "0.0.0.0"
|
||||||
NODE_ENV: development
|
NODE_ENV: development
|
||||||
API_URL: http://api.workadventure.localhost
|
API_URL: http://api.workadventure.localhost
|
||||||
|
3
e2e/.gitignore
vendored
Normal file
3
e2e/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
screenshots/
|
||||||
|
videos/
|
||||||
|
node_modules/
|
36
e2e/CYPRESS.md
Normal file
36
e2e/CYPRESS.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Testing with cypress
|
||||||
|
|
||||||
|
This project use [cypress](https://www.cypress.io/) to do functional testing of the website.
|
||||||
|
Unfortunately we cannot integrate it with docker-compose for the moment, so you will need to install some packages locally on your pc.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
You will need to install theses dependancies on linux (don't know about mac):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install libgtk2.0-0 libgtk-3-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
|
||||||
|
```
|
||||||
|
|
||||||
|
Cypress can be installed locally in the e2e directory
|
||||||
|
```bash
|
||||||
|
cd e2e
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
How to use:
|
||||||
|
```bash
|
||||||
|
npm run cy:run
|
||||||
|
npm run cy:open
|
||||||
|
```
|
||||||
|
|
||||||
|
The first command will run all tests in the terminal, while the second will open the interactive task runner which allow you to easily manage the test workflow
|
||||||
|
|
||||||
|
[More details here](https://docs.cypress.io/guides/getting-started/testing-your-app.html#Step-1-Start-your-server)
|
||||||
|
|
||||||
|
## How to test a game
|
||||||
|
|
||||||
|
Cypress cannot "see" and so cannot directly manipulate the canva created by Phaser.
|
||||||
|
|
||||||
|
This means we have to do workarounds such as exposing core objects in the window so that cypress can manipulate them or doing console that cypress can catch.
|
7
e2e/cypress.json
Normal file
7
e2e/cypress.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"baseUrl": "http://workadventure.localhost",
|
||||||
|
"video": false,
|
||||||
|
"defaultCommandTimeout": 20000,
|
||||||
|
"pluginsFile": false,
|
||||||
|
"supportFile": false
|
||||||
|
}
|
25
e2e/cypress/integration/spec.js
Normal file
25
e2e/cypress/integration/spec.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
Cypress.on('window:before:load', (win) => {
|
||||||
|
// because this is called before any scripts
|
||||||
|
// have loaded - the ga function is undefined
|
||||||
|
// so we need to create it.
|
||||||
|
win.cypressAsserter = cy.stub().as('ca')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('WorkAdventureGame', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/', {
|
||||||
|
onBeforeLoad (win) {
|
||||||
|
cy.spy(win.console, 'log').as('console.log')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads', () => {
|
||||||
|
cy.get('@console.log').should('be.calledWith', 'Started the game')
|
||||||
|
cy.get('@console.log').should('be.calledWith', 'Preloading')
|
||||||
|
cy.get('@console.log').should('be.calledWith', 'Preloading done')
|
||||||
|
cy.get('@console.log').should('be.calledWith', 'startInit')
|
||||||
|
cy.get('@console.log').should('be.calledWith', 'startInit done')
|
||||||
|
});
|
||||||
|
});
|
1406
e2e/package-lock.json
generated
Normal file
1406
e2e/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
e2e/package.json
Normal file
9
e2e/package.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"cypress": "^3.8.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"cy:run": "cypress run",
|
||||||
|
"cy:open": "cypress open"
|
||||||
|
}
|
||||||
|
}
|
4
front/.dockerignore
Normal file
4
front/.dockerignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/node_modules/
|
||||||
|
/dist/bundle.js
|
||||||
|
/yarn-error.log
|
||||||
|
/Dockerfile
|
9
front/Dockerfile
Normal file
9
front/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# we are rebuilding on each deploy to cope with the API_URL environment URL
|
||||||
|
FROM thecodingmachine/nodejs:12-apache
|
||||||
|
|
||||||
|
COPY --chown=docker:docker . .
|
||||||
|
RUN yarn install
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV STARTUP_COMMAND_1="yarn run build"
|
||||||
|
ENV APACHE_DOCUMENT_ROOT=dist/
|
BIN
front/dist/maps/floortileset.png
vendored
Normal file
BIN
front/dist/maps/floortileset.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 85 KiB |
62
front/dist/maps/map.json
vendored
62
front/dist/maps/map.json
vendored
@ -3,33 +3,45 @@
|
|||||||
{
|
{
|
||||||
"export":
|
"export":
|
||||||
{
|
{
|
||||||
"target":"."
|
"format":"json",
|
||||||
|
"target":"map.json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"height":20,
|
"height":18,
|
||||||
"infinite":false,
|
"infinite":false,
|
||||||
"layers":[
|
"layers":[
|
||||||
{
|
{
|
||||||
"data":[1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 1, 2, 2, 2, 2, 2, 2, 3, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 17, 18, 18, 18, 18, 18, 18, 19, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 17, 18, 18, 18, 18, 18, 18, 19, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 17, 18, 18, 18, 18, 18, 18, 19, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 33, 34, 34, 34, 34, 34, 34, 35, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178],
|
"data":[294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 294, 294, 294, 294, 294, 294, 294, 294, 294],
|
||||||
"height":20,
|
"height":18,
|
||||||
"id":1,
|
"id":2,
|
||||||
"name":"Calque 1",
|
"name":"bottom",
|
||||||
"opacity":1,
|
"opacity":1,
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
"width":20,
|
"width":46,
|
||||||
"x":0,
|
"x":0,
|
||||||
"y":0
|
"y":0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 62, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 94, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 110, 110, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 209, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 193, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 195, 164, 209, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 211],
|
"draworder":"topdown",
|
||||||
"height":20,
|
|
||||||
"id":3,
|
"id":3,
|
||||||
"name":"Calque 2",
|
"name":"floorLayer",
|
||||||
|
"objects":[],
|
||||||
|
"opacity":1,
|
||||||
|
"type":"objectgroup",
|
||||||
|
"visible":true,
|
||||||
|
"x":0,
|
||||||
|
"y":0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data":[0, 0, 115, 51, 52, 116, 115, 51, 52, 116, 115, 51, 52, 116, 0, 0, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 245, 246, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 0, 67, 68, 0, 0, 67, 68, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 245, 246, 247, 0, 0, 153, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 155, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 155, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 0, 0, 115, 67, 68, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 0, 0, 29, 30, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 169, 171, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 0, 0, 29, 30, 29, 30, 0, 0, 0, 0, 185, 187, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 116, 0, 0, 51, 52, 116, 0, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 67, 68, 0, 0, 115, 67, 68, 0, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 116, 0, 0, 51, 52, 116, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 0, 0, 0, 0, 0, 98, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 67, 68, 0, 0, 115, 67, 68, 0, 0, 0, 0, 13, 14, 13, 14, 13, 14, 13, 14, 13, 14, 13, 14, 13, 14, 13, 14, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 116, 0, 0, 51, 52, 116, 0, 0, 0, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 181, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 67, 68, 0, 0, 115, 67, 68, 0, 0, 0, 0, 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, 45, 46, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 113, 0, 113, 0, 113, 0, 0, 51, 52, 0, 0, 0, 113, 0, 113, 0, 113, 0, 0, 51, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 51, 49, 50, 49, 50, 49, 50, 0, 115, 67, 68, 116, 0, 49, 50, 49, 50, 49, 50, 0, 115, 67, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 0, 0, 0, 115, 67, 65, 66, 65, 66, 65, 66, 0, 0, 51, 52, 0, 0, 65, 66, 65, 66, 65, 66, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 67, 68, 116, 0, 0, 0, 0, 0, 114, 0, 114, 0, 114, 0, 0, 115, 67, 68, 116, 0, 114, 0, 114, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
"height":18,
|
||||||
|
"id":1,
|
||||||
|
"name":"top",
|
||||||
"opacity":1,
|
"opacity":1,
|
||||||
"type":"tilelayer",
|
"type":"tilelayer",
|
||||||
"visible":true,
|
"visible":true,
|
||||||
"width":20,
|
"width":46,
|
||||||
"x":0,
|
"x":0,
|
||||||
"y":0
|
"y":0
|
||||||
}],
|
}],
|
||||||
@ -41,20 +53,34 @@
|
|||||||
"tileheight":32,
|
"tileheight":32,
|
||||||
"tilesets":[
|
"tilesets":[
|
||||||
{
|
{
|
||||||
"columns":16,
|
|
||||||
"firstgid":1,
|
"firstgid":1,
|
||||||
"image":"tiles.png",
|
"source":"office_1.tsx"
|
||||||
"imageheight":512,
|
},
|
||||||
"imagewidth":512,
|
{
|
||||||
|
"columns":8,
|
||||||
|
"firstgid":257,
|
||||||
|
"image":"floortileset.png",
|
||||||
|
"imageheight":256,
|
||||||
|
"imagewidth":256,
|
||||||
"margin":0,
|
"margin":0,
|
||||||
"name":"tiles",
|
"name":"floortileset",
|
||||||
"spacing":0,
|
"spacing":0,
|
||||||
"tilecount":256,
|
"tilecount":64,
|
||||||
"tileheight":32,
|
"tileheight":32,
|
||||||
|
"tiles":[
|
||||||
|
{
|
||||||
|
"id":37,
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"collides",
|
||||||
|
"type":"bool",
|
||||||
|
"value":true
|
||||||
|
}]
|
||||||
|
}],
|
||||||
"tilewidth":32
|
"tilewidth":32
|
||||||
}],
|
}],
|
||||||
"tilewidth":32,
|
"tilewidth":32,
|
||||||
"type":"map",
|
"type":"map",
|
||||||
"version":1.2,
|
"version":1.2,
|
||||||
"width":20
|
"width":46
|
||||||
}
|
}
|
19
front/dist/maps/map2.json
vendored
19
front/dist/maps/map2.json
vendored
File diff suppressed because one or more lines are too long
254
front/dist/maps/office_1.tsx
vendored
Normal file
254
front/dist/maps/office_1.tsx
vendored
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tileset version="1.2" tiledversion="1.3.3" name="office_1" tilewidth="32" tileheight="32" tilecount="256" columns="16">
|
||||||
|
<image source="tilesets_deviant_milkian_1.png" width="512" height="512"/>
|
||||||
|
<tile id="7">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="12">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="13">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="14">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="15">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="23">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="28">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="29">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="30">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="31">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="39">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="44">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="45">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="48">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="49">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="50">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="51">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="52">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="56">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="57">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="64">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="65">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="66">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="67">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="68">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="72">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="73">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="84">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="152">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="153">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="154">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="155">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="156">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="157">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="161">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="162">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="168">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="169">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="170">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="171">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="172">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="173">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="177">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="178">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="184">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="185">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="186">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="196">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="198">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
<tile id="214">
|
||||||
|
<properties>
|
||||||
|
<property name="collides" type="bool" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</tile>
|
||||||
|
</tileset>
|
BIN
front/dist/maps/tilesets_deviant_milkian_1.png
vendored
Normal file
BIN
front/dist/maps/tilesets_deviant_milkian_1.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
front/dist/resources/objects/rockSprite.png
vendored
Normal file
BIN
front/dist/resources/objects/rockSprite.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
@ -1,14 +1,10 @@
|
|||||||
|
import {GameManagerInterface} from "./Phaser/Game/GameManager";
|
||||||
|
|
||||||
const SocketIo = require('socket.io-client');
|
const SocketIo = require('socket.io-client');
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import {API_URL} from "./Enum/EnvironmentVariable";
|
import {API_URL} from "./Enum/EnvironmentVariable";
|
||||||
|
|
||||||
export interface PointInterface {
|
class Message {
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
toJson() : object;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Message {
|
|
||||||
userId: string;
|
userId: string;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
|
||||||
@ -25,27 +21,42 @@ export class Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Point implements PointInterface{
|
export interface PointInterface {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
direction : string;
|
||||||
|
toJson() : object;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(x : number, y : number) {
|
class Point implements PointInterface{
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
direction : string;
|
||||||
|
|
||||||
|
constructor(x : number, y : number, direction : string = "none") {
|
||||||
if(x === null || y === null){
|
if(x === null || y === null){
|
||||||
throw Error("position x and y cannot be null");
|
throw Error("position x and y cannot be null");
|
||||||
}
|
}
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
this.direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson(){
|
toJson(){
|
||||||
return {
|
return {
|
||||||
x : this.x,
|
x : this.x,
|
||||||
y: this.y
|
y: this.y,
|
||||||
|
direction: this.direction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageUserPosition extends Message{
|
export interface MessageUserPositionInterface {
|
||||||
|
userId: string;
|
||||||
|
roomId: string;
|
||||||
|
position: PointInterface;
|
||||||
|
}
|
||||||
|
class MessageUserPosition extends Message implements MessageUserPositionInterface{
|
||||||
position: PointInterface;
|
position: PointInterface;
|
||||||
|
|
||||||
constructor(userId : string, roomId : string, point : Point) {
|
constructor(userId : string, roomId : string, point : Point) {
|
||||||
@ -64,18 +75,61 @@ export class MessageUserPosition extends Message{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Connexion {
|
export interface ListMessageUserPositionInterface {
|
||||||
|
roomId : string;
|
||||||
|
listUsersPosition: Array<MessageUserPosition>;
|
||||||
|
}
|
||||||
|
class ListMessageUserPosition{
|
||||||
|
roomId : string;
|
||||||
|
listUsersPosition: Array<MessageUserPosition>;
|
||||||
|
|
||||||
|
constructor(roomId : string, data : any) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
this.listUsersPosition = new Array<MessageUserPosition>();
|
||||||
|
data.forEach((userPosition: any) => {
|
||||||
|
this.listUsersPosition.push(new MessageUserPosition(
|
||||||
|
userPosition.userId,
|
||||||
|
userPosition.roomId,
|
||||||
|
new Point(
|
||||||
|
userPosition.position.x,
|
||||||
|
userPosition.position.y,
|
||||||
|
userPosition.position.direction
|
||||||
|
)
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export interface ConnexionInterface {
|
||||||
socket : any;
|
socket : any;
|
||||||
token : string;
|
token : string;
|
||||||
email : string;
|
email : string;
|
||||||
|
userId: string;
|
||||||
|
startedRoom : string;
|
||||||
|
createConnexion() : Promise<any>;
|
||||||
|
joinARoom(roomId : string) : void;
|
||||||
|
sharePosition(roomId : string, x : number, y : number, direction : string) : void;
|
||||||
|
positionOfAllUser() : void;
|
||||||
|
}
|
||||||
|
export class Connexion implements ConnexionInterface{
|
||||||
|
socket : any;
|
||||||
|
token : string;
|
||||||
|
email : string;
|
||||||
|
userId: string;
|
||||||
startedRoom : string;
|
startedRoom : string;
|
||||||
|
|
||||||
constructor(email : string) {
|
GameManager: GameManagerInterface;
|
||||||
|
|
||||||
|
constructor(email : string, GameManager: GameManagerInterface) {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
Axios.post(`${API_URL}/login`, {email: email})
|
this.GameManager = GameManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
createConnexion() : Promise<ConnexionInterface>{
|
||||||
|
return Axios.post(`${API_URL}/login`, {email: this.email})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.token = res.data.token;
|
this.token = res.data.token;
|
||||||
this.startedRoom = res.data.roomId;
|
this.startedRoom = res.data.roomId;
|
||||||
|
this.userId = res.data.userId;
|
||||||
|
|
||||||
this.socket = SocketIo(`${API_URL}`, {
|
this.socket = SocketIo(`${API_URL}`, {
|
||||||
query: {
|
query: {
|
||||||
@ -87,12 +141,13 @@ export class Connexion {
|
|||||||
this.joinARoom(this.startedRoom);
|
this.joinARoom(this.startedRoom);
|
||||||
|
|
||||||
//share your first position
|
//share your first position
|
||||||
this.sharePosition(0, 0);
|
this.sharePosition(this.startedRoom, 0, 0);
|
||||||
|
|
||||||
//create listen event to get all data user shared by the back
|
|
||||||
this.positionOfAllUser();
|
this.positionOfAllUser();
|
||||||
|
|
||||||
this.errorMessage();
|
this.errorMessage();
|
||||||
|
|
||||||
|
return this;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@ -104,18 +159,23 @@ export class Connexion {
|
|||||||
* Permit to join a room
|
* Permit to join a room
|
||||||
* @param roomId
|
* @param roomId
|
||||||
*/
|
*/
|
||||||
joinARoom(roomId : string){
|
joinARoom(roomId : string) : void {
|
||||||
let messageUserPosition = new MessageUserPosition(this.email, this.startedRoom, new Point(0, 0));
|
let messageUserPosition = new MessageUserPosition(this.userId, this.startedRoom, new Point(0, 0));
|
||||||
this.socket.emit('join-room', messageUserPosition.toString());
|
this.socket.emit('join-room', messageUserPosition.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Permit to share your position in map
|
*
|
||||||
|
* @param roomId
|
||||||
* @param x
|
* @param x
|
||||||
* @param y
|
* @param y
|
||||||
|
* @param direction
|
||||||
*/
|
*/
|
||||||
sharePosition(x : number, y : number){
|
sharePosition(roomId : string, x : number, y : number, direction : string = "none") : void{
|
||||||
let messageUserPosition = new MessageUserPosition(this.email, this.startedRoom, new Point(x, y));
|
if(!this.socket){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let messageUserPosition = new MessageUserPosition(this.userId, roomId, new Point(x, y, direction));
|
||||||
this.socket.emit('user-position', messageUserPosition.toString());
|
this.socket.emit('user-position', messageUserPosition.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,20 +187,24 @@ export class Connexion {
|
|||||||
* roomId: <string>,
|
* roomId: <string>,
|
||||||
* position: {
|
* position: {
|
||||||
* x : <number>,
|
* x : <number>,
|
||||||
* y : <number>
|
* y : <number>,
|
||||||
|
* direction: <string>
|
||||||
* }
|
* }
|
||||||
* },
|
* },
|
||||||
* ...
|
* ...
|
||||||
* ]
|
* ]
|
||||||
**/
|
**/
|
||||||
positionOfAllUser(){
|
positionOfAllUser() : void {
|
||||||
this.socket.on("user-position", (message : string) => {
|
this.socket.on("user-position", (message: string) => {
|
||||||
//TODO show all user in map
|
let dataList = JSON.parse(message);
|
||||||
console.info("user-position", message);
|
dataList.forEach((UserPositions: any) => {
|
||||||
|
let listMessageUserPosition = new ListMessageUserPosition(UserPositions[0], UserPositions[1]);
|
||||||
|
this.GameManager.shareUserPosition(listMessageUserPosition);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
errorMessage(){
|
errorMessage() : void {
|
||||||
this.socket.on('message-error', (message : string) => {
|
this.socket.on('message-error', (message : string) => {
|
||||||
console.error("message-error", message);
|
console.error("message-error", message);
|
||||||
})
|
})
|
||||||
|
32
front/src/Cypress/CypressAsserter.ts
Normal file
32
front/src/Cypress/CypressAsserter.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
declare let window:any;
|
||||||
|
|
||||||
|
//this class is used to communicate with cypress, our e2e testing client
|
||||||
|
//Since cypress cannot manipulate canvas, we notified it with console logs
|
||||||
|
class CypressAsserter {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
window.cypressAsserter = this
|
||||||
|
}
|
||||||
|
|
||||||
|
gameStarted() {
|
||||||
|
console.log('Started the game')
|
||||||
|
}
|
||||||
|
|
||||||
|
preloadStarted() {
|
||||||
|
console.log('Preloading')
|
||||||
|
}
|
||||||
|
|
||||||
|
preloadFinished() {
|
||||||
|
console.log('Preloading done')
|
||||||
|
}
|
||||||
|
|
||||||
|
initStarted() {
|
||||||
|
console.log('startInit')
|
||||||
|
}
|
||||||
|
|
||||||
|
initFinished() {
|
||||||
|
console.log('startInit done')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cypressAsserter = new CypressAsserter()
|
@ -1,7 +1,13 @@
|
|||||||
|
const DEBUG_MODE: boolean = !!process.env.DEBUG_MODE || false;
|
||||||
const API_URL = process.env.API_URL || "http://api.workadventure.localhost";
|
const API_URL = process.env.API_URL || "http://api.workadventure.localhost";
|
||||||
|
const ROOM = [process.env.ROOM || "THECODINGMACHINE"];
|
||||||
const RESOLUTION = 2;
|
const RESOLUTION = 2;
|
||||||
|
const ZOOM_LEVEL = 3/4;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
DEBUG_MODE,
|
||||||
API_URL,
|
API_URL,
|
||||||
RESOLUTION
|
RESOLUTION,
|
||||||
|
ZOOM_LEVEL,
|
||||||
|
ROOM
|
||||||
}
|
}
|
@ -1,185 +0,0 @@
|
|||||||
import {RESOLUTION} from "./Enum/EnvironmentVariable";
|
|
||||||
|
|
||||||
export class GameScene extends Phaser.Scene {
|
|
||||||
private player: Phaser.GameObjects.Sprite;
|
|
||||||
|
|
||||||
private keyZ: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyQ: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyS: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyD: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyRight: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyLeft: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyUp: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyDown: Phaser.Input.Keyboard.Key;
|
|
||||||
private keyShift: Phaser.Input.Keyboard.Key;
|
|
||||||
|
|
||||||
private Mappy : Phaser.Tilemaps.Tilemap;
|
|
||||||
|
|
||||||
private startX = ((window.innerWidth / 2) / RESOLUTION);
|
|
||||||
private startY = ((window.innerHeight / 2) / RESOLUTION);
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
key: "GameScene"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
preload(): void {
|
|
||||||
this.load.image('tiles', 'maps/tiles.png');
|
|
||||||
this.load.tilemapTiledJSON('map', 'maps/map2.json');
|
|
||||||
this.load.spritesheet('player',
|
|
||||||
'resources/characters/pipoya/Male 01-1.png',
|
|
||||||
{ frameWidth: 32, frameHeight: 32 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(): void {
|
|
||||||
this.keyShift = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SHIFT);
|
|
||||||
|
|
||||||
this.keyZ = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z);
|
|
||||||
this.keyQ = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q);
|
|
||||||
this.keyS = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
|
|
||||||
this.keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
|
|
||||||
|
|
||||||
this.keyUp = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP);
|
|
||||||
this.keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT);
|
|
||||||
this.keyDown = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN);
|
|
||||||
this.keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private moveCamera(x:number, y:number, speedMultiplier: number): void {
|
|
||||||
this.cameras.main.scrollX += speedMultiplier * 2 * x;
|
|
||||||
this.cameras.main.scrollY += speedMultiplier * 2 * y;
|
|
||||||
}
|
|
||||||
|
|
||||||
create(): void {
|
|
||||||
this.Mappy = this.add.tilemap("map");
|
|
||||||
let terrain = this.Mappy.addTilesetImage("tiles", "tiles");
|
|
||||||
|
|
||||||
let bottomLayer = this.Mappy.createStaticLayer("Calque 1", [terrain], 0, 0);
|
|
||||||
let topLayer = this.Mappy.createStaticLayer("Calque 2", [terrain], 0, 0);
|
|
||||||
|
|
||||||
// Let's manage animations of the player
|
|
||||||
this.anims.create({
|
|
||||||
key: 'down',
|
|
||||||
frames: this.anims.generateFrameNumbers('player', { start: 0, end: 2 }),
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
});
|
|
||||||
|
|
||||||
this.anims.create({
|
|
||||||
key: 'left',
|
|
||||||
frames: this.anims.generateFrameNumbers('player', { start: 3, end: 5 }),
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
});
|
|
||||||
|
|
||||||
this.anims.create({
|
|
||||||
key: 'right',
|
|
||||||
frames: this.anims.generateFrameNumbers('player', { start: 6, end: 8 }),
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
});
|
|
||||||
|
|
||||||
this.anims.create({
|
|
||||||
key: 'up',
|
|
||||||
frames: this.anims.generateFrameNumbers('player', { start: 9, end: 11 }),
|
|
||||||
frameRate: 10,
|
|
||||||
repeat: -1
|
|
||||||
});
|
|
||||||
|
|
||||||
//let player = this.add.sprite(450, 450, 'player');
|
|
||||||
//player.anims.play('down');
|
|
||||||
//player.setBounce(0.2);
|
|
||||||
//player.setCollideWorldBounds(true);
|
|
||||||
this.player = this.add.sprite(this.startX, this.startY, 'player');
|
|
||||||
}
|
|
||||||
|
|
||||||
private angle: number = 0;
|
|
||||||
|
|
||||||
update(dt: number): void {
|
|
||||||
let xCameraPosition = this.cameras.main.scrollX;
|
|
||||||
let yCameraPosition = this.cameras.main.scrollY;
|
|
||||||
|
|
||||||
let speedMultiplier = this.keyShift.isDown ? 5 : 1;
|
|
||||||
|
|
||||||
if (this.keyZ.isDown || this.keyUp.isDown) {
|
|
||||||
this.managePlayerAnimation('up');
|
|
||||||
if (this.player.y > 0) {
|
|
||||||
this.player.setY(this.player.y - 2);
|
|
||||||
} else {
|
|
||||||
this.player.setY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (yCameraPosition > 0) {
|
|
||||||
if (this.player.y < (this.Mappy.widthInPixels - this.startY)) {
|
|
||||||
this.moveCamera(0, -1, speedMultiplier);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.cameras.main.scrollY = 0;
|
|
||||||
}
|
|
||||||
} else if (this.keyQ.isDown || this.keyLeft.isDown) {
|
|
||||||
|
|
||||||
this.managePlayerAnimation('left');
|
|
||||||
if (this.player.x > 0) {
|
|
||||||
this.player.setX(this.player.x - 2);
|
|
||||||
} else {
|
|
||||||
this.player.setX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xCameraPosition > 0) {
|
|
||||||
if (this.player.x < (this.Mappy.heightInPixels - this.startX)) {
|
|
||||||
this.moveCamera(-1, 0, speedMultiplier);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.cameras.main.scrollX = 0;
|
|
||||||
}
|
|
||||||
} else if (this.keyS.isDown || this.keyDown.isDown) {
|
|
||||||
|
|
||||||
this.managePlayerAnimation('down');
|
|
||||||
if (this.Mappy.heightInPixels > this.player.y) {
|
|
||||||
this.player.setY(this.player.y + 2);
|
|
||||||
} else {
|
|
||||||
this.player.setY(this.Mappy.heightInPixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.Mappy.heightInPixels > (yCameraPosition + (window.innerHeight / RESOLUTION))) {
|
|
||||||
if (this.player.y > this.startY) {
|
|
||||||
this.moveCamera(0, 1, speedMultiplier);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.cameras.main.scrollY = (this.Mappy.heightInPixels - (window.innerHeight / RESOLUTION));
|
|
||||||
}
|
|
||||||
} else if (this.keyD.isDown || this.keyRight.isDown) {
|
|
||||||
|
|
||||||
this.managePlayerAnimation('right');
|
|
||||||
if (this.Mappy.widthInPixels > this.player.x) {
|
|
||||||
this.player.setX(this.player.x + 2)
|
|
||||||
} else {
|
|
||||||
this.player.setX(this.Mappy.widthInPixels)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.Mappy.widthInPixels > (xCameraPosition + (window.innerWidth / RESOLUTION))) {
|
|
||||||
if (this.player.x > this.startX) {
|
|
||||||
this.moveCamera(1, 0, speedMultiplier);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.cameras.main.scrollX = (this.Mappy.widthInPixels - (window.innerWidth / RESOLUTION));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.managePlayerAnimation('none');
|
|
||||||
}
|
|
||||||
/*this.cameras.main.scrollX = Math.floor(300 + 300 * Math.cos(this.angle));
|
|
||||||
this.cameras.main.scrollY = Math.floor(300 + 300 * Math.sin(this.angle));
|
|
||||||
|
|
||||||
this.angle = dt * 0.0001;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
managePlayerAnimation(direction: string) {
|
|
||||||
if (!this.player.anims.currentAnim || this.player.anims.currentAnim.key !== direction) {
|
|
||||||
this.player.anims.play(direction);
|
|
||||||
} else if (direction === 'none' && this.player.anims.currentAnim) {
|
|
||||||
this.player.anims.currentAnim.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
58
front/src/Phaser/Entity/PlayableCaracter.ts
Normal file
58
front/src/Phaser/Entity/PlayableCaracter.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import {getPlayerAnimations, playAnimation, PlayerAnimationNames} from "../Player/Animation";
|
||||||
|
import {ActiveEventList, UserInputEvent} from "../UserInput/UserInputManager";
|
||||||
|
import {SpeechBubble} from "./SpeechBubble";
|
||||||
|
|
||||||
|
export class PlayableCaracter extends Phaser.Physics.Arcade.Sprite {
|
||||||
|
private bubble: SpeechBubble;
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number, texture: string, frame?: string | number) {
|
||||||
|
super(scene, x, y, texture, frame);
|
||||||
|
|
||||||
|
this.scene.sys.updateList.add(this);
|
||||||
|
this.scene.sys.displayList.add(this);
|
||||||
|
this.setScale(2);
|
||||||
|
this.scene.physics.world.enableBody(this);
|
||||||
|
this.setImmovable(true);
|
||||||
|
this.setCollideWorldBounds(true);
|
||||||
|
this.setSize(16, 16); //edit the hitbox to better match the caracter model
|
||||||
|
this.setOffset(8, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
move(x: number, y: number){
|
||||||
|
|
||||||
|
this.setVelocity(x, y);
|
||||||
|
|
||||||
|
//todo improve animations to better account for diagonal movement
|
||||||
|
if (this.body.velocity.x > 0) { //moving right
|
||||||
|
this.play(PlayerAnimationNames.WalkRight, true);
|
||||||
|
}
|
||||||
|
if (this.body.velocity.x < 0) { //moving left
|
||||||
|
this.anims.playReverse(PlayerAnimationNames.WalkLeft, true);
|
||||||
|
}
|
||||||
|
if (this.body.velocity.y < 0) { //moving up
|
||||||
|
this.play(PlayerAnimationNames.WalkUp, true);
|
||||||
|
}
|
||||||
|
if (this.body.velocity.y > 0) { //moving down
|
||||||
|
this.play(PlayerAnimationNames.WalkDown, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.bubble) {
|
||||||
|
this.bubble.moveBubble(this.x, this.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stop(){
|
||||||
|
this.setVelocity(0, 0);
|
||||||
|
this.play(PlayerAnimationNames.None, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
say(text: string) {
|
||||||
|
if (this.bubble) return;
|
||||||
|
this.bubble = new SpeechBubble(this.scene, this, text)
|
||||||
|
//todo make the buble destroy on player movement?
|
||||||
|
setTimeout(() => {
|
||||||
|
this.bubble.destroy();
|
||||||
|
this.bubble = null;
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
}
|
88
front/src/Phaser/Entity/SpeechBubble.ts
Normal file
88
front/src/Phaser/Entity/SpeechBubble.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import Scene = Phaser.Scene;
|
||||||
|
import {PlayableCaracter} from "./PlayableCaracter";
|
||||||
|
|
||||||
|
export class SpeechBubble {
|
||||||
|
private bubble: Phaser.GameObjects.Graphics;
|
||||||
|
private content: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param scene
|
||||||
|
* @param player
|
||||||
|
* @param text
|
||||||
|
*/
|
||||||
|
constructor(scene: Scene, player: PlayableCaracter, text: string = "") {
|
||||||
|
|
||||||
|
let bubbleHeight = 50;
|
||||||
|
let bubblePadding = 10;
|
||||||
|
let bubbleWidth = bubblePadding * 2 + text.length * 10;
|
||||||
|
let arrowHeight = bubbleHeight / 4;
|
||||||
|
|
||||||
|
this.bubble = scene.add.graphics({ x: player.x + 16, y: player.y - 80 });
|
||||||
|
|
||||||
|
// Bubble shadow
|
||||||
|
this.bubble.fillStyle(0x222222, 0.5);
|
||||||
|
this.bubble.fillRoundedRect(6, 6, bubbleWidth, bubbleHeight, 16);
|
||||||
|
|
||||||
|
// this.bubble color
|
||||||
|
this.bubble.fillStyle(0xffffff, 1);
|
||||||
|
|
||||||
|
// this.bubble outline line style
|
||||||
|
this.bubble.lineStyle(4, 0x565656, 1);
|
||||||
|
|
||||||
|
// this.bubble shape and outline
|
||||||
|
this.bubble.strokeRoundedRect(0, 0, bubbleWidth, bubbleHeight, 16);
|
||||||
|
this.bubble.fillRoundedRect(0, 0, bubbleWidth, bubbleHeight, 16);
|
||||||
|
|
||||||
|
// Calculate arrow coordinates
|
||||||
|
let point1X = Math.floor(bubbleWidth / 7);
|
||||||
|
let point1Y = bubbleHeight;
|
||||||
|
let point2X = Math.floor((bubbleWidth / 7) * 2);
|
||||||
|
let point2Y = bubbleHeight;
|
||||||
|
let point3X = Math.floor(bubbleWidth / 7);
|
||||||
|
let point3Y = Math.floor(bubbleHeight + arrowHeight);
|
||||||
|
|
||||||
|
// bubble arrow shadow
|
||||||
|
this.bubble.lineStyle(4, 0x222222, 0.5);
|
||||||
|
this.bubble.lineBetween(point2X - 1, point2Y + 6, point3X + 2, point3Y);
|
||||||
|
|
||||||
|
// bubble arrow fill
|
||||||
|
this.bubble.fillTriangle(point1X, point1Y, point2X, point2Y, point3X, point3Y);
|
||||||
|
this.bubble.lineStyle(2, 0x565656, 1);
|
||||||
|
this.bubble.lineBetween(point2X, point2Y, point3X, point3Y);
|
||||||
|
this.bubble.lineBetween(point1X, point1Y, point3X, point3Y);
|
||||||
|
|
||||||
|
this.content = scene.add.text(0, 0, text, { fontFamily: 'Arial', fontSize: 20, color: '#000000', align: 'center', wordWrap: { width: bubbleWidth - (bubblePadding * 2) } });
|
||||||
|
|
||||||
|
let bounds = this.content.getBounds();
|
||||||
|
this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
*/
|
||||||
|
moveBubble(x : number, y : number) {
|
||||||
|
if (this.bubble) {
|
||||||
|
this.bubble.setPosition((x + 16), (y - 80));
|
||||||
|
}
|
||||||
|
if (this.content) {
|
||||||
|
let bubbleHeight = 50;
|
||||||
|
let bubblePadding = 10;
|
||||||
|
let bubbleWidth = bubblePadding * 2 + this.content.text.length * 10;
|
||||||
|
let bounds = this.content.getBounds();
|
||||||
|
//this.content.setPosition(x, y);
|
||||||
|
this.content.setPosition(this.bubble.x + (bubbleWidth / 2) - (bounds.width / 2), this.bubble.y + (bubbleHeight / 2) - (bounds.height / 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy(): void {
|
||||||
|
this.bubble.setVisible(false) //todo find a better way
|
||||||
|
this.bubble.destroy();
|
||||||
|
this.bubble = null;
|
||||||
|
this.content.destroy();
|
||||||
|
this.content = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
front/src/Phaser/Entity/Sprite.ts
Normal file
8
front/src/Phaser/Entity/Sprite.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export class Sprite extends Phaser.GameObjects.Sprite {
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number, texture: string, frame?: number | string) {
|
||||||
|
super(scene, x, y, texture, frame);
|
||||||
|
scene.sys.updateList.add(this);
|
||||||
|
scene.sys.displayList.add(this);
|
||||||
|
}
|
||||||
|
}
|
77
front/src/Phaser/Game/GameManager.ts
Normal file
77
front/src/Phaser/Game/GameManager.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import {GameSceneInterface, GameScene} from "./GameScene";
|
||||||
|
import {ROOM} from "../../Enum/EnvironmentVariable"
|
||||||
|
import {Connexion, ConnexionInterface, ListMessageUserPositionInterface} from "../../Connexion";
|
||||||
|
|
||||||
|
export enum StatusGameManagerEnum {
|
||||||
|
IN_PROGRESS = 1,
|
||||||
|
CURRENT_USER_CREATED = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export let ConnexionInstance : ConnexionInterface;
|
||||||
|
|
||||||
|
export interface GameManagerInterface {
|
||||||
|
GameScenes: Array<GameSceneInterface>;
|
||||||
|
status : number;
|
||||||
|
createCurrentPlayer() : void;
|
||||||
|
shareUserPosition(ListMessageUserPosition : ListMessageUserPositionInterface): void;
|
||||||
|
}
|
||||||
|
export class GameManager implements GameManagerInterface {
|
||||||
|
GameScenes: Array<GameSceneInterface> = [];
|
||||||
|
status: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.status = StatusGameManagerEnum.IN_PROGRESS;
|
||||||
|
ConnexionInstance = new Connexion("test@gmail.com", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
createGame(){
|
||||||
|
return ConnexionInstance.createConnexion().then(() => {
|
||||||
|
this.configureGame();
|
||||||
|
/** TODO add loader in the page **/
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* permit to config rooms
|
||||||
|
*/
|
||||||
|
configureGame() {
|
||||||
|
ROOM.forEach((roomId) => {
|
||||||
|
let newGame = new GameScene(roomId, this);
|
||||||
|
this.GameScenes.push((newGame as GameSceneInterface));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permit to create player in started room
|
||||||
|
* @param RoomId
|
||||||
|
* @param UserId
|
||||||
|
*/
|
||||||
|
createCurrentPlayer(): void {
|
||||||
|
//Get started room send by the backend
|
||||||
|
let game: GameSceneInterface = this.GameScenes.find((Game: GameSceneInterface) => Game.RoomId === ConnexionInstance.startedRoom);
|
||||||
|
game.createCurrentPlayer(ConnexionInstance.userId);
|
||||||
|
this.status = StatusGameManagerEnum.CURRENT_USER_CREATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share position in game
|
||||||
|
* @param ListMessageUserPosition
|
||||||
|
*/
|
||||||
|
shareUserPosition(ListMessageUserPosition: ListMessageUserPositionInterface): void {
|
||||||
|
if (this.status === StatusGameManagerEnum.IN_PROGRESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let Game: GameSceneInterface = this.GameScenes.find((Game: GameSceneInterface) => Game.RoomId === ListMessageUserPosition.roomId);
|
||||||
|
if (!Game) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Game.shareUserPosition(ListMessageUserPosition.listUsersPosition)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
266
front/src/Phaser/Game/GameScene.ts
Normal file
266
front/src/Phaser/Game/GameScene.ts
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
import {GameManagerInterface, StatusGameManagerEnum} from "./GameManager";
|
||||||
|
import {MessageUserPositionInterface} from "../../Connexion";
|
||||||
|
import {CurrentGamerInterface, GamerInterface, Player} from "../Player/Player";
|
||||||
|
import {DEBUG_MODE, RESOLUTION, ZOOM_LEVEL} from "../../Enum/EnvironmentVariable";
|
||||||
|
import Tile = Phaser.Tilemaps.Tile;
|
||||||
|
import {ITiledMap, ITiledTileSet} from "../Map/ITiledMap";
|
||||||
|
import {cypressAsserter} from "../../Cypress/CypressAsserter";
|
||||||
|
|
||||||
|
export enum Textures {
|
||||||
|
Rock = 'rock',
|
||||||
|
Player = 'playerModel',
|
||||||
|
Map = 'map'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameSceneInterface extends Phaser.Scene {
|
||||||
|
RoomId : string;
|
||||||
|
Map: Phaser.Tilemaps.Tilemap;
|
||||||
|
createCurrentPlayer(UserId : string) : void;
|
||||||
|
shareUserPosition(UsersPosition : Array<MessageUserPositionInterface>): void;
|
||||||
|
}
|
||||||
|
export class GameScene extends Phaser.Scene implements GameSceneInterface{
|
||||||
|
GameManager : GameManagerInterface;
|
||||||
|
RoomId : string;
|
||||||
|
Terrains : Array<Phaser.Tilemaps.Tileset>;
|
||||||
|
CurrentPlayer: CurrentGamerInterface;
|
||||||
|
MapPlayers : Phaser.Physics.Arcade.Group;
|
||||||
|
Map: Phaser.Tilemaps.Tilemap;
|
||||||
|
Layers : Array<Phaser.Tilemaps.StaticTilemapLayer>;
|
||||||
|
Objects : Array<Phaser.Physics.Arcade.Sprite>;
|
||||||
|
map: ITiledMap;
|
||||||
|
startX = (window.innerWidth / 2) / RESOLUTION;
|
||||||
|
startY = (window.innerHeight / 2) / RESOLUTION;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(RoomId : string, GameManager : GameManagerInterface) {
|
||||||
|
super({
|
||||||
|
key: "GameScene"
|
||||||
|
});
|
||||||
|
this.RoomId = RoomId;
|
||||||
|
this.GameManager = GameManager;
|
||||||
|
this.Terrains = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//hook preload scene
|
||||||
|
preload(): void {
|
||||||
|
cypressAsserter.preloadStarted();
|
||||||
|
let mapUrl = 'maps/map.json';
|
||||||
|
this.load.on('filecomplete-tilemapJSON-'+Textures.Map, (key: string, type: string, data: any) => {
|
||||||
|
// Triggered when the map is loaded
|
||||||
|
// Load tiles attached to the map recursively
|
||||||
|
this.map = data.data;
|
||||||
|
this.map.tilesets.forEach((tileset) => {
|
||||||
|
if (typeof tileset.name === 'undefined' || typeof tileset.image === 'undefined') {
|
||||||
|
console.warn("Don't know how to handle tileset ", tileset)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let path = mapUrl.substr(0, mapUrl.lastIndexOf('/'));
|
||||||
|
this.load.image(tileset.name, path + '/' + tileset.image);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
this.load.tilemapTiledJSON(Textures.Map, mapUrl);
|
||||||
|
this.load.image(Textures.Rock, 'resources/objects/rockSprite.png');
|
||||||
|
this.load.spritesheet(Textures.Player,
|
||||||
|
'resources/characters/pipoya/Male 01-1.png',
|
||||||
|
{ frameWidth: 32, frameHeight: 32 }
|
||||||
|
);
|
||||||
|
cypressAsserter.preloadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
//hook initialisation
|
||||||
|
init(){}
|
||||||
|
|
||||||
|
//hook create scene
|
||||||
|
create(): void {
|
||||||
|
cypressAsserter.initStarted();
|
||||||
|
|
||||||
|
//initalise map
|
||||||
|
this.Map = this.add.tilemap("map");
|
||||||
|
this.map.tilesets.forEach((tileset: ITiledTileSet) => {
|
||||||
|
this.Terrains.push(this.Map.addTilesetImage(tileset.name, tileset.name));
|
||||||
|
});
|
||||||
|
|
||||||
|
//permit to set bound collision
|
||||||
|
this.physics.world.setBounds(0,0, this.Map.widthInPixels, this.Map.heightInPixels);
|
||||||
|
|
||||||
|
//add layer on map
|
||||||
|
this.Layers = new Array<Phaser.Tilemaps.StaticTilemapLayer>();
|
||||||
|
let depth = -2;
|
||||||
|
this.map.layers.forEach((layer) => {
|
||||||
|
if (layer.type === 'tilelayer') {
|
||||||
|
this.addLayer( this.Map.createStaticLayer(layer.name, this.Terrains, 0, 0).setDepth(depth) );
|
||||||
|
} else if (layer.type === 'objectgroup' && layer.name === 'floorLayer') {
|
||||||
|
depth = -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (depth === -2) {
|
||||||
|
throw new Error('Your map MUST contain a layer of type "objectgroup" whose name is "floorLayer" that represents the layer characters are drawn at.');
|
||||||
|
}
|
||||||
|
|
||||||
|
//add entities
|
||||||
|
this.Objects = new Array<Phaser.Physics.Arcade.Sprite>();
|
||||||
|
this.addSpite(this.physics.add.sprite(200, 400, Textures.Rock, 26));
|
||||||
|
|
||||||
|
//init event click
|
||||||
|
this.EventToClickOnTile();
|
||||||
|
|
||||||
|
//initialise list of other player
|
||||||
|
this.MapPlayers = this.physics.add.group({ immovable: true });
|
||||||
|
|
||||||
|
//notify game manager can to create currentUser in map
|
||||||
|
this.GameManager.createCurrentPlayer();
|
||||||
|
|
||||||
|
|
||||||
|
//initialise camera
|
||||||
|
this.initCamera();
|
||||||
|
cypressAsserter.initFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: in a dedicated class/function?
|
||||||
|
initCamera() {
|
||||||
|
this.cameras.main.setBounds(0,0, this.Map.widthInPixels, this.Map.heightInPixels);
|
||||||
|
this.cameras.main.startFollow(this.CurrentPlayer);
|
||||||
|
this.cameras.main.setZoom(ZOOM_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
addLayer(Layer : Phaser.Tilemaps.StaticTilemapLayer){
|
||||||
|
this.Layers.push(Layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
createCollisionWithPlayer() {
|
||||||
|
//add collision layer
|
||||||
|
this.Layers.forEach((Layer: Phaser.Tilemaps.StaticTilemapLayer) => {
|
||||||
|
this.physics.add.collider(this.CurrentPlayer, Layer, (object1: any, object2: any) => {
|
||||||
|
//this.CurrentPlayer.say("Collision with layer : "+ (object2 as Tile).layer.name)
|
||||||
|
});
|
||||||
|
Layer.setCollisionByProperty({collides: true});
|
||||||
|
if (DEBUG_MODE) {
|
||||||
|
//debug code to see the collision hitbox of the object in the top layer
|
||||||
|
Layer.renderDebug(this.add.graphics(), {
|
||||||
|
tileColor: null, //non-colliding tiles
|
||||||
|
collidingTileColor: new Phaser.Display.Color(243, 134, 48, 200), // Colliding tiles,
|
||||||
|
faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Colliding face edges
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addSpite(Object : Phaser.Physics.Arcade.Sprite){
|
||||||
|
Object.setImmovable(true);
|
||||||
|
this.Objects.push(Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
createCollisionObject(){
|
||||||
|
this.Objects.forEach((Object : Phaser.Physics.Arcade.Sprite) => {
|
||||||
|
this.physics.add.collider(this.CurrentPlayer, Object, (object1: any, object2: any) => {
|
||||||
|
//this.CurrentPlayer.say("Collision with object : " + (object2 as Phaser.Physics.Arcade.Sprite).texture.key)
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
createCurrentPlayer(UserId : string){
|
||||||
|
//initialise player
|
||||||
|
this.CurrentPlayer = new Player(
|
||||||
|
UserId,
|
||||||
|
this,
|
||||||
|
this.startX,
|
||||||
|
this.startY,
|
||||||
|
);
|
||||||
|
this.CurrentPlayer.initAnimation();
|
||||||
|
|
||||||
|
//create collision
|
||||||
|
this.createCollisionWithPlayer();
|
||||||
|
this.createCollisionObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventToClickOnTile(){
|
||||||
|
// debug code to get a tile properties by clicking on it
|
||||||
|
this.input.on("pointerdown", (pointer: Phaser.Input.Pointer)=>{
|
||||||
|
//pixel position toz tile position
|
||||||
|
let tile = this.Map.getTileAt(this.Map.worldToTileX(pointer.worldX), this.Map.worldToTileY(pointer.worldY));
|
||||||
|
if(tile){
|
||||||
|
console.log(tile)
|
||||||
|
this.CurrentPlayer.say("Your touch " + tile.layer.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param time
|
||||||
|
* @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate.
|
||||||
|
*/
|
||||||
|
update(time: number, delta: number) : void {
|
||||||
|
this.CurrentPlayer.moveUser(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Share position in scene
|
||||||
|
* @param UsersPosition
|
||||||
|
*/
|
||||||
|
shareUserPosition(UsersPosition : Array<MessageUserPositionInterface>): void {
|
||||||
|
this.updateOrCreateMapPlayer(UsersPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new player and clean the player on the map
|
||||||
|
* @param UsersPosition
|
||||||
|
*/
|
||||||
|
updateOrCreateMapPlayer(UsersPosition : Array<MessageUserPositionInterface>){
|
||||||
|
if(!this.CurrentPlayer){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//add or create new user
|
||||||
|
UsersPosition.forEach((userPosition : MessageUserPositionInterface) => {
|
||||||
|
if(userPosition.userId === this.CurrentPlayer.userId){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let player = this.findPlayerInMap(userPosition.userId);
|
||||||
|
if(!player){
|
||||||
|
this.addPlayer(userPosition);
|
||||||
|
}else{
|
||||||
|
player.updatePosition(userPosition);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//clean map
|
||||||
|
this.MapPlayers.getChildren().forEach((player: GamerInterface) => {
|
||||||
|
if(UsersPosition.find((message : MessageUserPositionInterface) => message.userId === player.userId)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.destroy();
|
||||||
|
this.MapPlayers.remove(player);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private findPlayerInMap(UserId : string) : GamerInterface | null{
|
||||||
|
let player = this.MapPlayers.getChildren().find((player: Player) => UserId === player.userId);
|
||||||
|
if(!player){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (player as GamerInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new player
|
||||||
|
* @param MessageUserPosition
|
||||||
|
*/
|
||||||
|
addPlayer(MessageUserPosition : MessageUserPositionInterface){
|
||||||
|
//initialise player
|
||||||
|
let player = new Player(
|
||||||
|
MessageUserPosition.userId,
|
||||||
|
this,
|
||||||
|
MessageUserPosition.position.x,
|
||||||
|
MessageUserPosition.position.y,
|
||||||
|
);
|
||||||
|
player.initAnimation();
|
||||||
|
this.MapPlayers.add(player);
|
||||||
|
player.updatePosition(MessageUserPosition);
|
||||||
|
|
||||||
|
//init colision
|
||||||
|
this.physics.add.collider(this.CurrentPlayer, player, (CurrentPlayer: CurrentGamerInterface, MapPlayer: GamerInterface) => {
|
||||||
|
CurrentPlayer.say("Hello, how are you ? ");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
113
front/src/Phaser/Map/ITiledMap.ts
Normal file
113
front/src/Phaser/Map/ITiledMap.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* Tiled Map Interface
|
||||||
|
*
|
||||||
|
* Represents the interface for the Tiled exported data structure (JSON). Used
|
||||||
|
* when loading resources via Resource loader.
|
||||||
|
*/
|
||||||
|
export interface ITiledMap {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
layers: ITiledMapLayer[];
|
||||||
|
nextobjectid: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map orientation (orthogonal)
|
||||||
|
*/
|
||||||
|
orientation: string;
|
||||||
|
properties: {[key: string]: string};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render order (right-down)
|
||||||
|
*/
|
||||||
|
renderorder: string;
|
||||||
|
tileheight: number;
|
||||||
|
tilewidth: number;
|
||||||
|
tilesets: ITiledTileSet[];
|
||||||
|
version: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITiledMapLayer {
|
||||||
|
data: number[]|string;
|
||||||
|
height: number;
|
||||||
|
name: string;
|
||||||
|
opacity: number;
|
||||||
|
properties: {[key: string]: string};
|
||||||
|
encoding: string;
|
||||||
|
compression?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of layer (tilelayer, objectgroup)
|
||||||
|
*/
|
||||||
|
type: string;
|
||||||
|
visible: boolean;
|
||||||
|
width: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw order (topdown (default), index)
|
||||||
|
*/
|
||||||
|
draworder: string;
|
||||||
|
objects: ITiledMapObject[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITiledMapObject {
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tile object id
|
||||||
|
*/
|
||||||
|
gid: number;
|
||||||
|
height: number;
|
||||||
|
name: string;
|
||||||
|
properties: {[key: string]: string};
|
||||||
|
rotation: number;
|
||||||
|
type: string;
|
||||||
|
visible: boolean;
|
||||||
|
width: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not object is an ellipse
|
||||||
|
*/
|
||||||
|
ellipse: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polygon points
|
||||||
|
*/
|
||||||
|
polygon: {x: number, y: number}[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polyline points
|
||||||
|
*/
|
||||||
|
polyline: {x: number, y: number}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITiledTileSet {
|
||||||
|
firstgid: number;
|
||||||
|
image: string;
|
||||||
|
|
||||||
|
imageheight: number;
|
||||||
|
imagewidth: number;
|
||||||
|
margin: number;
|
||||||
|
name: string;
|
||||||
|
properties: {[key: string]: string};
|
||||||
|
spacing: number;
|
||||||
|
tilecount: number;
|
||||||
|
tileheight: number;
|
||||||
|
tilewidth: number;
|
||||||
|
transparentcolor: string;
|
||||||
|
terrains: ITiledMapTerrain[];
|
||||||
|
tiles: {[key: string]: { terrain: number[] }};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refers to external tileset file (should be JSON)
|
||||||
|
*/
|
||||||
|
source: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITiledMapTerrain {
|
||||||
|
name: string;
|
||||||
|
tile: number;
|
||||||
|
}
|
40
front/src/Phaser/NonPlayer/NonPlayer.ts
Normal file
40
front/src/Phaser/NonPlayer/NonPlayer.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import {PlayableCaracter} from "../Entity/PlayableCaracter";
|
||||||
|
import {Textures} from "../Game/GameScene";
|
||||||
|
import {UserInputEvent} from "../UserInput/UserInputManager";
|
||||||
|
import {Player} from "../Player/Player";
|
||||||
|
import {MessageUserPositionInterface} from "../../Connexion";
|
||||||
|
import {playAnimation} from "../Player/Animation";
|
||||||
|
|
||||||
|
export class NonPlayer extends PlayableCaracter {
|
||||||
|
|
||||||
|
isFleeing: boolean = false;
|
||||||
|
fleeingDirection:any = null //todo create a vector class
|
||||||
|
|
||||||
|
constructor(scene: Phaser.Scene, x: number, y: number) {
|
||||||
|
super(scene, x, y, Textures.Player, 1);
|
||||||
|
this.setSize(32, 32); //edit the hitbox to better match the caracter model
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updatePosition(MessageUserPosition : MessageUserPositionInterface){
|
||||||
|
playAnimation(this, MessageUserPosition.position.direction);
|
||||||
|
this.setX(MessageUserPosition.position.x);
|
||||||
|
this.setY(MessageUserPosition.position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
fleeFrom(player:Player) {
|
||||||
|
if (this.isFleeing) return;
|
||||||
|
this.say("Don't touch me!");
|
||||||
|
this.isFleeing = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.say("Feww, I escaped.");
|
||||||
|
this.isFleeing = false
|
||||||
|
this.fleeingDirection = null
|
||||||
|
}, 3000);
|
||||||
|
|
||||||
|
let vectorX = this.x - player.x;
|
||||||
|
let vectorY = this.y - player.y;
|
||||||
|
this.fleeingDirection = {x: vectorX, y: vectorY}
|
||||||
|
}
|
||||||
|
}
|
58
front/src/Phaser/Player/Animation.ts
Normal file
58
front/src/Phaser/Player/Animation.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import {Textures} from "../Game/GameScene";
|
||||||
|
|
||||||
|
interface AnimationData {
|
||||||
|
key: string;
|
||||||
|
frameRate: number;
|
||||||
|
repeat: number;
|
||||||
|
frameModel: string; //todo use an enum
|
||||||
|
frameStart: number;
|
||||||
|
frameEnd: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PlayerAnimationNames {
|
||||||
|
WalkDown = 'down',
|
||||||
|
WalkLeft = 'left',
|
||||||
|
WalkUp = 'up',
|
||||||
|
WalkRight = 'right',
|
||||||
|
None = 'none',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPlayerAnimations = (): AnimationData[] => {
|
||||||
|
return [{
|
||||||
|
key: PlayerAnimationNames.WalkDown,
|
||||||
|
frameModel: Textures.Player,
|
||||||
|
frameStart: 0,
|
||||||
|
frameEnd: 2,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}, {
|
||||||
|
key: PlayerAnimationNames.WalkLeft,
|
||||||
|
frameModel: Textures.Player,
|
||||||
|
frameStart: 3,
|
||||||
|
frameEnd: 5,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}, {
|
||||||
|
key: PlayerAnimationNames.WalkRight,
|
||||||
|
frameModel: Textures.Player,
|
||||||
|
frameStart: 6,
|
||||||
|
frameEnd: 8,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}, {
|
||||||
|
key: PlayerAnimationNames.WalkUp,
|
||||||
|
frameModel: Textures.Player,
|
||||||
|
frameStart: 9,
|
||||||
|
frameEnd: 11,
|
||||||
|
frameRate: 10,
|
||||||
|
repeat: -1
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const playAnimation = (Player : Phaser.GameObjects.Sprite, direction : string) => {
|
||||||
|
if (!Player.anims.currentAnim || Player.anims.currentAnim.key !== direction) {
|
||||||
|
Player.anims.play(direction);
|
||||||
|
} else if (direction === PlayerAnimationNames.None && Player.anims.currentAnim) {
|
||||||
|
Player.anims.currentAnim.destroy();
|
||||||
|
}
|
||||||
|
}
|
107
front/src/Phaser/Player/Player.ts
Normal file
107
front/src/Phaser/Player/Player.ts
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import {getPlayerAnimations, playAnimation, PlayerAnimationNames} from "./Animation";
|
||||||
|
import {GameSceneInterface, Textures} from "../Game/GameScene";
|
||||||
|
import {ConnexionInstance} from "../Game/GameManager";
|
||||||
|
import {MessageUserPositionInterface} from "../../Connexion";
|
||||||
|
import {ActiveEventList, UserInputEvent, UserInputManager} from "../UserInput/UserInputManager";
|
||||||
|
import {PlayableCaracter} from "../Entity/PlayableCaracter";
|
||||||
|
|
||||||
|
export interface CurrentGamerInterface extends PlayableCaracter{
|
||||||
|
userId : string;
|
||||||
|
PlayerValue : string;
|
||||||
|
initAnimation() : void;
|
||||||
|
moveUser(delta: number) : void;
|
||||||
|
say(text : string) : void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GamerInterface extends PlayableCaracter{
|
||||||
|
userId : string;
|
||||||
|
PlayerValue : string;
|
||||||
|
initAnimation() : void;
|
||||||
|
updatePosition(MessageUserPosition : MessageUserPositionInterface) : void;
|
||||||
|
say(text : string) : void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Player extends PlayableCaracter implements CurrentGamerInterface, GamerInterface {
|
||||||
|
userId: string;
|
||||||
|
PlayerValue: string;
|
||||||
|
userInputManager: UserInputManager;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
userId: string,
|
||||||
|
Scene: GameSceneInterface,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
PlayerValue: string = Textures.Player
|
||||||
|
) {
|
||||||
|
super(Scene, x, y, PlayerValue, 1);
|
||||||
|
|
||||||
|
//create input to move
|
||||||
|
this.userInputManager = new UserInputManager(Scene);
|
||||||
|
|
||||||
|
//set data
|
||||||
|
this.userId = userId;
|
||||||
|
this.PlayerValue = PlayerValue;
|
||||||
|
|
||||||
|
//the current player model should be push away by other players to prevent conflict
|
||||||
|
this.setImmovable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
initAnimation(): void {
|
||||||
|
getPlayerAnimations().forEach(d => {
|
||||||
|
this.scene.anims.create({
|
||||||
|
key: d.key,
|
||||||
|
frames: this.scene.anims.generateFrameNumbers(d.frameModel, {start: d.frameStart, end: d.frameEnd}),
|
||||||
|
frameRate: d.frameRate,
|
||||||
|
repeat: d.repeat
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
moveUser(delta: number): void {
|
||||||
|
//if user client on shift, camera and player speed
|
||||||
|
let haveMove = false;
|
||||||
|
let direction = null;
|
||||||
|
|
||||||
|
let activeEvents = this.userInputManager.getEventListForGameTick();
|
||||||
|
let speedMultiplier = activeEvents.get(UserInputEvent.SpeedUp) ? 25 : 9;
|
||||||
|
let moveAmount = speedMultiplier * delta;
|
||||||
|
|
||||||
|
if (activeEvents.get(UserInputEvent.MoveUp)) {
|
||||||
|
this.move(0, -moveAmount);
|
||||||
|
haveMove = true;
|
||||||
|
direction = PlayerAnimationNames.WalkUp;
|
||||||
|
}
|
||||||
|
if (activeEvents.get(UserInputEvent.MoveLeft)) {
|
||||||
|
this.move(-moveAmount, 0);
|
||||||
|
haveMove = true;
|
||||||
|
direction = PlayerAnimationNames.WalkLeft;
|
||||||
|
}
|
||||||
|
if (activeEvents.get(UserInputEvent.MoveDown)) {
|
||||||
|
this.move(0, moveAmount);
|
||||||
|
haveMove = true;
|
||||||
|
direction = PlayerAnimationNames.WalkDown;
|
||||||
|
}
|
||||||
|
if (activeEvents.get(UserInputEvent.MoveRight)) {
|
||||||
|
this.move(moveAmount, 0);
|
||||||
|
haveMove = true;
|
||||||
|
direction = PlayerAnimationNames.WalkRight;
|
||||||
|
}
|
||||||
|
if (!haveMove) {
|
||||||
|
direction = PlayerAnimationNames.None;
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
this.sharePosition(direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sharePosition(direction: string) {
|
||||||
|
if (ConnexionInstance) {
|
||||||
|
ConnexionInstance.sharePosition((this.scene as GameSceneInterface).RoomId, this.x, this.y, direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition(MessageUserPosition: MessageUserPositionInterface) {
|
||||||
|
playAnimation(this, MessageUserPosition.position.direction);
|
||||||
|
this.setX(MessageUserPosition.position.x);
|
||||||
|
this.setY(MessageUserPosition.position.y);
|
||||||
|
}
|
||||||
|
}
|
68
front/src/Phaser/UserInput/UserInputManager.ts
Normal file
68
front/src/Phaser/UserInput/UserInputManager.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import Map = Phaser.Structs.Map;
|
||||||
|
import {GameSceneInterface} from "../Game/GameScene";
|
||||||
|
|
||||||
|
interface UserInputManagerDatum {
|
||||||
|
keyCode: number;
|
||||||
|
keyInstance: Phaser.Input.Keyboard.Key;
|
||||||
|
event: UserInputEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum UserInputEvent {
|
||||||
|
MoveLeft = 1,
|
||||||
|
MoveUp,
|
||||||
|
MoveRight,
|
||||||
|
MoveDown,
|
||||||
|
SpeedUp,
|
||||||
|
Interact,
|
||||||
|
Shout,
|
||||||
|
}
|
||||||
|
|
||||||
|
//we cannot the map structure so we have to create a replacment
|
||||||
|
export class ActiveEventList {
|
||||||
|
private KeysCode : any;
|
||||||
|
constructor() {
|
||||||
|
this.KeysCode = {};
|
||||||
|
}
|
||||||
|
get(event: UserInputEvent): boolean {
|
||||||
|
return this.KeysCode[event] || false;
|
||||||
|
}
|
||||||
|
set(event: UserInputEvent, value: boolean): boolean {
|
||||||
|
return this.KeysCode[event] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//this class is responsible for catching user inputs and listing all active user actions at every game tick events.
|
||||||
|
export class UserInputManager {
|
||||||
|
private KeysCode: UserInputManagerDatum[] = [
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.Z, event: UserInputEvent.MoveUp, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.Q, event: UserInputEvent.MoveLeft, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.S, event: UserInputEvent.MoveDown, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.D, event: UserInputEvent.MoveRight, keyInstance: null},
|
||||||
|
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.UP, event: UserInputEvent.MoveUp, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.LEFT, event: UserInputEvent.MoveLeft, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.DOWN, event: UserInputEvent.MoveDown, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.RIGHT, event: UserInputEvent.MoveRight, keyInstance: null},
|
||||||
|
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.SHIFT, event: UserInputEvent.SpeedUp, keyInstance: null},
|
||||||
|
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.E, event: UserInputEvent.Interact, keyInstance: null},
|
||||||
|
{keyCode: Phaser.Input.Keyboard.KeyCodes.F, event: UserInputEvent.Shout, keyInstance: null},
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(Scene : GameSceneInterface) {
|
||||||
|
this.KeysCode.forEach(d => {
|
||||||
|
d.keyInstance = Scene.input.keyboard.addKey(d.keyCode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getEventListForGameTick(): ActiveEventList {
|
||||||
|
let eventsMap = new ActiveEventList();
|
||||||
|
this.KeysCode.forEach(d => {
|
||||||
|
if (d. keyInstance.isDown) {
|
||||||
|
eventsMap.set(d.event, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return eventsMap;
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,32 @@
|
|||||||
import 'phaser';
|
import 'phaser';
|
||||||
import GameConfig = Phaser.Types.Core.GameConfig;
|
import GameConfig = Phaser.Types.Core.GameConfig;
|
||||||
import {GameScene} from "./GameScene";
|
import {GameManager} from "./Phaser/Game/GameManager";
|
||||||
import {Connexion} from "./Connexion";
|
import {DEBUG_MODE, RESOLUTION} from "./Enum/EnvironmentVariable";
|
||||||
import {RESOLUTION} from "./Enum/EnvironmentVariable";
|
import {cypressAsserter} from "./Cypress/CypressAsserter";
|
||||||
|
|
||||||
|
let gameManager = new GameManager();
|
||||||
|
|
||||||
const config: GameConfig = {
|
const config: GameConfig = {
|
||||||
title: "Office game",
|
title: "Office game",
|
||||||
width: window.innerWidth / RESOLUTION,
|
width: window.innerWidth / RESOLUTION,
|
||||||
height: window.innerHeight / RESOLUTION,
|
height: window.innerHeight / RESOLUTION,
|
||||||
parent: "game",
|
parent: "game",
|
||||||
scene: [GameScene],
|
scene: gameManager.GameScenes,
|
||||||
zoom: RESOLUTION,
|
zoom: RESOLUTION,
|
||||||
|
physics: {
|
||||||
|
default: "arcade",
|
||||||
|
arcade: {
|
||||||
|
debug: DEBUG_MODE
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let game = new Phaser.Game(config);
|
cypressAsserter.gameStarted();
|
||||||
|
|
||||||
window.addEventListener('resize', function (event) {
|
gameManager.createGame().then(() => {
|
||||||
game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION);
|
let game = new Phaser.Game(config);
|
||||||
|
|
||||||
|
window.addEventListener('resize', function (event) {
|
||||||
|
game.scale.resize(window.innerWidth / RESOLUTION, window.innerHeight / RESOLUTION);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const connexion = new Connexion("test@gmail.com");
|
|
||||||
|
@ -29,6 +29,6 @@ module.exports = {
|
|||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
Phaser: 'phaser'
|
Phaser: 'phaser'
|
||||||
}),
|
}),
|
||||||
new webpack.EnvironmentPlugin(['API_URL'])
|
new webpack.EnvironmentPlugin(['API_URL', 'DEBUG_MODE'])
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user