Compare commits
No commits in common. "master" and "logout-button" have entirely different histories.
master
...
logout-but
15 changed files with 364 additions and 264 deletions
|
|
@ -1,6 +1,5 @@
|
|||
POSTGRES_PORT=5432
|
||||
EXPRESS_PORT=3000
|
||||
FRONTEND_PORT=8080
|
||||
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
|
|
|
|||
183
README.md
183
README.md
|
|
@ -1,30 +1,163 @@
|
|||
# RaspberryRocketeer
|
||||
|
||||
## How to run
|
||||
## Class Diagram of all classes
|
||||
|
||||
### Copy .env
|
||||
First you need to copy the `.env.example`.
|
||||
```mermaid
|
||||
classDiagram
|
||||
direction BT
|
||||
class Collidable {
|
||||
collides(o: Entity) boolean
|
||||
}
|
||||
class Database {
|
||||
any _db
|
||||
any db
|
||||
}
|
||||
class Entity {
|
||||
constructor(position: Position, width: number, height: number, fill: number)
|
||||
Position _position
|
||||
number _width
|
||||
number _height
|
||||
number fill
|
||||
boolean _showHitbox
|
||||
update() void
|
||||
draw() void
|
||||
Position position
|
||||
number width
|
||||
number height
|
||||
boolean showHitbox
|
||||
}
|
||||
class Game {
|
||||
number id
|
||||
number score
|
||||
string playtime
|
||||
Date date
|
||||
number userId
|
||||
}
|
||||
class GamePgPromiseRepository {
|
||||
insert(game: Game) Promise~Game~
|
||||
serialize(raw: any) Game
|
||||
}
|
||||
class GameRepository {
|
||||
insert(game: Game) Promise~Game~
|
||||
}
|
||||
class HighscoreLeaderboard
|
||||
class HighscoreLeaderboardPgPromiseRepository {
|
||||
getAll() Promise~HighscoreLeaderboard~
|
||||
serialize(raw: any) HighscoreLeaderboard
|
||||
}
|
||||
class HighscoreLeaderboardRepository {
|
||||
getAll() Promise~HighscoreLeaderboard~
|
||||
}
|
||||
class Leaderboard
|
||||
class LeaderboardEntry {
|
||||
number username
|
||||
number rank
|
||||
T score
|
||||
}
|
||||
class Obstacle {
|
||||
constructor(position: Position, obstacleWidth: number, obstacleHeight: number, pipeImagePath: string)
|
||||
Pipe pipeTop
|
||||
Pipe pipeBottom
|
||||
number padding
|
||||
number speed
|
||||
number _distanceBetweenPipes
|
||||
number _startX
|
||||
resetPosition() void
|
||||
randomizeHeight() void
|
||||
randomRange(min: number, max: number) number
|
||||
update() void
|
||||
draw() void
|
||||
collides(o: Entity) boolean
|
||||
any startX
|
||||
any distanceBetweenPipes
|
||||
}
|
||||
class Pipe {
|
||||
constructor(positionX: number, width: number, height: number)
|
||||
any _image
|
||||
update() void
|
||||
draw() void
|
||||
move(speed: number) void
|
||||
collides(o: Entity) boolean
|
||||
any image
|
||||
}
|
||||
class Position {
|
||||
constructor(x: number, y: number)
|
||||
number _x
|
||||
number _y
|
||||
number x
|
||||
number y
|
||||
}
|
||||
class Raspberry {
|
||||
constructor(image: string)
|
||||
number lift
|
||||
number gravity
|
||||
number _velocity
|
||||
any _image
|
||||
Position position
|
||||
number maxVelocity
|
||||
number WIDTH
|
||||
number HEIGHT
|
||||
number FILL
|
||||
update() void
|
||||
applyGravity() void
|
||||
forceBoundaries() void
|
||||
boost() void
|
||||
draw() void
|
||||
number velocity
|
||||
any image
|
||||
}
|
||||
class TimeLeaderboard
|
||||
class TimeLeaderboardPgPromiseRepository {
|
||||
getAll() Promise~TimeLeaderboard~
|
||||
serialize(raw: any) TimeLeaderboard
|
||||
}
|
||||
class TimeLeaderboardRepository {
|
||||
getAll() Promise~TimeLeaderboard~
|
||||
}
|
||||
class User {
|
||||
number id
|
||||
string name
|
||||
}
|
||||
class UserPgPromiseRepository {
|
||||
getById(id: number) Promise~User~
|
||||
getByName(name: string) Promise~User~
|
||||
withIdExists(id: number) Promise~boolean~
|
||||
withNameExists(name: string) Promise~boolean~
|
||||
insert(user: Omit~User, "id"~) Promise~User~
|
||||
serialize(raw: any) User
|
||||
}
|
||||
class UserRepository {
|
||||
getById(id: number) Promise~User~
|
||||
getByName(name: string) Promise~User~
|
||||
withIdExists(userId: number) Promise~boolean~
|
||||
withNameExists(username: string) Promise~boolean~
|
||||
insert(user: Omit~User, "id"~) Promise~User~
|
||||
}
|
||||
class UserScores {
|
||||
number userId
|
||||
number highscore
|
||||
number totalScore
|
||||
string totalPlaytime
|
||||
number averageScore
|
||||
number gamesPlayed
|
||||
}
|
||||
class UserScoresPgPromiseRepository {
|
||||
getById(id: number) Promise~UserScores~
|
||||
serialize(raw: any) UserScores
|
||||
}
|
||||
class UserScoresRepository {
|
||||
getById(userId: number) Promise~UserScores~
|
||||
}
|
||||
|
||||
GamePgPromiseRepository --> GameRepository
|
||||
HighscoreLeaderboardPgPromiseRepository --> HighscoreLeaderboardRepository
|
||||
Obstacle ..> Collidable
|
||||
Obstacle --> Entity
|
||||
Pipe ..> Collidable
|
||||
Pipe --> Entity
|
||||
Raspberry --> Entity
|
||||
TimeLeaderboardPgPromiseRepository --> TimeLeaderboardRepository
|
||||
UserPgPromiseRepository --> UserRepository
|
||||
UserScoresPgPromiseRepository --> UserScoresRepository
|
||||
|
||||
```shell
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
<small>Note: It is recommended to change the values for the database user.</small>
|
||||
|
||||
### Install node packages
|
||||
Go into the frontend folder using
|
||||
```shell
|
||||
cd frontend
|
||||
```
|
||||
and run:
|
||||
```shell
|
||||
npm install
|
||||
```
|
||||
|
||||
### Start the container (in the project root)
|
||||
|
||||
```shell
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
You can then access the website on `localhost:8080`
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class HighscoreLeaderboardPgPromiseRepository extends HighscoreLeaderboar
|
|||
|
||||
async getPage(entriesPerPage, page): Promise<HighscoreLeaderboard> {
|
||||
const raw: any = await Database.db.manyOrNone(
|
||||
'SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2;',
|
||||
'SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2*$1;',
|
||||
[entriesPerPage, page * entriesPerPage]
|
||||
);
|
||||
return this.serialize(raw);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class TimeLeaderboardPgPromiseRepository extends TimeLeaderboardRepositor
|
|||
|
||||
async getPage(entriesPerPage: number, page: number): Promise<TimeLeaderboard> {
|
||||
const raw: any = await Database.db.manyOrNone(
|
||||
'SELECT * FROM lb_total_playtime INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2;',
|
||||
'SELECT * FROM lb_total_playtime INNER JOIN "user" ON user_id = id ORDER BY rank LIMIT $1 OFFSET $2*$1;',
|
||||
[entriesPerPage, page * entriesPerPage]
|
||||
);
|
||||
return this.serialize(raw);
|
||||
|
|
|
|||
40
backend/db/initScripts/loadMockData.sql
Normal file
40
backend/db/initScripts/loadMockData.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
insert into "user" (name) values ('dpettus0');
|
||||
insert into "user" (name) values ('egreetland1');
|
||||
insert into "user" (name) values ('smontford2');
|
||||
insert into "user" (name) values ('idagwell3');
|
||||
insert into "user" (name) values ('lgagan4');
|
||||
insert into "user" (name) values ('acarmont5');
|
||||
insert into "user" (name) values ('kjermyn6');
|
||||
insert into "user" (name) values ('dokieran7');
|
||||
insert into "user" (name) values ('pdrinkel8');
|
||||
|
||||
insert into game (user_id, score, playtime, date) values ('1', 74, '19:59', '2022-07-19');
|
||||
insert into game (user_id, score, playtime, date) values ('1', 86, '20:32', '2022-11-24');
|
||||
insert into game (user_id, score, playtime, date) values ('1', 68, '10:41', '2022-03-24');
|
||||
insert into game (user_id, score, playtime, date) values ('2', 39, '5:55', '2022-06-01');
|
||||
insert into game (user_id, score, playtime, date) values ('2', 20, '9:23', '2022-03-12');
|
||||
insert into game (user_id, score, playtime, date) values ('2', 28, '23:45', '2022-04-01');
|
||||
insert into game (user_id, score, playtime, date) values ('2', 44, '18:43', '2022-06-24');
|
||||
insert into game (user_id, score, playtime, date) values ('3', 92, '14:54', '2022-11-06');
|
||||
insert into game (user_id, score, playtime, date) values ('3', 73, '0:45', '2022-07-26');
|
||||
insert into game (user_id, score, playtime, date) values ('3', 27, '2:49', '2022-02-03');
|
||||
insert into game (user_id, score, playtime, date) values ('4', 26, '2:32', '2022-07-19');
|
||||
insert into game (user_id, score, playtime, date) values ('4', 12, '17:03', '2022-04-25');
|
||||
insert into game (user_id, score, playtime, date) values ('4', 6, '8:49', '2021-12-03');
|
||||
insert into game (user_id, score, playtime, date) values ('4', 22, '22:27', '2022-03-02');
|
||||
insert into game (user_id, score, playtime, date) values ('5', 94, '1:04', '2022-10-19');
|
||||
insert into game (user_id, score, playtime, date) values ('5', 2, '2:14', '2022-04-06');
|
||||
insert into game (user_id, score, playtime, date) values ('5', 21, '17:18', '2022-06-03');
|
||||
insert into game (user_id, score, playtime, date) values ('6', 33, '16:01', '2022-02-02');
|
||||
insert into game (user_id, score, playtime, date) values ('6', 27, '7:03', '2022-02-06');
|
||||
insert into game (user_id, score, playtime, date) values ('6', 62, '0:45', '2022-11-15');
|
||||
insert into game (user_id, score, playtime, date) values ('7', 12, '8:54', '2022-06-29');
|
||||
insert into game (user_id, score, playtime, date) values ('7', 63, '16:01', '2022-11-05');
|
||||
insert into game (user_id, score, playtime, date) values ('7', 29, '0:46', '2022-10-01');
|
||||
insert into game (user_id, score, playtime, date) values ('8', 67, '1:27', '2022-09-29');
|
||||
insert into game (user_id, score, playtime, date) values ('8', 84, '10:37', '2021-12-18');
|
||||
insert into game (user_id, score, playtime, date) values ('8', 14, '19:14', '2022-01-31');
|
||||
insert into game (user_id, score, playtime, date) values ('9', 21, '19:04', '2022-03-08');
|
||||
insert into game (user_id, score, playtime, date) values ('9', 46, '2:34', '2022-04-18');
|
||||
insert into game (user_id, score, playtime, date) values ('9', 78, '9:33', '2022-09-10');
|
||||
insert into game (user_id, score, playtime, date) values ('9', 82, '11:19', '2022-11-29');
|
||||
|
|
@ -1,32 +1,23 @@
|
|||
version: '3.1'
|
||||
|
||||
services:
|
||||
db:
|
||||
build: backend/db
|
||||
container_name: postgres-db
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
ports:
|
||||
- "${POSTGRES_PORT}:5432"
|
||||
volumes:
|
||||
- ./backend/pgdata:/var/lib/postgresql/data
|
||||
|
||||
api:
|
||||
build: backend/api
|
||||
depends_on:
|
||||
- db
|
||||
container_name: express-api
|
||||
ports:
|
||||
- "${EXPRESS_PORT}:3000"
|
||||
|
||||
vue:
|
||||
build: frontend
|
||||
container_name: frontend
|
||||
ports:
|
||||
- "${FRONTEND_PORT}:8080"
|
||||
|
||||
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
version: '3.1'
|
||||
|
||||
services:
|
||||
db:
|
||||
build: backend/db
|
||||
container_name: postgres-db
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
ports:
|
||||
- "${POSTGRES_PORT}:5432"
|
||||
volumes:
|
||||
- ./backend/pgdata:/var/lib/postgresql/data
|
||||
|
||||
api:
|
||||
build: backend/api
|
||||
depends_on:
|
||||
- db
|
||||
container_name: express-api
|
||||
ports:
|
||||
- "${EXPRESS_PORT}:3000"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
node_modules
|
||||
.gitignore
|
||||
README.md
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
FROM node:18
|
||||
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["npm", "run", "serve"]
|
||||
|
||||
|
|
@ -10,11 +10,11 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.2.3",
|
||||
"vue": "^3.2.13",
|
||||
"@vue/cli-service": "~5.0.0"
|
||||
"vue": "^3.2.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-typescript": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"typescript": "~4.5.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
var __extends = (this && this.__extends) || (function(){
|
||||
var extendStatics = function(d, b){
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({__proto__: []} instanceof Array && function(d, b){
|
||||
({__proto__: []} instanceof Array && function (d, b) {
|
||||
d.__proto__ = b;
|
||||
}) ||
|
||||
function(d, b){
|
||||
for(var p in b) if(Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
|
||||
function (d, b) {
|
||||
for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
|
||||
};
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function(d, b){
|
||||
if(typeof b !== "function" && b !== null)
|
||||
return function (d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
|
||||
function __(){
|
||||
function __() {
|
||||
this.constructor = d;
|
||||
}
|
||||
|
||||
|
|
@ -45,21 +45,21 @@ var hasAlreadyScored = false;
|
|||
var hasDied = true;
|
||||
var ready = true;
|
||||
|
||||
function preload(){
|
||||
function preload() {
|
||||
font = loadFont(FONT_PATH);
|
||||
backgroundImage = loadImage(BACKGROUND_IMAGE_PATH);
|
||||
pipeImage = loadImage(PIPE_IMAGE_PATH);
|
||||
floorImage = loadImage(FLOOR_IMAGE_PATH);
|
||||
}
|
||||
|
||||
function setup(){
|
||||
function setup() {
|
||||
createCanvas(1085, 600);
|
||||
floorHeight = height / 5;
|
||||
setupObstacleConsts();
|
||||
setupFont();
|
||||
setupGame();
|
||||
var originalSetItem = localStorage.setItem;
|
||||
localStorage.setItem = function(key, value){
|
||||
localStorage.setItem = function (key, value) {
|
||||
var event = new Event('itemInserted');
|
||||
|
||||
event.value = value; // Optional..
|
||||
|
|
@ -69,57 +69,57 @@ function setup(){
|
|||
};
|
||||
}
|
||||
|
||||
function setupObstacleConsts(){
|
||||
function setupObstacleConsts() {
|
||||
obstacleOffset = width / OBSTACLE_COUNT;
|
||||
obstacleWidth = width / 22.727272727272727272;
|
||||
Obstacle.distanceBetweenPipes = height / 2.5;
|
||||
Obstacle.startX = width;
|
||||
}
|
||||
|
||||
function setupFont(){
|
||||
function setupFont() {
|
||||
textSize(75);
|
||||
textAlign(CENTER);
|
||||
textFont(font);
|
||||
}
|
||||
|
||||
function setupGame(){
|
||||
function setupGame() {
|
||||
paused = true;
|
||||
raspberry = new Raspberry(RASPBERRY_IMAGE_PATH);
|
||||
setupObstacles();
|
||||
}
|
||||
|
||||
function setupObstacles(){
|
||||
function setupObstacles() {
|
||||
obstacles = [];
|
||||
instantiateObstacles(OBSTACLE_COUNT);
|
||||
obstacles.forEach(function(obstacle){
|
||||
obstacles.forEach(function (obstacle) {
|
||||
return obstacle.randomizeHeight();
|
||||
});
|
||||
}
|
||||
|
||||
function instantiateObstacles(number){
|
||||
for(var i = 0; i < number; i++){
|
||||
function instantiateObstacles(number) {
|
||||
for (var i = 0; i < number; i++) {
|
||||
obstacles.push(new Obstacle(new Position(width + obstacleOffset * i, 0), obstacleWidth, height, pipeImage));
|
||||
}
|
||||
}
|
||||
|
||||
function draw(){
|
||||
function draw() {
|
||||
update();
|
||||
gameLoop();
|
||||
drawGame();
|
||||
}
|
||||
|
||||
function drawGame(){
|
||||
function drawGame() {
|
||||
drawScenery();
|
||||
drawEntities();
|
||||
displayScore();
|
||||
}
|
||||
|
||||
function drawScenery(){
|
||||
function drawScenery() {
|
||||
background(backgroundImage);
|
||||
drawFloor();
|
||||
}
|
||||
|
||||
function drawFloor(){
|
||||
function drawFloor() {
|
||||
push();
|
||||
noFill();
|
||||
image(floorImage, 0, height - floorHeight, width, floorHeight);
|
||||
|
|
@ -127,71 +127,68 @@ function drawFloor(){
|
|||
pop();
|
||||
}
|
||||
|
||||
function drawEntities(){
|
||||
function drawEntities() {
|
||||
raspberry.draw();
|
||||
drawObstacles();
|
||||
}
|
||||
|
||||
function drawObstacles(){
|
||||
obstacles.forEach(function(obstacle){
|
||||
function drawObstacles() {
|
||||
obstacles.forEach(function (obstacle) {
|
||||
obstacle.draw();
|
||||
});
|
||||
}
|
||||
|
||||
function gameLoop(){
|
||||
if(!paused){
|
||||
function gameLoop() {
|
||||
if (!paused) {
|
||||
collisionCheck(obstacles[0]);
|
||||
checkRaspberryScore();
|
||||
}
|
||||
}
|
||||
|
||||
function collisionCheck(o){
|
||||
if(o.collides(raspberry)){
|
||||
function collisionCheck(o) {
|
||||
if (o.collides(raspberry)) {
|
||||
die();
|
||||
setupGame();
|
||||
}
|
||||
}
|
||||
|
||||
function die(){
|
||||
if(localStorage.getItem("frontend-ready") == "false")
|
||||
return;
|
||||
|
||||
function die() {
|
||||
ready = false;
|
||||
hasDied = true;
|
||||
playTime = Date.now() - startTime;
|
||||
exportToLocalStorage();
|
||||
setTimeout(function(){
|
||||
setTimeout(function () {
|
||||
return ready = true;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function exportToLocalStorage(){
|
||||
function exportToLocalStorage() {
|
||||
localStorage.setItem("game-playTime", String(playTime));
|
||||
localStorage.setItem("game-score", String(score));
|
||||
localStorage.setItem("game-isRunning", String(!hasDied));
|
||||
}
|
||||
|
||||
function displayScore(){
|
||||
function displayScore() {
|
||||
push();
|
||||
fill(195, 33, 34);
|
||||
text(score, 0, height / 8, width, height);
|
||||
pop();
|
||||
}
|
||||
|
||||
function update(){
|
||||
if(!paused){
|
||||
function update() {
|
||||
if (!paused) {
|
||||
raspberry.update();
|
||||
}
|
||||
obstacles.forEach(function(obstacle){
|
||||
if(!paused){
|
||||
obstacles.forEach(function (obstacle) {
|
||||
if (!paused) {
|
||||
obstacle.update();
|
||||
checkObstacleReset(obstacle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkObstacleReset(obstacle){
|
||||
if(obstacle.position.x < -obstacleWidth){
|
||||
function checkObstacleReset(obstacle) {
|
||||
if (obstacle.position.x < -obstacleWidth) {
|
||||
obstacle.resetPosition();
|
||||
obstacles.shift();
|
||||
obstacles.push(obstacle);
|
||||
|
|
@ -199,41 +196,40 @@ function checkObstacleReset(obstacle){
|
|||
}
|
||||
}
|
||||
|
||||
function checkRaspberryScore(){
|
||||
if((obstacles[0].position.x + obstacles[0].width / 2) < (raspberry.position.x + raspberry.width / 2)
|
||||
&& !hasAlreadyScored){
|
||||
function checkRaspberryScore() {
|
||||
if ((obstacles[0].position.x + obstacles[0].width / 2) < (raspberry.position.x + raspberry.width / 2)
|
||||
&& !hasAlreadyScored) {
|
||||
score += 1;
|
||||
hasAlreadyScored = true;
|
||||
}
|
||||
}
|
||||
|
||||
function resetScore(){
|
||||
if(!hasDied || localStorage.getItem("frontend-ready") == "false")
|
||||
return;
|
||||
|
||||
hasDied = false;
|
||||
score = 0;
|
||||
hasAlreadyScored = false;
|
||||
startTime = Date.now();
|
||||
exportToLocalStorage();
|
||||
function resetScore() {
|
||||
if (hasDied) {
|
||||
hasDied = false;
|
||||
score = 0;
|
||||
hasAlreadyScored = false;
|
||||
startTime = Date.now();
|
||||
exportToLocalStorage();
|
||||
}
|
||||
}
|
||||
|
||||
function keyPressed(){
|
||||
if(!ready)
|
||||
function keyPressed() {
|
||||
if (!ready)
|
||||
return;
|
||||
if(BOOST_KEYS.includes(key.toLowerCase())){
|
||||
if (BOOST_KEYS.includes(key.toLowerCase())) {
|
||||
resetScore();
|
||||
raspberry.boost();
|
||||
}
|
||||
if(key == "Escape"){
|
||||
if (key == "Escape") {
|
||||
paused = !paused;
|
||||
} else if(paused){
|
||||
} else if (paused) {
|
||||
paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
var Entity = (function(){
|
||||
function Entity(position, width, height, fill){
|
||||
var Entity = (function () {
|
||||
function Entity(position, width, height, fill) {
|
||||
this.position = position;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
|
@ -242,46 +238,46 @@ var Entity = (function(){
|
|||
}
|
||||
|
||||
Object.defineProperty(Entity.prototype, "position", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._position;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._position = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Entity.prototype, "width", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._width;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._width = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Entity.prototype, "height", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._height;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._height = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Entity.prototype, "showHitbox", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._showHitbox;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._showHitbox = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Entity.prototype.draw = function(){
|
||||
Entity.prototype.draw = function () {
|
||||
push();
|
||||
fill(this.fill);
|
||||
rect(this.position.x, this.position.y, this.width, this.height);
|
||||
|
|
@ -289,10 +285,10 @@ var Entity = (function(){
|
|||
};
|
||||
return Entity;
|
||||
}());
|
||||
var Obstacle = (function(_super){
|
||||
var Obstacle = (function (_super) {
|
||||
__extends(Obstacle, _super);
|
||||
|
||||
function Obstacle(position, obstacleWidth, obstacleHeight, image){
|
||||
function Obstacle(position, obstacleWidth, obstacleHeight, image) {
|
||||
var _this = _super.call(this, position, obstacleWidth, obstacleHeight, 0) || this;
|
||||
_this.speed = 3;
|
||||
_this.padding = height / 6.6666666666666666;
|
||||
|
|
@ -301,62 +297,62 @@ var Obstacle = (function(_super){
|
|||
}
|
||||
|
||||
Object.defineProperty(Obstacle, "startX", {
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._startX = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Obstacle, "distanceBetweenPipes", {
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._distanceBetweenPipes = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Obstacle.prototype.createPipes = function(position, obstacleHeight, obstacleWidth, pipeImage){
|
||||
Obstacle.prototype.createPipes = function (position, obstacleHeight, obstacleWidth, pipeImage) {
|
||||
this.pipeTop = new Pipe(position.x, obstacleWidth, obstacleHeight, pipeImage);
|
||||
this.pipeBottom = new Pipe(position.x, obstacleWidth, obstacleHeight, pipeImage);
|
||||
};
|
||||
Obstacle.prototype.resetPosition = function(){
|
||||
Obstacle.prototype.resetPosition = function () {
|
||||
this.randomizeHeight();
|
||||
this.pipeBottom.position.x = Obstacle._startX;
|
||||
this.pipeTop.position.x = Obstacle._startX;
|
||||
};
|
||||
Obstacle.prototype.randomizeHeight = function(){
|
||||
Obstacle.prototype.randomizeHeight = function () {
|
||||
this.pipeTop.height = this.randomRange(this.padding, height - this.padding - Obstacle._distanceBetweenPipes);
|
||||
this.pipeBottom.position.y = this.pipeTop.height + Obstacle._distanceBetweenPipes;
|
||||
this.pipeBottom.height = height - this.pipeTop.height - this.padding;
|
||||
};
|
||||
Obstacle.prototype.randomRange = function(min, max){
|
||||
Obstacle.prototype.randomRange = function (min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
};
|
||||
Obstacle.prototype.update = function(){
|
||||
Obstacle.prototype.update = function () {
|
||||
this.pipeTop.move(this.speed);
|
||||
this.pipeBottom.move(this.speed);
|
||||
this.position.x = this.pipeTop.position.x;
|
||||
};
|
||||
Obstacle.prototype.draw = function(){
|
||||
Obstacle.prototype.draw = function () {
|
||||
this.pipeTop.draw();
|
||||
this.pipeBottom.draw();
|
||||
};
|
||||
Obstacle.prototype.collides = function(o){
|
||||
Obstacle.prototype.collides = function (o) {
|
||||
return this.pipeTop.collides(o) || this.pipeBottom.collides(o);
|
||||
};
|
||||
return Obstacle;
|
||||
}(Entity));
|
||||
var Pipe = (function(_super){
|
||||
var Pipe = (function (_super) {
|
||||
__extends(Pipe, _super);
|
||||
|
||||
function Pipe(positionX, width, height, image){
|
||||
function Pipe(positionX, width, height, image) {
|
||||
var _this = _super.call(this, new Position(positionX, 0), width, height, 0) || this;
|
||||
_this.image = image;
|
||||
return _this;
|
||||
}
|
||||
|
||||
Pipe.prototype.update = function(){
|
||||
Pipe.prototype.update = function () {
|
||||
};
|
||||
Pipe.prototype.draw = function(){
|
||||
Pipe.prototype.draw = function () {
|
||||
push();
|
||||
noFill();
|
||||
var imageAspectRatio = this.image.height / this.image.width;
|
||||
|
|
@ -365,30 +361,30 @@ var Pipe = (function(_super){
|
|||
rect(this.position.x, this.position.y, this.width, this.height);
|
||||
pop();
|
||||
};
|
||||
Pipe.prototype.drawImage = function(computedImageHeight, imageAspectRatio){
|
||||
if(this.height > computedImageHeight){
|
||||
Pipe.prototype.drawImage = function (computedImageHeight, imageAspectRatio) {
|
||||
if (this.height > computedImageHeight) {
|
||||
var maxImageYPos = Math.ceil(this.height / computedImageHeight) * computedImageHeight;
|
||||
for(var imageYPosition = 0; imageYPosition < maxImageYPos; imageYPosition += computedImageHeight){
|
||||
if(imageYPosition + computedImageHeight >= maxImageYPos){
|
||||
for (var imageYPosition = 0; imageYPosition < maxImageYPos; imageYPosition += computedImageHeight) {
|
||||
if (imageYPosition + computedImageHeight >= maxImageYPos) {
|
||||
this.cropLastImage(imageYPosition, computedImageHeight, imageAspectRatio);
|
||||
break;
|
||||
}
|
||||
image(this.image, this.position.x, this.position.y + imageYPosition, this.width, computedImageHeight);
|
||||
}
|
||||
} else{
|
||||
} else {
|
||||
image(this.image, this.position.x, this.position.y, this.width, this.height);
|
||||
}
|
||||
};
|
||||
Pipe.prototype.cropLastImage = function(imageYPosition, computedImageHeight, imageAspectRatio){
|
||||
Pipe.prototype.cropLastImage = function (imageYPosition, computedImageHeight, imageAspectRatio) {
|
||||
var amountOfImages = Math.floor(imageYPosition / computedImageHeight);
|
||||
var heightToEdge = this.height - (amountOfImages * computedImageHeight);
|
||||
var croppedImage = this.image.get(0, 0, this.image.width, this.image.height - (heightToEdge * imageAspectRatio));
|
||||
image(croppedImage, this.position.x, this.position.y + imageYPosition, this.width, heightToEdge);
|
||||
};
|
||||
Pipe.prototype.move = function(speed){
|
||||
Pipe.prototype.move = function (speed) {
|
||||
this.position.x -= speed;
|
||||
};
|
||||
Pipe.prototype.collides = function(o){
|
||||
Pipe.prototype.collides = function (o) {
|
||||
return this.position.x < (o.position.x + o.width) &&
|
||||
(this.position.x + this.width) > o.position.x &&
|
||||
this.position.y < (o.position.y + o.height) &&
|
||||
|
|
@ -396,27 +392,27 @@ var Pipe = (function(_super){
|
|||
};
|
||||
return Pipe;
|
||||
}(Entity));
|
||||
var Position = (function(){
|
||||
function Position(x, y){
|
||||
var Position = (function () {
|
||||
function Position(x, y) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
|
||||
Object.defineProperty(Position.prototype, "x", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._x;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._x = value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Position.prototype, "y", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._y;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._y = value;
|
||||
},
|
||||
enumerable: false,
|
||||
|
|
@ -424,10 +420,10 @@ var Position = (function(){
|
|||
});
|
||||
return Position;
|
||||
}());
|
||||
var Raspberry = (function(_super){
|
||||
var Raspberry = (function (_super) {
|
||||
__extends(Raspberry, _super);
|
||||
|
||||
function Raspberry(image){
|
||||
function Raspberry(image) {
|
||||
var _this = this;
|
||||
Raspberry.position = new Position(width / 6, height / 2);
|
||||
Raspberry.height = height / 14.2857142857142857;
|
||||
|
|
@ -442,73 +438,73 @@ var Raspberry = (function(_super){
|
|||
}
|
||||
|
||||
Object.defineProperty(Raspberry.prototype, "velocity", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._velocity;
|
||||
},
|
||||
set: function(value){
|
||||
set: function (value) {
|
||||
this._velocity = (Math.abs(this.velocity) > Raspberry.maxVelocity) ? Raspberry.maxVelocity : value;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Raspberry.prototype, "image", {
|
||||
get: function(){
|
||||
get: function () {
|
||||
return this._image;
|
||||
},
|
||||
set: function(path){
|
||||
set: function (path) {
|
||||
this._image = loadImage(path);
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Raspberry.prototype.update = function(){
|
||||
Raspberry.prototype.update = function () {
|
||||
this.applyGravity();
|
||||
this.forceBoundaries();
|
||||
};
|
||||
Raspberry.prototype.applyGravity = function(){
|
||||
Raspberry.prototype.applyGravity = function () {
|
||||
this.velocity += this.gravity;
|
||||
this.position.y += this.velocity;
|
||||
};
|
||||
Raspberry.prototype.forceBoundaries = function(){
|
||||
Raspberry.prototype.forceBoundaries = function () {
|
||||
this.boundaryTop();
|
||||
this.boundaryBottom();
|
||||
};
|
||||
Raspberry.prototype.boundaryTop = function(){
|
||||
if(this.position.y < 0){
|
||||
Raspberry.prototype.boundaryTop = function () {
|
||||
if (this.position.y < 0) {
|
||||
this.position.y = 0;
|
||||
this.velocity = 0;
|
||||
}
|
||||
};
|
||||
Raspberry.prototype.boundaryBottom = function(){
|
||||
if(this.position.y + this.height + Raspberry.bottomFloorOffset > height){
|
||||
Raspberry.prototype.boundaryBottom = function () {
|
||||
if (this.position.y + this.height + Raspberry.bottomFloorOffset > height) {
|
||||
this.position.y = height - this.height - Raspberry.bottomFloorOffset;
|
||||
this.velocity = 0;
|
||||
}
|
||||
};
|
||||
Raspberry.prototype.boost = function(){
|
||||
Raspberry.prototype.boost = function () {
|
||||
this.velocity += this.lift;
|
||||
};
|
||||
Raspberry.prototype.draw = function(){
|
||||
Raspberry.prototype.draw = function () {
|
||||
push();
|
||||
noFill();
|
||||
this.setPose();
|
||||
this.drawObject();
|
||||
pop();
|
||||
};
|
||||
Raspberry.prototype.drawObject = function(){
|
||||
Raspberry.prototype.drawObject = function () {
|
||||
this.drawHitBox();
|
||||
this.drawRocket();
|
||||
};
|
||||
Raspberry.prototype.drawRocket = function(){
|
||||
Raspberry.prototype.drawRocket = function () {
|
||||
image(this.image, 0, 0, this.width, this.height);
|
||||
rect(0, 0, this.width, this.height);
|
||||
};
|
||||
Raspberry.prototype.drawHitBox = function(){
|
||||
if(!this.showHitbox){
|
||||
Raspberry.prototype.drawHitBox = function () {
|
||||
if (!this.showHitbox) {
|
||||
noStroke();
|
||||
}
|
||||
};
|
||||
Raspberry.prototype.setPose = function(){
|
||||
Raspberry.prototype.setPose = function () {
|
||||
translate(this.position.x, this.position.y);
|
||||
rotate((PI / 2) * (this.velocity / Raspberry.maxVelocity));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<Login v-if="!user" @userChange="(event) => {this.updateUser(event);}">
|
||||
</Login>
|
||||
<div v-if="user" class="logout-wrapper offset-10 col-2">
|
||||
<RRButton @click="logOut()" text="Logout"></RRButton>
|
||||
<RRButton @click="this.user = null; this.userId = -1;" text="Logout"></RRButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
@ -59,9 +59,7 @@ export default defineComponent({
|
|||
leaderboardEvent: new Event('reloadLeaderboard')
|
||||
}
|
||||
},
|
||||
created() {
|
||||
localStorage.setItem("frontend-ready", "false");
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
async fetchFromApi(path: string, method: "GET" | "POST") {
|
||||
|
|
@ -82,12 +80,6 @@ export default defineComponent({
|
|||
await this.updateUserScores();
|
||||
}
|
||||
window.dispatchEvent(this.leaderboardEvent);
|
||||
},
|
||||
logOut(){
|
||||
this.user = null;
|
||||
this.userId = -1;
|
||||
this.userScores = {};
|
||||
localStorage.setItem('frontend-ready', 'false');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -107,11 +99,9 @@ export default defineComponent({
|
|||
.everything {
|
||||
margin-bottom: 4em;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.logout-wrapper {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
|
|
|
|||
|
|
@ -58,9 +58,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#p5_loading {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -9,12 +9,9 @@
|
|||
<RRButton @click="nextPage" text=">"></RRButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="this.page.length > 0" v-for="entry in this.page" :key="entry.rank">
|
||||
<div class="row" v-for="entry in this.page" :key="entry.rank">
|
||||
<LeaderboardEntry :entry="entry"></LeaderboardEntry>
|
||||
</div>
|
||||
<div class="row" v-else>
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -42,7 +39,11 @@ export default {
|
|||
},
|
||||
created() {
|
||||
this.updatePage();
|
||||
window.addEventListener('itemInserted', event => this.onItemInserted(event), false);
|
||||
window.addEventListener('itemInserted', (event) => {
|
||||
if (event.key === 'game-isRunning' && event.value === 'false'){
|
||||
this.updatePage();
|
||||
}
|
||||
}, false)
|
||||
},
|
||||
methods: {
|
||||
async fetchPage() {
|
||||
|
|
@ -52,33 +53,21 @@ export default {
|
|||
title() {
|
||||
return this.type === "totalplaytime" ? "Total Playtime" : "Highscore";
|
||||
},
|
||||
async nextPage() {
|
||||
if (this.page.length !== this.entriesPerPage) return;
|
||||
|
||||
nextPage() {
|
||||
this.pageNumber++;
|
||||
await this.updatePage();
|
||||
if (this.page.length === 0) {
|
||||
this.prevPage();
|
||||
}
|
||||
this.updatePage();
|
||||
},
|
||||
prevPage() {
|
||||
if (this.pageNumber <= 0) return;
|
||||
|
||||
this.pageNumber--;
|
||||
if (this.pageNumber > 0) this.pageNumber--;
|
||||
this.updatePage();
|
||||
},
|
||||
async updatePage() {
|
||||
let tempPage = await this.fetchPage();
|
||||
for (let i = 0; i < this.entriesPerPage; i++) {
|
||||
this.page.pop();
|
||||
this.page.pop()
|
||||
}
|
||||
for (const entry of tempPage) {
|
||||
this.page.push(entry);
|
||||
}
|
||||
},
|
||||
onItemInserted(event) {
|
||||
if (event.key === 'game-isRunning' && event.value === 'false') {
|
||||
this.updatePage();
|
||||
this.page.push(entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
<template>
|
||||
<div class="col-1 text-right">{{this.entry.rank}}</div>
|
||||
<span class="col offset-1 text-left username">{{this.entry.username}}</span>
|
||||
<div class="col-2 text-right">{{this.entry.score}}</div>
|
||||
<div class="col-1 text-left">{{this.entry.rank}}</div>
|
||||
<div class="col text-left">{{this.entry.username}}</div>
|
||||
<div class="col text-right">{{this.entry.score}}</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, PropType} from 'vue';
|
||||
import {Leaderboard, LeaderboardEntry} from "@/model/Leaderboard";
|
||||
import {defineComponent} from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: "LeaderboardEntry",
|
||||
props: {
|
||||
entry: {
|
||||
type: Object as PropType<LeaderboardEntry<string>>,
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
|
@ -23,9 +22,4 @@ export default defineComponent({
|
|||
* {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.username {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<h2>Enter a username</h2>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="floatingInput" placeholder="example name" v-model="username">
|
||||
<input type="email" class="form-control" id="floatingInput" placeholder="example name" v-model="username">
|
||||
<label for="floatingInput">Username</label>
|
||||
<RRButton @click="setUser()" text="Confirm"></RRButton>
|
||||
</div>
|
||||
|
|
@ -19,26 +19,26 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
username: '',
|
||||
user: null,
|
||||
}
|
||||
},
|
||||
emits: ['userChange'],
|
||||
methods: {
|
||||
async setUser() {
|
||||
if (this.username === '') return;
|
||||
|
||||
let user;
|
||||
user = await User.getByName(this.username);
|
||||
if(user.errors){
|
||||
if (user.errors) {
|
||||
user = await User.create(this.username);
|
||||
}
|
||||
|
||||
if(user.errors){
|
||||
if (user.errors) {
|
||||
console.error("Something when wrong when logging in, please contact admin!")
|
||||
return;
|
||||
}
|
||||
|
||||
if (user) {
|
||||
this.$emit('userChange', user);
|
||||
this.user = user;
|
||||
this.$emit('userChange', this.user);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -48,18 +48,6 @@ export default {
|
|||
<style scoped>
|
||||
input {
|
||||
border: 3px solid black;
|
||||
border-radius: 0;
|
||||
background-color: beige;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
background: beige;
|
||||
border-color: rgba(184,134,11, 0.8);
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(184,134,11, 0.6);
|
||||
}
|
||||
|
||||
label {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue