some more moving code around
This commit is contained in:
parent
d4ddf91259
commit
73872ebb6f
3 changed files with 564 additions and 535 deletions
49
game/Communication.js
Normal file
49
game/Communication.js
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import WsClient from './WsClient.js'
|
||||||
|
|
||||||
|
let conn
|
||||||
|
let changesCallback = () => {}
|
||||||
|
|
||||||
|
function onChanges(callback) {
|
||||||
|
changesCallback = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect(gameId, playerId) {
|
||||||
|
conn = new WsClient(WS_ADDRESS, playerId + '|' + gameId)
|
||||||
|
return new Promise(r => {
|
||||||
|
conn.connect()
|
||||||
|
conn.send(JSON.stringify({ type: 'init' }))
|
||||||
|
conn.onSocket('message', async ({ data }) => {
|
||||||
|
const d = JSON.parse(data)
|
||||||
|
if (d.type === 'init') {
|
||||||
|
r(d.game)
|
||||||
|
} else if (d.type === 'state_changed' && d.origin !== playerId) {
|
||||||
|
changesCallback(d.changes)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const _STATE = {
|
||||||
|
changed: false,
|
||||||
|
changes: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
function addChange(change) {
|
||||||
|
_STATE.changes.push(change)
|
||||||
|
_STATE.changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendChanges() {
|
||||||
|
if (_STATE.changed) {
|
||||||
|
conn.send(JSON.stringify({ type: 'state', state: _STATE }))
|
||||||
|
_STATE.changes = []
|
||||||
|
_STATE.changed = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
connect,
|
||||||
|
onChanges,
|
||||||
|
addChange,
|
||||||
|
sendChanges,
|
||||||
|
}
|
||||||
21
game/Debug.js
Normal file
21
game/Debug.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
let _pt = 0
|
||||||
|
let _mindiff = 0
|
||||||
|
|
||||||
|
const checkpoint_start = (mindiff) => {
|
||||||
|
_pt = performance.now()
|
||||||
|
_mindiff = mindiff
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkpoint = (label) => {
|
||||||
|
const now = performance.now();
|
||||||
|
const diff = now - _pt
|
||||||
|
if (diff > _mindiff) {
|
||||||
|
console.log(label + ': ' + (diff));
|
||||||
|
}
|
||||||
|
_pt = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
checkpoint_start,
|
||||||
|
checkpoint,
|
||||||
|
}
|
||||||
177
game/index.js
177
game/index.js
|
|
@ -7,9 +7,13 @@ import Camera from './Camera.js'
|
||||||
import EventAdapter from './EventAdapter.js'
|
import EventAdapter from './EventAdapter.js'
|
||||||
import WsClient from './WsClient.js'
|
import WsClient from './WsClient.js'
|
||||||
import Graphics from './Graphics.js'
|
import Graphics from './Graphics.js'
|
||||||
|
import Debug from './Debug.js'
|
||||||
|
import Communication from './Communication.js'
|
||||||
|
|
||||||
if (!GAME_ID) throw '[ GAME_ID not set ]'
|
if (typeof GAME_ID === 'undefined') throw '[ GAME_ID not set ]'
|
||||||
if (!WS_ADDRESS) throw '[ WS_ADDRESS not set ]'
|
if (typeof WS_ADDRESS === 'undefined') throw '[ WS_ADDRESS not set ]'
|
||||||
|
|
||||||
|
if (typeof DEBUG === 'undefined') window.DEBUG = false
|
||||||
|
|
||||||
function addCanvasToDom(canvas) {
|
function addCanvasToDom(canvas) {
|
||||||
document.body.append(canvas)
|
document.body.append(canvas)
|
||||||
|
|
@ -178,6 +182,33 @@ const unfinishedTileByPos = (puzzle, pos) => {
|
||||||
return tileIdx
|
return tileIdx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DirtyRect {
|
||||||
|
constructor() {
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
get () {
|
||||||
|
return this.x0 === null ? null : [
|
||||||
|
{x0: this.x0, x1: this.x1, y0: this.y0, y1: this.y1}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
add (pos, offset) {
|
||||||
|
const x0 = pos.x - offset
|
||||||
|
const x1 = pos.x + offset
|
||||||
|
const y0 = pos.y - offset
|
||||||
|
const y1 = pos.y + offset
|
||||||
|
this.x0 = this.x0 === null ? x0 : Math.min(this.x0, x0)
|
||||||
|
this.x1 = this.x1 === null ? x1 : Math.max(this.x1, x1)
|
||||||
|
this.y0 = this.y0 === null ? y0 : Math.min(this.y0, y0)
|
||||||
|
this.y1 = this.y1 === null ? y1 : Math.max(this.y1, y1)
|
||||||
|
}
|
||||||
|
reset () {
|
||||||
|
this.x0 = null
|
||||||
|
this.x1 = null
|
||||||
|
this.y0 = null
|
||||||
|
this.y1 = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadPuzzleBitmaps(puzzle) {
|
async function loadPuzzleBitmaps(puzzle) {
|
||||||
// load bitmap, to determine the original size of the image
|
// load bitmap, to determine the original size of the image
|
||||||
const bmp = await Graphics.loadImageToBitmap(puzzle.info.imageUrl)
|
const bmp = await Graphics.loadImageToBitmap(puzzle.info.imageUrl)
|
||||||
|
|
@ -203,12 +234,6 @@ function initme() {
|
||||||
return ID
|
return ID
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupNetwork(me) {
|
|
||||||
const wsc = new WsClient(WS_ADDRESS, me)
|
|
||||||
wsc.connect()
|
|
||||||
return wsc
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main () {
|
async function main () {
|
||||||
let gameId = GAME_ID
|
let gameId = GAME_ID
|
||||||
let me = initme()
|
let me = initme()
|
||||||
|
|
@ -216,58 +241,16 @@ async function main () {
|
||||||
let cursorGrab = await Graphics.loadImageToBitmap('/grab.png')
|
let cursorGrab = await Graphics.loadImageToBitmap('/grab.png')
|
||||||
let cursorHand = await Graphics.loadImageToBitmap('/hand.png')
|
let cursorHand = await Graphics.loadImageToBitmap('/hand.png')
|
||||||
|
|
||||||
let conn = setupNetwork(me + '|' + gameId)
|
const game = await Communication.connect(gameId, me)
|
||||||
conn.send(JSON.stringify({ type: 'init' }))
|
|
||||||
conn.onSocket('message', async ({data}) => {
|
|
||||||
const d = JSON.parse(data)
|
|
||||||
if (d.type === 'init') {
|
|
||||||
console.log('the game ', d.game)
|
|
||||||
let bitmaps = await loadPuzzleBitmaps(d.game.puzzle)
|
|
||||||
startGame(d.game, bitmaps, conn)
|
|
||||||
} else {
|
|
||||||
// console.log(d)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const _STATE = {
|
const bitmaps = await loadPuzzleBitmaps(game.puzzle)
|
||||||
changes: [],
|
const puzzle = game.puzzle
|
||||||
}
|
const players = game.players
|
||||||
let _STATE_CHANGED = false
|
|
||||||
|
|
||||||
class renderRect {
|
|
||||||
constructor() {
|
|
||||||
this.reset()
|
|
||||||
}
|
|
||||||
get () {
|
|
||||||
return this.x0 === null ? null : [
|
|
||||||
{x0: this.x0, x1: this.x1, y0: this.y0, y1: this.y1}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
add (pos, offset) {
|
|
||||||
const x0 = pos.x - offset
|
|
||||||
const x1 = pos.x + offset
|
|
||||||
const y0 = pos.y - offset
|
|
||||||
const y1 = pos.y + offset
|
|
||||||
this.x0 = this.x0 === null ? x0 : Math.min(this.x0, x0)
|
|
||||||
this.x1 = this.x1 === null ? x1 : Math.max(this.x1, x1)
|
|
||||||
this.y0 = this.y0 === null ? y0 : Math.min(this.y0, y0)
|
|
||||||
this.y1 = this.y1 === null ? y1 : Math.max(this.y1, y1)
|
|
||||||
}
|
|
||||||
reset () {
|
|
||||||
this.x0 = null
|
|
||||||
this.x1 = null
|
|
||||||
this.y0 = null
|
|
||||||
this.y1 = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const startGame = (game, bitmaps, conn) => {
|
|
||||||
let puzzle = game.puzzle
|
|
||||||
let players = game.players
|
|
||||||
// information for next render cycle
|
// information for next render cycle
|
||||||
let rectPlayer = new renderRect()
|
let rectPlayer = new DirtyRect()
|
||||||
let rerenderPlayer = true
|
let rerenderPlayer = true
|
||||||
let rectTable = new renderRect()
|
let rectTable = new DirtyRect()
|
||||||
let rerenderTable = true
|
let rerenderTable = true
|
||||||
let rerender = true
|
let rerender = true
|
||||||
|
|
||||||
|
|
@ -275,23 +258,19 @@ async function main () {
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
players[me][k] = change[k]
|
players[me][k] = change[k]
|
||||||
}
|
}
|
||||||
_STATE.changes.push({type: 'change_player', player: players[me]})
|
Communication.addChange({type: 'change_player', player: players[me]})
|
||||||
_STATE_CHANGED = true
|
|
||||||
}
|
}
|
||||||
const changeData = (change) => {
|
const changeData = (change) => {
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
puzzle.data[k] = change[k]
|
puzzle.data[k] = change[k]
|
||||||
}
|
}
|
||||||
_STATE.changes.push({type: 'change_data', data: puzzle.data})
|
Communication.addChange({type: 'change_data', data: puzzle.data})
|
||||||
_STATE_CHANGED = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeTile = (t, change) => {
|
const changeTile = (t, change) => {
|
||||||
for (let k of Object.keys(change)) {
|
for (let k of Object.keys(change)) {
|
||||||
t[k] = change[k]
|
t[k] = change[k]
|
||||||
}
|
}
|
||||||
_STATE.changes.push({type: 'change_tile', tile: t})
|
Communication.addChange({type: 'change_tile', tile: t})
|
||||||
_STATE_CHANGED = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a dom and attach adapters to it so we can work with it
|
// Create a dom and attach adapters to it so we can work with it
|
||||||
|
|
@ -303,10 +282,8 @@ async function main () {
|
||||||
// this global data will change according to input events
|
// this global data will change according to input events
|
||||||
const viewport = new Camera(canvas)
|
const viewport = new Camera(canvas)
|
||||||
|
|
||||||
conn.onSocket('message', ({data}) => {
|
Communication.onChanges((changes) => {
|
||||||
const d = JSON.parse(data)
|
for (let change of changes) {
|
||||||
if (d.type === 'state_changed' && d.origin !== me) {
|
|
||||||
for (let change of d.changes) {
|
|
||||||
switch (change.type) {
|
switch (change.type) {
|
||||||
case 'change_player': {
|
case 'change_player': {
|
||||||
if (players[change.player.id]) {
|
if (players[change.player.id]) {
|
||||||
|
|
@ -330,7 +307,6 @@ async function main () {
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Information about what tile is the player currently grabbing
|
// Information about what tile is the player currently grabbing
|
||||||
|
|
@ -509,11 +485,11 @@ async function main () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grabbingTileIdx >= 0) {
|
if (grabbingTileIdx >= 0) {
|
||||||
let tp_last = viewport.viewportToWorld({ x: last_x, y: last_y })
|
const tp_last = viewport.viewportToWorld({ x: last_x, y: last_y })
|
||||||
const diffX = tp.x - tp_last.x
|
const diffX = tp.x - tp_last.x
|
||||||
const diffY = tp.y - tp_last.y
|
const diffY = tp.y - tp_last.y
|
||||||
|
|
||||||
let t = puzzle.tiles[grabbingTileIdx]
|
const t = puzzle.tiles[grabbingTileIdx]
|
||||||
moveGroupedTilesDiff(t, diffX, diffY)
|
moveGroupedTilesDiff(t, diffX, diffY)
|
||||||
|
|
||||||
// todo: dont +- tileDrawSize, we can work with less?
|
// todo: dont +- tileDrawSize, we can work with less?
|
||||||
|
|
@ -544,7 +520,6 @@ async function main () {
|
||||||
setGroupedZIndex(puzzle.tiles[grabbingTileIdx], puzzle.data.maxZ)
|
setGroupedZIndex(puzzle.tiles[grabbingTileIdx], puzzle.data.maxZ)
|
||||||
setGroupedOwner(puzzle.tiles[grabbingTileIdx], me)
|
setGroupedOwner(puzzle.tiles[grabbingTileIdx], me)
|
||||||
}
|
}
|
||||||
console.log('down', tp)
|
|
||||||
|
|
||||||
} else if (mouse.type === 'up') {
|
} else if (mouse.type === 'up') {
|
||||||
changePlayer({ down: false })
|
changePlayer({ down: false })
|
||||||
|
|
@ -568,7 +543,6 @@ async function main () {
|
||||||
let srcRect = srcRectByIdx(puzzle.info, grabbingTileIdx)
|
let srcRect = srcRectByIdx(puzzle.info, grabbingTileIdx)
|
||||||
if (srcRect.centerDistance(dst) < puzzle.info.snapDistance) {
|
if (srcRect.centerDistance(dst) < puzzle.info.snapDistance) {
|
||||||
// Snap the tile to the final destination
|
// Snap the tile to the final destination
|
||||||
console.log('ok! !!!')
|
|
||||||
moveGroupedTiles(tile, {
|
moveGroupedTiles(tile, {
|
||||||
x: srcRect.x0 + boardPos.x,
|
x: srcRect.x0 + boardPos.x,
|
||||||
y: srcRect.y0 + boardPos.y,
|
y: srcRect.y0 + boardPos.y,
|
||||||
|
|
@ -610,7 +584,6 @@ async function main () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
grabbingTileIdx = -1
|
grabbingTileIdx = -1
|
||||||
console.log('up', tp)
|
|
||||||
} else if (mouse.type === 'wheel') {
|
} else if (mouse.type === 'wheel') {
|
||||||
if (
|
if (
|
||||||
mouse.deltaY < 0 && viewport.zoomIn()
|
mouse.deltaY < 0 && viewport.zoomIn()
|
||||||
|
|
@ -634,31 +607,7 @@ async function main () {
|
||||||
rerenderPlayer = true
|
rerenderPlayer = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_STATE_CHANGED) {
|
Communication.sendChanges()
|
||||||
conn.send(JSON.stringify({
|
|
||||||
type: 'state',
|
|
||||||
state: _STATE,
|
|
||||||
}))
|
|
||||||
_STATE.changes = []
|
|
||||||
_STATE_CHANGED = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// helper for measuring performance
|
|
||||||
let _pt = 0
|
|
||||||
let _mindiff = 0
|
|
||||||
const checkpoint_start = (mindiff) => {
|
|
||||||
_pt = performance.now()
|
|
||||||
_mindiff = mindiff
|
|
||||||
}
|
|
||||||
const checkpoint = (n) => {
|
|
||||||
const now = performance.now();
|
|
||||||
const diff = now - _pt
|
|
||||||
if (diff > _mindiff) {
|
|
||||||
console.log(n + ': ' + (diff));
|
|
||||||
}
|
|
||||||
_pt = now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
|
|
@ -676,13 +625,14 @@ async function main () {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
checkpoint_start(20)
|
if (DEBUG) Debug.checkpoint_start(20)
|
||||||
|
|
||||||
// draw the puzzle table
|
// draw the puzzle table
|
||||||
if (rerenderTable) {
|
if (rerenderTable) {
|
||||||
|
|
||||||
Graphics.fillBitmapCapped(puzzleTable, puzzleTableColor, rectTable.get())
|
Graphics.fillBitmapCapped(puzzleTable, puzzleTableColor, rectTable.get())
|
||||||
checkpoint('after fill')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('after fill')
|
||||||
|
|
||||||
// draw the puzzle board on the table
|
// draw the puzzle board on the table
|
||||||
Graphics.mapBitmapToBitmapCapped(board, board.getBoundingRect(), puzzleTable, new BoundingRectangle(
|
Graphics.mapBitmapToBitmapCapped(board, board.getBoundingRect(), puzzleTable, new BoundingRectangle(
|
||||||
|
|
@ -691,7 +641,8 @@ async function main () {
|
||||||
boardPos.y,
|
boardPos.y,
|
||||||
boardPos.y + board.height - 1,
|
boardPos.y + board.height - 1,
|
||||||
), rectTable.get())
|
), rectTable.get())
|
||||||
checkpoint('imgtoimg')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('imgtoimg')
|
||||||
|
|
||||||
// draw all the tiles on the table
|
// draw all the tiles on the table
|
||||||
|
|
||||||
|
|
@ -711,7 +662,8 @@ async function main () {
|
||||||
rectTable.get()
|
rectTable.get()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
checkpoint('tiles')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('tiles')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rerenderTable || rerender) {
|
if (rerenderTable || rerender) {
|
||||||
|
|
@ -720,7 +672,8 @@ async function main () {
|
||||||
// camera
|
// camera
|
||||||
adapter.clear()
|
adapter.clear()
|
||||||
adapter.apply()
|
adapter.apply()
|
||||||
checkpoint('afterclear_1')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('afterclear_1')
|
||||||
|
|
||||||
// TODO: improve the rendering
|
// TODO: improve the rendering
|
||||||
// atm it is pretty slow (~40-50ms)
|
// atm it is pretty slow (~40-50ms)
|
||||||
|
|
@ -730,10 +683,14 @@ async function main () {
|
||||||
adapter,
|
adapter,
|
||||||
adapter.getBoundingRect()
|
adapter.getBoundingRect()
|
||||||
)
|
)
|
||||||
checkpoint('to_adapter_1')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('to_adapter_1')
|
||||||
|
|
||||||
} else if (rerenderPlayer) {
|
} else if (rerenderPlayer) {
|
||||||
adapter.clearRect(rectPlayer.get())
|
adapter.clearRect(rectPlayer.get())
|
||||||
checkpoint('afterclear_2')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('afterclear_2')
|
||||||
|
|
||||||
Graphics.mapBitmapToAdapterCapped(
|
Graphics.mapBitmapToAdapterCapped(
|
||||||
puzzleTable,
|
puzzleTable,
|
||||||
viewport.rect(),
|
viewport.rect(),
|
||||||
|
|
@ -741,7 +698,8 @@ async function main () {
|
||||||
adapter.getBoundingRect(),
|
adapter.getBoundingRect(),
|
||||||
rectPlayer.get()
|
rectPlayer.get()
|
||||||
)
|
)
|
||||||
checkpoint('to_adapter_2')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('to_adapter_2')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rerenderPlayer) {
|
if (rerenderPlayer) {
|
||||||
|
|
@ -761,11 +719,13 @@ async function main () {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
checkpoint('after_players')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('after_players')
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.apply()
|
adapter.apply()
|
||||||
checkpoint('finals')
|
|
||||||
|
if (DEBUG) Debug.checkpoint('finals')
|
||||||
|
|
||||||
rerenderTable = false
|
rerenderTable = false
|
||||||
rerenderPlayer = false
|
rerenderPlayer = false
|
||||||
|
|
@ -778,7 +738,6 @@ async function main () {
|
||||||
update: onUpdate,
|
update: onUpdate,
|
||||||
render: onRender,
|
render: onRender,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue