快捷搜索:  汽车  科技

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)前两种情况相对来说比较简单,但第三种情况在游戏中可能出现多种连线。两个拐角。在连连看中,能消除的情况只有以下三种。直线相连。一个拐角。

“连连看”这款经典小游戏想必九零后们都玩过,无论是在电脑上还是手机上,规则十分简单,就是将相同的方块连接起来消除,要求连接线不能大于3条,小编最近编写了一下这款经典小游戏,首先展示一下游戏界面:

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)(1)

解析:如何连线

连连看游戏的核心在于如何判断两个方块是相连的。这其实是一般游戏中寻路算法的一种,如何寻找从一个点到另一个点的最短路径,但是实现一个寻路算法的过程比较复杂,本文就不深入展开了。这里会使用另一种思路来寻找路径。

小编整理了一份java学习资料,私信回复【01】,获取源码。

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)(2)

在连连看中,能消除的情况只有以下三种。

直线相连。

一个拐角。

两个拐角。

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)(3)

前两种情况相对来说比较简单,但第三种情况在游戏中可能出现多种连线。

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)(4)

看似比较复杂,其实只需要先分别计算出两个方块在地图上 X 轴与 Y 轴上能直接联通的坐标,每个方块得到两个数组(X 轴与 Y 轴上能直接联通的点),然后对两个方块的 X 轴和 Y 轴的数组做一个比较运算,即可得到拐角所在的位置。

上面简单分析了一下连线基本的实现思路,下面开始写代码。

流程

生成地图

点击事件

获得连接线

绘制连接线

生成地图

第一件要干的事当然是随机生成一个地图。

game.vue

<template>

<div :class="currentTheme.name">

<table class="game" @click="handleClick">

<tr :key="row" v-for="(cols row) in cellData">

<cell :key="col" v-for="(cell col) in cols" :isSelected="cell.isSelected" :isLine="cell.isLine" :lineClass="cell.lineClass" :isBlank="cell.isBlank" :className="cell.className"></cell>

</tr>

</table>

</div>

</template>

<script>

import Cell from './cell'

import Utils from '../utils'

import config from '../config'

import themes from '../themes'

export default {

components: {

Cell

}

data () {

return {

cellData: [] // 地图数据数组

currentSelect: null // 当前选中的方块

config: Object.assign(config) // 配置信息

}

}

computed: {

currentTheme () {

// 当前theme

return themes.filter(e => e.name === this.config.defaultTheme)[0]

}

}

mounted () {

this.init()

}

methods: {

// ...

}

}

</script>

cell.vue

这里使用了一个空的 div 的 :before 和 :after 伪类来展示连接线

<template>

<td :class="classNames">

<div v-if="isLine" :class="lineClass"></div>

</td>

</template>

<script>

export default {

name: 'cell'

props: ['isSelected' 'isBlank' 'className' 'lineClass' 'isLine']

computed: {

classNames () {

return {

'selected': this.isSelected // 选中

'blank': this.isBlank // 空白

[this.className]: true

}

}

}

}

</script>

为了更好的对连连看的方块内容进行拓展,我们使用一个数组来装不同色块的 className,然后将对应的 className 放到色块上,通过 css 来控制色块的背景图片。

init(){

console.time('initData')

this.cellData=this.initData()

console.timeEnd('initData')

}

initData(){

// classNames => ['a' 'b' 'c' 'd'] 每个元素代表一个方块的className

// 生成一个方块的数组,将className放到其中letcellGroup=this.currentTheme.classNames.map(e=>{

return{

isBlank:false // 是否空白方块

className:e // 方块的className

lineClass:'' // 连接线的className

isLine:false // 是否显示连接线

isSelected:false

}

})

// 空白方块

letblankCell{

isBlank:true

className:''

lineClass:''

isLine:false

isSelected:false

}

// 先根据配置中的方块个数从方块数组中随机取出几条letrandomCellGroup=Utils.arrayRandom(cellGroup this.config.cellGroupCount)

// 再根据配置中的行和列随机填充一个地图数据letcellData=Utils.arrayFillByRandomGroup(this.config.row*this.config.col randomCellGroup)

// 将数据根据行的大小转为二维数组,然后外部包裹一层空白节点

