使用JS实现2048小游戏

使用JS实现2048小游戏

 JS实现2048小游戏源码

效果图:

使用JS实现2048小游戏_第1张图片

 代码如下,复制即可使用:

(适用浏览器:360、FireFox、Chrome、Opera、傲游、搜狗、世界之窗. 不支持Safari、IE8及以下浏览器。)






使用JS实现2048小游戏







2048

by the原2048的灵感。

如何玩: 使用你的箭头键移动瓷砖。当两个瓦片相互滑动时,它们合并成一个!

最佳:
0
分数:
0
游戏结束

适用浏览器:360、FireFox、Chrome、Opera、傲游、搜狗、世界之窗. 不支持Safari、IE8及以下浏览器。

 reset.min.css

html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0}

style.css

@charset "UTF-8";
* {
  box-sizing: border-box;
}

a {
  color: #1B9AAA;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}
a:hover {
  color: #14727e;
}
a:focus, a:active {
  color: #0d4a52;
}

body,
html {
  position: relative;
  width: 100%;
  height: 100%;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  font-family: "Arvo", Helvetica, sans-serif;
  font-family: 12px;
  color: #555;
  background: #F8FFE5;
}

strong {
  font-weight: bold;
}

p {
  line-height: 1.6;
}

.inspired {
  margin-top: 1em;
  font-size: 0.9rem;
  color: #9a9a95;
}

header {
  color: #F8FFE5;
  text-align: center;
}
header span {
  display: inline-block;
  box-sizing: border-box;
  width: 4rem;
  height: 4rem;
  line-height: 4rem;
  margin: 0 0.4rem;
  background: #FFC43D;
}
header span:nth-of-type(2) {
  background: #EF476F;
}
header span:nth-of-type(3) {
  background: #1B9AAA;
}
header span:nth-of-type(4) {
  background: #06D6A0;
}

h1 {
  font-size: 2.2rem;
}

.directions {
  padding: 2rem;
  border-top: 1px solid #9a9a95;
  border-bottom: 1px solid #9a9a95;
}

.container {
  margin: 0 auto;
  padding-bottom: 3.5rem;
  -webkit-box-flex: 1;
      -ms-flex: 1;
          flex: 1;
  width: 100%;
  max-width: 550px;
  text-align: center;
}
header .container {
  padding: 0;
  padding: 2rem 4rem;
  max-width: 900px;
}

.scores {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
}

.score-container {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  margin: 1.8rem;
  font-size: 1.2rem;
  line-height: 1;
  color: #555;
}
.score-container.best-score {
  color: #9a9a95;
}

.score {
  margin-left: 1rem;
  position: relative;
  font-weight: bold;
  font-size: 1.5rem;
  vertical-align: middle;
  text-align: right;
}

.game {
  position: relative;
  margin: 0 auto;
  background: #9a9a95;
  padding: 7px;
  display: inline-block;
  border-radius: 3px;
  box-sizing: border-box;
}

.tile-container {
  border-radius: 6px;
  position: relative;
  width: 400px;
  height: 400px;
}

.tile, .background {
  display: block;
  color: #F8FFE5;
  position: absolute;
  width: 100px;
  height: 100px;
  box-sizing: border-box;
  text-align: center;
}

.background {
  z-index: 1;
  text-align: center;
  border: 7px solid #9a9a95;
  background-color: #F8FFE5;
}

.tile {
  opacity: 0;
  z-index: 2;
  background: #FFC43D;
  color: #F8FFE5;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  font-size: 1.8rem;
  align-items: center;
  -webkit-transition: 110ms ease-in-out;
  transition: 110ms ease-in-out;
  border-radius: 3px;
  border: 7px solid #9a9a95;
  box-sizing: border-box;
}
.tile--4 {
  background: #EF476F;
  color: #F8FFE5;
}
.tile--8 {
  background: #1B9AAA;
  color: #F8FFE5;
}
.tile--16 {
  background: #06D6A0;
  color: #F8FFE5;
}
.tile--32 {
  background: #f37694;
  color: #F8FFE5;
}
.tile--64 {
  background: #22c2d6;
  color: #F8FFE5;
}
.tile--128 {
  background: #17f8be;
  color: #F8FFE5;
}
.tile--256 {
  background: #ffd470;
  color: #F8FFE5;
}
.tile--512 {
  background: #eb184a;
  color: #F8FFE5;
}
.tile--1024 {
  background: #14727e;
  color: #F8FFE5;
}
.tile--2048 {
  background: #05a47b;
  color: #F8FFE5;
}
.tile--pop {
  -webkit-animation: pop 0.3s ease-in-out;
          animation: pop 0.3s ease-in-out;
  -webkit-animation-fill-mode: forwards;
          animation-fill-mode: forwards;
}
.tile--shrink {
  -webkit-animation: shrink 0.5s ease-in-out;
          animation: shrink 0.5s ease-in-out;
  -webkit-animation-fill-mode: forwards;
          animation-fill-mode: forwards;
}

.add {
  position: absolute;
  opacity: 0;
  left: 120%;
  top: 0;
  font-size: 1rem;
  color: #1B9AAA;
}
.add.active {
  -webkit-animation: add 0.8s ease-in-out;
          animation: add 0.8s ease-in-out;
}

@-webkit-keyframes add {
  0% {
    opacity: 1;
    top: 0;
  }
  100% {
    opacity: 0;
    top: -100%;
  }
}

@keyframes add {
  0% {
    opacity: 1;
    top: 0;
  }
  100% {
    opacity: 0;
    top: -100%;
  }
}
@-webkit-keyframes pop {
  0% {
    -webkit-transform: scale(0.5);
            transform: scale(0.5);
    opacity: 0;
  }
  90% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
    opacity: 1;
  }
  100% {
    -webkit-transform: scale(1);
            transform: scale(1);
    opacity: 1;
  }
}
@keyframes pop {
  0% {
    -webkit-transform: scale(0.5);
            transform: scale(0.5);
    opacity: 0;
  }
  90% {
    -webkit-transform: scale(1.1);
            transform: scale(1.1);
    opacity: 1;
  }
  100% {
    -webkit-transform: scale(1);
            transform: scale(1);
    opacity: 1;
  }
}
@-webkit-keyframes shrink {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
    opacity: 1;
  }
  100% {
    -webkit-transform: scale(0.9);
            transform: scale(0.9);
    opacity: 0.9;
  }
}
@keyframes shrink {
  0% {
    -webkit-transform: scale(1);
            transform: scale(1);
    opacity: 1;
  }
  100% {
    -webkit-transform: scale(0.9);
            transform: scale(0.9);
    opacity: 0.9;
  }
}
.end {
  opacity: 0;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  background: rgba(85, 85, 85, 0.9);
  color: white;
  font-size: 2rem;
  -webkit-transition: opacity 0.3s ease-in-out;
  transition: opacity 0.3s ease-in-out;
}
.end btn {
  margin-top: 1rem;
}
.end.active {
  opacity: 1;
  z-index: 1000;
}

