小游戏--2048
只用了HTML、CSS和JavaScript,代码纯手写,逻辑简单已实现,可以尝试自己动手做一下
目前代码是做了PC端的展示,没有做移动端的适配.滑动效果做的不太好,请见谅!
效果展示如下
代码展示如下
页面布局--HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="css/new.css" />
<script type="text/javascript" src="js/js.js" ></script>
</head>
<body>
<div id="continer">
<div id="header">
<h1 class="title">2048</h1>
<!--<h3 class="author">by lichong</h3>-->
<div id="">
<label>得分:</label><span id="score">0</span>
<button id="newGame">newGame</button>
</div>
</div>
<div id="footer">
<div id="mask">
<h3>当前得分为:</h3>
<label id="nowScore"></label> <br />
<button id="again">重新开始</button>
</div>
<div id="mask-cell-0-0" class="mask-cell"></div>
<div id="mask-cell-0-1" class="mask-cell"></div>
<div id="mask-cell-0-2" class="mask-cell"></div>
<div id="mask-cell-0-3" class="mask-cell"></div>
<div id="mask-cell-1-0" class="mask-cell"></div>
<div id="mask-cell-1-1" class="mask-cell"></div>
<div id="mask-cell-1-2" class="mask-cell"></div>
<div id="mask-cell-1-3" class="mask-cell"></div>
<div id="mask-cell-2-0" class="mask-cell"></div>
<div id="mask-cell-2-1" class="mask-cell"></div>
<div id="mask-cell-2-2" class="mask-cell"></div>
<div id="mask-cell-2-3" class="mask-cell"></div>
<div id="mask-cell-3-0" class="mask-cell"></div>
<div id="mask-cell-3-1" class="mask-cell"></div>
<div id="mask-cell-3-2" class="mask-cell"></div>
<div id="mask-cell-3-3" class="mask-cell"></div>
</div>
</div>
</body>
</html>
页面的渲染--CSS
*{
margin: 0px;
padding: 0px;
}
#continer{
border: 1px solid black;
width: 500px;
margin: 0 auto;
text-align: center;
background-color: #8E8E38
}
#header .author{
margin-left: 200px;
padding: 20px 0 ;
}
#header label,span{
position: relative;
left: -130px;
text-align: left;
font-size: 20px;
border-radius: 2px;
background-color:blueviolet;
}
#header label{
margin-right: 0px;
}
#newGame{
position: relative;
right: -130px;
font-size: 20px;
border-radius: 4px;
border: 1px solid;
background-color: blueviolet;
}
#footer{
width: 500px;
height: 500px;
/*background-color: #655123;*/
position: relative;
}
#mask{
position: absolute;
width: 200px;
height: 300px;
top: 100px;
left: 150px;
z-index: 4;
border-radius: 10px;
text-align: center;
line-height: 100px;
background-color: #ff33cc;
visibility: hidden;
}
#nowScore{
padding: 20px;
margin: 10px;
font-size: 50px;
}
#again{
background-color: #ccff66;
padding: 10px 20px;
letter-spacing: 2px;
border: none;
border-radius: 5px;
}
#footer .mask-cell{
position: absolute;
width: 100px;
height: 100px;
border-radius: 6px;
}
逻辑层的实现--JS
//声明一个数组存放卡片上的数字
var nums = new Array();
//获取得分和newGame两个控件
var score = document.getElementById("score");
var newGames = document.getElementById("newGame");
//预加载
window.onload = function(){
//给newGame添加点击事件
document.getElementById("newGame").onclick = function(){
newGame();
document.getElementById("score").innerHTML = 0;
}
//给again添加点击事件
document.getElementById("again").onclick = function(){
newGame();
document.getElementById("score").innerHTML = 0;
document.getElementById("mask").style.visibility = "hidden";
}
document.getElementById("score").innerHTML = 0;
newGame();
}
function newGame(){
//初始化
init();
//初始化生成两个卡片
getOneNewNumber();
getOneNewNumber();
document.onkeydown = function(e){
//阻止window默认事件
e.preventDefault();
//获取按键的code值
var keyCode = e.keyCode;
/*
* 1.判断是否能向指定的方向移动
* 能>向左移动>更新视图>重新生成一个卡片
* 2.不能
* 游戏结束
*/
switch (keyCode){
case 37:
if(canMoveLeft()){
moveLeft();
updateView();
getOneNewNumber();
console.log("还剩下"+noZeroNum()+"个格子")
}
if(!noCanMove()){
gameOver();
}
break;
case 38:
if(canMoveUp()){
moveUp();
updateView();
getOneNewNumber();
console.log("还剩下"+noZeroNum()+"个格子")
}
if(!noCanMove()){
gameOver();
}
break;
case 39:
if(canMoveRight()){
moveRigth();
updateView();
getOneNewNumber();
console.log("还剩下"+noZeroNum()+"个格子")
}
if(!noCanMove()){
gameOver();
}
break;
case 40:
if(canMoveDown()){
moveDown();
updateView();
getOneNewNumber();
console.log("还剩下"+noZeroNum()+"个格子")
}
if(!noCanMove()){
gameOver();
}
break;
}
}
}
function init(){
//初始化布局
for(var i = 0;i<4;i++){
for(var j = 0;j<4;j++){
document.getElementById("mask-cell-"+i+"-"+j).style.top = i*120 + 20 + "px";
document.getElementById("mask-cell-"+i+"-"+j).style.left = j*120 + 20 + "px";
document.getElementById("mask-cell-"+i+"-"+j).style.backgroundColor = "yellowgreen"
}
}
//初始化创建16张数字卡片,放在原来的16个div上(定位)
for(var i = 0;i<4;i++){
for(var j = 0;j<4;j++){
var div = document.createElement("div")
div.setAttribute("id","number-cell-"+ i +"-"+ j );
div.setAttribute("class","number-cell" )
document.getElementById("footer").appendChild(div)
document.getElementById("number-cell-"+i+"-"+j).style.position = "absolute"
document.getElementById("number-cell-"+i+"-"+j).style.top = i*120 + 20 + "px";
document.getElementById("number-cell-"+i+"-"+j).style.left = j*120 + 20 + "px";
}
}
//初始化数字
for(var m = 0;m<4;m++){
nums[m] = new Array();
for(var n = 0;n<4;n++){
nums[m][n] = 0;
}
}
//动态更新布局
updateView();
}
/*
* 动态更新视图
*/
function updateView(){
for(var i = 0;i<4;i++){
for(var j = 0;j<4;j++){
var numberCell = document.getElementById("number-cell-"+ i +"-"+ j);
numberCell.innerText = "";
if(nums[i][j] == 0){
numberCell.style.width = 0 + "px";
numberCell.style.height = 0 + "px";
}else{
numberCell.style.width = 100 + "px";
numberCell.style.height = 100 + "px";
numberCell.style.textAlign = "center";
numberCell.style.fontSize = "50px"
numberCell.style.lineHeight = "100px"
/*
* 根据卡片上的数字不同,添加不同的背景颜色
*/
switch (nums[i][j]){
case 2:
numberCell.style.backgroundColor = "#ffff33";
break;
case 4:
numberCell.style.backgroundColor = "#ffcc33";
break;
case 8:
numberCell.style.backgroundColor = "#ff6633";
break;
case 16:
numberCell.style.backgroundColor = "#ff3333";
break;
case 32:
numberCell.style.backgroundColor = "#ff0033";
break;
case 64:
numberCell.style.backgroundColor = "#ccff66";
break;
case 128:
numberCell.style.backgroundColor = "#cc3399";
break;
case 256:
numberCell.style.backgroundColor = "#9933cc";
break;
case 512:
numberCell.style.backgroundColor = "#66ffff";
break;
case 1024:
numberCell.style.backgroundColor = "#6600cc";
break;
case 2048:
numberCell.style.backgroundColor = "#0066ff";
break;
default:
break;
}
numberCell.innerText = nums[i][j];
}
}
}
}
function getOneNewNumber(){
//声明一个数组.存放不为零的卡片,存放的内容 i*4+j
var numPosition = new Array();
//判断是否还有为零 的空间
if(noSpace(nums)){
return;
}
//找到数字为零的卡片的位置
for (var i = 0;i<4;i++) {
for (var j = 0;j<4;j++) {
if(nums[i][j] == 0){
numPosition.push(i*4+j);
}
}
}
//从不为零的数组中,随机选取一个,还原它的X,Y坐标,然后设置它的css样式,同时把它放进nums数组中
var random = numPosition[Math.floor(Math.random()*numPosition.length)];
var randX = Math.floor(random/4);
var randY = Math.floor(random%4);
var randNum = Math.random()>0.5?2:4;
console.log(numPosition);
document.getElementById("number-cell-"+randX+"-"+randY).style.borderRadius = "6px";
document.getElementById("number-cell-"+randX+"-"+randY).innerText = randNum;
document.getElementById("number-cell-"+randX+"-"+randY).style.textAlign = "center";
document.getElementById("number-cell-"+randX+"-"+randY).style.fontSize = "50px"
document.getElementById("number-cell-"+randX+"-"+randY).style.lineHeight = "100px"
switch (randNum){
case 2:
document.getElementById("number-cell-"+randX+"-"+randY).style.backgroundColor = "#ffff33";
break;
case 4:
document.getElementById("number-cell-"+randX+"-"+randY).style.backgroundColor = "#ffcc33";
break;
default:
break;
}
showAnimation(randX,randY);
nums[randX][randY] = randNum;
}
function noSpace(nums){
//判断是否还有不为零的卡片
for (var i = 0;i<4;i++) {
for (var j = 0;j<4;j++) {
if(nums[i][j] == 0){
return false;
}
}
}
return true;
}
//生成卡片上数字时的动画
function showAnimation(randX,randY,){
var lefts = randY*120 + 70;
var tops = randX*120 + 70;
var width = 0;
var height = 0;
var intervalId = setInterval(function(){
if(tops == (randX*120+20)){
clearInterval(intervalId);
return;
}else{
width += 2;
height += 2;
tops--;
lefts--;
document.getElementById("number-cell-"+randX+"-"+randY).style.width = width + "px";
document.getElementById("number-cell-"+randX+"-"+randY).style.height = height + "px";
document.getElementById("number-cell-"+randX+"-"+randY).style.top = tops + "px";
document.getElementById("number-cell-"+randX+"-"+randY).style.left = lefts + "px";
}
},5)
}
//如果上下左右都不能移动
function noCanMove(){
return canMoveLeft()||canMoveUp()||canMoveRight()||canMoveDown();
}
//游戏结束
function gameOver(){
setTimeout('document.getElementById("nowScore").innerHTML = document.getElementById("score").innerText',500)
setTimeout('document.getElementById("mask").style.visibility = "visible"',500)
document.onkeydown = null;
}
//获取卡片上数字为零的的数量
function noZeroNum(){
var num = 0;
for (var i = 0;i<4;i++) {
for (var j = 0;j<4;j++) {
if(nums[i][j] == 0){
num++;
}
}
}
return num;
}
//能否左移
function canMoveLeft(){
//有空余格
if(noZeroNum()>0){
return true;
}else{
//格子满了,判断相邻的各自是否有相同的
for (var i = 0;i<4;i++) {
for (var j = 1;j<4;j++) {
if(nums[i][j] == nums[i][j-1]){
return true;
}
}
}
}
return false;
}
//能都上移
function canMoveUp(){
//有空余格
if(noZeroNum()>0){
return true;
}else{
//格子满了,判断相邻的各自是否有相同的
for (var i = 1;i<4;i++) {
for (var j = 0;j<4;j++) {
if(nums[i][j] == nums[i-1][j]){
return true;
}
}
}
}
return false;
}
//能否右移
function canMoveRight(){
//有空余格
if(noZeroNum()>0){
return true;
}else{
//格子满了,判断相邻的各自是否有相同的
for (var i = 3;i>=0;i--) {
for (var j = 2;j>=0;j--) {
if(nums[i][j] == nums[i][j+1]){
return true;
}
}
}
}
return false;
}
//能否下移
function canMoveDown(){
//有空余格
if(noZeroNum()>0){
return true;
}else{
//格子满了,判断相邻的各自是否有相同的
for (var i = 2;i>=0;i--) {
for (var j = 3;j>=0;j--) {
if(nums[i][j] == nums[i+1][j]){
return true;
}
}
}
}
return false;
}
/*
* 判断卡片上数字相同时,能否叠加
* 由于是一个4x4的布局,
* 传过来四个参数,分别是两个卡片的坐标
* 如果两个坐标相差1,即相邻,则直接相加
* 如果两个坐标相差2,即 中间隔一个卡片,判断此 卡片上数字是否为零,是零则相加
* 如果两个坐标相差3,即中间隔两个卡片,这两个卡片上数字都为零,则相加
*/
function canAdd(i,j,k,l){
if(i == k){
if(l-j == 1){
return true;
}
if(l-j == 2){
return nums[i][j+1] == 0 ;
}
if(l-j == 3){
return nums[i][j+1] == 0 && nums[i][j+2] == 0;
}
}
if(j == l){
if(k-i == 1 ){
return true;
}
if(k-i == 2){
return nums[i+1][j] == 0;
}
if(k-i == 3){
return nums[i+1][j] == 0 && nums[i+2][j] == 0;
}
}
}
/*
* 左移
* 遍历nums二维数组,如果左边为零,直接位移
* ,如果相等,判断中间是否有间隔,没有则直接相加
*/
function moveLeft(){
for (var i = 0;i<4;i++) {
for(var j = 0;j<4;j++){
if(nums[i][j] != 0){
for(var k = 0;k<j;k++){
if(nums[i][k] == 0){
nums[i][k] = nums[i][j];
nums[i][j] = 0;
}
if(nums[i][k] == nums[i][j] ){
if(canAdd(i,k,i,j)){
nums[i][k] *= 2;
nums[i][j] = 0
var grade = document.getElementById("score").innerText;
grade = Number(grade);
grade += nums[i][k];
document.getElementById("score").innerHTML = grade;
}
}
}
}
}
}
}
function moveUp(){
for (var i = 0;i<4;i++) {
for(var j = 0;j<4;j++){
if(nums[i][j] != 0){
for(var k = 0;k<i;k++){
if(nums[k][j] == 0){
nums[k][j] = nums[i][j];
nums[i][j] = 0;
}
if(nums[k][j] == nums[i][j] ){
if(canAdd(k,j,i,j)){
nums[k][j] *= 2;
nums[i][j] = 0;
var grade = document.getElementById("score").innerText;
grade = Number(grade);
grade += nums[k][j];
document.getElementById("score").innerHTML = grade;
}
}
}
}
}
}
}
function moveRigth(){
for (var i = 3;i>=0;i--) {
for(var j = 3;j>=0;j--){
if(nums[i][j] != 0){
for(var k = 3;k>j;k--){
if(nums[i][k] == 0){
nums[i][k] = nums[i][j];
nums[i][j] = 0;
}
if(nums[i][k] == nums[i][j] ){
if(canAdd(i,j,i,k)){
nums[i][k] *= 2;
nums[i][j] = 0;
var grade = document.getElementById("score").innerText;
grade = Number(grade);
grade += nums[i][k];
document.getElementById("score").innerHTML = grade;
}
}
}
}
}
}
}
function moveDown(){
for (var i = 3;i>=0;i--) {
for(var j = 3;j>=0;j--){
if(nums[i][j] != 0){
for(var k = 3;k>i;k--){
if(nums[k][j] == 0){
nums[k][j] = nums[i][j];
nums[i][j] = 0;
}
if(nums[k][j] == nums[i][j] ){
if(canAdd(i,j,k,j)){
nums[k][j] *= 2;
nums[i][j] = 0;
var grade = document.getElementById("score").innerText;
grade = Number(grade);
grade += nums[k][j];
document.getElementById("score").innerHTML = grade;
}
}
}
}
}
}
}
逻辑层的实现用了最原始的js,如果采用jq,代码量可以少很多,并且滑动效果也可以做的更好,有兴趣的话可以尝试一下!