超甜!我用 Vue+UniApp 写了款情侣专属飞行棋
大家好!我有个朋友用 Vue 连夜开发了一款情侣专属飞行棋小游戏,现在他俩每天晚上都要玩上三百回合,感情直接原地升温!今天就把这个超有趣的项目拆解开来,分享核心实现思路和关键代码,手把手教你打造专属情侣小游戏。
先看效果

游戏界面粉嫩可爱,棋盘随机生成,玩家轮流掷骰子,走到特定格子会触发甜蜜任务或者炸弹惩罚。女生走到任务格必须完成一个任务(比如“亲对方一下”),男生走到惩罚格也要接受挑战。终点还有神秘奖励哦~
技术栈
-
前端框架:Vue 2(其实Vue 3也通用) -
多端支持:UniApp(可打包成小程序或App) -
动画:CSS3 + JS定时器 -
状态管理:Vue组件内状态(简单项目无需Vuex)
核心实现
1. 页面布局
<!-- 游戏主体 --><viewclass="game-content"><!-- 棋盘容器 --><viewclass="chessboard-container"><viewclass="chessboard"><!-- 动态生成棋盘格子 --><blockv-for="(row, rowIndex) in checkerboard":key="rowIndex"><blockv-for="(cell, colIndex) in row":key="cell.id"><viewclass="cell":class="{ show: cell.pathNum > 0,start:cell.type==='start',end:cell.type==='end',task:cell.type==='task',warn:cell.type==='warn',trap:cell.type==='trap',normal:cell.type==='normal' }" :style="{ backgroundColor: cell.bgColor }"><viewv-if="cell.pathNum>0"><viewclass="image-container glowPulse"v-if="cell.type==='trap'"><cl-icontype="icon-bomb"size="30"color="#111"></cl-icon></view><viewclass="image-container scaleAnimation"v-if="cell.type==='task'"><cl-icontype="icon-qinglv"size="20"color="#ff758c"></cl-icon></view><viewclass="image-container pulse"v-if="cell.type==='warn'"><cl-icontype="icon-baojingshu"size="20"color="#f44336"></cl-icon></view><viewclass="image-container"v-if="cell.type==='start'"><cl-icontype="icon-qidian"size="50"color="#4CAF50"></cl-icon></view><viewclass="image-container"v-else-if="cell.type==='end'"><cl-icontype="icon-zhongdian"size="40"color="#FF5722"></cl-icon></view><viewv-elseclass="step"> {{ cell.pathNum }}</view></view></view></block></block></view><!-- 人物 --><viewclass="character man":style="[manStyle]"><imageclass="image"src="/static/images/fly/man.png"mode="aspectFill" /></view><viewclass="character woman":style="[womanStyle]"><imageclass="image"src="/static/images/fly/woman.png"mode="aspectFill" /></view></view><!-- 控制面板 --><viewclass="control-panel":class="{man:isCurrentPlayerMan,woman:!isCurrentPlayerMan}"><viewclass="dice-container":class="{ rolling: isRolling }" @click="rollDice"><cl-diceref="flyDice" @result="getDiceData":size="100"backgroundColor="#ff758c"></cl-dice></view><viewclass="operateBtn"><viewclass="reload-btn" @click="reloadBoard"><cl-icontype="icon-shuaxin"size="26"color="#fff"class="icon" /><text>刷新棋盘</text></view><viewclass="player-turn"><text>{{ isCurrentPlayerMan? '男生' : '女生' }}回合</text></view></view></view></view>
棋盘容器是一个白色半透明的卡片,内边距10rpx,圆角16px,带内阴影,模拟纸张质感。里面用CSS Grid布局实现7×7的格子:
.chessboard {display: grid;grid-template-columns: repeat(7, 1fr);gap: 10rpx;margin: 0 auto;position: relative;}
每个格子(.cell)高100rpx,圆角10px,默认是柔和的粉色系(#FFF0E6)。根据格子类型(起点、终点、任务、陷阱等),背景色和图标会变化:
-
起点(绿色, icon-qidian) -
终点(橙色, icon-zhongdian) -
任务(粉色,爱心图标,带缩放动画) -
惩罚(浅橙色,警告图标,带脉冲光效) -
炸弹(深粉色,炸弹图标,带忽明忽暗的呼吸效果)
每个格子右下角还显示路径序号(pathNum),方便玩家知道当前走到第几步,细节拉满。
角色头像是绝对定位的两个圆形头像(男生蓝色渐变,女生粉色渐变),它们通过top和left属性动态定位到对应格子,并且移动时有平滑的CSS过渡(transition: all 0.5s ease-in-out)。这里用了一个小技巧:格子尺寸是calc(100%/7 * 坐标),这样无论屏幕大小,头像总能精准落在格子中央。
2. 棋盘生成算法
飞行棋的棋盘是个7×7的网格,我们需要生成一条连续且足够长的路径(至少30个格子),并随机分布任务、陷阱、惩罚点。
这里我用了DFS + 回溯 + 分支优先的策略,保证路径最长且不重复:
generateLongContinuousPath(size, minLength) {// 四个方向const directions = [[-1,0],[1,0],[0,-1],[0,1]];const visited = Array(size).fill().map(() => Array(size).fill(false));const path = [];// 随机起点let row = Math.floor(Math.random() * size);let col = Math.floor(Math.random() * size);path.push([row, col]);visited[row][col] = true;// 回溯栈和分支点记录const stack = [[row, col]];const branchPoints = [];while (path.length < minLength) {const current = stack[stack.length - 1];const possibleMoves = [];// 找出所有未访问的相邻格子,并计算分支数directions.forEach(dir => {const newRow = current[0] + dir[0];const newCol = current[1] + dir[1];if (newRow>=0 && newRow<size && newCol>=0 && newCol<size && !visited[newRow][newCol]) {// 计算这个格子还有几个未访问邻居(分支数)const branches = directions.filter(d => {const r = newRow + d[0], c = newCol + d[1];return r>=0 && r<size && c>=0 && c<size && !visited[r][c];}).length;possibleMoves.push({ coord: [newRow, newCol], branches });}});// 按照分支数排序,优先走分支多的(贪心)possibleMoves.sort((a,b) => b.branches - a.branches);if (possibleMoves.length > 0) {const next = possibleMoves[0].coord;path.push(next);visited[next[0]][next[1]] = true;stack.push(next);branchPoints.push([...stack]); // 记录分支点} else {// 无路可走,回溯stack.pop();if (stack.length === 0) {// 从最近的分支点重新开始const newStart = branchPoints.pop();if (!newStart) return null;stack.length = 0;stack.push(...newStart);path.length = newStart.length;} else {path.pop();}}}return path;}
生成路径后,再随机把中间的一些格子设为 task(任务)、warn(惩罚)、trap(炸弹)。炸弹格子会让玩家直接回到起点,刺激吧?
3. 玩家移动与动画
两个玩家(男生和女生)各自有一个位置对象,包含当前坐标、下一个格子坐标、缩放旋转等动画参数。移动时使用 setTimeout 逐步移动,配合CSS过渡实现平滑动画:
async move(playerData, moveNum) {this.isRolling = true;for (let i = 0; i < moveNum; i++) {if (this.gameOver) break;this.moveNext(playerData);// 播放音效this.playMusic();await this.sleep(700); // 每一步等待0.7秒}// 移动结束后检查格子类型const targetCell = this.checkerboard[playerData.top][playerData.left];if (targetCell.type === 'task') {this.showTask = true; // 弹出任务框} else if (targetCell.type === 'trap') {// 炸弹:回到原点this.resetUserData(this.srcCell, playerData, 3, 360, 1.5);this.playMusic('boom');}// ... 切换回合}
注意这里用了 async/await 配合 sleep,让每一步移动都有节奏感。
4. 骰子组件
骰子是自己封装的一个小组件 cl-dice (之前文章有介绍过),通过 startRolling 方法触发随机动画,完成后通过 @result 事件返回点数。为了真实感,我还加上了掷骰子的音效。
<cl-diceref="flyDice" @result="getDiceData":size="100"backgroundColor="#ff758c"></cl-dice>
在父组件中监听结果,然后触发移动。
5. 任务系统
任务数据是外置的,可以灵活切换不同版本(甜蜜版、羞羞版、18禁版)。任务弹窗 cl-fly-task 接收任务内容,用户可以选择“完成”或“未完成”,然后根据选择奖励或惩罚步数。
handleTaskResult(isCompleted) {const steps = isCompleted ? Math.floor(Math.random()*3)+1 : Math.floor(Math.random()*3)+3;this.move(this.manTask ? this.manData : this.womanData, steps, true, false);this.showTask = false;}
完成任务就少走几步,没完成就多走几步,增加博弈趣味。
6.自定义你的版本
你可以轻松修改任务列表,在 data/flyTask.js 中添加自己的版本:
export const taskMap = {'sweet': {version: '甜蜜版',tasks: ['亲对方一下', '说一句情话', '喂对方一颗糖']},'hot': {version: '火热版',tasks: ['拥抱10秒', '挠痒痒', '真心话']}}
甚至可以在设置界面动态切换版本,满足不同场合需求。
写在最后
这个小小的情侣飞行棋项目,不仅让朋友的日常充满乐趣,也很好地实践了 Vue 组件化开发、算法设计和动效实现。技术的价值不仅在于完成功能,更在于创造美好和快乐~
如果你也想为另一半打造专属小游戏,这个项目绝对值得一试!遇到任何问题,欢迎在评论区交流探讨。
想要获取完整源码的,公众号发送:情侣飞行棋 ,后面我整理了会一一发给大家。
互动时间:
你和另一半尝试过哪些有趣的情侣游戏?
如果是你,会在飞行棋里加入什么专属任务?
夜雨聆风
