很多时候在学习或者尝试做游戏的时候总是会无疾而终,现在把自己的收获和做出来的示例记下来给自己一个督促吧。
平台环境: cocos2dx(3.8)+lua vs2012
基础的三消游戏是在一个二维空间上,放置不同的元素,通过滑动消除相邻的几个相同元素,来获得积分或过关。当然完整的上线项目会有很多玩法,像是一次消除多个会产生一个炸弹,或者地图上有各种的障碍,甚至有的游戏像best friends是通过连接临近相同元素来进行消除。
这次的一个小尝试期望做出的效果只是在一个二维的空间中,随机几种不同颜色的元素进行填充,接受玩家的滑动操作,能够检测相邻三个以上的相同元素进行消除,并且判断当无法有滑动消除的情况时,会随机交换几个元素的位置重新继续。暂时不包含其他的玩法。
我把整个三消流程分为四个状态:
在实现过程中,考虑到的一些核心的算法总共有三个:
根据玩家输入获得的两个相邻元素,判断交换位置后是否能够达到消除条件,lua代码实现如下:
function UIMainLayer:FunGetRowSameBlocks( row, col )
local ltabBlocks = {}
local block = self:FunGetBlock( row, col )
if not block then return {} end
table.insert( ltabBlocks, block )
for i = col - 1, 1, -1 do
if block:FunSameType( self:FunGetBlock( row, i ) ) then
table.insert( ltabBlocks, self:FunGetBlock( row, i ) )
else
break
end
end
for i = col + 1, NUM_COL do
if block:FunSameType( self:FunGetBlock( row, i ) ) then
table.insert( ltabBlocks, self:FunGetBlock( row, i ) )
else
break
end
end
return ltabBlocks
end
function UIMainLayer:FunGetColSameBlocks( row, col )
local ltabBlocks = {}
local block = self:FunGetBlock( row, col )
if not block then return {} end
table.insert( ltabBlocks, block )
for i = row - 1, 1, -1 do
if block:FunSameType( self:FunGetBlock( i, col ) ) then
table.insert( ltabBlocks, self:FunGetBlock( i, col ) )
else
break
end
end
for i = row + 1, NUM_ROW do
if block:FunSameType( self:FunGetBlock( i, col ) ) then
table.insert( ltabBlocks, self:FunGetBlock( i, col ) )
else
break
end
end
return ltabBlocks
end
-- 判断
local ltabRowSame1 = self:FunGetRowSameBlocks( block1.mvarRow, block1.mvarCol )
local ltabRowSame2 = self:FunGetRowSameBlocks( block2.mvarRow, block2.mvarCol )
local ltabColSame1 = self:FunGetColSameBlocks( block1.mvarRow, block1.mvarCol )
local ltabColSame2 = self:FunGetColSameBlocks( block2.mvarRow, block2.mvarCol )
if #ltabRowSame1 >= 3 or #ltabRowSame2 >= 3 or #ltabColSame1 >= 3 or #ltabColSame2 >= 3 then
-- 达到条件可以交换
else
-- 未达到
end
符合的条件如下所示,当如下相邻位置元素类型一样时,可以消除
判断逻辑如下:
function UIMainLayer:FunCheckIsFixCon3R2C( row, col )
-- 5 6
-- 3 4
-- 1 2
local ltabType = {}
for r = row, row + 2 do
for c = col, col + 1 do
table.insert( ltabType, self:FunGetBlock( r, c ):FunGetType() )
end
end
if not (ltabType[1] == ltabType[3] and ltabType[1] == ltabType[6]) then
if not (ltabType[1] == ltabType[4] and ltabType[1] == ltabType[5]) then
if not (ltabType[2] == ltabType[3] and ltabType[2] == ltabType[5]) then
if not (ltabType[1] == ltabType[4] and ltabType[1] == ltabType[6]) then
if not (ltabType[2] == ltabType[3] and ltabType[2] == ltabType[6]) then
if not (ltabType[2] == ltabType[4] and ltabType[2] == ltabType[5]) then
return false
end
end
end
end
end
end
return true
end
function UIMainLayer:FunCheckIsFixCon2R3C( row, col )
-- 4 5 6
-- 1 2 3
local ltabType = {}
for r = row, row + 1 do
for c = col, col + 2 do
table.insert( ltabType, self:FunGetBlock( r, c ):FunGetType() )
end
end
if not (ltabType[3] == ltabType[4] and ltabType[3] == ltabType[5]) then
if not (ltabType[2] == ltabType[4] and ltabType[2] == ltabType[6]) then
if not (ltabType[1] == ltabType[5] and ltabType[1] == ltabType[6]) then
if not (ltabType[2] == ltabType[3] and ltabType[2] == ltabType[4]) then
if not (ltabType[1] == ltabType[3] and ltabType[1] == ltabType[5]) then
if not (ltabType[1] == ltabType[2] and ltabType[1] == ltabType[6]) then
return false
end
end
end
end
end
end
return true
end
function UIMainLayer:FunCheckIsEnd()
for r = 1, NUM_ROW - 2 do
for c = 1, NUM_COL - 1 do
if self:FunCheckIsFixCon3R2C( r, c ) then
return false
end
end
end
for r = 1, NUM_ROW - 1 do
for c = 1, NUM_COL - 2 do
if self:FunCheckIsFixCon2R3C( r, c ) then
return false
end
end
end
return true
end
代码如下示:
function UIMainLayer:FunGetRandomGroups()
local lvarNum = MAX_RANDOM_GROUP_WHEN_END * 2
local ltabIndex = {}
while(#ltabIndex
local lvarIndex = math.random(1, NUM_ROW*NUM_COL)
local lvarIsIn = false
for k, v in pairs( ltabIndex ) do
if v == lvarIndex then
lvarIsIn = true
break
end
end
if not lvarIsIn then
table.insert( ltabIndex, lvarIndex )
end
end
local ltabBlocks = {}
for k, v in pairs( ltabIndex ) do
table.insert( ltabBlocks, self.mtabBlocks[math.floor((v-1)/NUM_COL)+1][(v-1)%NUM_COL+1])
end
return ltabBlocks
end
function UIMainLayer:FunRandomSwap()
local function SwapGroup( ltabBlocks, lvarCover )
for i = 1, MAX_RANDOM_GROUP_WHEN_END do
local block1 = ltabBlocks[i*2 - 1]
local block2 = ltabBlocks[i*2]
self.mtabBlocks[block2.mvarRow][block2.mvarCol] = lvarCover and block2 or block1
self.mtabBlocks[block1.mvarRow][block1.mvarCol] = lvarCover and block1 or block2
end
end
local ltabRandomBlocks = self:FunGetRandomGroups()
SwapGroup( ltabRandomBlocks, false )
if not self:FunCheckIsEnd() then
-- 交换位置
return
else
-- 仍然不符合
SwapGroup( ltabRandomBlocks, true )
end
end
这几天的尝试,实现了这个简单的三消demo,但是在玩法上并没有什么乐趣…
还有一个可能出现的问题如果总行,列比较少会造成如何随机都不能消除的bug,导致一直卡在第四个状态。
暂时到这里吧,有进一步完善的话后续添加。
完整的可玩demo和lua代码在此下载 。