.monkey {
  font-size: 3rem;
  margin: 1rem 0;
}

.btn {
  font-family: inherit;
  font-size: 1rem;
  border: none;
  background: #1B9AAA;
  letter-spacing: 1px;
  color: white;
  font-weight: 300;
  padding: 0.9em 1.5em;
  border-radius: 3px;
  border: 1px solid transparent;
  cursor: pointer;
}
.btn:hover {
  background-color: #14727e;
}
.btn:active {
  background-color: #0d4a52;
}
.btn:focus {
  box-shadow: 0 0 10px #0d4a52 inset;
  outline: none;
}

.not-recommended {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  margin-top: 3rem;
}
.not-recommended * + * {
  margin-left: 10px;
}
.not-recommended__item + .not-recommended__annotation:before {
  font-size: 30px;
  content: "?";
}
.not-recommended__item:hover + .not-recommended__annotation:before {
  content: "?";
}
.not-recommended__item:focus + .not-recommended__annotation:before {
  content: "?";
}
.not-recommended__item:active + .not-recommended__annotation:before {
  content: "?";
}

 index.js

'use strict';

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var game = null;
var bestScore = 0;
var scoreDiv = document.getElementById('score');
var bestScoreDiv = document.getElementById('bestScore');
var addDiv = document.getElementById('add');
var endDiv = document.getElementById('end');
var size = 4;
var nextId = 1;
var score = 0;

function initGame() {
  game = Array(size * size).fill(null); // 4 x 4 grid, represented as an array
  initBestScore();
}

function initBestScore() {
  bestScore = localStorage.getItem('bestScore') || 0;
  bestScoreDiv.innerHTML = bestScore;
}

function updateDOM(before, after) {
  var newElements = getNewElementsDOM(before, after);
  var existingElements = getExistingElementsDOM(before, after);
  var mergedTiles = getMergedTiles(after);
  removeElements(mergedTiles);
  drawGame(newElements, true);
  drawGame(existingElements);
}

function removeElements(mergedTiles) {
  for (var _iterator = mergedTiles, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
    var _ref;

    if (_isArray) {
      if (_i >= _iterator.length) break;
      _ref = _iterator[_i++];
    } else {
      _i = _iterator.next();
      if (_i.done) break;
      _ref = _i.value;
    }

    var tile = _ref;

    var _loop = function _loop() {
      if (_isArray2) {
        if (_i2 >= _iterator2.length) return 'break';
        _ref2 = _iterator2[_i2++];
      } else {
        _i2 = _iterator2.next();
        if (_i2.done) return 'break';
        _ref2 = _i2.value;
      }

      var id = _ref2;

      var currentElm = document.getElementById(id);
      positionTile(tile, currentElm);
      currentElm.classList.add('tile--shrink');
      setTimeout(function () {
        currentElm.remove();
      }, 100);
    };

    for (var _iterator2 = tile.mergedIds, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
      var _ref2;

      var _ret = _loop();

      if (_ret === 'break') break;
    }
  }
}

