added Vue

This commit is contained in:
j-weissen 2023-01-12 12:24:38 +01:00
parent d93a5fd6a1
commit 10508ded4b
37 changed files with 15941 additions and 2884 deletions

4
frontend/.browserslistrc Normal file
View file

@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

19
frontend/.eslintrc.js Normal file
View file

@ -0,0 +1,19 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/typescript/recommended'
],
parserOptions: {
ecmaVersion: 2020
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 'off',
}
}

247
frontend/.gitignore vendored
View file

@ -1,235 +1,24 @@
# Project exclude paths .DS_Store
/frontend/node_modules/ node_modules
/dist
# Created by https://www.toptal.com/developers/gitignore/api/node,phpstorm+all
# Edit at https://www.toptal.com/developers/gitignore?templates=node,phpstorm+all
### Node ### # local env files
# Logs .env.local
logs .env.*.local
*.log
# Log files
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log* pnpm-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html) # Editor directories and files
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json .idea
.vscode
# Runtime data *.suo
pids *.ntvs*
*.pid *.njsproj
*.seed *.sln
*.pid.lock *.sw?
/public/game/
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
### PhpStorm+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### PhpStorm+all Patch ###
# Ignore everything but code style settings and run configurations
# that are supposed to be shared within teams.
.idea/*
!.idea/codeStyles
!.idea/runConfigurations
# End of https://www.toptal.com/developers/gitignore/api/node,phpstorm+all

View file

@ -1,87 +1,24 @@
```mermaid # raspberryrocketeer
classDiagram
direction BT
class Collidable {
collides(o: Entity) boolean
}
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 Obstacle {
constructor(position: Position, obstacleWidth: number, obstacleHeight: number, pipeImagePath: string)
Pipe pipeTop
Pipe pipeBottom
number padding
number speed
number _distanceBetweenPipes
number _startX
createPipes(position: Position, obstacleHeight: number, obstacleWidth: number, pipeImagePath: string) void
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, image: string)
p5.Image _image
update() void
draw() void
move(speed: number) void
collides(o: Entity) boolean
p5.Image 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
p5.Image _image
Position position
number maxVelocity
number WIDTH
number HEIGHT
number FILL
update() void
applyGravity() void
forceBoundaries() void
boundaryTop() void
boundaryBottom() void
boost() void
draw() void
drawObject() void
drawRocket() void
drawHitBox() void
setPose() void
number velocity
p5.Image image
}
Obstacle ..> Collidable
Obstacle --> Entity
Pipe ..> Collidable
Pipe --> Entity
Raspberry --> Entity
## Project setup
``` ```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View file

@ -20,7 +20,7 @@ let ready: boolean = true;
*/ */
function setup() { function setup() {
backgroundImage = loadImage(BACKGROUND_IMAGE_PATH); backgroundImage = loadImage(BACKGROUND_IMAGE_PATH);
createCanvas(2000, 1000); createCanvas(1200, 750);
setupObstacleConsts(); setupObstacleConsts();
setupFont(); setupFont();
setupGame(); setupGame();

4
frontend/game/global.d.ts vendored Normal file
View file

@ -0,0 +1,4 @@
// This file will add both p5 instanced and global intellisense
import module = require('p5');
export = module;
export as namespace p5;

View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"noImplicitAny": true,
"outFile": "../public/game/build.js",
"preserveConstEnums": true,
"removeComments": true,
"rootDir": ".",
"sourceMap": true,
"target": "es5",
"moduleResolution": "node",
"lib": [
"dom",
"es5",
"scripthost"
]
}
}

View file

@ -1,5 +0,0 @@
// This file will add both p5 instanced and global intellisence
import * as p5Global from 'p5/global'
import module = require('p5');
export = module;
export as namespace p5;

View file

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Raspberyy Rocketeer</title>
<script src="build/build.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"
integrity="sha512-N4kV7GkNv7QR7RX9YF/olywyIgIwNvfEe2nZtfyj73HdjCUkAfOBDbcuJ/cTaN04JKRnw1YG1wnUyNKMsNgg3g=="
crossorigin="anonymous"
referrerpolicy="no-referrer">
</script>
</head>
<body>
<main></main>
</body>
</html>

19330
frontend/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,28 @@
{ {
"name": "raspberryrocketeer",
"version": "0.1.0",
"private": true,
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "serve": "vue-cli-service serve",
"start": "run-p start-compile start-run", "build": "npm run build-game && vue-cli-service build",
"start-compile": "tsc --watch", "build-game": "tsc -p ./game",
"start-run": "browser-sync start --server -w" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"@types/p5": "^1.4.3", "@types/p5": "^1.4.3",
"browser-sync": "^2.27.10", "bootstrap": "^5.2.3",
"npm-run-all": "^4.1.5",
"p5": "^1.5.0", "p5": "^1.5.0",
"typedoc": "^0.23.24" "vue": "^3.2.13"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-typescript": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"@vue/eslint-config-typescript": "^9.1.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"typescript": "~4.5.5"
} }
} }

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="./game/build.js"></script>
<title><%= htmlWebpackPlugin.options.title %></title>
<script src="https://cdn.jsdelivr.net/npm/p5@1.5.0/lib/p5.js"></script>
</head>
<body style="background-color: beige;">
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div class="container">
<div class="row">
<div id="app" class="offset-1 col-10"></div>
</div>
</div>
</body>
<script>
window.addEventListener('keydown', function(e) {
if(e.keyCode === 32 && e.target === document.body) {
e.preventDefault();
}
});
</script>
</html>

