其他
社区精选 | 数字华容道「思否猫版」
今天小编为大家带来的是社区作者wuwhs的文章,让我们一起来看看怎么利用思否猫素材实现一个丝滑的华容道吧。
背景
将面板划分 nxn 个方格,除了最后一格,每一个方格有一个滑块; 初始游戏会将滑块顺序打乱,空出最后一格; 空格相邻的滑块才可以滑动,并且只能滑倒空白格里; 将所有滑块按顺序拼接则游戏闯关成功;
实现基础布局
<section class="content">
<ul class="row" v-for="row in level" :key="row" :style="{width: `${appWidth}px`}">
<li class="col" v-for="col in level" :key="col" :style="{width: `${itemWidth}px`}">
<div
class="item"
:style="{
height: `${itemWidth}px`,
}"
>
{{row}}:{{col}}
</div>
</li>
</ul>
</section>
</div>
return {
appWidth: 600,
level: 3,
}
},
computed: {
itemWidth() {
return this.appWidth / this.level
},
},
实现方格块背景图
class="item"
:style="{
height: `${itemWidth}px`,
backgroundPosition: getBgPos(row, col)
}"
></div> return this.appWidth / this.level
},
},
getBgPos(row, col) {
const w = this.itemWidth
const { level } = this
const offsetX = ((col - 1) % level) * w
const offsetY = ((row - 1) % level) * w
return `-${offsetX}px -${offsetY}px`
},
background-color: #99a9bf;
background-repeat: no-repeat;
background-image: url('./issue.png');
overflow: hidden;
}
实现方格交换
响应式数组的数据结构定义成这样
{
index: 0, // 索引
bgPos: '0px 0px', // 背景图偏移量
isSpace: false // 是否是空白格
},
...{
index: 8, // 索引
bgPos: '-400px -400px', // 背景图偏移量
isSpace: true // 是否是空白格
}
]
在乱序数组的最后一项预留,作为相邻滑块交换空间,实现方式是复制一份有序数组(除去最后一项),然后插入一个空白项。其中空白项将背景图片移出可视区即可。
init() {
this.initOrigList()
this.initMessList()
},
// 初始化原始列表
initOrigList() {
const { level } = this
const list = []
for (let i = 0; i < level; i++) {
for (let j = 0; j < level; j++) {
list.push({
index: i * level + j,
bgPos: this.getBgPos(i + 1, j + 1),
isSpace: false
})
}
}
this.origList = list
},
// 初始化乱序列表
initMessList() {
// 除去最后一项的列表打乱
const list = this.sufflex(this.origList.slice(0, -1))
// 最后一项设置为空白:背景图片移出可视区
this.messList = [
...list,
{
index: Math.pow(this.level, 2) - 1,
bgPos: `-${this.appWidth}px`,
isSpace: true
}
]
},
sufflex(arr) {
const len = arr.length
const cards = [...arr]
let r = len - 1
while (r >= 0) {
const i = Math.floor(Math.random() * (r + 1))
;[cards[r], cards[i]] = [cards[i], cards[r]]
r--
}
return cards
},
class="item"
@click="handleMove(row, col)"
:style="{
height: `${itemWidth}px`,
backgroundPosition: getMessBgPos(row, col),
}"
></div>
handleMove(row, col) {
const targetPos = this.getNearbySpacePos(row - 1, col - 1)
if (!targetPos.length) return
this.changePos((row - 1) * this.level + col - 1, targetPos[0] * this.level + targetPos[1])
},
// 获取当前点击模块紧挨着的空白模块位置
// 如果有则可以移动:当前模块上下左右相邻模块有空白模块则可以移动
getNearbySpacePos(row, col) {
const { level, messList } = this
// 上
if (row > 0 && messList[(row - 1) * level + col].isSpace) return [row - 1, col]
// 下
if (row < level - 1 && messList[(row + 1) * level + col].isSpace) return [row + 1, col]
// 左
if (col > 0 && messList[row * level + col - 1].isSpace) return [row, col - 1]
// 右
if (col < level - 1 && messList[row * level + col + 1].isSpace) return [row, col + 1]
return []
},
// 交换位置
changePos(index, targetIndex) {
const temp = this.messList[index]
const targetTemp = this.messList[targetIndex]
this.$set(this.messList, targetIndex, temp)
this.$set(this.messList, index, targetTemp)
},
完善游戏功能
游戏开始和游戏结束开关; 游戏难度(nxn 中 n 越大,难度越大); 支持更换自己喜欢的背景图片; 游戏步数和用时记录;
活动预告:ADM十周年来啦!
腾讯Light与你一起共赴“兴”纪元~