function getMergedTiles(after) {
  return after.filter(function (tile) {
    return tile && tile.mergedIds;
  });
}

function getNewElementsDOM(before, after) {
  var beforeIds = before.filter(function (tile) {
    return tile;
  }).map(function (tile) {
    return tile.id;
  });
  var newElements = after.filter(function (tile) {
    return tile && beforeIds.indexOf(tile.id) === -1;
  });
  return newElements;
}

function getExistingElementsDOM(before, after) {
  var beforeIds = before.filter(function (tile) {
    return tile;
  }).map(function (tile) {
    return tile.id;
  });
  var existingElements = after.filter(function (tile) {
    return tile && beforeIds.indexOf(tile.id) !== -1;
  });
  return existingElements;
}

function drawBackground() {
  var tileContainer = document.getElementById('tile-container');
  tileContainer.innerHTML = '';
  for (var i = 0; i < game.length; i++) {
    var tile = game[i];
    var tileDiv = document.createElement('div');
    var x = i % size;
    var y = Math.floor(i / size);
    tileDiv.style.top = y * 100 + 'px';
    tileDiv.style.left = x * 100 + 'px';

    tileDiv.classList.add("background");
    tileContainer.appendChild(tileDiv);
  }
}

function positionTile(tile, elm) {
  var x = tile.index % size;
  var y = Math.floor(tile.index / size);
  elm.style.top = y * 100 + 'px';
  elm.style.left = x * 100 + 'px';
}

