Add move animation.
This commit is contained in:
parent
85a1b1e1a0
commit
7ccea94dc6
@ -646,16 +646,19 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
let mut response = PacketUserListResponse::new();
|
let mut response = PacketUserListResponse::new();
|
||||||
response.status = STATUS_NOAUTH;
|
response.status = STATUS_NOAUTH;
|
||||||
|
|
||||||
if user_id.is_some() {
|
if let Some(user_id) = user_id {
|
||||||
let users_list = app.users.list();
|
for (_, uid) in app.user_id.pairs() {
|
||||||
for tid in users_list {
|
let uid = *uid as u32;
|
||||||
if let Some(user) = app.users.get(tid) {
|
|
||||||
|
if uid != user_id {
|
||||||
|
if let Some(user) = app.get_user_by_id(uid) {
|
||||||
response.records.push(PacketUserListData {
|
response.records.push(PacketUserListData {
|
||||||
handle:user.handle.clone(),
|
handle:user.handle.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some(QRPacket::new(qr.id, QRPacketData::RUserList(response)))
|
Some(QRPacket::new(qr.id, QRPacketData::RUserList(response)))
|
||||||
}
|
}
|
||||||
|
@ -290,16 +290,15 @@ const INTERFACE = {
|
|||||||
draw() {
|
draw() {
|
||||||
if(INTERFACE_DATA === null) return;
|
if(INTERFACE_DATA === null) return;
|
||||||
|
|
||||||
let canvas = INTERFACE_DATA.canvas;
|
|
||||||
let ctx = INTERFACE_DATA.context;
|
|
||||||
|
|
||||||
INTERFACE.resize();
|
INTERFACE.resize();
|
||||||
INTERFACE.resolve_board();
|
INTERFACE.resolve_board();
|
||||||
|
|
||||||
let play = null;
|
INTERFACE.render();
|
||||||
if(INTERFACE_DATA.replay_turn > 0) {
|
},
|
||||||
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1];
|
|
||||||
}
|
render() {
|
||||||
|
let canvas = INTERFACE_DATA.canvas;
|
||||||
|
let ctx = INTERFACE_DATA.context;
|
||||||
|
|
||||||
let width = canvas.width;
|
let width = canvas.width;
|
||||||
let height = canvas.height;
|
let height = canvas.height;
|
||||||
@ -308,6 +307,11 @@ const INTERFACE = {
|
|||||||
let gui_offset = INTERFACE_DATA.Ui.offset;
|
let gui_offset = INTERFACE_DATA.Ui.offset;
|
||||||
let gui_scale = INTERFACE_DATA.Ui.scale;
|
let gui_scale = INTERFACE_DATA.Ui.scale;
|
||||||
|
|
||||||
|
let play = null;
|
||||||
|
if(INTERFACE_DATA.replay_turn > 0) {
|
||||||
|
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Draw background
|
// Draw background
|
||||||
ctx.clearRect(0, 0, width, height);
|
ctx.clearRect(0, 0, width, height);
|
||||||
@ -335,6 +339,13 @@ const INTERFACE = {
|
|||||||
let tile_state = INTERFACE_DATA.board_state[i][1];
|
let tile_state = INTERFACE_DATA.board_state[i][1];
|
||||||
let hover_state = INTERFACE_DATA.board_state[i][0];
|
let hover_state = INTERFACE_DATA.board_state[i][0];
|
||||||
|
|
||||||
|
let draw_piece = true;
|
||||||
|
if(INTERFACE_DATA.Animate.play !== null) {
|
||||||
|
let play = INTERFACE_DATA.Animate.play;
|
||||||
|
draw_piece = draw_piece && !(play.source == 0 && (play.from == i || play.to == i));
|
||||||
|
draw_piece = draw_piece && !(play.source == 1 && play.to == i);
|
||||||
|
}
|
||||||
|
|
||||||
let coord = HEX.tile_to_hex(i);
|
let coord = HEX.tile_to_hex(i);
|
||||||
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
||||||
coord.x = 8 - coord.x;
|
coord.x = 8 - coord.x;
|
||||||
@ -352,7 +363,7 @@ const INTERFACE = {
|
|||||||
|
|
||||||
// Draw border
|
// Draw border
|
||||||
ctx.fillStyle = INTERFACE.Color.TileBorder;
|
ctx.fillStyle = INTERFACE.Color.TileBorder;
|
||||||
if(tile.piece !== null) {
|
if(draw_piece && tile.piece !== null) {
|
||||||
if(GAME_DATA.board.pieces[tile.piece].player == GAME.Const.Player.Dawn) { ctx.fillStyle = INTERFACE.Color.DawnDark; }
|
if(GAME_DATA.board.pieces[tile.piece].player == GAME.Const.Player.Dawn) { ctx.fillStyle = INTERFACE.Color.DawnDark; }
|
||||||
else { ctx.fillStyle = INTERFACE.Color.DuskDark; }
|
else { ctx.fillStyle = INTERFACE.Color.DuskDark; }
|
||||||
}
|
}
|
||||||
@ -395,7 +406,7 @@ const INTERFACE = {
|
|||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
// Draw tile content
|
// Draw tile content
|
||||||
if(piece !== null) {
|
if(draw_piece && piece !== null) {
|
||||||
// Draw border hints
|
// Draw border hints
|
||||||
if(!is_hover) { draw.hints(piece); }
|
if(!is_hover) { draw.hints(piece); }
|
||||||
|
|
||||||
@ -594,6 +605,75 @@ const INTERFACE = {
|
|||||||
ctx.textAlign = "left";
|
ctx.textAlign = "left";
|
||||||
ctx.fillText(message, gui_margin, height - gui_margin);
|
ctx.fillText(message, gui_margin, height - gui_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(INTERFACE_DATA.Animate.play !== null) {
|
||||||
|
let time = Math.min(1 - (INTERFACE_DATA.Animate.time - Date.now()) / 1000, 1);
|
||||||
|
time = time * time;
|
||||||
|
let play = INTERFACE_DATA.Animate.play;
|
||||||
|
|
||||||
|
// Get to and from coordinates.
|
||||||
|
let coord_to = HEX.tile_to_hex(play.to);
|
||||||
|
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
||||||
|
coord_to.x = 8 - coord_to.x;
|
||||||
|
coord_to.y = 8 - coord_to.y;
|
||||||
|
}
|
||||||
|
let to_x = basis_x + (1.5 * radius * coord_to.x);
|
||||||
|
let to_y = basis_y - (2 * gui_scale * coord_to.y) + (gui_scale * coord_to.x);
|
||||||
|
|
||||||
|
let from_x = 0;
|
||||||
|
let from_y = 0;
|
||||||
|
switch(play.source) {
|
||||||
|
// Lerp between board positions.
|
||||||
|
case 0: {
|
||||||
|
let coord_from = HEX.tile_to_hex(play.from);
|
||||||
|
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
||||||
|
coord_from.x = 8 - coord_from.x;
|
||||||
|
coord_from.y = 8 - coord_from.y;
|
||||||
|
}
|
||||||
|
from_x = basis_x + (1.5 * radius * coord_from.x);
|
||||||
|
from_y = basis_y - (2 * gui_scale * coord_from.y) + (gui_scale * coord_from.x);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
// Lerp between pool and board positions.
|
||||||
|
case 1: {
|
||||||
|
let coord_from = HEX.tile_to_hex(play.from);
|
||||||
|
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
||||||
|
coord_from.x = 8 - coord_from.x;
|
||||||
|
coord_from.y = 8 - coord_from.y;
|
||||||
|
}
|
||||||
|
from_x = basis_x + (radius * 14);
|
||||||
|
from_y = basis_y - (9 - (2 * coord_from.y)) * gui_scale;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get animation coordinates.
|
||||||
|
let x = MATH.lerp(from_x, to_x, time);
|
||||||
|
let y = MATH.lerp(from_y, to_y, time);
|
||||||
|
|
||||||
|
let piece = INTERFACE_DATA.Animate.piece;
|
||||||
|
let target = INTERFACE_DATA.Animate.target;
|
||||||
|
|
||||||
|
// Draw target piece.
|
||||||
|
if(target !== null) {
|
||||||
|
if(target.player == piece.player) {
|
||||||
|
let x = MATH.lerp(to_x, from_x, time);
|
||||||
|
let y = MATH.lerp(to_y, from_y, time);
|
||||||
|
draw.piece(target, x, y);
|
||||||
|
} else {
|
||||||
|
draw.piece(target, to_x, to_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw moving piece.
|
||||||
|
draw.piece(piece, x, y);
|
||||||
|
|
||||||
|
if(Date.now() < INTERFACE_DATA.Animate.time) {
|
||||||
|
setTimeout(INTERFACE.render, 1000 / 30);
|
||||||
|
} else {
|
||||||
|
INTERFACE_DATA.Animate.play = null;
|
||||||
|
INTERFACE_DATA.Animate.time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Draw: class {
|
Draw: class {
|
||||||
@ -669,6 +749,44 @@ const INTERFACE = {
|
|||||||
moves &= ~mask;
|
moves &= ~mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
piece(piece, x, y) {
|
||||||
|
let radius = INTERFACE.Radius * this.scale;
|
||||||
|
let icon_radius = 0.69 * radius;
|
||||||
|
|
||||||
|
this.ctx.save();
|
||||||
|
this.ctx.translate(x, y);
|
||||||
|
|
||||||
|
// Draw border
|
||||||
|
if(piece.player == GAME.Const.Player.Dawn) { this.ctx.fillStyle = INTERFACE.Color.DawnDark; }
|
||||||
|
else { this.ctx.fillStyle = INTERFACE.Color.DuskDark; }
|
||||||
|
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.hex();
|
||||||
|
this.ctx.fill();
|
||||||
|
|
||||||
|
// Draw background.
|
||||||
|
this.ctx.fillStyle = INTERFACE.Color.TileDark;
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.hex(0.94);
|
||||||
|
this.ctx.fill();
|
||||||
|
|
||||||
|
// Draw tile content
|
||||||
|
if(piece !== null) {
|
||||||
|
// Draw border hints
|
||||||
|
this.hints(piece);
|
||||||
|
|
||||||
|
// Draw piece icon
|
||||||
|
if(INTERFACE_DATA.mirror && (piece.player ^ (INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate) != 0) {
|
||||||
|
this.ctx.rotate(Math.PI);
|
||||||
|
}
|
||||||
|
if(piece.promoted) { this.ctx.drawImage(GAME_ASSET.Image.Promote, -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.); }
|
||||||
|
this.ctx.drawImage(GAME_ASSET.Image.Piece[piece.piece][piece.player], -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx.restore();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Ui: {
|
Ui: {
|
||||||
@ -749,6 +867,13 @@ const INTERFACE = {
|
|||||||
board_width: 0,
|
board_width: 0,
|
||||||
pool_offset: 0,
|
pool_offset: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Animate: {
|
||||||
|
play: null,
|
||||||
|
piece: null,
|
||||||
|
target: null,
|
||||||
|
time: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
for(let i = 0; i < 61; ++i) { INTERFACE_DATA.board_state.push([0, 0]); }
|
for(let i = 0; i < 61; ++i) { INTERFACE_DATA.board_state.push([0, 0]); }
|
||||||
|
|
||||||
@ -841,7 +966,7 @@ const INTERFACE = {
|
|||||||
|
|
||||||
case OpCode.GamePlay: {
|
case OpCode.GamePlay: {
|
||||||
if(data.status == Status.Ok && data.turn == INTERFACE_DATA.history.length) {
|
if(data.status == Status.Ok && data.turn == INTERFACE_DATA.history.length) {
|
||||||
INTERFACE.history_push(data.play);
|
INTERFACE.history_push(data.play, true);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -852,7 +977,7 @@ const INTERFACE = {
|
|||||||
switch(INTERFACE_DATA.mode) {
|
switch(INTERFACE_DATA.mode) {
|
||||||
// Apply action and change turn for local game.
|
// Apply action and change turn for local game.
|
||||||
case INTERFACE.Mode.Local: {
|
case INTERFACE.Mode.Local: {
|
||||||
INTERFACE.history_push(play);
|
INTERFACE.history_push(play, true);
|
||||||
|
|
||||||
INTERFACE_DATA.player = +(!INTERFACE_DATA.player);
|
INTERFACE_DATA.player = +(!INTERFACE_DATA.player);
|
||||||
INTERFACE_DATA.rotate = +(!INTERFACE_DATA.rotate);
|
INTERFACE_DATA.rotate = +(!INTERFACE_DATA.rotate);
|
||||||
@ -917,31 +1042,53 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
history_push(play) {
|
history_push(play, animate=false) {
|
||||||
INTERFACE_DATA.history.push(play);
|
INTERFACE_DATA.history.push(play);
|
||||||
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
||||||
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " of " + INTERFACE_DATA.history.length;
|
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " of " + INTERFACE_DATA.history.length;
|
||||||
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.history.length);
|
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.history.length);
|
||||||
}
|
}
|
||||||
if(INTERFACE_DATA.replay_turn == INTERFACE_DATA.history.length - 1) {
|
if(INTERFACE_DATA.replay_turn == INTERFACE_DATA.history.length - 1) {
|
||||||
INTERFACE.replay_next();
|
INTERFACE.replay_next(animate);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
replay_jump(turn) {
|
replay_jump(turn, animate=false) {
|
||||||
turn = +turn;
|
turn = +turn;
|
||||||
|
|
||||||
if(turn >= 0 && turn <= INTERFACE_DATA.history.length) {
|
if(turn >= 0 && turn <= INTERFACE_DATA.history.length) {
|
||||||
if(turn < INTERFACE_DATA.replay_turn) {
|
if(turn < INTERFACE_DATA.replay_turn) {
|
||||||
|
INTERFACE_DATA.replay_turn = 0;
|
||||||
GAME.init();
|
GAME.init();
|
||||||
for(let i = 0; i < turn; ++i) {
|
|
||||||
GAME_DATA.process(INTERFACE_DATA.history[i]);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
let play = null;
|
||||||
|
let piece = null;
|
||||||
|
let target = null;
|
||||||
while(INTERFACE_DATA.replay_turn < turn) {
|
while(INTERFACE_DATA.replay_turn < turn) {
|
||||||
GAME_DATA.process(INTERFACE_DATA.history[INTERFACE_DATA.replay_turn]);
|
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn];
|
||||||
|
|
||||||
|
if(play.source == 0) {
|
||||||
|
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
||||||
|
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id]; }
|
||||||
|
piece_id = GAME_DATA.board.tiles[play.to].piece;
|
||||||
|
if(piece_id !== null) { target = GAME_DATA.board.pieces[piece_id]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
GAME_DATA.process(play);
|
||||||
|
|
||||||
|
if(play.source == 1) {
|
||||||
|
let piece_id = GAME_DATA.board.tiles[play.to].piece;
|
||||||
|
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id]; }
|
||||||
|
}
|
||||||
|
|
||||||
INTERFACE_DATA.replay_turn++;
|
INTERFACE_DATA.replay_turn++;
|
||||||
}
|
}
|
||||||
|
if(animate) {
|
||||||
|
INTERFACE_DATA.Animate.time = Date.now() + 500;
|
||||||
|
INTERFACE_DATA.Animate.play = play;
|
||||||
|
INTERFACE_DATA.Animate.piece = piece;
|
||||||
|
INTERFACE_DATA.Animate.target = target;
|
||||||
}
|
}
|
||||||
INTERFACE_DATA.replay_turn = turn;
|
INTERFACE_DATA.replay_turn = turn;
|
||||||
|
|
||||||
@ -965,9 +1112,9 @@ const INTERFACE = {
|
|||||||
INTERFACE_DATA.replay_auto = false;
|
INTERFACE_DATA.replay_auto = false;
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn - 1);
|
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn - 1);
|
||||||
},
|
},
|
||||||
replay_next() {
|
replay_next(animate=false) {
|
||||||
INTERFACE_DATA.replay_auto = false;
|
INTERFACE_DATA.replay_auto = false;
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn + 1);
|
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn + 1, animate);
|
||||||
},
|
},
|
||||||
replay_toggle_auto() {
|
replay_toggle_auto() {
|
||||||
INTERFACE_DATA.replay_auto = !INTERFACE_DATA.replay_auto;
|
INTERFACE_DATA.replay_auto = !INTERFACE_DATA.replay_auto;
|
||||||
|
@ -29,7 +29,6 @@ function RECONNECT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function RESUME() {
|
function RESUME() {
|
||||||
//sessionStorage.clear();
|
|
||||||
let b64_auth = sessionStorage.getItem("auth");
|
let b64_auth = sessionStorage.getItem("auth");
|
||||||
if(b64_auth !== null) {
|
if(b64_auth !== null) {
|
||||||
let auth = UNPACK.base64(b64_auth);
|
let auth = UNPACK.base64(b64_auth);
|
||||||
|
@ -205,6 +205,10 @@ const MATH = {
|
|||||||
return ((a % b) + b) % b
|
return ((a % b) + b) % b
|
||||||
},
|
},
|
||||||
|
|
||||||
|
lerp(a, b, t) {
|
||||||
|
return a + ((b - a) * t);
|
||||||
|
},
|
||||||
|
|
||||||
sign_branch(v) {
|
sign_branch(v) {
|
||||||
return (v * 2) - 1;
|
return (v * 2) - 1;
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user