Animated sprite support, server bug fixes
This commit is contained in:
21567
client/package-lock.json
generated
21567
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
BIN
client/src/assets/sprite/explosion.png
Normal file
BIN
client/src/assets/sprite/explosion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
@@ -18,6 +18,7 @@
|
||||
import { send } from '@/store/socketPlugin'
|
||||
import { render } from '@/game/render.js'
|
||||
import { sound } from '@/game/sound.js'
|
||||
import { Explosion } from '@/game/sprites.js'
|
||||
|
||||
export default {
|
||||
name: 'Game',
|
||||
@@ -34,8 +35,10 @@ export default {
|
||||
stats: {
|
||||
totalWalls: 0,
|
||||
lastUpdateTime: {},
|
||||
lastFrame: 0
|
||||
lastFrame: 0,
|
||||
lastSpriteFrame: 0
|
||||
},
|
||||
deadPlayers: [],
|
||||
renderTimer: null
|
||||
}
|
||||
},
|
||||
@@ -52,6 +55,9 @@ export default {
|
||||
player () {
|
||||
return this.$store.state.game.player
|
||||
},
|
||||
sprites () {
|
||||
return this.$store.state.game.sprites
|
||||
},
|
||||
players () {
|
||||
const pastUpdate = this.$store.state.game.updates[0]
|
||||
const nextUpdate = this.$store.state.game.updates[1]
|
||||
@@ -69,7 +75,6 @@ export default {
|
||||
return this.$store.state.game.leaderboard
|
||||
},
|
||||
playerIsDead () {
|
||||
if (this.player.state === 'DEAD') sound.explosion()
|
||||
return this.player.state === 'DEAD'
|
||||
}
|
||||
},
|
||||
@@ -78,7 +83,8 @@ export default {
|
||||
this.canvas.addEventListener('mousemove', this.mouseEvent)
|
||||
this.canvas.addEventListener('touchmove', this.touchEvent)
|
||||
this.canvas.addEventListener('resize', this.setCanvasSize)
|
||||
// this.renderTimer = setInterval(this.render, 1000 / 120)
|
||||
// this.renderTimer = setInterval(this.render, 1000 / 60)
|
||||
// this.renderTimer = setInterval(this.renderSprites, 1000 / 30)
|
||||
this.render()
|
||||
},
|
||||
methods: {
|
||||
@@ -108,19 +114,59 @@ export default {
|
||||
if (player.state === 'DEAD') this.context.globalAlpha = 1
|
||||
|
||||
this.stats.totalWalls += player.walls.length
|
||||
|
||||
// Check if player was dead before for one time event
|
||||
if (player.state === 'DEAD' && !this.deadPlayers.includes(player.id)) {
|
||||
this.deadPlayers.push(player.id)
|
||||
sound.explosion()
|
||||
this.sprites.push(new Explosion(player.x, player.y))
|
||||
}
|
||||
|
||||
// Remove player from dead list
|
||||
if (player.state !== 'DEAD' && this.deadPlayers.includes(player.id)) {
|
||||
const i = this.deadPlayers.indexOf(player.id)
|
||||
this.deadPlayers.splice(i, 1)
|
||||
}
|
||||
})
|
||||
|
||||
render.leaderboard(this.context, this.canvas, this.leaderboard)
|
||||
this.renderSprites()
|
||||
|
||||
render.mouse(this.context, this.mouse, this.player)
|
||||
render.leaderboard(this.context, this.canvas, this.leaderboard)
|
||||
render.debug(this.context, this.camera, this.mouse, this.canvas, this.stats)
|
||||
|
||||
this.stats.lastFrame = performance.now()
|
||||
|
||||
const nextUpdate = this.$store.state.game.updates[1]
|
||||
if (nextUpdate !== undefined) this.stats.lastUpdateTime = nextUpdate.time
|
||||
|
||||
requestAnimationFrame(this.render, this.canvas)
|
||||
},
|
||||
renderSprites () {
|
||||
let nextFrame = false
|
||||
// Check if needed to show next frame for animations
|
||||
if ((performance.now() - this.stats.lastSpriteFrame) > 50) {
|
||||
nextFrame = true
|
||||
this.stats.lastSpriteFrame = performance.now()
|
||||
}
|
||||
|
||||
this.sprites.forEach((sprite, index, object) => {
|
||||
render.sprite(this.context, this.canvas, this.camera, sprite)
|
||||
if (nextFrame) {
|
||||
if (sprite.framesCounter === sprite.frames) {
|
||||
if (sprite.removeAfterAnimation) {
|
||||
object.splice(index, 1)
|
||||
console.log('SPRITE ', index, 'REMOVE')
|
||||
} else {
|
||||
// console.log('SPRITE ', index, 'frame reset')
|
||||
sprite.framesCounter = 0
|
||||
}
|
||||
} else {
|
||||
// console.log('SPRITE ', index, 'frame++', sprite.framesCounter)
|
||||
sprite.framesCounter++
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
mouseEvent (event) {
|
||||
var rect = this.canvas.getBoundingClientRect()
|
||||
this.mouse.x = event.clientX - rect.left
|
||||
@@ -171,7 +217,8 @@ export default {
|
||||
send({ type: 'respawn' })
|
||||
},
|
||||
quit () {
|
||||
|
||||
send({ type: 'logout' })
|
||||
this.$store.dispatch('game/logout')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export const render = {
|
||||
context.beginPath()
|
||||
context.lineWidth = settings.wallSize
|
||||
context.strokeStyle = player.color
|
||||
// context.shadowBlur = 0
|
||||
// context.shadowBlur = 0.5
|
||||
// context.shadowColor = player.color
|
||||
player.walls.forEach(wall => {
|
||||
const canvasX = canvas.width / 2 + wall.x - camera.x
|
||||
@@ -129,5 +129,22 @@ export const render = {
|
||||
context.fillText(player.name + ' - ' + player.score + ' (' + player.bestScore + ')', canvas.width - 50, 15 + i * 10)
|
||||
i++
|
||||
})
|
||||
},
|
||||
sprite (context, canvas, camera, sprite) {
|
||||
const canvasX = canvas.width / 2 + sprite.x - camera.x
|
||||
const canvasY = canvas.height / 2 + sprite.y - camera.y
|
||||
|
||||
const posX = canvasX - sprite.sizeX * 2
|
||||
const posY = canvasY - sprite.sizeY * 2
|
||||
const sizeL = sprite.sizeX * 4
|
||||
const sizeH = sprite.sizeY * 4
|
||||
|
||||
if (sprite.isAnimated) {
|
||||
const frameX = sprite.heightX * (sprite.framesCounter % 8)
|
||||
const frameY = sprite.heightY * Math.floor(sprite.framesCounter / 8)
|
||||
context.drawImage(sprite.image, frameX, frameY, sprite.heightX, sprite.heightY, posX, posY, sizeL, sizeH)
|
||||
} else {
|
||||
context.drawImage(sprite.image, posX, posY, sizeL, sizeH)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
client/src/game/sprites.js
Normal file
41
client/src/game/sprites.js
Normal file
@@ -0,0 +1,41 @@
|
||||
export class Player {
|
||||
|
||||
}
|
||||
|
||||
export class Sprite {
|
||||
x = 0;
|
||||
y = 0;
|
||||
sizeX = 0;
|
||||
sizeY = 0;
|
||||
heightX = 0;
|
||||
heightY = 0;
|
||||
image = new Image();
|
||||
isAnimated = false;
|
||||
removeAfterAnimation = false;
|
||||
frames = 0;
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
export class Wall {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
export class Explosion extends Sprite {
|
||||
constructor (x, y) {
|
||||
super()
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.sizeX = 50
|
||||
this.sizeY = 50
|
||||
this.heightX = 256
|
||||
this.heightY = 256
|
||||
this.image = new Image()
|
||||
this.isAnimated = true
|
||||
this.removeAfterAnimation = true
|
||||
this.frames = 32
|
||||
this.framesCounter = 0
|
||||
|
||||
this.image.src = require('@/assets/sprite/explosion.png')
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ const state = {
|
||||
color: 'red',
|
||||
state: 'DEAD'
|
||||
},
|
||||
sprites: [],
|
||||
leaderboard: [],
|
||||
updates: [],
|
||||
firstUpdateTime: null,
|
||||
@@ -36,6 +37,10 @@ const actions = {
|
||||
commit('SET_PLAYER', player)
|
||||
commit('SET_LOGIN', true)
|
||||
},
|
||||
logout ({ commit }) {
|
||||
commit('SET_LOGIN', false)
|
||||
commit('CLEAR_UPDATE')
|
||||
},
|
||||
settings ({ commit }, settings) {
|
||||
commit('SET_SETTINGS', settings)
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ToastProgrammatic as Toast } from 'buefy'
|
||||
|
||||
const connection = new WebSocket('wss://tronio.gltronic.ovh/socket')
|
||||
// const connection = new WebSocket('ws://localhost:3000/socket')
|
||||
// const connection = new WebSocket('wss://tronio.gltronic.ovh/socket')
|
||||
const connection = new WebSocket('ws://localhost:3000/socket')
|
||||
|
||||
export default function createSocketPlugin () {
|
||||
return store => {
|
||||
|
||||
Reference in New Issue
Block a user