提交 75195630 编写于 作者: 6 630d14904d78574832a7080b

修改

上级 b8245353
......@@ -360,45 +360,7 @@
choose_count: function (numData) {
let operation = operateMap[numData] || operateMap.defalut
operation.call(this, numData)
// if (numData == 'C') {
// this.result = ""
// this.countView = ""
// } else if (numData == 'CE') {
// this.result = 0
// this.countView = ""
// } else if (numData == 'Del') {
// var str = this.result + ""
// this.result = str.substring(0, str.length - 1)
// }
// // else if (this.result == 0) {
// // this.result = numData
// // }
// else if (numData == '+/-') {
// this.result = this.result.charAt(0) === '-' ? this.result.slice(1) : `-${this.result}`
// } else if (numData == '%') {
// this.result = `${parseFloat(this.result) / 100}`
// } else if (numData == '1/x') {
// if (this.result == 0) {
// this.countView = parseInt(1) + '/' + '(' + parseFloat((this.result)) + ')'
// this.result = '除数不能为0'
// } else {
// this.countView = parseInt(1) + '/' + '(' + parseFloat((this.result)) + ')'
// this.result = `${parseInt(1) / parseFloat((this.result))}`
// }
// } else if (numData == 'x*x') {
// this.countView = 'sqr(' + parseFloat(this.result) + ')'
// this.result = `${parseFloat(this.result) * parseFloat(this.result)}`
// } else if (numData == 'sqrt(x)') {
// this.countView = 'sqrt(' + parseFloat(this.result) + ')'
// this.result = Math.sqrt(parseFloat(this.result))
// } else {
// this.result += numData
// }
// },
// countnum: function () {
// this.countView = this.result
// this.result = eval(this.result)
}
},
}).mount("#app");
......
(function () {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] ||
window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function (callback) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function () {
callback(currTime + timeToCall);
},
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function (id) {
clearTimeout(id);
};
}
}());
// Wait till the browser is ready to render the game (avoids glitches)
window.requestAnimationFrame(function () {
new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager);
});
Function.prototype.bind = Function.prototype.bind || function (target) {
var self = this;
return function (args) {
if (!(args instanceof Array)) {
args = [args];
}
self.apply(target, args);
};
};
(function () {
if (typeof window.Element === "undefined" ||
"classList" in document.documentElement) {
return;
}
var prototype = Array.prototype,
push = prototype.push,
splice = prototype.splice,
join = prototype.join;
function DOMTokenList(el) {
this.el = el;
// The className needs to be trimmed and split on whitespace
// to retrieve a list of classes.
var classes = el.className.replace(/^\s+|\s+$/g, '').split(/\s+/);
for (var i = 0; i < classes.length; i++) {
push.call(this, classes[i]);
}
}
DOMTokenList.prototype = {
add: function (token) {
if (this.contains(token)) return;
push.call(this, token);
this.el.className = this.toString();
},
contains: function (token) {
return this.el.className.indexOf(token) != -1;
},
item: function (index) {
return this[index] || null;
},
remove: function (token) {
if (!this.contains(token)) return;
for (var i = 0; i < this.length; i++) {
if (this[i] == token) break;
}
splice.call(this, i, 1);
this.el.className = this.toString();
},
toString: function () {
return join.call(this, ' ');
},
toggle: function (token) {
if (!this.contains(token)) {
this.add(token);
} else {
this.remove(token);
}
return this.contains(token);
}
};
window.DOMTokenList = DOMTokenList;
function defineElementGetter(obj, prop, getter) {
if (Object.defineProperty) {
Object.defineProperty(obj, prop, {
get: getter
});
} else {
obj.__defineGetter__(prop, getter);
}
}
defineElementGetter(HTMLElement.prototype, 'classList', function () {
return new DOMTokenList(this);
});
})();
function GameManager(size, InputManager, Actuator, StorageManager) {
this.size = size; // Size of the grid
this.inputManager = new InputManager;
this.storageManager = new StorageManager;
this.actuator = new Actuator;
this.startTiles = 2;
this.inputManager.on("move", this.move.bind(this));
this.inputManager.on("restart", this.restart.bind(this));
this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
this.setup();
}
// Restart the game
GameManager.prototype.restart = function () {
this.storageManager.clearGameState();
this.actuator.continueGame(); // Clear the game won/lost message
this.setup();
};
// Keep playing after winning (allows going over 2048)
GameManager.prototype.keepPlaying = function () {
this.keepPlaying = true;
this.actuator.continueGame(); // Clear the game won/lost message
};
// Return true if the game is lost, or has won and the user hasn't kept playing
GameManager.prototype.isGameTerminated = function () {
return this.over || (this.won && !this.keepPlaying);
};
// Set up the game
GameManager.prototype.setup = function () {
var previousState = this.storageManager.getGameState();
// Reload the game from a previous game if present
if (previousState) {
this.grid = new Grid(previousState.grid.size,
previousState.grid.cells); // Reload grid
this.score = previousState.score;
this.over = previousState.over;
this.won = previousState.won;
this.keepPlaying = previousState.keepPlaying;
} else {
this.grid = new Grid(this.size);
this.score = 0;
this.over = false;
this.won = false;
this.keepPlaying = false;
// Add the initial tiles
this.addStartTiles();
}
// Update the actuator
this.actuate();
};
// Set up the initial tiles to start the game with
GameManager.prototype.addStartTiles = function () {
for (var i = 0; i < this.startTiles; i++) {
this.addRandomTile();
}
};
// Adds a tile in a random position
GameManager.prototype.addRandomTile = function () {
if (this.grid.cellsAvailable()) {
var value = Math.random() < 0.9 ? 2 : 4;
var tile = new Tile(this.grid.randomAvailableCell(), value);
this.grid.insertTile(tile);
}
};
// Sends the updated grid to the actuator
GameManager.prototype.actuate = function () {
if (this.storageManager.getBestScore() < this.score) {
this.storageManager.setBestScore(this.score);
}
// Clear the state when the game is over (game over only, not win)
if (this.over) {
this.storageManager.clearGameState();
} else {
this.storageManager.setGameState(this.serialize());
}
this.actuator.actuate(this.grid, {
score: this.score,
over: this.over,
won: this.won,
bestScore: this.storageManager.getBestScore(),
terminated: this.isGameTerminated()
});
};
// Represent the current game as an object
GameManager.prototype.serialize = function () {
return {
grid: this.grid.serialize(),
score: this.score,
over: this.over,
won: this.won,
keepPlaying: this.keepPlaying
};
};
// Save all tile positions and remove merger info
GameManager.prototype.prepareTiles = function () {
this.grid.eachCell(function (x, y, tile) {
if (tile) {
tile.mergedFrom = null;
tile.savePosition();
}
});
};
// Move a tile and its representation
GameManager.prototype.moveTile = function (tile, cell) {
this.grid.cells[tile.x][tile.y] = null;
this.grid.cells[cell.x][cell.y] = tile;
tile.updatePosition(cell);
};
// Move tiles on the grid in the specified direction
GameManager.prototype.move = function (direction) {
// 0: up, 1: right, 2: down, 3: left
var self = this;
if (this.isGameTerminated()) return; // Don't do anything if the game's over
var cell, tile;
var vector = this.getVector(direction);
var traversals = this.buildTraversals(vector);
var moved = false;
// Save the current tile positions and remove merger information
this.prepareTiles();
// Traverse the grid in the right direction and move tiles
traversals.x.forEach(function (x) {
traversals.y.forEach(function (y) {
cell = { x: x, y: y };
tile = self.grid.cellContent(cell);
if (tile) {
var positions = self.findFarthestPosition(cell, vector);
var next = self.grid.cellContent(positions.next);
// Only one merger per row traversal?
if (next && next.value === tile.value && !next.mergedFrom) {
var merged = new Tile(positions.next, tile.value * 2);
merged.mergedFrom = [tile, next];
self.grid.insertTile(merged);
self.grid.removeTile(tile);
// Converge the two tiles' positions
tile.updatePosition(positions.next);
// Update the score
self.score += merged.value;
// The mighty 2048 tile
if (merged.value === 2048) self.won = true;
} else {
self.moveTile(tile, positions.farthest);
}
if (!self.positionsEqual(cell, tile)) {
moved = true; // The tile moved from its original cell!
}
}
});
});
if (moved) {
this.addRandomTile();
if (!this.movesAvailable()) {
this.over = true; // Game over!
}
this.actuate();
}
};
// Get the vector representing the chosen direction
GameManager.prototype.getVector = function (direction) {
// Vectors representing tile movement
var map = {
0: { x: 0, y: -1 }, // Up
1: { x: 1, y: 0 }, // Right
2: { x: 0, y: 1 }, // Down
3: { x: -1, y: 0 } // Left
};
return map[direction];
};
// Build a list of positions to traverse in the right order
GameManager.prototype.buildTraversals = function (vector) {
var traversals = { x: [], y: [] };
for (var pos = 0; pos < this.size; pos++) {
traversals.x.push(pos);
traversals.y.push(pos);
}
// Always traverse from the farthest cell in the chosen direction
if (vector.x === 1) traversals.x = traversals.x.reverse();
if (vector.y === 1) traversals.y = traversals.y.reverse();
return traversals;
};
GameManager.prototype.findFarthestPosition = function (cell, vector) {
var previous;
// Progress towards the vector direction until an obstacle is found
do {
previous = cell;
cell = { x: previous.x + vector.x, y: previous.y + vector.y };
} while (this.grid.withinBounds(cell) &&
this.grid.cellAvailable(cell));
return {
farthest: previous,
next: cell // Used to check if a merge is required
};
};
GameManager.prototype.movesAvailable = function () {
return this.grid.cellsAvailable() || this.tileMatchesAvailable();
};
// Check for available matches between tiles (more expensive check)
GameManager.prototype.tileMatchesAvailable = function () {
var self = this;
var tile;
for (var x = 0; x < this.size; x++) {
for (var y = 0; y < this.size; y++) {
tile = this.grid.cellContent({ x: x, y: y });
if (tile) {
for (var direction = 0; direction < 4; direction++) {
var vector = self.getVector(direction);
var cell = { x: x + vector.x, y: y + vector.y };
var other = self.grid.cellContent(cell);
if (other && other.value === tile.value) {
return true; // These two tiles can be merged
}
}
}
}
}
return false;
};
GameManager.prototype.positionsEqual = function (first, second) {
return first.x === second.x && first.y === second.y;
};
function Grid(size, previousState) {
this.size = size;
this.cells = previousState ? this.fromState(previousState) : this.empty();
}
// Build a grid of the specified size
Grid.prototype.empty = function () {
var cells = [];
for (var x = 0; x < this.size; x++) {
var row = cells[x] = [];
for (var y = 0; y < this.size; y++) {
row.push(null);
}
}
return cells;
};
Grid.prototype.fromState = function (state) {
var cells = [];
for (var x = 0; x < this.size; x++) {
var row = cells[x] = [];
for (var y = 0; y < this.size; y++) {
var tile = state[x][y];
row.push(tile ? new Tile(tile.position, tile.value) : null);
}
}
return cells;
};
// Find the first available random position
Grid.prototype.randomAvailableCell = function () {
var cells = this.availableCells();
if (cells.length) {
return cells[Math.floor(Math.random() * cells.length)];
}
};
Grid.prototype.availableCells = function () {
var cells = [];
this.eachCell(function (x, y, tile) {
if (!tile) {
cells.push({ x: x, y: y });
}
});
return cells;
};
// Call callback for every cell
Grid.prototype.eachCell = function (callback) {
for (var x = 0; x < this.size; x++) {
for (var y = 0; y < this.size; y++) {
callback(x, y, this.cells[x][y]);
}
}
};
// Check if there are any cells available
Grid.prototype.cellsAvailable = function () {
return !!this.availableCells().length;
};
// Check if the specified cell is taken
Grid.prototype.cellAvailable = function (cell) {
return !this.cellOccupied(cell);
};
Grid.prototype.cellOccupied = function (cell) {
return !!this.cellContent(cell);
};
Grid.prototype.cellContent = function (cell) {
if (this.withinBounds(cell)) {
return this.cells[cell.x][cell.y];
} else {
return null;
}
};
// Inserts a tile at its position
Grid.prototype.insertTile = function (tile) {
this.cells[tile.x][tile.y] = tile;
};
Grid.prototype.removeTile = function (tile) {
this.cells[tile.x][tile.y] = null;
};
Grid.prototype.withinBounds = function (position) {
return position.x >= 0 && position.x < this.size &&
position.y >= 0 && position.y < this.size;
};
Grid.prototype.serialize = function () {
var cellState = [];
for (var x = 0; x < this.size; x++) {
var row = cellState[x] = [];
for (var y = 0; y < this.size; y++) {
row.push(this.cells[x][y] ? this.cells[x][y].serialize() : null);
}
}
return {
size: this.size,
cells: cellState
};
};
function HTMLActuator() {
this.tileContainer = document.querySelector(".tile-container");
this.scoreContainer = document.querySelector(".score-container");
this.bestContainer = document.querySelector(".best-container");
this.messageContainer = document.querySelector(".game-message");
this.score = 0;
}
HTMLActuator.prototype.actuate = function (grid, metadata) {
var self = this;
window.requestAnimationFrame(function () {
self.clearContainer(self.tileContainer);
grid.cells.forEach(function (column) {
column.forEach(function (cell) {
if (cell) {
self.addTile(cell);
}
});
});
self.updateScore(metadata.score);
self.updateBestScore(metadata.bestScore);
if (metadata.terminated) {
if (metadata.over) {
self.message(false); // You lose
} else if (metadata.won) {
self.message(true); // You win!
}
}
});
};
// Continues the game (both restart and keep playing)
HTMLActuator.prototype.continueGame = function () {
this.clearMessage();
};
HTMLActuator.prototype.clearContainer = function (container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
};
HTMLActuator.prototype.addTile = function (tile) {
var self = this;
var wrapper = document.createElement("div");
var inner = document.createElement("div");
var position = tile.previousPosition || { x: tile.x, y: tile.y };
var positionClass = this.positionClass(position);
// We can't use classlist because it somehow glitches when replacing classes
var classes = ["tile", "tile-" + tile.value, positionClass];
if (tile.value > 2048) classes.push("tile-super");
this.applyClasses(wrapper, classes);
inner.classList.add("tile-inner");
inner.textContent = tile.value;
if (tile.previousPosition) {
// Make sure that the tile gets rendered in the previous position first
window.requestAnimationFrame(function () {
classes[2] = self.positionClass({ x: tile.x, y: tile.y });
self.applyClasses(wrapper, classes); // Update the position
});
} else if (tile.mergedFrom) {
classes.push("tile-merged");
this.applyClasses(wrapper, classes);
// Render the tiles that merged
tile.mergedFrom.forEach(function (merged) {
self.addTile(merged);
});
} else {
classes.push("tile-new");
this.applyClasses(wrapper, classes);
}
// Add the inner part of the tile to the wrapper
wrapper.appendChild(inner);
// Put the tile on the board
this.tileContainer.appendChild(wrapper);
};
HTMLActuator.prototype.applyClasses = function (element, classes) {
element.setAttribute("class", classes.join(" "));
};
HTMLActuator.prototype.normalizePosition = function (position) {
return { x: position.x + 1, y: position.y + 1 };
};
HTMLActuator.prototype.positionClass = function (position) {
position = this.normalizePosition(position);
return "tile-position-" + position.x + "-" + position.y;
};
HTMLActuator.prototype.updateScore = function (score) {
this.clearContainer(this.scoreContainer);
var difference = score - this.score;
this.score = score;
this.scoreContainer.textContent = this.score;
if (difference > 0) {
var addition = document.createElement("div");
addition.classList.add("score-addition");
addition.textContent = "+" + difference;
this.scoreContainer.appendChild(addition);
}
};
HTMLActuator.prototype.updateBestScore = function (bestScore) {
this.bestContainer.textContent = bestScore;
};
HTMLActuator.prototype.message = function (won) {
var type = won ? "game-won" : "game-over";
var message = won ? "You win!" : "Game over!";
this.messageContainer.classList.add(type);
this.messageContainer.getElementsByTagName("p")[0].textContent = message;
};
HTMLActuator.prototype.clearMessage = function () {
// IE only takes one value to remove at a time.
this.messageContainer.classList.remove("game-won");
this.messageContainer.classList.remove("game-over");
};
function KeyboardInputManager() {
this.events = {};
if (window.navigator.msPointerEnabled) {
//Internet Explorer 10 style
this.eventTouchstart = "MSPointerDown";
this.eventTouchmove = "MSPointerMove";
this.eventTouchend = "MSPointerUp";
} else {
this.eventTouchstart = "touchstart";
this.eventTouchmove = "touchmove";
this.eventTouchend = "touchend";
}
this.listen();
}
KeyboardInputManager.prototype.on = function (event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
};
KeyboardInputManager.prototype.emit = function (event, data) {
var callbacks = this.events[event];
if (callbacks) {
callbacks.forEach(function (callback) {
callback(data);
});
}
};
KeyboardInputManager.prototype.listen = function () {
var self = this;
var map = {
38: 0, // Up
39: 1, // Right
40: 2, // Down
37: 3, // Left
75: 0, // Vim up
76: 1, // Vim right
74: 2, // Vim down
72: 3, // Vim left
87: 0, // W
68: 1, // D
83: 2, // S
65: 3 // A
};
// Respond to direction keys
document.addEventListener("keydown", function (event) {
var modifiers = event.altKey || event.ctrlKey || event.metaKey ||
event.shiftKey;
var mapped = map[event.which];
if (!modifiers) {
if (mapped !== undefined) {
event.preventDefault();
self.emit("move", mapped);
}
}
// R key restarts the game
if (!modifiers && event.which === 82) {
self.restart.call(self, event);
}
});
// Respond to button presses
this.bindButtonPress(".retry-button", this.restart);
this.bindButtonPress(".restart-button", this.restart);
this.bindButtonPress(".keep-playing-button", this.keepPlaying);
// Respond to swipe events
var touchStartClientX, touchStartClientY;
var gameContainer = document.getElementsByClassName("game-container")[0];
gameContainer.addEventListener(this.eventTouchstart, function (event) {
if ((!window.navigator.msPointerEnabled && event.touches.length > 1) ||
event.targetTouches.length > 1) {
return; // Ignore if touching with more than 1 finger
}
if (window.navigator.msPointerEnabled) {
touchStartClientX = event.pageX;
touchStartClientY = event.pageY;
} else {
touchStartClientX = event.touches[0].clientX;
touchStartClientY = event.touches[0].clientY;
}
event.preventDefault();
});
gameContainer.addEventListener(this.eventTouchmove, function (event) {
event.preventDefault();
});
gameContainer.addEventListener(this.eventTouchend, function (event) {
if ((!window.navigator.msPointerEnabled && event.touches.length > 0) ||
event.targetTouches.length > 0) {
return; // Ignore if still touching with one or more fingers
}
var touchEndClientX, touchEndClientY;
if (window.navigator.msPointerEnabled) {
touchEndClientX = event.pageX;
touchEndClientY = event.pageY;
} else {
touchEndClientX = event.changedTouches[0].clientX;
touchEndClientY = event.changedTouches[0].clientY;
}
var dx = touchEndClientX - touchStartClientX;
var absDx = Math.abs(dx);
var dy = touchEndClientY - touchStartClientY;
var absDy = Math.abs(dy);
if (Math.max(absDx, absDy) > 10) {
// (right : left) : (down : up)
self.emit("move", absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 2 : 0));
}
});
};
KeyboardInputManager.prototype.restart = function (event) {
event.preventDefault();
this.emit("restart");
};
KeyboardInputManager.prototype.keepPlaying = function (event) {
event.preventDefault();
this.emit("keepPlaying");
};
KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
var button = document.querySelector(selector);
button.addEventListener("click", fn.bind(this));
button.addEventListener(this.eventTouchend, fn.bind(this));
};
window.fakeStorage = {
_data: {},
setItem: function (id, val) {
return this._data[id] = String(val);
},
getItem: function (id) {
return this._data.hasOwnProperty(id) ? this._data[id] : undefined;
},
removeItem: function (id) {
return delete this._data[id];
},
clear: function () {
return this._data = {};
}
};
function LocalStorageManager() {
this.bestScoreKey = "bestScore";
this.gameStateKey = "gameState";
var supported = this.localStorageSupported();
this.storage = supported ? window.localStorage : window.fakeStorage;
}
LocalStorageManager.prototype.localStorageSupported = function () {
var testKey = "test";
try {
var storage = window.localStorage;
storage.setItem(testKey, "1");
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
};
// Best score getters/setters
LocalStorageManager.prototype.getBestScore = function () {
return this.storage.getItem(this.bestScoreKey) || 0;
};
LocalStorageManager.prototype.setBestScore = function (score) {
this.storage.setItem(this.bestScoreKey, score);
};
// Game state getters/setters and clearing
LocalStorageManager.prototype.getGameState = function () {
var stateJSON = this.storage.getItem(this.gameStateKey);
return stateJSON ? JSON.parse(stateJSON) : null;
};
LocalStorageManager.prototype.setGameState = function (gameState) {
this.storage.setItem(this.gameStateKey, JSON.stringify(gameState));
};
LocalStorageManager.prototype.clearGameState = function () {
this.storage.removeItem(this.gameStateKey);
};
function Tile(position, value) {
this.x = position.x;
this.y = position.y;
this.value = value || 2;
this.previousPosition = null;
this.mergedFrom = null; // Tracks tiles that merged together
}
Tile.prototype.savePosition = function () {
this.previousPosition = { x: this.x, y: this.y };
};
Tile.prototype.updatePosition = function (position) {
this.x = position.x;
this.y = position.y;
};
Tile.prototype.serialize = function () {
return {
position: {
x: this.x,
y: this.y
},
value: this.value
};
};
......@@ -5,6 +5,6 @@ apps:
run: npm i && npm run dev # 应用的启动命
command: # 使用此命令启动服务,且不执行run
root: ./ # 应用的启动目录
name: 2048 # 应用名称
name: Vue计算器 # 应用名称
description: 我的第一个 App。 # 应用描述
autoOpen: true # 打开工作空间时是否自动开启预览(优先级高于根级 autoOpen
此差异已折叠。
此差异已折叠。
此差异已折叠。
@font-face {
font-family: "Clear Sans";
src: url("ClearSans-Light-webfont.eot");
src: url("ClearSans-Light-webfont.eot?#iefix") format("embedded-opentype"),
url("ClearSans-Light-webfont.svg#clear_sans_lightregular") format("svg"),
url("ClearSans-Light-webfont.woff") format("woff");
font-weight: 200;
font-style: normal;
}
@font-face {
font-family: "Clear Sans";
src: url("ClearSans-Regular-webfont.eot");
src: url("ClearSans-Regular-webfont.eot?#iefix") format("embedded-opentype"),
url("ClearSans-Regular-webfont.svg#clear_sansregular") format("svg"),
url("ClearSans-Regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Clear Sans";
src: url("ClearSans-Bold-webfont.eot");
src: url("ClearSans-Bold-webfont.eot?#iefix") format("embedded-opentype"),
url("ClearSans-Bold-webfont.svg#clear_sansbold") format("svg"),
url("ClearSans-Bold-webfont.woff") format("woff");
font-weight: 700;
font-style: normal;
}
// Exponent
// From: https://github.com/Team-Sass/Sassy-math/blob/master/sass/math.scss#L36
@function exponent($base, $exponent) {
// reset value
$value: $base;
// positive intergers get multiplied
@if $exponent > 1 {
@for $i from 2 through $exponent {
$value: $value * $base; } }
// negitive intergers get divided. A number divided by itself is 1
@if $exponent < 1 {
@for $i from 0 through -$exponent {
$value: $value / $base; } }
// return the last value written
@return $value;
}
@function pow($base, $exponent) {
@return exponent($base, $exponent);
}
// Transition mixins
@mixin transition($args...) {
-webkit-transition: $args;
-moz-transition: $args;
transition: $args;
}
@mixin transition-property($args...) {
-webkit-transition-property: $args;
-moz-transition-property: $args;
transition-property: $args;
}
@mixin animation($args...) {
-webkit-animation: $args;
-moz-animation: $args;
animation: $args;
}
@mixin animation-fill-mode($args...) {
-webkit-animation-fill-mode: $args;
-moz-animation-fill-mode: $args;
animation-fill-mode: $args;
}
@mixin transform($args...) {
-webkit-transform: $args;
-moz-transform: $args;
-ms-transform: $args;
transform: $args;
}
// Keyframe animations
@mixin keyframes($animation-name) {
@-webkit-keyframes $animation-name {
@content;
}
@-moz-keyframes $animation-name {
@content;
}
@keyframes $animation-name {
@content;
}
}
// Media queries
@mixin smaller($width) {
@media screen and (max-width: $width) {
@content;
}
}
// Clearfix
@mixin clearfix {
&:after {
content: "";
display: block;
clear: both;
}
}
此差异已折叠。
@import "helpers";
@import "fonts/clear-sans.css";
$field-width: 500px;
$grid-spacing: 15px;
$grid-row-cells: 4;
$tile-size: ($field-width - $grid-spacing * ($grid-row-cells + 1)) / $grid-row-cells;
$tile-border-radius: 3px;
$mobile-threshold: $field-width + 20px;
$text-color: #776E65;
$bright-text-color: #f9f6f2;
$tile-color: #eee4da;
$tile-gold-color: #edc22e;
$tile-gold-glow-color: lighten($tile-gold-color, 15%);
$game-container-margin-top: 40px;
$game-container-background: #bbada0;
$transition-speed: 100ms;
html, body {
margin: 0;
padding: 0;
background: #faf8ef;
color: $text-color;
font-family: "Clear Sans", "Helvetica Neue", Arial, sans-serif;
font-size: 18px;
}
body {
margin: 80px 0;
}
.heading {
@include clearfix;
}
h1.title {
font-size: 80px;
font-weight: bold;
margin: 0;
display: block;
float: left;
}
@include keyframes(move-up) {
0% {
top: 25px;
opacity: 1;
}
100% {
top: -50px;
opacity: 0;
}
}
.scores-container {
float: right;
text-align: right;
}
.score-container, .best-container {
$height: 25px;
position: relative;
display: inline-block;
background: $game-container-background;
padding: 15px 25px;
font-size: $height;
height: $height;
line-height: $height + 22px;
font-weight: bold;
border-radius: 3px;
color: white;
margin-top: 8px;
text-align: center;
&:after {
position: absolute;
width: 100%;
top: 10px;
left: 0;
text-transform: uppercase;
font-size: 13px;
line-height: 13px;
text-align: center;
color: $tile-color;
}
.score-addition {
position: absolute;
right: 30px;
color: red;
font-size: $height;
line-height: $height;
font-weight: bold;
color: rgba($text-color, .9);
z-index: 100;
@include animation(move-up 600ms ease-in);
@include animation-fill-mode(both);
}
}
.score-container:after {
content: "Score";
}
.best-container:after {
content: "Best";
}
p {
margin-top: 0;
margin-bottom: 10px;
line-height: 1.65;
}
a {
color: $text-color;
font-weight: bold;
text-decoration: underline;
cursor: pointer;
}
strong {
&.important {
text-transform: uppercase;
}
}
hr {
border: none;
border-bottom: 1px solid lighten($text-color, 40%);
margin-top: 20px;
margin-bottom: 30px;
}
.container {
width: $field-width;
margin: 0 auto;
}
@include keyframes(fade-in) {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
// Styles for buttons
@mixin button {
display: inline-block;
background: darken($game-container-background, 20%);
border-radius: 3px;
padding: 0 20px;
text-decoration: none;
color: $bright-text-color;
height: 40px;
line-height: 42px;
}
// Game field mixin used to render CSS at different width
@mixin game-field {
.game-container {
margin-top: $game-container-margin-top;
position: relative;
padding: $grid-spacing;
cursor: default;
-webkit-touch-callout: none;
-ms-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-ms-touch-action: none;
touch-action: none;
background: $game-container-background;
border-radius: $tile-border-radius * 2;
width: $field-width;
height: $field-width;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
.game-message {
display: none;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba($tile-color, .5);
z-index: 100;
text-align: center;
p {
font-size: 60px;
font-weight: bold;
height: 60px;
line-height: 60px;
margin-top: 222px;
// height: $field-width;
// line-height: $field-width;
}
.lower {
display: block;
margin-top: 59px;
}
a {
@include button;
margin-left: 9px;
// margin-top: 59px;
&.keep-playing-button {
display: none;
}
}
@include animation(fade-in 800ms ease $transition-speed * 12);
@include animation-fill-mode(both);
&.game-won {
background: rgba($tile-gold-color, .5);
color: $bright-text-color;
a.keep-playing-button {
display: inline-block;
}
}
&.game-won, &.game-over {
display: block;
}
}
}
.grid-container {
position: absolute;
z-index: 1;
}
.grid-row {
margin-bottom: $grid-spacing;
&:last-child {
margin-bottom: 0;
}
&:after {
content: "";
display: block;
clear: both;
}
}
.grid-cell {
width: $tile-size;
height: $tile-size;
margin-right: $grid-spacing;
float: left;
border-radius: $tile-border-radius;
background: rgba($tile-color, .35);
&:last-child {
margin-right: 0;
}
}
.tile-container {
position: absolute;
z-index: 2;
}
.tile {
&, .tile-inner {
width: ceil($tile-size);
height: ceil($tile-size);
line-height: ceil($tile-size);
}
// Build position classes
@for $x from 1 through $grid-row-cells {
@for $y from 1 through $grid-row-cells {
&.tile-position-#{$x}-#{$y} {
$xPos: floor(($tile-size + $grid-spacing) * ($x - 1));
$yPos: floor(($tile-size + $grid-spacing) * ($y - 1));
@include transform(translate($xPos, $yPos));
}
}
}
}
}
// End of game-field mixin
@include game-field;
.tile {
position: absolute; // Makes transforms relative to the top-left corner
.tile-inner {
border-radius: $tile-border-radius;
background: $tile-color;
text-align: center;
font-weight: bold;
z-index: 10;
font-size: 55px;
}
// Movement transition
@include transition($transition-speed ease-in-out);
-webkit-transition-property: -webkit-transform;
-moz-transition-property: -moz-transform;
transition-property: transform;
$base: 2;
$exponent: 1;
$limit: 11;
// Colors for all 11 states, false = no special color
$special-colors: false false, // 2
false false, // 4
#f78e48 true, // 8
#fc5e2e true, // 16
#ff3333 true, // 32
#ff0000 true, // 64
false true, // 128
false true, // 256
false true, // 512
false true, // 1024
false true; // 2048
// Build tile colors
@while $exponent <= $limit {
$power: pow($base, $exponent);
&.tile-#{$power} .tile-inner {
// Calculate base background color
$gold-percent: ($exponent - 1) / ($limit - 1) * 100;
$mixed-background: mix($tile-gold-color, $tile-color, $gold-percent);
$nth-color: nth($special-colors, $exponent);
$special-background: nth($nth-color, 1);
$bright-color: nth($nth-color, 2);
@if $special-background {
$mixed-background: mix($special-background, $mixed-background, 55%);
}
@if $bright-color {
color: $bright-text-color;
}
// Set background
background: $mixed-background;
// Add glow
$glow-opacity: max($exponent - 4, 0) / ($limit - 4);
@if not $special-background {
box-shadow: 0 0 30px 10px rgba($tile-gold-glow-color, $glow-opacity / 1.8),
inset 0 0 0 1px rgba(white, $glow-opacity / 3);
}
// Adjust font size for bigger numbers
@if $power >= 100 and $power < 1000 {
font-size: 45px;
// Media queries placed here to avoid carrying over the rest of the logic
@include smaller($mobile-threshold) {
font-size: 25px;
}
} @else if $power >= 1000 {
font-size: 35px;
@include smaller($mobile-threshold) {
font-size: 15px;
}
}
}
$exponent: $exponent + 1;
}
// Super tiles (above 2048)
&.tile-super .tile-inner {
color: $bright-text-color;
background: mix(#333, $tile-gold-color, 95%);
font-size: 30px;
@include smaller($mobile-threshold) {
font-size: 10px;
}
}
}
@include keyframes(appear) {
0% {
opacity: 0;
@include transform(scale(0));
}
100% {
opacity: 1;
@include transform(scale(1));
}
}
.tile-new .tile-inner {
@include animation(appear 200ms ease $transition-speed);
@include animation-fill-mode(backwards);
}
@include keyframes(pop) {
0% {
@include transform(scale(0));
}
50% {
@include transform(scale(1.2));
}
100% {
@include transform(scale(1));
}
}
.tile-merged .tile-inner {
z-index: 20;
@include animation(pop 200ms ease $transition-speed);
@include animation-fill-mode(backwards);
}
.above-game {
@include clearfix;
}
.game-intro {
float: left;
line-height: 42px;
margin-bottom: 0;
}
.restart-button {
@include button;
display: block;
text-align: center;
float: right;
}
.game-explanation {
margin-top: 50px;
}
@include smaller($mobile-threshold) {
// Redefine variables for smaller screens
$field-width: 280px;
$grid-spacing: 10px;
$grid-row-cells: 4;
$tile-size: ($field-width - $grid-spacing * ($grid-row-cells + 1)) / $grid-row-cells;
$tile-border-radius: 3px;
$game-container-margin-top: 17px;
html, body {
font-size: 15px;
}
body {
margin: 20px 0;
padding: 0 20px;
}
h1.title {
font-size: 27px;
margin-top: 15px;
}
.container {
width: $field-width;
margin: 0 auto;
}
.score-container, .best-container {
margin-top: 0;
padding: 15px 10px;
min-width: 40px;
}
.heading {
margin-bottom: 10px;
}
// Show intro and restart button side by side
.game-intro {
width: 55%;
display: block;
box-sizing: border-box;
line-height: 1.65;
}
.restart-button {
width: 42%;
padding: 0;
display: block;
box-sizing: border-box;
margin-top: 2px;
}
// Render the game field at the right width
@include game-field;
// Rest of the font-size adjustments in the tile class
.tile .tile-inner {
font-size: 35px;
}
.game-message {
p {
font-size: 30px !important;
height: 30px !important;
line-height: 30px !important;
margin-top: 90px !important;
}
.lower {
margin-top: 30px !important;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册