/*

* Utils.dyadicArrayWrap

* Wrap a dyadic array by fill

* @params arr the source arr

* @params fill which to wrap source arr

*

* 0 0 0 0 0

* 1 1 1 0 1 1 1 0

* 1 1 1 => 0 1 1 1 0

* 1 1 1 0 1 1 1 0

* 0 0 0 0 0 */letresult=Utils.dyadicArrayWrap(Utils.arrayToDyadic(cellData this.config.col) blankCell)

// 最后把行和列的坐标设置到节点上

result.forEach((cols row)=>{

cols.forEach((cell col)=>{

cell.row=row

cell.col=col

})

})

returnresult

}

最后我们得到了一个地图数据的二维数组。

选取事件

接下来就是选取方块的事件了。

为了提高性能,没有将点击事件直接绑定到方块上,而是通过绑定在外层的 table 上,用事件代理来实现。这里也吐槽一下 Vue 目前是没有事件代理的,为了提高绑定的性能需要自己实现一个事件代理。

// 点击事件代理

handleClick(ev){

// 如果点击事件不是触发在方块上那么退出if(ev.target.nodeName!=='TD')return

// 获取点击方块的坐标,如果方块是空的那么退出letcol=ev.target.cellIndex

letrow=ev.target.parentNode.rowIndex

letcurrentCell=this.cellData[row[col]

if(currentCell.isBlank===true)return

this.selectCell(currentCell)

}

// 选择方块

selectCell(currCell){

if(!this.currentSelect){

// 如果没有选中任何方块那么就直接设置选中currCell.isSelected=true

this.currentSelect=currCellre

turn

}

if(this.currentSelect===currCell){

// 如果点击的方块和已选中方块是同一个,那么就取消这个方块的选中状态currCell.isSelected=false

this.currentSelect=null

return

}

letprevCell=this.currentSelect

// 通过className来判断前后两个方块的图片是否相同if(prevCell.className!==currCell.className){

// 如果两个方块的className不同,那么将点击的方块设置为选中状态prevCell.isSelected=false

currCell.isSelected=true

this.currentSelect=currCell

return

}

// 获取两个方块的连接线路径数组console.time('getLine')

letresult=this.getLine(prevCell currCell)

console.timeEnd('getLine')

if(result.length===0){

// 如果没有获取到连接线,说明两个方块无法连接,那么将点击的方块设置为选中状态prevCell.isSelected=false

currCell.isSelected=true

this.currentSelect=currCell

}else{

// 如果获取到连接线,那么将两个方块设置为空白方块prevCell.isBlank=true

currCell.isBlank=true

prevCell.className=''

currCell.className=''

prevCell.isSelected=false

currCell.isSelected=false

this.currentSelect=null

// 最后绘制连接线

this.drawLine(result)

}

}

选择的逻辑在这里就判断完毕了,接下来也是本文的核心,如何获得连接线路径。.

获得连接线

这个内容稍微有点长,分为几块来写。

首先描述一下在下文中多次提到的可连接线。

有没有java开发千行代码小游戏(小伙用Java开发经典小游戏连连看)(5)

在查找可连接线时,红色方块是需要查找的方块,黑色是其他方块,白色是空白方块,那么可以从红色方块开始向前与向后遍历得到一个可以达到的方块Set对象,也就是图中所有的白色方块。

getLine

获取连接线的入口

getLine(prev curr){

// 连接线数组

letresult=[]

// 一条直线连通的情况

// 分别获取上一个选中方块的X轴与Y轴上的可连接线,这里getHorizontalLine与getVerticalLine返回的均为一个Set对象,使用has来快速高效地判断在可连接线上是否包含某个方块letprevH=this.getHorizontalLine(prev)

letprevH=this.getHorizontalLine(prev)

if(prevH.has(curr))returnthis.getBeeline(prev curr)

letprevV=this.getVerticalLine(prev)

if(prevV.has(curr))returnthis.getBeeline(prev curr)

// 如果直线连通失败了,那么获取另一个方块的可连接线

letcurrH=this.getHorizontalLine(curr)

letcurrV=this.getVerticalLine(curr)

// 做一个快速判断,如果其中一个方块在X轴和Y轴上的可连接线长度都为0,那么返回空数组

if((!prevH.size&&!prevV.size)||(!currH.size&&!currV.size))returnresult

// 一个拐角可以连通的情况

// 分别对X轴和Y轴上的可连接线做一个交点判断

etintersection=this.getIntersection(prevH currV)||this.getIntersection(prevV currH)

以上为部分代码

声明:本文内容来源于网络,如有侵权请联系删除

猜您喜欢: