目录
项目源码:GitHub - Atopos-suyu/256game: 这是改编 的2048小游戏,为防止有人通关不成功,让他们体验下通关的满足感,写了256小游戏
2048设计稿:腾讯 CoDesign - 腾讯 CoDesign
项目源码:GitHub - Atopos-suyu/256game: 这是改编 的2048小游戏,为防止有人通关不成功,让他们体验下通关的满足感,写了256小游戏
2048设计稿:腾讯 CoDesign - 腾讯 CoDesign
页面效果展示:
游戏开始界面:
游戏结束页面:
游戏胜利页面:
实战需求:
1.游戏是一个4x4的方格,每个方格我们称作为一个Tile或者Cel。
2.游戏开始能随机出现2个Tile,每个的值90%可能为2,10%可能为4。
3.可以通过上、下、左、右键盘操作,每个Tle按照方向移动到不可移动为止。
4.如果移动以后两个Tile的内容值一样,则进行合并。
5.每个Tile移动会有100ms的移动动画。
6.每个Tile的出现有个短暂的放大效果。
7.每次Tile的合并有个短暂的放大回弹效果。
8.J顶部Score记录当前分数,BestScore记录有史以来最高
分,每次合并都会产生分数的变化,分数计算规则为:分数
=原来分数+合并后的值。
9.游戏将时时刻刻记录进度,刷新页面重现游戏进度。
10.当某个Tile的值为2048,游戏胜利。
11.当每个方格都有值,并且相邻两个方格无法再进行合并,则游戏结束。
实战技术知识点:
1.静态页面渲染:需要HTML、CSS基础知识,包括学习的SCSS知识。
2.开始游戏等事件处理:需要使用DOM监听事件。
3.Tle移动处理:需要监听键盘事件(暂时不处理H5中手势事件的情况)。
4.Tile动态随机添加:需要使用DOM动态操作。
5.Tile移动,合并:需要使用Javascript列表,对象,方法等数据结构和常用技巧。
6.Tile动画:需要使用CSS的transform和animation等动画效果。
7.本地缓存:需要使用Javascript localStorage浏览器缓存。
8…
静态页面开发
2048静态页面一:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>优课达-2048</title>
<link rel="stylesheet" href="./style/index.css" />
</head>
<body>
<div class="container">
<nav>...</nav>
<div class="desc">...</div>
<main>
<div class="game-grid">...</div>
<div class="tile-container">...</div>
</main>
<footer>...</footer>
</div>
</body>
</html>
整个页面的CSS文件较大,为了更加清晰的理解CSS文件。我们利用scss@import特性对文件进行分离,如下文件目录。
|-- images
|-- style
|-- index.scss // scss入口文件 + footer
|-- nav.scss // 头部区域文件
|-- main.scss // 主体区域文件
|-- desc.scss // 描述区域文件
|-- index.html
$field-width: 290px;
$grid-spacing: 10px;
$grid-row-cells: 4;
$tile-size: ($field-width - $grid-spacing * ($grid-row-cells + 1)) / $grid-row-cells;
$tile-border-radius: 3px;
main {
margin-top: 20px;
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
width: $field-width;
height: $field-width;
position: relative;
padding: $grid-spacing;
background: #bbada0;
border-radius: 8px;
.game-grid {
.grid-row {
.grid-cell {
}
}
}
}
静态页面二
为了方便以后Tile方块动态渲染,我们加入2、4、8到2048,11个方块静态页面,最终效果如下:
我们分析下其相同点和不同点:
1.它们都有一样的大小,圆角,动效。所以我们需要设置一个统一的class为tile
2.它们每个数字颜色和字体大小都不同,因此我们需要为每个值设置单独的样式,class为ti1e-(x)(x为2、4、8、16.2048)。
3.它们的位置可以总结为*行(roW),列(column),因此我们可以使用绝对定位进行布局class为title-position-(row)-(column)
4.每个元素都有移动(translate)和放缩(scale)动画,因为两个动画都是transform的一个属性,会出现冲突。因此我们将每个Tile分为外框tile和tile-inner两个部分,tile用于元素移动,title-inner用于元素放缩。
<div class="tile tile-2 tile-position-1-1">
<div class="tile-inner">2</div>
</div>
.tile-container {
position: absolute;
left: 0;
top: 0;
.tile {
position: absolute;
width: $tile-size;
height: $tile-size;
border-radius: 4px;
transition: transform 100ms ease-in-out;
}
.tile-inner {
width: 100%;
height: 100%;
line-height: $tile-size;
background: #eee4da;
text-align: center;
font-weight: bold;
font-size: 34px;
color: #776e65;
}
//通过scss的循环和变量,动态生成4行4列的Tile Position样式
@for $x from 1 through $grid-row-cells {
@for $y from 1 through $grid-row-cells {
.tile-position-#{$x}-#{$y} {
$xPos: $grid-spacing + floor(($tile-size + $grid-spacing) * ($y - 1));
$yPos: $grid-spacing + floor(($tile-size + $grid-spacing) * ($x - 1));
transform: translate($xPos, $yPos);
}
}
}
.tile.tile-2 .tile-inner {
background: #eee4da;
}
}
<div class="tile-container"><!--存放游戏中出现的小方块-->
<!-- <div class="tile tile-2 tile-position-1-1">
<div class="tile-inner">2</div>
</div>
<div class="tile tile-4 tile-position-1-2">
<div class="tile-inner">4</div>
</div>
<div class="tile tile-8 tile-position-1-3">
<div class="tile-inner">8</div>
</div>
<div class="tile tile-16 tile-position-1-4">
<div class="tile-inner">16</div>
</div>
<div class="tile tile-32 tile-position-2-1">
<div class="tile-inner">32</div>
</div>
<div class="tile tile-64 tile-position-2-2">
<div class="tile-inner">64</div>
</div>
<div class="tile tile-128 tile-position-2-3">
<div class="tile-inner">128</div>
</div>
<div class="tile tile-256 tile-position-2-4">
<div class="tile-inner">256</div>
</div>
<div class="tile tile-512 tile-position-3-1">
<div class="tile-inner">512</div>
</div>
<div class="tile tile-1024 tile-position-3-2">
<div class="tile-inner">1024</div>
</div>
<div class="tile tile-2048 tile-position-3-3">
<div class="tile-inner">2048</div>
</div> -->
</div>
main .tile-container {
position: absolute;
left: 0;
top: 0;
}
main .tile-container .tile {
position: absolute;
width: 60px;
height: 60px;
border-radius: 4px;
transition: transform 100ms ease-in-out;
}
main .tile-container .tile-inner {
width: 100%;
height: 100%;
line-height: 60px;
background: #eee4da;
text-align: center;
font-weight: bold;
font-size: 34px;
color: #776e65;
}
main .tile-container .tile-position-1-1 {
transform: translate(10px, 10px);
}
main .tile-container .tile-position-1-2 {
transform: translate(80px, 10px);
}
main .tile-container .tile-position-1-3 {
transform: translate(150px, 10px);
}
main .tile-container .tile-position-1-4 {
transform: translate(220px, 10px);
}
main .tile-container .tile-position-2-1 {
transform: translate(10px, 80px);
}
main .tile-container .tile-position-2-2 {
transform: translate(80px, 80px);
}
main .tile-container .tile-position-2-3 {
transform: translate(150px, 80px);
}
main .tile-container .tile-position-2-4 {
transform: translate(220px, 80px);
}
main .tile-container .tile-position-3-1 {
transform: translate(10px, 150px);
}
main .tile-container .tile-position-3-2 {
transform: translate(80px, 150px);
}
main .tile-container .tile-position-3-3 {
transform: translate(150px, 150px);
}
main .tile-container .tile-position-3-4 {
transform: translate(220px, 150px);
}
main .tile-container .tile-position-4-1 {
transform: translate(10px, 220px);
}
main .tile-container .tile-position-4-2 {
transform: translate(80px, 220px);
}
main .tile-container .tile-position-4-3 {
transform: translate(150px, 220px);
}
main .tile-container .tile-position-4-4 {
transform: translate(220px, 220px);
}
main .tile-container .tile-merged .tile-inner {
z-index: 20;
animation: pop 200ms ease 100ms;
animation-fill-mode: backwards;
}
main .tile-container .tile-new .tile-inner {
animation: appear 200ms ease-in-out;
animation-delay: 100ms;
animation-fill-mode: backwards;
}
main .tile-container .tile.tile-2 .tile-inner {
background: #eee4da;
}
main .tile-container .tile.tile-4 .tile-inner {
background: #ede0c8;
}
main .tile-container .tile.tile-8 .tile-inner {
color: #f9f6f2;
background: #f2b179;
}
main .tile-container .tile.tile-16 .tile-inner {
color: #f9f6f2;
background: #f59563;
}
main .tile-container .tile.tile-32 .tile-inner {
color: #f9f6f2;
background: #f67c5f;
}
main .tile-container .tile.tile-64 .tile-inner {
color: #f9f6f2;
background: #f65e3b;
}
main .tile-container .tile.tile-128 .tile-inner {
color: #f9f6f2;
background: #edcf72;
font-size: 30px;
}
main .tile-container .tile.tile-256 .tile-inner {
color: #f9f6f2;
background: #edcc61;
font-size: 30px;
}
main .tile-container .tile.tile-512 .tile-inner {
color: #f9f6f2;
background: #edc850;
font-size: 30px;
}
main .tile-container .tile.tile-1024 .tile-inner {
color: #f9f6f2;
background: #edc53f;
font-size: 22px;
}
main .tile-container .tile.tile-2048 .tile-inner {
color: #f9f6f2;
background: #edc22e;
font-size: 22px;
}