UNPKG

@zimjs/game

Version:

Game module for ZIM JavaScript Canvas Framework

1,230 lines (1,149 loc) 92.5 kB
// ZIM - https://zimjs.com - Code Creativity! // JavaScript Canvas Framework for General Interactive Media // free to use - donations welcome of course! https://zimjs.com/donate // ZIM GAME - see https://zimjs.com/code#libraries for examples // ~~~~~~~~~~~~~~~~~~~~~~~~ // DESCRIPTION - LeaderBoard coded in 2017, Board in 2019 (c) ZIM // Helper code for making games on the HTML Canvas with JavaScript // ZIM already has a number of functions and classes that can help with games for example: // well... just about everthing in ZIM ;-) Okay, here are a list of common ones: // hitTestPoint, hitTestReg, hitTestRect, hitTestCircle, hitTestGrid // Sprite, Dynamo, Scroller, Accelerator, loadAssets and asset // animate, move, Ticker, GamePad, MotionController // Label, Button, Slider, Dial, Tabs, Pane, ColorPicker, Swipe, Swiper, Indicator // scale, scaleTo, center, centerReg, addTo, removeFrom // Circle, Rectangle, Triangle // constrain, Damp, ProportionDamp // The Game Module has LeaderBoard(), Meter(), Board(), Person(), Orb(), Tree(), Timer(), Scorer(), and Dialog() // DOCS // Docs are provided at https://zimjs.com/docs.html // See GAME MODULE at bottom // ~~~~~~~~~~~~~~~~~~~~~~~~ import zim from "zimjs"; // note - removed the ES5 module pattern as we are getting zim from import // ~~~~~~~~~~~~~~~~~~~~~~~~ var WW = window||{}; zim.LeaderBoard = function(data, title, width, height, corner, backgroundColor, titleColor, colors, total, scoreWidth, scorePlaces, scoreZeros, spacing, arrows, borderColor, borderWidth, shadowColor, shadowBlur, reverse, allowZero, font, fontSize, nameShift, scoreShift, rankShift) { var sig = "data, title, width, height, corner, backgroundColor, titleColor, colors, total, scoreWidth, scorePlaces, scoreZeros, spacing, arrows, borderColor, borderWidth, shadowColor, shadowBlur, reverse, allowZero, font, fontSize, nameShift, scoreShift, rankShift"; var duo; if (duo = zob(zim.LeaderBoard, arguments, sig, this)) return duo; this.arguments = arguments; if (zot(data)) data = "localStorage"; if (zot(width)) width = 400; if (zot(height)) height = 600; this.super_constructor(width, height); if (zot(corner)) corner = 20; if (zot(backgroundColor)) backgroundColor = "white"; if (zot(titleColor)) titleColor = "#222"; if (zot(total)) total = 10; if (zot(scoreWidth)) scoreWidth = 300; if (zot(scorePlaces)) scorePlaces = 6; if (zot(scoreZeros)) scoreZeros = false; if (zot(spacing)) spacing = 10; if (zot(arrows)) arrows = false; if (!zot(borderColor) && zot(borderWidth)) borderWidth = 2; if (zot(shadowColor)) shadowColor = "rgba(0,0,0,.3)"; if (zot(shadowBlur)) shadowBlur = 14; if (zot(reverse)) reverse = false; if (zot(allowZero)) allowZero = false; if (zot(font)) font = "courier"; if (zot(fontSize)) fontSize = 60; if (zot(nameShift)) nameShift = 0; if (zot(scoreShift)) scoreShift = 0; if (zot(rankShift)) rankShift = 0; if (typeof frame == "undefined" || zot(frame)) var frame = zimDefaultFrame; var backing = this.backing = new zim.Rectangle(width, height, backgroundColor, borderColor, borderWidth, corner); backing.mouseEnabled = false; var backingEvent = backing.on("click", function() { }); backing.off("click", backingEvent); backing.off("click", backingEvent); this.addChild(backing); this.setBounds(0, 0, width, height); this.backdrop = new Rectangle(2000, 1000, "rgba(0,0,0,.01)").center(this, 0); if (typeof frame == "undefined" && typeof zimDefaultFrame != "undefined") {var frame = zimDefaultFrame;} var stage = frame.stage; this.backdrop.on("mousedown", function() { stage = that.stage; that.removeFrom(); that.dispatchEvent("close"); if (stage) stage.update(); }); this.filled = false; this.info = {reverse: reverse, total: total, allowZero: allowZero, type: gameSaved}; // ES6 to fix if (shadowColor != -1 && shadowBlur > 0) backing.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur); var grid = this.grid = new zim.Container(); var row; var stepper; var rank; var score; var that = this; var c = { rankBackgroundColor: zim.darker, rankColor: zim.light, currentRankBackgroundColor: zim.pink, currentRankColor: "white", nameBackgroundColor: zim.lighter, nameColor: zim.darker, currentNameBackgroundColor: "#f0d2e8", currentNameColor: zim.darker, scoreBackgroundColor: zim.light, scoreColor: zim.darker, currentScoreBackgroundColor: "#f0d2e8", currentScoreColor: zim.darker }; var c = zim.merge(c, colors); var fakeText = zim.decimals(8, -scorePlaces, true); // force text to 000008 to start var winSteppers; var gameSaved; var button; var winRow; if (data == "localStorage") { initLocalStorage(); } else if (!Array.isArray(data)) { // data is a key to get the data from the ZIM Game Database that.dataSource = "database"; that.key = data; zim.async("https://zimjs.com/gamedata.php?id=" + data, gameData); function gameData(d) { if (d == "error") { var e = new createjs.Event("error"); e.type = "data"; that.dispatchEvent(e); initLocalStorage(); // drop to localStorage return; } if (d == "noscores") { d = []; } data = d; makeGrid(); } } else { that.dataSource = "custom"; makeGrid(); } function initLocalStorage() { // localStorage.clear(); that.dataSource = "localStorage"; if (localStorage && localStorage.gameData) { data = JSON.parse(localStorage.gameData); } else { data = []; } makeGrid(); } var keydownEvent; function makeGrid() { scaleStart = that.scaleX; that.sca(1); that.filled = false; frame.off("keydown", keydownEvent); if (!zot(title)) { var titleText = that.titleText = new zim.Label({ text: title, size: fontSize, color: titleColor, align: "center", font: font }).addTo(grid); titleText.x = titleText.width / 2; titleText.mouseEnabled = false; } var winCheck; if (!zot(that.winner)) winSteppers = []; backing.mouseEnabled = false; backing.off("click", backingEvent); for (var j = 0; j < total; j++) { winCheck = j == that.winner; var p, s; if (data[j]) { p = data[j].player; s = data[j].score; } else { p = s = " "; } row = new zim.Container(); rank = new zim.Label({ text: (j + 1), size: 50, color: j == that.winner ? c.currentRankColor : c.rankColor, align: "center", valign: "center", backing: new zim.Rectangle(100, 100, winCheck ? c.currentRankBackgroundColor : c.rankBackgroundColor), }); rank.reg(-rank.width / 2, -rank.height / 2); rank.label.regY = -rankShift; rank.addTo(row); if (arrows && !zot(that.winner)) { rank.mov(0, j >= that.winner ? 50 : 0) .mov(0, j > that.winner ? 50 : 0); } for (var i = 0; i < 3; i++) { stepper = new zim.Stepper({ list: winCheck ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-*_".split("") : p[i], width: 70, continuous: true, label: new zim.Label({text: "", font: font, color: j == that.winner ? c.currentNameColor : c.nameColor, size: fontSize, align: "center", shiftV: -5 - nameShift}), backgroundColor: winCheck ? c.currentNameBackgroundColor : c.nameBackgroundColor, vertical: false, arrows: false, arrows2: (winCheck && arrows), corner: 0, shadowBlur: 0 }).sca(100 / 60); if (winCheck) { backing.mouseEnabled = true; backing.on("click", backingEvent); if (frame.tabOrder) frame.tabOrder.push(stepper); winSteppers.push(stepper); stepper.currentValue = "_"; stepper.on("change", function(e) { if (e.target.text != "_") { e.target.label.y = 19 - nameShift; e.target.stage.update(); } var done = zim.loop(winSteppers, function(s) { if (s.currentValue == "_") return false; }); if (done) { that.filled = true; winScore.text = ""; button.loc(winScore.backing).addTo(winRow); if (that.stage) that.stage.update(); } that.dispatchEvent("change"); }); if (i == 0) stepper.keyFocus = true; } else { stepper.label.y = 19 - nameShift; } // stepper.label.reg(0,-2-nameShift) // stepper.label.mov(0,2+nameShift) stepper.x = rank.width + spacing + i * (stepper.width + spacing); if (arrows && !zot(that.winner)) { stepper.mov(0, j >= that.winner ? 50 : 0).mov(0, j > that.winner ? 50 : 0); } // stepper.enabled = winCheck; row.addChild(stepper); var scoreText = new zim.Label({ text: fakeText, color: winCheck ? c.currentScoreColor : c.scoreColor, font: font, size: fontSize + 4, align: "right", valign: "center", backing: new zim.Rectangle(scoreWidth, 100, winCheck ? c.currentScoreBackgroundColor : c.scoreBackgroundColor) }); scoreText.text = scoreZeros ? zim.decimals(s, -scorePlaces, true) : s; scoreText.reg(-scoreText.width / 2, -scoreText.height / 2); scoreText.label.regY = -4 - scoreShift; scoreText.label.skewX = 10; row.addChild(scoreText); scoreText.x = rank.width + spacing + 3 * (stepper.width + spacing) + 60; // scoreText.outline() if (arrows && !zot(that.winner)) { scoreText.mov(0, j >= that.winner ? 50 : 0) .mov(0, j > that.winner ? 50 : 0); } } if (winCheck) { winRow = row; var winScore = scoreText; button = that.button = new zim.Button({ label: new zim.Label({text: "SAVE", size: 50, align: "center", color: c.currentRankColor, rollColor: c.currentRankBackgroundColor}), width: scoreText.width, backgroundColor: c.currentRankBackgroundColor, rollBackgroundColor: c.currentRankColor, height: 100, corner: 0, shadowBlur: 0 }); // button.x = scoreText.x-60; // button.y = scoreText.y; if (frame.tabOrder) frame.tabOrder.push(button); button.on("mousedown", that.submitScore); keydownEvent = frame.on("keydown", function(e) { if (!that.stage) return; if (button.focus && e.keyCode == 13) { // enter key submitScore(); e.preventDefault(); } }); } row.addTo(grid); row.x = 0; row.y = (zot(title) ? 0 : (titleText.height + spacing * 2)) + j * (100 + spacing); row.mouseChildren = winCheck; row.mouseEnabled = winCheck; } if (!zot(title)) {titleText.center(grid); titleText.y = 0;} grid.scaleTo(that, 95, 95) .center(that); that.sca(scaleStart); if (stage) stage.update(); } this.submitScore = function() { button.text = that.dataSource == "localStorage" ? "LOCAL" : "SENT"; winRow.mouseChildren = false; winRow.mouseEnbabled = false; that.stage.update(); if (zot(data[that.winner])) data[that.winner] = {}; data[that.winner].player = winSteppers[0].currentValue + winSteppers[1].currentValue + winSteppers[2].currentValue; var e = new createjs.Event("press"); var player = e.player = data[that.winner].player; var score = e.score = data[that.winner].score; e.key = that.key; e.info = that.info; that.dispatchEvent(e); if (that.dataSource == "custom") return; if (zim.decimals(score, null, null, null, null, null, e)) that.save(); return that; }; this.score = function(score) { if (!Array.isArray(data)) { timeout(.1, function() {that.score(score);}); return; } if (!zot(that.pendingIndex)) that.cancel(); var position; if (data.length == 0) { position = 0; data.push({player: "", score: score}); } else { position = zim.loop(data, function(s, i) { if ((!reverse && s.score <= score) || (reverse && s.score >= score)) { data.splice(i, 0, {player: "", score: score}); return i; } }); } if (position === true && (allowZero || score > 0) && (data.length == 0 || data.length < total)) { data.push({player: "", score: score}); position = data.length - 1; } if (position !== true) { that.pendingIndex = position; that.redraw(null, position); } return position !== true ? position : null; }; this.save = function() { if (zot(that.pendingIndex)) return that; if (that.dataSource == "database") { var player = data[that.pendingIndex].player; var score = data[that.pendingIndex].score; zim.async("https://zimjs.com/gamedata.php?id=" + that.key + "&player=" + player + "&score=" + score + "&reverse=" + reverse + "&total=" + total + "&allowZero=" + allowZero, gameSaved); } if (that.dataSource == "localStorage") { that.pendingIndex = null; if (localStorage) localStorage.gameData = JSON.stringify(data); setTimeout(function() { button.text = "DONE"; if (that.stage) that.stage.update(); }, 500); setTimeout(function() {that.redraw();}, 1500); } return that; }; function gameSaved(d) { if (d == "error") { var e = new createjs.Event("error"); e.type = "save"; that.dispatchEvent(e); button.text = "ERROR"; data.splice(that.pendingIndex, 1); } else { var e = new createjs.Event("save"); e.data = data = d; that.dispatchEvent(e); button.text = "DONE"; } that.pendingIndex = null; if (that.stage) that.stage.update(); setTimeout(function() {that.redraw();}, 1000); } this.startTime = function() { zim.async("https://zimjs.com/gamedata.php?id=" + that.key + "&command=start", timeReply); return that; }; this.stopTime = function() { zim.async("https://zimjs.com/gamedata.php?id=" + that.key + "&command=stop", timeReply); return that; }; function timeReply(data) { }; this.cancel = function() { if (zot(that.pendingIndex)) return that; data.splice(that.pendingIndex, 1); that.pendingIndex = null; that.redraw(); var e = new createjs.Event("cancel"); e.data = data; that.dispatchEvent(e); return that; }; var scaleStart = that.scaleX; this.redraw = function(newData, newWinner) { if (newData) data = newData; scaleStart = that.scaleX; that.dispose(); if (zot(newWinner)) {that.winner = null;} else {that.winner = newWinner;} grid.removeAllChildren(); makeGrid(); if (that.stage) that.stage.update(); return that; }; this.dispose = function() { if (winSteppers) { var ind; zim.loop(winSteppers, function(s) { if (frame.tabOrder) { var ind = frame.tabOrder.indexOf(s); if (ind > -1) frame.tabOrder.splice(ind, 1); } s.dispose(); }); if (frame.tabOrder) { ind = frame.tabOrder.indexOf(button); if (ind > -1) frame.tabOrder.splice(ind, 1); } if (button) button.dispose(); } }; }; zim.extend(zim.LeaderBoard, zim.Container); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ zim.Meter = function(stage, vertical, horizontal, color, textColor, padding, decimals, alpha, skew) { var sig = "stage, vertical, horizontal, color, textColor, padding, decimals, alpha, skew"; var duo; if (duo = zob(zim.Meter, arguments, sig, this)) return duo; this.arguments = arguments; if (zot(vertical)) vertical = "bottom"; if (zot(horizontal)) horizontal = "left"; if (zot(padding)) padding = 20; if (zot(decimals)) decimals = 0; if (zot(color)) color = "#acd241"; // frame.green if (zot(textColor)) textColor = "black"; // frame.green if (zot(alpha)) alpha = .6; if (zot(skew)) skew = 10; this.super_constructor("", 30, null, textColor, null, null, null, "center", "center", null, null, null, null, null, new zim.Rectangle(100, 40, color)); var that = this; var meterFunction; var initFunction; if (zot(stage)) {initFunction = that.on("added", init);} else {init();} var fps = new zim.Label({text: "FPS", size: 18, color: textColor}).rot(-90).addTo(that).alp(.5); fps.x = 59; fps.y = 17; function init() { if (zot(stage)) stage = that.stage; if (zot(stage)) return; that.off("added", initFunction); stage.addChild(that); that.alpha = alpha; that.skewX = skew; that.setBounds(null); that.pos(padding, padding, horizontal, vertical); // that.x = horizontal=="left"?padding+skew/2+50:stage.getBounds().width-that.width-padding-skew/2+50; // that.y = vertical=="top"?padding:stage.getBounds().height-that.height-padding; meterFunction = zim.Ticker.add(function() { that.text = zim.decimals(createjs.Ticker.getMeasuredFPS(), decimals, true); if (stage) stage.update(); }, stage); } this.position = function(v, h) { if (!zot(v)) vertical = v; if (!zot(h)) horizontal = h; that.setBounds(null); // that.x = horizontal=="left"?padding+skew/2+50:stage.getBounds().width-that.width-padding-skew/2+50; // that.y = vertical=="top"?padding:stage.getBounds().height-that.height-padding; that.pos(padding, padding, horizontal, vertical); return that; }; this.dispose = function() { zim.Ticker.remove(meterFunction); }; }; zim.extend(zim.Meter, zim.Label); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ zim.Board = function(size, cols, rows, backgroundColor, rollBackgroundColor, borderColor, borderWidth, icon, isometric, indicatorColor, indicatorBorderColor, indicatorBorderWidth, indicatorSize, indicatorType, arrows, arrowColor, arrowRollColor, swipe, info, labels, color, scaleMin, scaleMax, buffer) { var sig = "size, cols, rows, backgroundColor, rollBackgroundColor, borderColor, borderWidth, icon, isometric, indicatorColor, indicatorBorderColor, indicatorBorderWidth, indicatorSize, indicatorType, arrows, arrowColor, arrowRollColor, swipe, info, labels, color, scaleMin, scaleMax, buffer"; var duo; if (duo = zob(zim.Board, arguments, sig, this)) return duo; this.arguments = arguments; if (zot(size)) size = 50; this.size = size; if (zot(cols)) cols = zot(rows) ? 8 : rows; if (zot(rows)) rows = cols; this.cols = cols; this.rows = rows; this.num = cols * rows; if (zot(backgroundColor)) backgroundColor = "#eee"; if (zot(rollBackgroundColor)) rollBackgroundColor = "#aaa"; if (zot(borderColor)) borderColor = "#111"; if (zot(borderWidth)) borderWidth = 2; if (zot(isometric)) isometric = true; var isoFirst = isometric; if (zot(indicatorColor)) indicatorColor = null; if (zot(indicatorBorderColor)) indicatorBorderColor = "#111"; if (zot(indicatorBorderWidth)) indicatorBorderWidth = 2; if (zot(indicatorType)) indicatorType = "circle"; if (indicatorType != "circle") indicatorType = "rectangle"; if (zot(indicatorSize)) indicatorSize = indicatorType == "rectangle" ? (size - indicatorBorderWidth) : size / 4; if (zot(arrows)) arrows = true; if (zot(arrowColor)) arrowColor = "rgba(0,0,0,.4)"; if (zot(arrowRollColor)) arrowRollColor = "#fff"; if (zot(swipe)) swipe = arrows; var timeType = typeof TIME == "undefined" ? "seconds" : TIME; function emptyInfo() { // info is rows (j) then cols (i) info = []; zim.loop(rows, function(j) { var inf = info[j] = []; zim.loop(cols, function(i) { inf[i] = {data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []}; }); }); } if (zot(info)) { // create empty info if no provided info emptyInfo(); } else if (typeof info == "string") { if (info.match(/zimon/) && typeof ZIMON !== 'undefined') info = ZIMON.parse(info); else emptyInfo(); } else if (!Array.isArray(info) || info.length == 0) { emptyInfo(); } else { // info are rows (j) then cols (i) var info2 = []; var i0 = 0; // get most cols zim.loop(Math.max(cols, info.length), function(j) { if (info[j] && info[j].length > i0) i0 = info[j].length; }); zim.loop(Math.max(cols, info.length), function(j) { var inf = info2[j] = []; zim.loop(Math.max(rows, i0), function(i) { if (info[j] && !zot(info[j][i])) { if (zot(info[j][i].data)) info[j][i].data = "x"; if (zot(info[j][i].color)) info[j][i].color = backgroundColor; if (zot(info[j][i].icon)) info[j][i].icon = icon ? icon.clone() : null; if (zot(info[j][i].items)) info[j][i].items = []; inf[i] = info[j][i]; } else inf[i] = {data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []}; }); }); info = copy(info2); } this.info = info; if (zot(labels)) labels = false; if (zot(color)) color = "#666"; if (zot(scaleMin)) scaleMin = 1.2; if (zot(scaleMax)) scaleMax = 1.8; if (zot(swipe)) swipe = true; if (zot(buffer)) buffer = 2; this.super_constructor(); this.type = "Board"; this.buffer = buffer; var that = this; var holder = new zim.Container().addTo(this); var container = new zim.Container(size, size); new zim.Rectangle(size, size, zik(backgroundColor), zik(borderColor), zik(borderWidth)).addTo(container); // labels for debugging if (labels) new zim.Label({text: "", color: color, align: "center", valign: "center"}).center(container); var tiles = this.tiles = new zim.Tile(container.centerReg(), cols, rows); if (isometric) { tiles.rot(45) .centerReg(holder); holder.sca(2, 1); } else { tiles.centerReg(holder); } this.arrows = arrows; var startCol = 0; var startRow = 0; var lastStartCol = 0; var lastStartRow = 0; Object.defineProperty(this, 'numCols', { get: function() { return that.info[0].length; }, set: function(value) { zog("zim.Board() - numCols is read only"); } }); Object.defineProperty(this, 'numRows', { get: function() { return that.info.length; }, set: function(value) { zog("zim.Board() - numRows is read only"); } }); Object.defineProperty(this, 'startCol', { get: function() { return startCol; }, set: function(value) { startCol = zim.constrain(value, 0, that.numCols - cols); if (startCol != lastStartCol) { that.update(); that.shiftPath(lastStartCol, startCol); // no obj so for all pieces } lastStartCol = startCol; } }); Object.defineProperty(this, 'startRow', { get: function() { return startRow; }, set: function(value) { startRow = zim.constrain(value, 0, that.numRows - rows); if (startRow != lastStartRow) { that.update(); that.shiftPath(null, null, lastStartRow, startRow); // no obj so for all pieces } lastStartRow = startRow; } }); Object.defineProperty(this, 'data', { // gets board data only - not all data get: function() { var data = []; zim.loop(startRow + rows, function(j) { var d = []; data.push(d); zim.loop(startCol + cols, function(i) { d.push(that.info[j][i].data); }, null, null, null, startCol); }, null, null, null, startRow); return data; }, set: function(value) { zog("zim.Board() - data is read only - use setData(tile) or change info property and update()"); } }); Object.defineProperty(this, 'isometric', { get: function() { return isometric; }, set: function(value) { if (value != isometric) { isometric = value; that.removeArrows(); if (isometric) { holder.removeAllChildren(); that.tiles.rot(45).centerReg(holder); var ss = isoFirst ? 1 : 1.2; holder.sca(2 / ss, 1 / ss).mov(0, (isoFirst ? 20 : 0)); } else { holder.removeAllChildren(); that.tiles.rot(0).centerReg(holder); holder.sca(1 * (isoFirst ? 1.2 : 1)).mov(0, (isoFirst ? -20 : 0)); } if (swipe) { var swap = {left: "right", right: "left", up: "down", down: "up"}; if (that.swipeEvent) that.swipe.off("swipe", that.swipeEvent); that.swipe = new zim.Swipe(that, null, null, isometric); that.swipeEvent = that.swipe.on("swipe", function(e) { if (e.target.direction == "none") return; that.moveCamera(swap[e.target.direction]); }); } that.setArrows(); that.update(); if (that.stage) that.stage.update(); } } }); this.update = function() { // updates data, colors and pieces for currently visible board if (labels) { tiles.loop(function(tile) { tile.getChildAt(1).text = that.getData(tile); }); } that.pieces.loop(function(piece) { piece.visible = false; }); that.clearBoardColors(); that.clearBoardIcons(); zim.loop(rows + startRow, function(j) { zim.loop(cols + startCol, function(i) { var info = that.info[j][i]; var tile = that.getTile(i - startCol, j - startRow); that.setColor(tile, info.color, true); if (info.icon) that.setIcon(tile, info.icon, true); zim.loop(info.items, function(item) { that.add(item, i - startCol, j - startRow, null, null, null, true); }); }, null, null, null, startCol); }, null, null, null, startRow); if (that.stage) that.stage.update(); return that; }; if (swipe) { this.swipe = new zim.Swipe(this, null, null, isometric); this.swipeEvent = this.swipe.on("swipe", function(e) { if (e.target.direction == "none") return; var swap = {left: "right", right: "left", up: "down", down: "up"}; that.moveCamera(swap[e.target.direction]); }); } this.moveCamera = function(dir) { // moves camera one square left, right, up or down // by setting startCol and startRow // which moves any items, paths and sets activeData if (dir == "left") { if (that.arrowRight && startCol == that.numCols - cols) that.arrowRight.hov(arrowRollColor); that.startCol = startCol - 1; if (that.arrowLeft && startCol == 0) that.arrowLeft.hov(-1); } else if (dir == "right") { if (that.arrowLeft && startCol == 0) that.arrowLeft.hov(arrowRollColor); that.startCol = startCol + 1; if (that.arrowRight && startCol == that.numCols - cols) that.arrowRight.hov(-1); } else if (dir == "up") { if (that.arrowDown && startRow == that.numRows - rows) that.arrowDown.hov(arrowRollColor); that.startRow = startRow - 1; if (that.arrowUp && startRow == 0) that.arrowUp.hov(-1); } else if (dir == "down") { if (that.arrowUp && startRow == 0) that.arrowUp.hov(arrowRollColor); that.startRow = startRow + 1; if (that.arrowDown && startRow == that.numRows - rows) that.arrowDown.hov(-1); } return that; }; this.positionBoard = function(i, j) { // starts board off at provided location in info that.startCol = i; that.startRow = j; if (that.arrows) that.setArrowHover(); return that; }; this.setArrowHover = function() { if (that.arrowLeft) that.arrowLeft.hov(startCol == 0 ? -1 : arrowRollColor); if (that.arrowRight) that.arrowRight.hov(startCol == that.numCols - cols ? -1 : arrowRollColor); if (that.arrowUp) that.arrowUp.hov(startRow == 0 ? -1 : arrowRollColor); if (that.arrowDown) that.arrowDown.hov(startRow == that.numRows - rows ? -1 : arrowRollColor); return that; }; this.addCol = function(index) { // adds info column at an index if (zot(index)) index = that.numCols; zim.loop(that.info, function(inf, i) { inf.splice(index, 0, {data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []}); }); if (that.arrows) { that.setArrows(); that.setArrowHover(); } that.update(); return that; }; this.addRow = function(index) { // adds info row at an index if (zot(index)) index = that.numRows; var inf = []; zim.loop(that.numCols, function() { inf.push({data: "x", color: backgroundColor, icon: icon ? icon.clone() : null, items: []}); }); that.info.splice(index, 0, inf); if (that.arrows) { that.setArrows(); that.setArrowHover(); } that.update(); return that; }; this.setArrows = function() { // sets arrows to handle shifting board if (!that.arrows) return; if (that.info.length > rows || that.info[0].length > cols) { if (!that.arrowUp) { that.arrowUp = new Triangle({color: arrowColor}).sca(.4).center(holder); if (isometric) { that.arrowUp .rot(45) .mov(tiles.width / 2, tiles.width / 2 - 50); } else { that.arrowUp .mov(tiles.width / 2 + 40, -30); } that.arrowDown = new Triangle({color: arrowColor}).sca(.4).center(holder); if (isometric) { that.arrowDown .rot(+45 - 180) .mov(tiles.width / 2 - 50, tiles.width / 2); } else { that.arrowDown .rot(-180) .mov(tiles.width / 2 + 10, +30); } that.arrowUp.on("mousedown", function() { that.moveCamera("up"); if (that.stage) that.stage.update(); }); that.arrowDown.on("mousedown", function() { that.moveCamera("down"); if (that.stage) that.stage.update(); }); } } else { // may have removed data so no scroll is needed if (that.arrowUp) removeRowArrows(); } var colArrows = zim.loop(that.info, function(d) { if (d.length > cols) return "yes"; }); if (colArrows == "yes") { if (!that.arrowLeft) { that.arrowLeft = new Triangle({color: arrowColor}).sca(.4).cur().center(holder); if (isometric) { that.arrowLeft .rot(+45 - 180 + 90) .mov(-tiles.width / 2, tiles.width / 2 - 50); } else { that.arrowLeft .rot(-180 + 90) .mov(-60, tiles.width / 2 + 40); } that.arrowRight = new Triangle({color: arrowColor}).sca(.4).center(holder); that.arrowRight.n = "b"; if (isometric) { that.arrowRight .rot(45 + 90) .mov(-tiles.width / 2 + 50, tiles.width / 2); } else { that.arrowRight .rot(+90) .mov(0, tiles.width / 2 + 10); } that.arrowLeft.on("mousedown", function() { that.moveCamera("left"); }); that.arrowRight.on("mousedown", function() { that.moveCamera("right"); }); // FIX bounds so move camera not board } that.setArrowHover(); } else { if (that.arrowLeft) removeColArrows(); } return that; }; that.setArrows(); this.removeArrows = function() { removeColArrows(); removeRowArrows(); return that; }; function removeColArrows() { if (!that.arrowLeft || !that.arrowRight) return; that.arrowLeft.removeAllEventListeners(); that.arrowRight.removeAllEventListeners(); that.arrowLeft.removeFrom(); that.arrowLeft = null; that.arrowRight.removeFrom(); that.arrowRight = null; } function removeRowArrows() { if (!that.arrowUp || !that.arrowDown) return; that.arrowUp.removeAllEventListeners(); that.arrowDown.removeAllEventListeners(); that.arrowUp.removeFrom(); that.arrowUp = null; that.arrowDown.removeFrom(); that.arrowDown = null; } that.lastTile = null; tiles.tap(function(e) { that.currentTile = e.target; }); tiles.on("mouseover", function(e) { if (that.timeout) that.timeout.clear(); e.target.lastColor = e.target.getChildAt(0).color; e.target.getChildAt(0).color = rollBackgroundColor; that.currentTile = e.target; if (e.target != that.lastTile) {that.dispatchEvent("change");} that.lastTile = e.target; if (that.stage) that.stage.update(); }); tiles.on("mouseout", outHandler); zimDefaultFrame.canvas.addEventListener("mouseleave", outHandler); function outHandler(e) { that.timeout = zim.timeout(timeType == "seconds" ? .05 : 50, function() { that.currentTile = null; that.lastTile = null; that.dispatchEvent("change"); }); if (e.target && e.target.getChildAt) e.target.getChildAt(0).color = e.target.lastColor; if (that.lastTile) that.lastTile.getChildAt(0).color = that.lastTile.lastColor; if (that.stage) that.stage.update(); }; this.getIndexes = function(tile) { // gets the row and col for a tile var n = tiles.getChildIndex(tile); var col = n % cols; var row = Math.floor(n / cols); return {col: col, row: row}; }; this.getInfo = function(a, b) { // gets the info object for a tile (or i,j info point) if (zot(a)) return; if (zot(b)) { var indexes = that.getIndexes(a); a = indexes.col + startCol; b = indexes.row + startRow; } if (a < 0 || a > that.numCols - 1 || b < 0 || b > that.numRows - 1) return; return that.info[b][a]; }; this.getData = function(a, b) { // gets items from info for a tile (or i,j info point) if (zot(a)) return; return that.getInfo(a, b).data; }; this.getColor = function(a, b) { // gets the color data for a tile (or i,j info point) if (zot(a)) return; return that.getInfo(a, b).color; }; this.getIcon = function(a, b) { // gets the icon for a tile (or i,j info point) if (zot(a)) return; return that.getInfo(a, b).icon; }; this.getItems = function(a, b) { // gets items from info for a tile (or i,j info point) if (zot(a)) return; var i = that.getInfo(a, b); if (i) return that.getInfo(a, b).items; }; this.getAllItems = function(filter) { // gets an array of all items - add optional filter var items = []; if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); zim.loop(that.info, function(rows, j) { zim.loop(rows, function(info, i) { if (!includeTest(i, j, filter)) return; zim.loop(info.items, function(item) { items.push(item); }); }); }); return items; }; this.getTilesAround = function(a, b) { // gets tiles around a tile (or i,j info point) if (zot(a)) return; if (zot(b)) { var indexes = that.getIndexes(a); a = indexes.col + startCol; b = indexes.row + startRow; } if (a < 0 || a > that.numCols - 1 || b < 0 || b > that.numRows - 1) return []; return [ that.getTile(a - 1, b - 1), that.getTile(a - 0, b - 1), that.getTile(a + 1, b - 1), that.getTile(a + 1, b - 0), that.getTile(a + 1, b + 1), that.getTile(a - 0, b + 1), that.getTile(a - 1, b + 1), that.getTile(a - 1, b - 0) ]; }; tiles.loop(function(t) { if (indicatorType == "circle") { t.indicator = new zim.Circle(zik(indicatorSize), zik(indicatorColor), zik(indicatorBorderColor), indicatorBorderWidth).center(t).alp(0); } else { var size = zik(indicatorSize); t.indicator = new zim.Rectangle(size, size, zik(indicatorColor), zik(indicatorBorderColor), indicatorBorderWidth).centerReg(t).alp(0); } t.mouseChildren = false; var i = that.getIndexes(t); t.boardCol = i.col; t.boardRow = i.row; var icon = that.getInfo(t).icon; t.icon = icon; if (icon) icon.center(t.getChildAt(0)); }); this.getTile = function(col, row) { // gets tile at visible col and row if (col < 0 || row < 0 || col > that.cols - 1 || row > that.rows - 1) return; return tiles.getChildAt(row * cols + col); }; this.setData = function(tile, value) { // updates a data entry for a tile that.getInfo(tile).data = value; return that.data; }; this.setColor = function(tile, color, internal) { // adds a color to board and info for the color tile.lastColor = tile.getChildAt(0).color = color; if (zot(internal)) that.getInfo(tile).color = color; return that; }; this.setIcon = function(tile, icon, internal) { if (zot(icon)) return; // adds an icon to board and info for the icon if (zot(internal)) that.getInfo(tile).icon = icon; if (tile.icon) tile.icon.removeFrom(); tile.icon = icon; icon.center(tile.getChildAt(0)); return that; }; this.clearInfo = function(filter) { if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); // clears info for data, colors and items zim.loop(that.info, function(rows, j) { zim.loop(rows, function(inf, i) { if (!includeTest(i, j, filter)) return; inf.data = "x"; zim.loop(inf.items, function(item) { item.boardCol = null; item.boardRow = null; item.tile = null; item.removeFrom(); }); inf.items = []; inf.icon = that.icon ? that.icon.clone() : null; inf.color = backgroundColor; var tile = that.getTile(i - startCol, j - startRow); if (tile) { tile.getChildAt(0).color = backgroundColor; if (inf.icon) inf.icon.center(tile.getChildAt(0)); } }); }); return that; }; this.clearData = function(filter) { if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); // clears data but leaves colors and items zim.loop(that.info, function(rows, j) { zim.loop(rows, function(info, i) { if (!includeTest(i, j, filter)) return; info.data = "x"; }); }); return that; }; this.clearItems = function(filter) { if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); // clears items but leaves data and colors zim.loop(that.info, function(rows, j) { zim.loop(rows, function(info, i) { if (!includeTest(i, j, filter)) return; zim.loop(info.items, function(item) { item.boardCol = null; item.boardRow = null; item.tile = null; item.removeFrom(); }); info.items = []; }); }); return that; }; this.clearColors = function(filter) { if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); // clears color but leaves data and items zim.loop(that.info, function(rows, j) { zim.loop(rows, function(info, i) { if (!includeTest(i, j, filter)) return; info.color = backgroundColor; var tile = that.getTile(i - startCol, j - startRow); if (tile) tile.getChildAt(0).color = backgroundColor; }); }); return that; }; this.clearBoardColors = function() { // clears board colors but leaves color info zim.loop(tiles, function(tile) { tile.getChildAt(0).color = backgroundColor; }); return that; }; this.clearIcons = function(filter) { if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); // clears color but leaves data and items zim.loop(that.info, function(rows, j) { zim.loop(rows, function(info, i) { if (!includeTest(i, j, filter)) return; if (info.icon) { info.icon.removeFrom(); if (info.icon.dispose) info.icon.dispose(); info.icon = null; } info.icon = that.icon ? that.icon.clone() : null; var tile = that.getTile(i - startCol, j - startRow); if (tile && info.icon) info.icon.center(tile.getChildAt(0)); }); }); return that; }; this.clearBoardIcons = function() { // clears board icons but leaves icon info zim.loop(tiles, function(tile) { if (tile.icon) tile.icon.removeFrom(); tile.icon = null; }); return that; }; this.getRandomTile = function(filter) { if (zot(filter)) filter = {}; else filter = normalizeFilter(filter); // gets random visible tile var tile; var count = 0; while (!tile && count < 10000) { var i = zim.rand(0, cols - 1) + startCol; var j = zim.rand(0, rows - 1) + startRow; if (filter && includeTest(i, j, filter)) tile = that.getTile(i - startCol, j - startRow); count++; } return tile; }; function normalizeFilter(filter) { if (filter.constructor != {}.constructor) { // assume filtering by data filter = {data: !Array.isArray(filter) ? [filter] : filter}; return filter; } var types = ["data", "notData", "color", "notColor", "icon", "notIcon", "item", "notItem", "col", "notCol", "row", "notRow"]; var wrong = ["datas", "notDatas", "colors", "notColors", "icons", "notIcons", "items", "notItems", "cols", "notCols", "rows", "notRows"]; zim.loop(wrong, function(w, i) { if (filter[w]) filter[types[i]] = filter[w]; delete filter[w]; }); zim.loop(types, function(type) { if (!zot(filter[type]) && !Array.isArray(filter[type])) filter[type] = [filter[type]]; }); return filter; } function includeTest(i, j, filter) { // test for there or not there and if wrong - then return false else return true if (!zot(filter.data) && filter.data.indexOf(that.info[j][i].data) == -1) return false; if (!zot(filter.notData) && filter.notData.indexOf(that.info[j][i].data) != -1) return false; if (!zot(filter.color) && filter.color.indexOf(that.info[j][i].color) == -1) return false; if (!zot(filter.notColor) && filter.notColor.indexOf(that.info[j][i].color) != -1) return false; if (!zot(filter.icon) && (!that.info[j][i].icon || filter.icon.indexOf(that.info[j][i].icon.type) == -1)) return false; if (!zot(filter.notIcon) && (that.info[j][i].icon && filter.notIcon.indexOf(that.info[j][i].icon.type) != -1)) return false; if (!zot(filter.item) || !zot(filter.notItem)) { var itemList = that.getItems(i, j); if (!zot(filter.item)) { var noMatch = zim.loop(itemList, function(it) { if (filter.item.indexOf(it) != -1) return "yes"; }); // making it through the loop returns true and we are supposed to match something if (noMatch === true) return false; } if (!zot(filter.notItem)) { var match = zim.loop(itemList, function(it) { if (filter.notItem.indexOf(it) != -1) return "yes"; }); // we matched something and we are not supposed to if (match == "yes") return false; } } if (!zot(filter.col) && filter.col.indexOf(i - startCol) == -1) return fa