Player name, pwa & branding
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<Game v-if="isSocketConnected"/>
|
||||
<div v-else>
|
||||
<h1>Game loadin mate</h1>
|
||||
<Game v-if="isLoggedIn"/>
|
||||
<div v-else class="container mainMenu">
|
||||
<img src="./assets/logo.png" alt="TronIo logo" width="150px"/>
|
||||
<h1 class="title">Tron.io</h1>
|
||||
<b-button @click="loginPrompt">Start</b-button>
|
||||
</div>
|
||||
<b-loading v-model="isLoading"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { send } from './store/socketPlugin'
|
||||
import Game from './components/Game'
|
||||
export default {
|
||||
name: 'App',
|
||||
@@ -17,6 +21,37 @@ export default {
|
||||
computed: {
|
||||
isSocketConnected () {
|
||||
return this.$store.state.game.socketConnected
|
||||
},
|
||||
isLoading () {
|
||||
return !this.isSocketConnected
|
||||
},
|
||||
isLoggedIn () {
|
||||
return this.$store.state.game.loggedIn
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loginPrompt () {
|
||||
this.$buefy.dialog.prompt({
|
||||
message: 'Choose a name',
|
||||
trapFocus: true,
|
||||
canCancel: false,
|
||||
inputAttrs: {
|
||||
placeholder: 'pedro',
|
||||
minlength: 3,
|
||||
maxlength: 30
|
||||
},
|
||||
confirmText: 'KK',
|
||||
onConfirm: (name) => {
|
||||
localStorage.setItem('name', name)
|
||||
this.login(name)
|
||||
}
|
||||
})
|
||||
},
|
||||
login (name) {
|
||||
send({
|
||||
type: 'login',
|
||||
message: name
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +63,9 @@ export default {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
background-color: #475b6e;
|
||||
}
|
||||
|
||||
.mainMenu {
|
||||
top: 30vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
BIN
client/src/assets/Gravity-Regular.otf
Normal file
BIN
client/src/assets/Gravity-Regular.otf
Normal file
Binary file not shown.
289
client/src/assets/_overrides.scss
Normal file
289
client/src/assets/_overrides.scss
Normal file
@@ -0,0 +1,289 @@
|
||||
// Overrides
|
||||
@import url("https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=swap");
|
||||
|
||||
@font-face {
|
||||
font-family: 'Gravity Regular';
|
||||
src: url('Gravity-Regular.otf') format('opentype');
|
||||
}
|
||||
|
||||
hr {
|
||||
height: $border-width;
|
||||
}
|
||||
|
||||
h6 {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.hero {
|
||||
background-color: $grey-dark;
|
||||
}
|
||||
|
||||
a {
|
||||
transition: all 200ms ease;
|
||||
}
|
||||
|
||||
.button {
|
||||
transition: all 200ms ease;
|
||||
border-width: $border-width;
|
||||
color: $white;
|
||||
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2px rgba($button-focus-border-color, 0.5);
|
||||
}
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
&.is-hovered,
|
||||
&:hover {
|
||||
background-color: lighten($color, 7.5%);
|
||||
}
|
||||
|
||||
&.is-active,
|
||||
&.is-focused,
|
||||
&:active,
|
||||
&:focus {
|
||||
border-color: $color;
|
||||
box-shadow: 0 0 0 2px rgba($color, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
color: $grey-lighter;
|
||||
}
|
||||
|
||||
.input,
|
||||
.textarea {
|
||||
transition: all 200ms ease;
|
||||
box-shadow: none;
|
||||
border-width: $border-width;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.select {
|
||||
&:after,
|
||||
select {
|
||||
border-width: $border-width;
|
||||
}
|
||||
}
|
||||
|
||||
.control {
|
||||
&.has-addons {
|
||||
.button,
|
||||
.input,
|
||||
.select {
|
||||
margin-right: -$border-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
background-color: $grey-dark;
|
||||
}
|
||||
|
||||
.card {
|
||||
$card-border-color: lighten($grey-darker, 5);
|
||||
box-shadow: none;
|
||||
border: $border-width solid $card-border-color;
|
||||
background-color: $grey-darker;
|
||||
border-radius: $radius;
|
||||
|
||||
.card-image {
|
||||
img {
|
||||
border-radius: $radius $radius 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
box-shadow: none;
|
||||
background-color: rgba($black-bis, 0.2);
|
||||
border-radius: $radius $radius 0 0;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
background-color: rgba($black-bis, 0.2);
|
||||
}
|
||||
|
||||
.card-footer,
|
||||
.card-footer-item {
|
||||
border-width: $border-width;
|
||||
border-color: $card-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
a:not(.button) {
|
||||
color: $color-invert;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
border-radius: $radius;
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
a {
|
||||
transition: all 300ms ease;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-card-body {
|
||||
background-color: $grey-darker;
|
||||
}
|
||||
|
||||
.modal-card-foot,
|
||||
.modal-card-head {
|
||||
border-color: $grey-dark;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
font-weight: $weight-bold;
|
||||
background-color: $grey-dark;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.message-body {
|
||||
border-width: $border-width;
|
||||
border-color: $grey-dark;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-radius: $radius;
|
||||
|
||||
&.is-transparent {
|
||||
background: none;
|
||||
}
|
||||
|
||||
&.is-primary {
|
||||
.navbar-dropdown {
|
||||
a.navbar-item.is-active {
|
||||
background-color: $link;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include touch {
|
||||
.navbar-menu {
|
||||
background-color: $navbar-background-color;
|
||||
border-radius: 0 0 $radius $radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hero .navbar,
|
||||
body > .navbar {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.pagination-link,
|
||||
.pagination-next,
|
||||
.pagination-previous {
|
||||
border-width: $border-width;
|
||||
}
|
||||
|
||||
.panel-block,
|
||||
.panel-heading,
|
||||
.panel-tabs {
|
||||
border-width: $border-width;
|
||||
|
||||
&:first-child {
|
||||
border-top-width: $border-width;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
font-weight: $weight-bold;
|
||||
}
|
||||
|
||||
.panel-tabs {
|
||||
a {
|
||||
border-width: $border-width;
|
||||
margin-bottom: -$border-width;
|
||||
|
||||
&.is-active {
|
||||
border-bottom-color: $link-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel-block {
|
||||
&:hover {
|
||||
color: $link-hover;
|
||||
|
||||
.panel-icon {
|
||||
color: $link-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
.panel-icon {
|
||||
color: $link-active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
a {
|
||||
border-bottom-width: $border-width;
|
||||
margin-bottom: -$border-width;
|
||||
}
|
||||
|
||||
ul {
|
||||
border-bottom-width: $border-width;
|
||||
}
|
||||
|
||||
&.is-boxed {
|
||||
a {
|
||||
border-width: $border-width;
|
||||
}
|
||||
|
||||
li.is-active a {
|
||||
background-color: darken($grey-darker, 4);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-toggle {
|
||||
li a {
|
||||
border-width: $border-width;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
li + li {
|
||||
margin-left: -$border-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hero {
|
||||
// Colors
|
||||
@each $name, $pair in $colors {
|
||||
$color: nth($pair, 1);
|
||||
$color-invert: nth($pair, 2);
|
||||
|
||||
&.is-#{$name} {
|
||||
.navbar {
|
||||
.navbar-dropdown {
|
||||
.navbar-item:hover {
|
||||
background-color: $navbar-dropdown-item-hover-background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
114
client/src/assets/_variables.scss
Normal file
114
client/src/assets/_variables.scss
Normal file
@@ -0,0 +1,114 @@
|
||||
$grey-lighter: #dbdee0;
|
||||
$grey-light: #8c9b9d;
|
||||
$grey: darken($grey-light, 18);
|
||||
$grey-dark: darken($grey, 18);
|
||||
$grey-darker: darken($grey, 23);
|
||||
|
||||
$orange: #e67e22;
|
||||
$yellow: #f1b70e;
|
||||
$green: #2ecc71;
|
||||
$turquoise: #26a8a2;
|
||||
$blue: #3498db;
|
||||
$purple: #8e44ad;
|
||||
$red: #e74c3c;
|
||||
$white-ter: #ecf0f1;
|
||||
$primary: $turquoise;
|
||||
$yellow-invert: #fff;
|
||||
|
||||
$family-sans-serif: "Gravity Regular", "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
"Helvetica Neue", "Helvetica", "Arial", sans-serif;
|
||||
$family-monospace: "Inconsolata", "Consolas", "Monaco", monospace;
|
||||
|
||||
$radius-small: 3px;
|
||||
$radius: 0.4em;
|
||||
$radius-large: 8px;
|
||||
$size-6: 15px;
|
||||
$size-7: 0.85em;
|
||||
$title-weight: 500;
|
||||
$subtitle-weight: 400;
|
||||
$subtitle-color: $grey-dark;
|
||||
|
||||
$border-width: 2px;
|
||||
$border: $grey;
|
||||
|
||||
$body-background-color: darken($grey-darker, 4);
|
||||
$body-size: 15px;
|
||||
|
||||
$background: $grey-darker;
|
||||
$footer-background-color: $background;
|
||||
$button-background-color: $background;
|
||||
$button-border-color: lighten($button-background-color, 15);
|
||||
|
||||
$title-color: #fff;
|
||||
$subtitle-color: $grey-light;
|
||||
$subtitle-strong-color: $grey-light;
|
||||
|
||||
$text: #fff;
|
||||
$text-light: lighten($text, 10);
|
||||
$text-strong: darken($text, 5);
|
||||
|
||||
$box-color: $text;
|
||||
$box-background-color: $grey-dark;
|
||||
$box-shadow: none;
|
||||
|
||||
$link: $turquoise;
|
||||
$link-hover: lighten($link, 5);
|
||||
$link-focus: darken($link, 5);
|
||||
$link-active: darken($link, 5);
|
||||
$link-focus-border: $grey-light;
|
||||
|
||||
$button-color: $primary;
|
||||
$button-hover-color: darken($text, 5); // text-dark
|
||||
$button-focus: darken($text, 5); // text-dark
|
||||
$button-active-color: darken($text, 5); // text-dark
|
||||
$button-disabled-background-color: $grey-light;
|
||||
|
||||
$control-height: 2.5em;
|
||||
|
||||
$input-color: $grey-darker;
|
||||
$input-icon-color: $grey;
|
||||
$input-icon-active-color: $input-color;
|
||||
$input-hover-color: $grey-light;
|
||||
$input-disabled-background-color: $grey-light;
|
||||
$input-disabled-border: $grey-lighter;
|
||||
|
||||
$table-color: $text;
|
||||
$table-head: $grey-lighter;
|
||||
$table-background-color: $grey-dark;
|
||||
$table-cell-border: 1px solid $grey;
|
||||
|
||||
$table-row-hover-background-color: $grey-darker;
|
||||
$table-striped-row-even-background-color: $grey-darker;
|
||||
$table-striped-row-even-hover-background-color: lighten($grey-darker, 2);
|
||||
|
||||
$pagination-color: $link;
|
||||
$pagination-border-color: $border;
|
||||
|
||||
$navbar-height: 4rem;
|
||||
|
||||
$navbar-background-color: $primary;
|
||||
$navbar-item-color: $text;
|
||||
$navbar-item-hover-color: $link;
|
||||
$navbar-item-hover-background-color: transparent;
|
||||
$navbar-item-active-color: $link;
|
||||
$navbar-dropdown-arrow: #fff;
|
||||
$navbar-divider-background-color: rgba(0, 0, 0, 0.2);
|
||||
$navbar-dropdown-border-top: 1px solid $navbar-divider-background-color;
|
||||
$navbar-dropdown-background-color: $primary;
|
||||
$navbar-dropdown-item-hover-color: $grey-lighter;
|
||||
$navbar-dropdown-item-hover-background-color: transparent;
|
||||
$navbar-dropdown-item-active-background-color: transparent;
|
||||
$navbar-dropdown-item-active-color: $link;
|
||||
|
||||
$dropdown-content-background-color: $background;
|
||||
$dropdown-item-color: $text;
|
||||
|
||||
$progress-value-background-color: $grey-lighter;
|
||||
|
||||
$file-cta-background-color: $grey-darker;
|
||||
|
||||
$progress-bar-background-color: $grey-dark;
|
||||
|
||||
$panel-heading-background-color: $grey-dark;
|
||||
|
||||
$control-label: $grey-lighter;
|
||||
BIN
client/src/assets/logo.png
Normal file
BIN
client/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
4
client/src/assets/style.scss
Normal file
4
client/src/assets/style.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
@import "variables";
|
||||
@import "~bulma";
|
||||
@import "~buefy/src/scss/buefy";
|
||||
@import "overrides";
|
||||
@@ -21,7 +21,12 @@ export default {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
leaderboard: [],
|
||||
stats: {
|
||||
leaderboard: [],
|
||||
totalWalls: 0,
|
||||
lastUpdateTime: 0,
|
||||
lastFrame: 0
|
||||
},
|
||||
renderTimer: null
|
||||
}
|
||||
},
|
||||
@@ -67,31 +72,36 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
render () {
|
||||
this.stats.lastFrame = performance.now()
|
||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
||||
this.renderBorders()
|
||||
|
||||
if (!this.players) return
|
||||
|
||||
this.players.sort((a, b) => {
|
||||
return a.walls.length - b.walls.length
|
||||
return b.walls.length - a.walls.length
|
||||
})
|
||||
this.leaderboard = []
|
||||
this.stats.leaderboard = []
|
||||
this.stats.totalWalls = 0
|
||||
|
||||
this.players.forEach(player => {
|
||||
if (player.color === this.player.color) {
|
||||
this.camera.x = player.x
|
||||
this.camera.y = player.y
|
||||
this.renderDebug(player)
|
||||
}
|
||||
this.renderPlayer(player)
|
||||
this.renderWalls(player)
|
||||
this.leaderboard.push(player.id + ' - ' + player.walls.length)
|
||||
this.stats.leaderboard.push(player.name + ' - ' + player.walls.length)
|
||||
this.stats.totalWalls += player.walls.length
|
||||
})
|
||||
|
||||
this.renderLeaderboard()
|
||||
this.renderMouse()
|
||||
|
||||
this.renderDebug()
|
||||
},
|
||||
renderBorders () {
|
||||
this.context.strokeStyle = 'black'
|
||||
this.context.strokeStyle = 'white'
|
||||
this.context.lineWidth = 1
|
||||
this.context.strokeRect(this.canvas.width / 2 - this.camera.x, this.canvas.height / 2 - this.camera.y, this.settings.arenaSize, this.settings.arenaSize)
|
||||
},
|
||||
@@ -121,27 +131,33 @@ export default {
|
||||
this.context.lineTo(this.canvas.width / 2 + player.x - this.camera.x, this.canvas.height / 2 + player.y - this.camera.y)
|
||||
this.context.stroke()
|
||||
},
|
||||
renderDebug (player) {
|
||||
renderDebug () {
|
||||
const canvasX = this.canvas.width / 2
|
||||
const canvasY = this.canvas.height / 2
|
||||
|
||||
this.context.fillStyle = 'white'
|
||||
this.context.textAlign = 'start'
|
||||
this.context.fillText('player x: ' + player.x + ' y:' + player.y, 10, 12)
|
||||
this.context.fillText('a:' + player.angle + ' a_t' + player.targetAngle, 10, 24)
|
||||
this.context.fillText('camera x: ' + this.camera.x + ' y:' + this.camera.y, 10, 12)
|
||||
// this.context.fillText('a:' + player.angle + ' a_t' + player.targetAngle, 10, 24)
|
||||
this.context.fillText('canvasX: ' + canvasX + ' canvasY:' + canvasY, 10, 36)
|
||||
this.context.fillText('walls: ' + player.walls.length, 10, 48)
|
||||
|
||||
this.context.fillText('Total walls: ' + this.stats.totalWalls, 10, 48)
|
||||
this.context.fillText('Last update: ' + this.stats.lastUpdateTime, 10, 60)
|
||||
const fps = (performance.now() - this.stats.lastFrame) * 60
|
||||
this.context.fillText('FPS: ' + fps, 10, 72)
|
||||
},
|
||||
renderMouse () {
|
||||
this.context.beginPath()
|
||||
this.context.arc(this.mouse.x, this.mouse.y, 25, 0, 2 * Math.PI, false)
|
||||
this.context.lineWidth = 1
|
||||
this.context.strokeStyle = player.color
|
||||
this.context.strokeStyle = this.player.color
|
||||
this.context.stroke()
|
||||
},
|
||||
renderLeaderboard () {
|
||||
this.context.fillStyle = 'white'
|
||||
this.context.textAlign = 'end'
|
||||
this.context.fillText('Leaderboard: ', this.canvas.width - 50, 10)
|
||||
for (var i = 0; i < this.leaderboard.length; i++) {
|
||||
this.context.fillText(this.players[i].color + ' - ' + this.players[i].walls.length, this.canvas.width - 50, 15 + (i + 1) * 10)
|
||||
for (var i = 0; i < this.stats.leaderboard.length; i++) {
|
||||
this.context.fillText(this.players[i].name + ' - ' + this.players[i].walls.length, this.canvas.width - 50, 15 + (i + 1) * 10)
|
||||
}
|
||||
},
|
||||
mouseEvent (event) {
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import store from './store'
|
||||
import Buefy from 'buefy'
|
||||
import './registerServiceWorker'
|
||||
|
||||
// import 'buefy/dist/buefy.css'
|
||||
import './assets/style.scss'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.use(Buefy)
|
||||
|
||||
new Vue({
|
||||
store,
|
||||
|
||||
@@ -16,7 +16,8 @@ const state = {
|
||||
arenaSize: 1000
|
||||
},
|
||||
paused: true,
|
||||
socketConnected: false
|
||||
socketConnected: false,
|
||||
loggedIn: false
|
||||
}
|
||||
|
||||
const getters = {
|
||||
@@ -37,6 +38,7 @@ const actions = {
|
||||
},
|
||||
login ({ commit }, player) {
|
||||
commit('SET_PLAYER', player)
|
||||
commit('SET_LOGIN', true)
|
||||
},
|
||||
settings ({ commit }, settings) {
|
||||
commit('SET_SETTINGS', settings)
|
||||
@@ -57,6 +59,9 @@ const mutations = {
|
||||
SET_PLAYER (state, player) {
|
||||
state.player = player
|
||||
},
|
||||
SET_LOGIN (state, login) {
|
||||
state.loggedIn = login
|
||||
},
|
||||
SET_PLAYERS (state, players) {
|
||||
state.players = players
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ToastProgrammatic as Toast } from 'buefy'
|
||||
|
||||
const connection = new WebSocket('ws://localhost:8181/socket')
|
||||
// const connection = new WebSocket('wss://tronio.gltronic.ovh/socket')
|
||||
|
||||
@@ -14,7 +16,11 @@ export default function createSocketPlugin () {
|
||||
|
||||
connection.onerror = function (error) {
|
||||
console.log('[WS] error ' + error.message)
|
||||
store.dispatch('game/error', 'Connection problem')
|
||||
// store.dispatch('game/error', 'Connection problem')
|
||||
Toast.open('Connection problem. Retrying in 10s...')
|
||||
setTimeout(function () {
|
||||
location.reload()
|
||||
}, 10000)
|
||||
}
|
||||
|
||||
connection.onmessage = function (message) {
|
||||
|
||||
Reference in New Issue
Block a user