View file

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 586 KiB

After

Width:  |  Height:  |  Size: 586 KiB

Before After
Before After

81
frontend/src/App.vue Normal file
View file

@ -0,0 +1,81 @@
<template>
<div class="container">
<div class="row">
<Header></Header>
</div>
<div class="row">
<UserScores :userScores="userScores" ></UserScores>
</div>
<div class="row">
<Game class="col">
</Game>
</div>
<div class="row">
<div class="col">
<Leaderboard :title="'Highscore'" :data="higscoreLeaderboard"></Leaderboard>
</div>
<div class="col">
<Leaderboard :title="'Total Playtime'" :data="totalPlaytimeLeaderboard"></Leaderboard>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Leaderboard from './components/Leaderboard.vue';
import UserScores from './components/UserScores.vue';
import Game from './components/Game.vue';
import Header from './components/Header.vue';
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap.min.js";
export default defineComponent({
name: 'App',
components: {
UserScores,
Leaderboard,
Game,
Header,
},
data() {
return {
userScores: {},
higscoreLeaderboard: [],
totalPlaytimeLeaderboard: [],
userId: 1,
}
},
methods: {
async fetchFromApi(path: string, method: "GET" | "POST") {
let res: Response = await fetch("http://localhost:3000" + path, {method: method,});
return await res.json();
},
async fetchUserScores() {
return await this.fetchFromApi(`/user/${this.userId}/scores`, "GET");
},
async fetchLeaderboard(type: "highscore" | "totalplaytime") {
return await this.fetchFromApi(`/leaderboard/${type}`, "GET");
},
},
async created() {
this.userScores = await this.fetchUserScores();
this.higscoreLeaderboard = await this.fetchLeaderboard("highscore")
this.totalPlaytimeLeaderboard = await this.fetchLeaderboard("totalplaytime")
}
});
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
* {
font-family: 'Press Start 2P', serif;
}
.row {
margin-top:2em;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View file

View file

@ -0,0 +1,11 @@
<template>
<div class="wrapper">
<main></main>
</div>
</template>
<script lang="ts">
export default {
name: "Game"
}
</script>

View file

@ -0,0 +1,18 @@
<template>
<h1>Raspberry Rocketeer</h1>
</template>
<script lang="ts">
export default {
name: "Header",
}
</script>
<style scoped>
h1 {
text-align: center;
font-size: 5em;
}
</style>

View file

@ -0,0 +1,25 @@
<template>
<h3>{{ title }}</h3>
<div class="container">
<div class="row" v-for="entry in data" :key="entry.rank" >
<div class="col-1 text-left">{{entry.rank}}</div>
<div class="offset-1 col text-left">{{entry.username}}</div>
<div class="col text-left">{{entry.score}}</div>
</div>
</div>
</template>
<script>
export default {
name: "Leaderboard",
props: {
title: {
type: String
},
data: {
type: Array
}
}
}
</script>

View file

@ -0,0 +1,34 @@
<template>
<div class="container">
<div class="row">
<div class="col text-center" >Highscore</div>
<div class="col text-center" >Total Score</div>
<div class="col text-center" >Total Playtime</div>
<div class="col text-center" >Average Score</div>
<div class="col text-center" >Games Played</div>
</div>
<div class="row">
<div class="col text-center" >{{ this.userScores.highscore }}</div>
<div class="col text-center" >{{ this.userScores.totalScore }}</div>
<div class="col text-center" >{{ this.userScores.totalPlaytime }}</div>
<div class="col text-center" >{{ this.userScores.averageScore }}</div>
<div class="col text-center" >{{ this.userScores.gamesPlayed }}</div>
</div>
</div>
</template>
<script>
export default {
props: {
userScores: {
type: Object
}
},
}
</script>
<style scoped>
* {
font-size: 1.2em;
}
</style>

4
frontend/src/main.ts Normal file
View file

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

View file

@ -0,0 +1,7 @@
export interface Game {
id?: number,
score: number,
playtime: string,
date: Date,
userId: number,
}

View file

@ -0,0 +1,10 @@
export type Leaderboard<T> = LeaderboardEntry<T>[];
export type HighscoreLeaderboard = Leaderboard<number>;
export type TimeLeaderboard = Leaderboard<string>;
export interface LeaderboardEntry<T> {
username: number,
rank: number,
score: T,
}

View file

@ -0,0 +1,6 @@
export interface Time {
seconds: number,
minutes?: number,
hours?: number,
days?: number,
}

View file

@ -0,0 +1,4 @@
export interface User {
id?: number,
name: string,
}

View file

@ -0,0 +1,10 @@
import {Time} from "./Time.js";
export interface UserScores {
userId: number,
highscore: number,
totalScore: number,
totalPlaytime: Time,
averageScore: number,
gamesPlayed: number,
}

6
frontend/src/shims-vue.d.ts vendored Normal file
View file

@ -0,0 +1,6 @@
/* eslint-disable */
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

View file

@ -1,17 +1,41 @@
{ {
"compilerOptions": { "compilerOptions": {
"noImplicitAny": true,
"outFile": "./build/build.js",
"preserveConstEnums": true,
"removeComments": true,
"rootDir": ".",
"sourceMap": true,
"target": "es5", "target": "es5",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node", "moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*",
]
},
"lib": [ "lib": [
"esnext",
"dom", "dom",
"es5", "dom.iterable",
"scripthost" "scripthost"
] ]
} },
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
} }