function drawGame(tiles, isNew) {
  var tileContainer = document.getElementById('tile-container');
  for (var i = 0; i < tiles.length; i++) {
    var tile = tiles[i];
    if (tile) {
      if (isNew) {
        (function () {
          var tileDiv = document.createElement('div');
          positionTile(tile, tileDiv);
          tileDiv.classList.add('tile', 'tile--' + tile.value);
          tileDiv.id = tile.id;
          setTimeout(function () {
            tileDiv.classList.add("tile--pop");
          }, tile.mergedIds ? 1 : 150);
          tileDiv.innerHTML = '

' + tile.value + '

'; tileContainer.appendChild(tileDiv); })(); } else { var currentElement = document.getElementById(tile.id); positionTile(tile, currentElement); } } } } function gameOver() { if (game.filter(function (number) { return number === null; }).length === 0) { var sameNeighbors = game.find(function (tile, i) { var isRightSame = game[i + 1] && (i + 1) % 4 !== 0 ? tile.value === game[i + 1].value : false; var isDownSame = game[i + 4] ? tile.value === game[i + 4].value : false; if (isRightSame || isDownSame) { return true; } return false; }); return !sameNeighbors; } } function generateNewNumber() { // 0.9 probability of 2, 0.1 probability of 4 var p = Math.random() * 100; return p <= 90 ? 2 : 4; } function addRandomNumber() { // Adds either a 2 or a 4 to an empty position in the game array var emptyCells = game.map(function (_, index) { return index; }).filter(function (index) { return game[index] === null; }); if (emptyCells.length === 0) { return; } var newPos = emptyCells[Math.floor(Math.random() * emptyCells.length)]; var newObj = { id: nextId++, index: newPos, value: generateNewNumber() }; game.splice(newPos, 1, newObj); } function getIndexForPoint(x, y) { return y * size + x; } function reflectGrid(grid) { var reflectedGame = Array(size * size).fill(0); for (var row = 0; row < size; row++) { for (var col = 0; col < size; col++) { var index1 = getIndexForPoint(col, row); var index2 = getIndexForPoint(size - col - 1, row); reflectedGame[index1] = grid[index2]; } } return reflectedGame; } function rotateLeft90Deg(grid) { var rotatedGame = Array(size * size).fill(0); for (var row = 0; row < size; row++) { for (var col = 0; col < size; col++) { var index1 = getIndexForPoint(col, row); var index2 = getIndexForPoint(size - 1 - row, col); rotatedGame[index1] = grid[index2]; } } return rotatedGame; } function rotateRight90Deg(grid) { var rotatedGame = Array(size * size).fill(0); for (var row = 0; row < size; row++) { for (var col = 0; col < size; col++) { var index1 = getIndexForPoint(col, row); var index2 = getIndexForPoint(row, size - 1 - col); rotatedGame[index1] = grid[index2]; } } return rotatedGame; } /* For any cell whose neighbor to the right is empty, move that cell to the right. For any cell whose neighbor to the right is equal to the same value, combine the values together (e.g. 2+2 = 4) */ function shiftGameRight(gameGrid) { // reflect game grid var reflectedGame = reflectGrid(gameGrid); // shift left reflectedGame = shiftGameLeft(reflectedGame); // reflect back return reflectGrid(reflectedGame); } function shiftGameLeft(gameGrid) { var newGameState = []; var totalAdd = 0; // for rows for (var i = 0; i < size; i++) { // for columns var firstPos = 4 * i; var lastPos = size + 4 * i; var currentRow = gameGrid.slice(firstPos, lastPos); var filteredRow = currentRow.filter(function (row) { return row; }); for (var _iterator3 = filteredRow, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { var _ref3; if (_isArray3) { if (_i3 >= _iterator3.length) break; _ref3 = _iterator3[_i3++]; } else { _i3 = _iterator3.next(); if (_i3.done) break; _ref3 = _i3.value; } var row = _ref3; delete row.mergedIds; } for (var j = 0; j < filteredRow.length - 1; j++) { if (filteredRow[j].value === filteredRow[j + 1].value) { var sum = filteredRow[j].value * 2; filteredRow[j] = { id: nextId++, mergedIds: [filteredRow[j].id, filteredRow[j + 1].id], value: sum }; filteredRow.splice(j + 1, 1); score += sum; totalAdd += sum; } } while (filteredRow.length < size) { filteredRow.push(null); }; newGameState = [].concat(newGameState, filteredRow); } if (totalAdd > 0) { scoreDiv.innerHTML = score; addDiv.innerHTML = '+' + totalAdd; addDiv.classList.add('active'); setTimeout(function () { addDiv.classList.remove("active"); }, 800); if (score > bestScore) { localStorage.setItem('bestScore', score); initBestScore(); } } return newGameState; } function shiftGameUp(gameGrid) { var rotatedGame = rotateLeft90Deg(gameGrid); rotatedGame = shiftGameLeft(rotatedGame); return rotateRight90Deg(rotatedGame); } function shiftGameDown(gameGrid) { var rotatedGame = rotateRight90Deg(gameGrid); rotatedGame = shiftGameLeft(rotatedGame); return rotateLeft90Deg(rotatedGame); } var buttons = document.querySelectorAll(".js-restart-btn"); var length = buttons.length; for (var i = 0; i < length; i++) { if (document.addEventListener) { buttons[i].addEventListener("click", function () { newGameStart(); }); } else { buttons[i].attachEvent("onclick", function () { newGameStart(); }); }; }; document.addEventListener("keydown", handleKeypress); document.addEventListener('touchstart', handleTouchStart, false); document.addEventListener('touchmove', handleTouchMove, false); var xDown = null; var yDown = null; function handleTouchStart(evt) { xDown = evt.touches[0].clientX; yDown = evt.touches[0].clientY; }; function handleTouchMove(evt) { var prevGame = [].concat(game); if (!xDown || !yDown) { return; } var xUp = evt.touches[0].clientX; var yUp = evt.touches[0].clientY; var xDiff = xDown - xUp; var yDiff = yDown - yUp; if (Math.abs(xDiff) > Math.abs(yDiff)) { if (xDiff > 0) { game = shiftGameLeft(game); } else { game = shiftGameRight(game); } } else { if (yDiff > 0) { game = shiftGameUp(game); } else { game = shiftGameDown(game); } } game = game.map(function (tile, index) { if (tile) { return _extends({}, tile, { index: index }); } else { return null; } }); addRandomNumber(); updateDOM(prevGame, game); if (gameOver()) { setTimeout(function () { endDiv.classList.add('active'); }, 800); return; } xDown = null; yDown = null; }; function handleKeypress(evt) { var modifiers = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; var whichKey = event.which; var prevGame = [].concat(game); if (!modifiers) { event.preventDefault(); switch (whichKey) { case 37: game = shiftGameLeft(game); break; case 38: game = shiftGameUp(game); break; case 39: game = shiftGameRight(game); break; case 40: game = shiftGameDown(game); break; } game = game.map(function (tile, index) { if (tile) { return _extends({}, tile, { index: index }); } else { return null; } }); addRandomNumber(); updateDOM(prevGame, game); if (gameOver()) { setTimeout(function () { endDiv.classList.add('active'); }, 800); return; } } } function newGameStart() { document.getElementById('tile-container').innerHTML = ''; endDiv.classList.remove('active'); score = 0; scoreDiv.innerHTML = score; initGame(); drawBackground(); var previousGame = [].concat(game); addRandomNumber(); addRandomNumber(); updateDOM(previousGame, game); } newGameStart();

 如果有更好的方法或更多的功能,可以和我们大家一起分享哦,如有错误,欢迎联系我改正,非常感谢!!!

你可能感兴趣的:(JavaScript)