每个男孩都有一个游戏梦吧,本例简单讲述一款很火的游戏《2048》的制作。
本例参考地址:https://www.imooc.com/learn/76
游戏准备
1、游戏的逻辑(2048大家去玩一玩就知道逻辑了)
2、制作技术:Html,Css,Javascript,Jquery
3、美术
游戏架构
游戏代码
html代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>2048</title>
<link rel="stylesheet" type="text/css" href="css/index.css">
<script type="text/javascript" src="lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="js/support.js"></script>
<script type="text/javascript" src="js/animation.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</head>
<body>
<!-- 头部 -->
<header>
<h1>2048</h1>
<a href="javascript:newgame();" id="newgamebutton">New Game</a>
<p>score:<span id="score">0</span></p>
</header> <section id="grid-container">
<div class="grid-cell" id="grid-cell-0-0"></div>
<div class="grid-cell" id="grid-cell-0-1"></div>
<div class="grid-cell" id="grid-cell-0-2"></div>
<div class="grid-cell" id="grid-cell-0-3"></div>
<div class="grid-cell" id="grid-cell-1-0"></div>
<div class="grid-cell" id="grid-cell-1-1"></div>
<div class="grid-cell" id="grid-cell-1-2"></div>
<div class="grid-cell" id="grid-cell-1-3"></div>
<div class="grid-cell" id="grid-cell-2-0"></div>
<div class="grid-cell" id="grid-cell-2-1"></div>
<div class="grid-cell" id="grid-cell-2-2"></div>
<div class="grid-cell" id="grid-cell-2-3"></div>
<div class="grid-cell" id="grid-cell-3-0"></div>
<div class="grid-cell" id="grid-cell-3-1"></div>
<div class="grid-cell" id="grid-cell-3-2"></div>
<div class="grid-cell" id="grid-cell-3-3"></div> </section>
</body>
</html>
css代码:
/*头部*/
header {
margin: 0 auto;
width: 500px;
text-align: center;
} header h1 {
font-family: Arial;
font-size: 60px;
font-weight: bold;
} header #newgamebutton {
display: block;
margin: 20px auto; width: 100px;
padding: 10px;
background-color: #8f7a66; font-family: Arial;
color: white;
border-radius: 10px;
text-decoration: none;
} header #newgamebutton:hover {
background-color: #9f8b77;
} header p {
font-family: Arial;
font-size: 25px;
margin: 20px auto;
} /*格子*/
#grid-container {
width: 460px;
height: 460px;
padding: 20px; margin: 50px auto;
background-color: #bbada0; border-radius: 10px;
position: relative;
}
#grid-container .grid-cell {
width: 100px;
height: 100px;
border-radius: 6px;
background-color: #ccc0b3; position: absolute;
} #grid-container .number-cell {
border-radius: 6px; font-family: Arial;
font-weight: bold;
font-size: 60px;
line-height: 100px;
text-align: center; position: absolute;
}
js部分
底层js:
/* 底层支持js */ //获取格子距离顶部的距离
function getPosTop(i, j) {
return 20 + i * 120;
}
//获取格子距离左边的距离
function getPosLeft(i, j) {
return 20 + j * 120;
} //获取格子背景色
function getNumberBackgroundColor(number) {
switch (number) {
case 2:
return "#eee4da";
break;
case 4:
return "#ede0c8";
break;
case 8:
return "#f2b179";
break;
case 16:
return "#f59563";
break;
case 32:
return "#f67c5f";
break;
case 64:
return "#f65e3b";
break;
case 128:
return "#edcf72";
break;
case 256:
return "#edcc61";
break;
case 512:
return "#9c0";
break;
case 1024:
return "#33b5e5";
break;
case 2048:
return "#09c";
break;
case 4096:
return "#s6c";
break;
case 8192:
return "#93c";
break;
}
return "black";
} //获取格子文字色
function getNumberColor(number) {
if (number <= 4) {
return "#776e65";
}
return "white";
} // 判断格子是否有无空余
function nospace(board) {
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 4; col++) {
if (board[row][col] == 0) {
return false;
}
}
}
return true;
} //判断能否左移
function canMoveLeft(board) {
for (var i = 0; i < 4; i++) { for (var j = 1; j < 4; j++) {
if (board[i][j] != 0) { if (board[i][j-1] == 0 || board[i][j-1] == board[i][j]) {
// 左侧格子空 或 左侧盒子等于自己
return true;
}
}
}
}
return false;
} function canMoveRight(board) {
for (var i = 0; i < 4; i++) {
for (var j = 2; j >= 0; j--) {
if (board[i][j] != 0) {
if (board[i][j+1] == 0 || board[i][j+1] == board[i][j]) { return true;
}
}
}
}
return false;
} //判断能否上移
function canMoveUp(board) {
for (var j = 0; j < 4; j++) {
for (var i = 1; i < 4; i++) {
if (board[i][j] != 0) {
if (board[i-1][j] == 0 || board[i-1][j] == board[i][j]) { return true;
}
}
}
}
return false;
} function canMoveDown(board) {
for (var j = 0; j < 4; j++) {
for (var i = 2; i >= 0; i--) {
if (board[i][j] != 0) {
if (board[i+1][j] == 0 || board[i+1][j] == board[i][j]) { return true;
}
}
}
}
return false;
} // 判断水平方向上是否有障碍物
function noBlockHorizontal(row, col1, col2, board) {
for (var i = col1 + 1; i < col2; i++) {
if(board[row][i] != 0){
return false;
}
}
return true;
} // 判断垂直方向是否有障碍物
function noBlockVertical(col, row1, row2, board) {
for (var i = row1 + 1; i < row2; i++) {
if(board[i][col] != 0){
return false;
}
}
return true;
} function nomove(board) {
if(canMoveLeft(board)
|| canMoveRight(board)
|| canMoveUp(board)
|| canMoveDown(board))
return false;
return true;
}
动画js:
// 显示随机数字
function showNumberWithAnimation(randx, randy, randNumber) {
var numberCell = $("#number-cell-" + randx + "-" + randy);
numberCell.css("background-color", getNumberBackgroundColor(randNumber));
numberCell.css("color", getNumberColor(randNumber));
numberCell.text(randNumber); numberCell.animate({
width: "100px",
height: "100px",
top: getPosTop(randx, randy),
left: getPosLeft(randx, randy)
}, 50);
} // 显示移动动画
function showMoveAnimation(fromx, fromy, tox, toy){
var numberCell = $("#number-cell-" + fromx + "-" + fromy);
numberCell.animate({
top: getPosTop(tox, toy),
left: getPosLeft(tox, toy)
},200);
} function updateScore(score) {
$("#score").text(score);
}
逻辑js:
var board = new Array();//全局二维数组
var score = 0;//全局分数
var hasConflicted = new Array();//全局碰撞二维数组 //入口
$(document).ready(function() {
newgame();
}); //新游戏
function newgame() {
// 初始化棋盘格
init();
// 在随机两个各自生成数字
generateOneNumber();
generateOneNumber();
} // 初始化棋盘格
function init() { // 初始位子
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var gridCell = $("#grid-cell-" + i + "-" + j);
gridCell.css("top", getPosTop(i, j));
gridCell.css("left", getPosLeft(i, j));
}
} // 初始值
for (var i = 0; i < 4; i++) {
board[i] = new Array();
hasConflicted[i] = new Array();
for (var j = 0; j < 4; j++) {
board[i][j] = 0;
hasConflicted[i][j] = false;
}
} // 更新界面显示
updateBoardView(); score = 0;
updateScore(score); } // 更新界面显示
function updateBoardView() {
// 移除已有值的元素
$(".number-cell").remove(); for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
$("#grid-container").append("<div class='number-cell' id='number-cell-" + i + "-" + j + "'></div>");
var theNumberCell = $("#number-cell-" + i + "-" + j); if (board[i][j] == 0) {
theNumberCell.css("width", "0px");
theNumberCell.css("height", "0px");
theNumberCell.css("top", getPosTop(i, j) + 50);
theNumberCell.css("left", getPosLeft(i, j) + 50);
} else {
theNumberCell.css("width", "100px");
theNumberCell.css("height", "100px");
theNumberCell.css("top", getPosTop(i, j));
theNumberCell.css("left", getPosLeft(i, j));
theNumberCell.css("background-color", getNumberBackgroundColor(board[i][j]));
theNumberCell.css("color", getNumberColor(board[i][j]));
theNumberCell.text(board[i][j]); }
hasConflicted[i][j] = false;
}
}
} // 随机在格子中生成一个数
function generateOneNumber() { // 判断格子空间
if (nospace(board)) {
return false;
} // 随机一个位子 var randx = 0;
var randy = 0;
do {
randx = parseInt(Math.floor(Math.random() * 4));
randy = parseInt(Math.floor(Math.random() * 4));
if (board[randx][randy] == 0) break;
}
while(true); // 随机一个数
var randNumber = Math.random() < 0.5 ? 2 : 4 ; // 在随机位子显示随机数
board[randx][randy] = randNumber;
showNumberWithAnimation(randx, randy, randNumber); return true; } // 添加操作事件
$(document).keydown(function(event){
switch(event.keyCode) {
case 37: // left
if(moveLeft()) {
setTimeout("generateOneNumber()", 210);
setTimeout("isgameover()", 300);
}
console.log(board);
break;
case 38: // up
if(moveUp()) {
setTimeout("generateOneNumber()", 210);
setTimeout("isgameover()", 300);
}
break;
case 39: // right
if(moveRight()) {
setTimeout("generateOneNumber()", 210);
setTimeout("isgameover()", 300);
}
break;
case 40: // down
if(moveDown()) {
setTimeout("generateOneNumber()", 210);
setTimeout("isgameover()", 300);
}
break;
default: break;
}
return false;
}); function isgameover(){
if(nospace(board) && nomove(board)) {
gameover();
}
} function gameover(){
alert("gameover");
} // 左移
function moveLeft() {
// 判断能否左移
if(!canMoveLeft(board)) {
return false;
} for (var row = 0; row < 4; row++) {
for (var col = 1; col < 4; col++) {
if(board[row][col] != 0) { for (var k = 0; k < col; k++) {
// 左侧为0
if(board[row][k] == 0 && noBlockHorizontal(row, k, col, board)){
// move
showMoveAnimation(row, col, row, k);
board[row][k] = board[row][col];
board[row][col] = 0;
continue;
}
// 左侧等于自己
else if (board[row][ k] == board[row][col] && noBlockHorizontal(row, k, col, board) && !hasConflicted[row][k])
{
// move
showMoveAnimation(row, col, row, k); // add
board[row][k] += board[row][col];
board[row][col] = 0; score += board[row][k];
updateScore(score); hasConflicted[row][k] = true; continue;
}
}
}
}
} setTimeout("updateBoardView()", 200);
return true;
} // 右移
function moveRight() {
// 判断能否右移
if(!canMoveRight(board)) {
return false;
} for (var row = 0; row < 4; row++) {
for (var col = 2; col >= 0; col--) {
if(board[row][col] != 0) { for (var k = 3; k > col; k--) { if(board[row][k] == 0 && noBlockHorizontal(row, col, k, board)){
// move
showMoveAnimation(row, col, row, k);
board[row][k] = board[row][col];
board[row][col] = 0;
continue;
} else if (board[row][k] == board[row][col] && noBlockHorizontal(row, col, k, board) && !hasConflicted[row][k])
{
// move
showMoveAnimation(row, col, row, k); // add
board[row][k] += board[row][col];
board[row][col] = 0; score += board[row][k];
updateScore(score); hasConflicted[row][k] = true; continue;
}
}
}
}
} setTimeout("updateBoardView()", 200);
return true;
} // 上移
function moveUp() {
// 判断能否上移
if(!canMoveUp(board)) {
return false;
} for (var col = 0; col < 4; col++) {
for (var row = 1; row < 4; row++) { if(board[row][col] != 0) { for (var k = 0; k < row; k++) { if(board[k][col] == 0 && noBlockVertical(col, k, row, board)){
// move
showMoveAnimation(row, col, k, col);
board[k][col] = board[row][col];
board[row][col] = 0;
continue;
} else if (board[k][col] == board[row][col] && noBlockVertical(col, k, row, board) && !hasConflicted[k][col])
{
// move
showMoveAnimation(row, col, k, col); // add
board[k][col] += board[row][col];
board[row][col] = 0; score += board[k][col];
updateScore(score); hasConflicted[k][col] = true; continue;
}
}
}
}
} setTimeout("updateBoardView()", 200);
return true;
} // 下移
function moveDown() {
// 判断能否下移
if(!canMoveDown(board)) {
return false;
} for (var col = 0; col < 4; col++) { for (var row = 2; row >= 0; row--) {
if(board[row][col] != 0) { for (var k = 3; k > row; k--) { if(board[k][col] == 0 && noBlockVertical(col, row, k, board)){
// move
showMoveAnimation(row, col, k, col);
board[k][col] = board[row][col];
board[row][col] = 0;
continue;
} else if (board[k][col] == board[row][col] && noBlockVertical(col, row, k, board) && !hasConflicted[k][col])
{
// move
showMoveAnimation(row, col, k, col); // add
board[k][col] += board[row][col];
board[row][col] = 0; score += board[k][col]
updateScore(score); hasConflicted[k][col] = true;
continue;
}
}
}
}
} setTimeout("updateBoardView()", 200);
return true;
}
游戏展示
普通版地址:http://naughty7878.top/game/2048
优化版地址:http://naughty7878.top/game/2048plus
游戏优化
1、随机数的参数,怎么更加准确的找空空位,在随机空位中产生随机数
2、增加分数时,增加动画。
3、游戏结束时,动画结束
4、私人定制游戏,显示时:2-->小白,4-->实习生,8 -->程序猿,16-->项目经理
5、操作问题,怎么鼠标操作,触摸滑动操作
6、设备适配的问题,兼容手机等。