summaryrefslogtreecommitdiff
path: root/interactor
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2018-07-01 22:02:06 +0200
committerTom Smeding <tom.smeding@gmail.com>2018-07-01 22:02:06 +0200
commitbc51c3834928e388d16cc4b286da0574e3d94c32 (patch)
tree57d63cae4c9ca20cd6d2cb973943f0714d8de07a /interactor
parentd181aa1597ee875560ad52848b6092b59c48778d (diff)
interactor: move animation
Diffstat (limited to 'interactor')
-rw-r--r--interactor/game.js93
1 files 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;