From bc51c3834928e388d16cc4b286da0574e3d94c32 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sun, 1 Jul 2018 22:02:06 +0200 Subject: interactor: move animation --- interactor/game.js | 93 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 10 deletions(-) diff --git a/interactor/game.js b/interactor/game.js index a9ecf2e..15ab83b 100644 --- a/interactor/game.js +++ b/interactor/game.js @@ -47,6 +47,14 @@ function cellY(i) {return (cellSize + 1) * ~~(i / N);} function cellMidX(i) {return (cellSize + 1) * (i % N + 0.5);} function cellMidY(i) {return (cellSize + 1) * (~~(i / N) + 0.5);} +var tileDrawers = [ + function(px, py) {}, + function(px, py) { drawCircle(px, py, "#ffffff"); }, + function(px, py) { drawKing(px, py); }, + function(px, py) {}, // unused + function(px, py) { drawCircle(px, py, "#000000"); }, +]; + function redraw() { ctx.fillStyle = "#e0c29f"; ctx.fillRect(0, 0, cvsSize, cvsSize); @@ -65,16 +73,8 @@ function redraw() { } ctx.stroke(); - var drawers = [ - function() {}, - function(px, py) { drawCircle(px, py, "#ffffff"); }, - function(px, py) { drawKing(px, py); }, - function() {}, - function(px, py) { drawCircle(px, py, "#000000"); }, - ]; - for (var i = 0; i < N * N; i++) { - drawers[board[i]](cellMidX(i), cellMidY(i)); + tileDrawers[board[i]](cellMidX(i), cellMidY(i)); } if (lastMove != null) { @@ -92,6 +92,76 @@ function redraw() { } } +var animateSlideDuration = 0.2; +function animateSlideInterpolate(a, b, t) {return (1-t) * a + t * b;} + +var animateSlideState = { + value: null, + move: null, + progress: null, + lastStamp: null, + imgdata: null, + aniframe: null, +}; + +function animateSlide(mv) { + cancelAnimateSlide(); + + var value = board[mv.from]; + + // Bit of a hack, the board being global state. We capture the imgdata while it's + // hot, to be able to repeatedly re-apply it during the animation. + board[mv.from] = EMPTY; + redraw(); + animateSlideState.imgdata = ctx.getImageData(0, 0, cvsSize, cvsSize); + board[mv.from] = value; + + animateSlideState.value = value; + animateSlideState.move = mv; + animateSlideState.progress = 0; + animateSlideState.lastStamp = performance.now(); + animateSlideState.aniframe = requestAnimationFrame(animateFrame); + + animateFrame(animateSlideState.lastStamp); +} + +function animateFrame(stamp) { + // stamp can be 0 in case of the first frame + + var st = animateSlideState; + + var delta = stamp - st.lastStamp; + st.lastStamp = stamp; + st.progress += delta / 1000; + + if (st.progress >= animateSlideDuration) { + cancelAnimateSlide(); + return; + } + + ctx.putImageData(st.imgdata, 0, 0); + + var x1 = cellMidX(st.move.from), y1 = cellMidY(st.move.from); + var x2 = cellMidX(st.move.to), y2 = cellMidY(st.move.to); + var x = animateSlideInterpolate(x1, x2, st.progress / animateSlideDuration); + var y = animateSlideInterpolate(y1, y2, st.progress / animateSlideDuration); + tileDrawers[st.value](x, y); + + requestAnimationFrame(animateFrame); +} + +function cancelAnimateSlide() { + if (animateSlideState.move == null) return; + + board[animateSlideState.move.from] = EMPTY; + board[animateSlideState.move.to] = animateSlideState.value; + cancelAnimationFrame(animateSlideState.aniframe); + + animateSlideState.move = null; + + redraw(); +} + function drawCircle(x, y, clr) { ctx.fillStyle = clr; ctx.beginPath(); @@ -214,11 +284,14 @@ function humanMove(mv) { } function processMove(mv) { + cancelAnimateSlide(); + + animateSlide(mv); + var captures = applyMove(mv); addMoveLog(onturn, mv, captures); onturn = -onturn; lastMove = mv; - redraw(); var win = checkWin(); var msg = win == 1 ? "White won." : win == -1 ? "Black won." : null; -- cgit v1.2.3-70-g09d2