Add move animation.
This commit is contained in:
parent
85a1b1e1a0
commit
7ccea94dc6
@ -646,13 +646,16 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
let mut response = PacketUserListResponse::new();
|
||||
response.status = STATUS_NOAUTH;
|
||||
|
||||
if user_id.is_some() {
|
||||
let users_list = app.users.list();
|
||||
for tid in users_list {
|
||||
if let Some(user) = app.users.get(tid) {
|
||||
response.records.push(PacketUserListData {
|
||||
handle:user.handle.clone(),
|
||||
});
|
||||
if let Some(user_id) = user_id {
|
||||
for (_, uid) in app.user_id.pairs() {
|
||||
let uid = *uid as u32;
|
||||
|
||||
if uid != user_id {
|
||||
if let Some(user) = app.get_user_by_id(uid) {
|
||||
response.records.push(PacketUserListData {
|
||||
handle:user.handle.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,16 +290,15 @@ const INTERFACE = {
|
||||
draw() {
|
||||
if(INTERFACE_DATA === null) return;
|
||||
|
||||
let canvas = INTERFACE_DATA.canvas;
|
||||
let ctx = INTERFACE_DATA.context;
|
||||
|
||||
INTERFACE.resize();
|
||||
INTERFACE.resolve_board();
|
||||
|
||||
let play = null;
|
||||
if(INTERFACE_DATA.replay_turn > 0) {
|
||||
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1];
|
||||
}
|
||||
INTERFACE.render();
|
||||
},
|
||||
|
||||
render() {
|
||||
let canvas = INTERFACE_DATA.canvas;
|
||||
let ctx = INTERFACE_DATA.context;
|
||||
|
||||
let width = canvas.width;
|
||||
let height = canvas.height;
|
||||
@ -308,6 +307,11 @@ const INTERFACE = {
|
||||
let gui_offset = INTERFACE_DATA.Ui.offset;
|
||||
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
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
@ -335,6 +339,13 @@ const INTERFACE = {
|
||||
let tile_state = INTERFACE_DATA.board_state[i][1];
|
||||
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);
|
||||
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
|
||||
coord.x = 8 - coord.x;
|
||||
@ -352,7 +363,7 @@ const INTERFACE = {
|
||||
|
||||
// Draw border
|
||||
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; }
|
||||
else { ctx.fillStyle = INTERFACE.Color.DuskDark; }
|
||||
}
|
||||
@ -395,7 +406,7 @@ const INTERFACE = {
|
||||
ctx.fill();
|
||||
|
||||
// Draw tile content
|
||||
if(piece !== null) {
|
||||
if(draw_piece && piece !== null) {
|
||||
// Draw border hints
|
||||
if(!is_hover) { draw.hints(piece); }
|
||||
|
||||
@ -594,6 +605,75 @@ const INTERFACE = {
|
||||
ctx.textAlign = "left";
|
||||
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 {
|
||||
@ -669,6 +749,44 @@ const INTERFACE = {
|
||||
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: {
|
||||
@ -749,6 +867,13 @@ const INTERFACE = {
|
||||
board_width: 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]); }
|
||||
|
||||
@ -841,7 +966,7 @@ const INTERFACE = {
|
||||
|
||||
case OpCode.GamePlay: {
|
||||
if(data.status == Status.Ok && data.turn == INTERFACE_DATA.history.length) {
|
||||
INTERFACE.history_push(data.play);
|
||||
INTERFACE.history_push(data.play, true);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -852,7 +977,7 @@ const INTERFACE = {
|
||||
switch(INTERFACE_DATA.mode) {
|
||||
// Apply action and change turn for local game.
|
||||
case INTERFACE.Mode.Local: {
|
||||
INTERFACE.history_push(play);
|
||||
INTERFACE.history_push(play, true);
|
||||
|
||||
INTERFACE_DATA.player = +(!INTERFACE_DATA.player);
|
||||
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);
|
||||
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
||||
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " of " + INTERFACE_DATA.history.length;
|
||||
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.history.length);
|
||||
}
|
||||
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;
|
||||
|
||||
if(turn >= 0 && turn <= INTERFACE_DATA.history.length) {
|
||||
if(turn < INTERFACE_DATA.replay_turn) {
|
||||
INTERFACE_DATA.replay_turn = 0;
|
||||
GAME.init();
|
||||
for(let i = 0; i < turn; ++i) {
|
||||
GAME_DATA.process(INTERFACE_DATA.history[i]);
|
||||
}
|
||||
|
||||
let play = null;
|
||||
let piece = null;
|
||||
let target = null;
|
||||
while(INTERFACE_DATA.replay_turn < 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]; }
|
||||
}
|
||||
} else {
|
||||
while(INTERFACE_DATA.replay_turn < turn) {
|
||||
GAME_DATA.process(INTERFACE_DATA.history[INTERFACE_DATA.replay_turn]);
|
||||
INTERFACE_DATA.replay_turn++;
|
||||
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
|
||||
@ -965,9 +1112,9 @@ const INTERFACE = {
|
||||
INTERFACE_DATA.replay_auto = false;
|
||||
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn - 1);
|
||||
},
|
||||
replay_next() {
|
||||
replay_next(animate=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() {
|
||||
INTERFACE_DATA.replay_auto = !INTERFACE_DATA.replay_auto;
|
||||
|
@ -29,7 +29,6 @@ function RECONNECT() {
|
||||
}
|
||||
|
||||
function RESUME() {
|
||||
//sessionStorage.clear();
|
||||
let b64_auth = sessionStorage.getItem("auth");
|
||||
if(b64_auth !== null) {
|
||||
let auth = UNPACK.base64(b64_auth);
|
||||
|
@ -205,6 +205,10 @@ const MATH = {
|
||||
return ((a % b) + b) % b
|
||||
},
|
||||
|
||||
lerp(a, b, t) {
|
||||
return a + ((b - a) * t);
|
||||
},
|
||||
|
||||
sign_branch(v) {
|
||||
return (v * 2) - 1;
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user