Add move animation.

This commit is contained in:
yukirij 2024-08-26 16:17:44 -07:00
parent 85a1b1e1a0
commit 7ccea94dc6
4 changed files with 183 additions and 30 deletions

View File

@ -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(),
});
}
}
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
},