基于Vue.js的2048小游戏的实现
程序员文章站
2022-04-07 19:13:30
...
基于Vue.js的2048小游戏的实现
游戏规则
- 游戏盘内有16个方格,初始状态是有两个值为2或4的数字格
- 指定向↑ ↓ ← →方向滑动,则所有方块都会向该方向滑动
- 相碰撞的两个数字格的值相等则会将其合并
- 每次滑动都会在随机空位上生成一个值为2或4的数字格
- 若游戏盘的16个方格均被填满且无法移动,则判定为游戏失败
- 若有一数字格的值为8192,则游戏通关
一、准备工作
1. 项目结构
2. 入口组件App.vue
这一块没什么好说的,就是给游戏提供入口,由于想照顾兼容更多情况引入了vue-router。
我用到了SCSS主要是为了让css写起来简洁一点,为了好看点,个人习惯用到了苹方字体,可以不必在意。
<template>
<div id="app">
<router-view />
</div>
</template>
<style lang="scss">
@import "./assets/font/font.css";
body {
margin: 0;
font-family: "PingFang-RE", "Montserrat-RE", "Microsoft YaHei";
button,
input {
font-family: "PingFang-RE";
}
}
#app {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
3. 路由文件router -> index.js
这一块没什么好说的,主要是把组件引入进来应用到App里面的router-view
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
];
const router = new VueRouter({
routes,
});
export default router;
二、界面布局
1. 游戏盘背景 Background.vue
这里我用一个v-for循环把16个格子展现出来
background就是用的Grid布局,分成四行四列
<template>
<div class="background">
<div v-for="i of 16" :key="i" class="grid-cell"></div>
</div>
</template>
<script>
export default {};
</script>
<style lang="scss" scoped>
.background {
width: 365px;
height: 365px;
padding: 20px;
background-color: #bbada0;
border-radius: 10px;
display: grid;
grid-row-gap: 15px;
grid-column-gap: 15px;
grid-template-columns: repeat(4, 80px);
grid-template-rows: repeat(4, 80px);
.grid-cell {
width: 80px;
height: 80px;
border-radius: 5px;
background-color: #ccc0b3;
}
}
</style>
2. 游戏界面的头部信息
这里也相当简单,我用一个header标签包裹
<header>
<h1>2048</h1>
<button @click="init" class="init-button">New Game</button>
<p>
Score: <span>{{ score }}</span>
</p>
</header>
header {
h1 {
margin: 0;
font-size: 32px;
}
p {
margin: 0;
margin-top: 10px;
font-size: 16px;
span {
font-weight: bold;
}
}
}
.init-button {
width: 110px;
padding: 10px;
background-color: #8f7a66;
color: #fff;
border: none;
border-radius: 8px;
cursor: pointer;
outline: none;
font-size: 16px;
font-weight: bold;
&:hover {
background-color: #9f8a77;
}
}
3. 游戏界面主体的编写
用一个container包裹
mask是游戏通关或失败的遮罩
Background是背景以组件形式引入了的标签
number-cells是游戏的数字格子,transition-group是为了给这些格子加过渡动画,数字格我以数组形式存起来然后v-for逐个展示出来
<div class="container">
<div class="mask" v-if="success">
<h1>You win!</h1>
<button @click="init" class="init-button">Try again</button>
</div>
<div class="mask" v-if="gameover">
<h1>Game over!</h1>
<button @click="init" class="init-button">Try again</button>
</div>
<Background />
<div class="number-cells">
<transition-group name="appear">
<div
class="number-cell"
v-for="cell of numberCells"
:id="`c${cell.id}`"
:key="cell.id"
:style="
`
width: 80px;
height: 80px;
border-radius: 5px;
font-size: 32px;
font-weight: bold;
line-height: 80px;
color: #776e65;
position: absolute;
z-index: ${cell.num};
backgroundColor: ${cell.color};
top: ${getTop(cell)};
left: ${getLeft(cell)};
`
"
>
{{ cell.num }}
</div>
</transition-group>
</div>
</div>
container包裹了background,然后整个容器用margin来做水平居中
mask以container为基准做绝对定位,用top…等定位来拉伸展开
number-cell(数字格子)也是以container为基准做绝对定位,top和left的数值通过格子的数据结构计算出。
因为合并时可能会存在大数值的格子需要覆盖小数值的格子,所以以数值来作为z-index
然后就是用到了vue的transition以及CSS3的transition,前者是用来在DOM生成时的一个从无到有的动画,后者是数字格的滑动
.container {
width: 405px;
height: 405px;
margin: 20px auto;
position: relative;
.mask {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9999;
background: rgba(238, 228, 218, 0.5);
text-align: center;
h1 {
font-size: 60px;
font-weight: 700;
height: 60px;
line-height: 60px;
margin-top: 120px;
color: #776e65;
}
button {
margin-top: 30px;
}
}
.number-cells {
.number-cell {
transition: $transitionTime top, $transitionTime left;
// animation-fill-mode: backwards;
// animation: appear 200ms ease-in-out;
}
}
}
.appear-enter-active {
animation: appear 100ms ease-in-out;
}
.appear-leave-active {
transition: $transitionTime top, $transitionTime left;
}
@keyframes appear {
0% {
opacity: 0;
transform: scale(0);
}
50% {
opacity: 0;
transform: scale(0.5);
}
100% {
opacity: 1;
transform: scale(1);
}
}
getTop(cell) {
return `${20 + cell.y * 95}px`;
},
getLeft(cell) {
return `${20 + cell.x * 95}px`;
},
总结
后续将完善游戏的基本逻辑
上一篇: jsp el表达式无法正常显示解决方法
下一篇: 用java如何表白
推荐阅读
-
PHP基于php_imagick_st-Q8.dll实现JPG合成GIF图片的方法
-
.net core 实现基于 cron 表达式的任务调度
-
使用vue.js实现checkbox的全选和多个的删除功能
-
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
-
Android 实现抖音小游戏潜艇大挑战的思路详解
-
C#基于UDP实现的P2P语音聊天工具
-
基于ajax实现无刷新分页的方法
-
详解Vue.js基于$.ajax获取数据并与组件的data绑定
-
[开源]基于goapp+xterm实现webssh-网页上的SSH终端linux管理工具(golang)
-
基于jquery的时间段实现代码