【Daily Games——开发篇】:一个帅气的副本效果之翻牌兑换
不知不觉已经干了这么久了,看看我完成的界面吧。
一个帅气的翻牌匹配小游戏不是吗,涉及的内容是发牌,位置点确定,翻转匹配
翻转匹配是服务器的返回数据,但是本地同样可以抢先配对。
发牌代码如下:
服务器给的是点的位置,由于最多7*4列,服务器给的数据是3,7,11这样的数字
首先计算牌的位置最为重要,代码如下:
--子长度,子间距,子个数
function GetPos(width_item,width_cell,count)
local posx_table = {}
local x_len = width_item + width_cell
local num = math.floor(count/2)
local ys = count%2
if ys == 1 then
for i=0,num do
posx_table[num+1+i] = x_len*i
posx_table[num+1-i] = 0-x_len*i
end
else
for i=0,num-1 do
posx_table[num+1+i] = 0-x_len*i - width_cell/2 - width_item/2
posx_table[num-i] = x_len*i + width_cell/2 + width_item/2
end
end
return posx_table
end
--子长宽,子间距xy,规格,横着数的位置
function InitPosTable(i_w,i_h,c_x,c_y,l_x,l_y)
local table_x = GetPos(i_w,c_x,l_y)
local table_y = GetPos(i_h,c_y,l_x)
for i=1,l_x*l_y do
local x = i%l_y
if x == 0 then
x = l_y
end
local y = math.ceil(i/l_y)
local temp = {}
temp.posx = table_x[x]
temp.posy = table_y[y]
postable[i] = temp
end
end
只需要指定牌的大小和间距就可以了,原理计算按照原点开始的对称点计算。
每次翻牌判定要将其他牌设为不可按,当服务器返回匹配成功失败数据,raycast再设为true
整体代码如下:
local GameObject=CS.UnityEngine.GameObject
local Vector3=CS.UnityEngine.Vector3
local UIMgr = CS.UIMgr
local UIDataMgr = CS.UIDataMgr
--表单信息 位置点 Onshow获取一次
local postable = {}
--cardtable_tran 生成卡牌transform
local cardtable_tran = {}
--cardtable_btnscript 卡牌button脚本,修改enable
local cardtable_btnscript = {}
local cardlist = {} --服务器获取的卡牌表单
--当前关卡 card_num:翻正面的牌数 oldcard:第一次点击的牌 newcard:第二次点击的牌
local round_now = 0
local card_num = 0
local oldcard
local newcard
--时分秒用于计时器
local timer_hour = 0
local timer_min = 0
local timer_sec = 0
local timer_total = 0
local card_width = 100
local card_height = 100
--初始化获取组件,文本组件 头像img组建 crosspanel的文本框
local btntable = {}
local txttable = {}
local head_img_table = {}
local crosstable = {}
local cell = 25
--右侧世界最佳data 玩家最佳data 人物头像img
local worldbestdata = {}
local playerdata = {}
local bestplayerheadimg
--发牌点
local startPos
--发牌个数 第几关文本 通关奖励money exp
local num_give = 1
local roundtext
local earn_money
local earn_exp
--翻牌相关特效
local Quaternion = CS.UnityEngine.Quaternion
local EffectMgr = CS.EffectMgr.Instance
local Object=CS.UnityEngine.Object
local eff_table=
{
[1]="ef_ui_fanpai_xuanzhong",
[2]="ef_ui_fanpai_chenggong",
[3]="ef_ui_fanpai_shibai",
[4]="ef_ui_fanpai_fapai",
[5]="ef_ui_fanpai_jiesuan",
}
--子长度,子间距,子个数
function GetPos(width_item,width_cell,count)
local posx_table = {}
local x_len = width_item + width_cell
local num = math.floor(count/2)
local ys = count%2
if ys == 1 then
for i=0,num do
posx_table[num+1+i] = x_len*i
posx_table[num+1-i] = 0-x_len*i
end
else
for i=0,num-1 do
posx_table[num+1+i] = 0-x_len*i - width_cell/2 - width_item/2
posx_table[num-i] = x_len*i + width_cell/2 + width_item/2
end
end
return posx_table
end
--子长宽,子间距xy,规格,横着数的位置
function InitPosTable(i_w,i_h,c_x,c_y,l_x,l_y)
local table_x = GetPos(i_w,c_x,l_y)
local table_y = GetPos(i_h,c_y,l_x)
for i=1,l_x*l_y do
local x = i%l_y
if x == 0 then
x = l_y
end
local y = math.ceil(i/l_y)
local temp = {}
temp.posx = table_x[x]
temp.posy = table_y[y]
postable[i] = temp
end
end
--输入间距即可
function ResetPanel(cell_x,cell_y,l_x,l_y)
l_content.transform:EX_ClearChild(1)
local w_i = l_card_back:GetComponent("RectTransform").rect.width
local h_i = l_card_back:GetComponent("RectTransform").rect.height
GetPosXY(w_i,h_i,cell_x,cell_x,l_x,l_y)
end
function OnShow(param)
HandEvent(true)
InitPosTable(card_width,card_height,cell,cell,4,7)
InitDataInfo()
InitPanelInfo()
l_startText:GetComponent("Text").text = LanguageMnager.Get(91006)
l_card_start:SetActive(true)
l_passPanel:SetActive(false)
l_next_text:GetComponent("Text").text = LanguageMnager.Get(91000)
end
function OnHide()
HandEvent(false)
OnGameEnd()
l_startText:GetComponent("Text").text = LanguageMnager.Get(91006)
end
function InitDataInfo()
local k
--round_now:当前关卡 round_text:"第x关" roundtext:"x/5" 当前玩家pid
round_now = PlayerManager.getEventDataX(EID.opencard) + 1
roundtext = LanguageMnager.Get(91004)
roundtext = string.format(roundtext,round_now)
--玩家名字时间头像
playerdata.name = PlayerManager.PlayerInfo.PlayerName
playerdata.time = PlayerManager.getEntityPAttr(EntityProp.opencard_function+round_now)
k,playerdata.headimg = PlayerManager.GetRoleJobNameAndIcon()
--世界玩家信息(datax:time datay:转职等级 dataz:玩家职业 datas:玩家名字)
local worlddata = WorldMediator.getWorldAttrs(WorldProp.opencard_function+round_now)
--我就是最强玩家! 设置名字时间头像
if worlddata.datas == playerdata.name then
worldbestdata.name = playerdata.name
worldbestdata.time = playerdata.time
bestplayerheadimg = playerdata.headimg
--如果最佳时间不为0
elseif not EX_HasNotData(worlddata) and worlddata.datax ~= 0 then
worldbestdata.name = worlddata.datas
worldbestdata.time = worlddata.datax
bestplayerheadimg = PlayerManager.GetRoleJobSprite(worlddata.dataz,worlddata.datay)
else
worldbestdata.name = LanguageMnager.Get(91005)
worldbestdata.time = 0
bestplayerheadimg = playerdata.headimg
end
if not EX_HasNotData(gdOpenCardRewards) then
--这里要按照等级等策划配完 先默认获取第一个数据
--到时候这里的1换成当前玩家等级就可以=v=
earn_money = gdOpenCardRewards[1].money
earn_exp = gdOpenCardRewards[1].exp
end
end
function InitPanelInfo()
if EX_HasNotData(btntable) then
btntable[1] = l_startBtn:GetComponent("Button")
btntable[1].onClick:AddListener(OnClickRestart)
btntable[2] = l_passbtn:GetComponent("Button")
btntable[2].onClick:AddListener(OnClickNext)
btntable[3] = l_exitBtn:GetComponent("Button")
btntable[3].onClick:AddListener(OnClickExit)
end
if EX_HasNotData(txttable) then
txttable[1] = l_roundTitle:GetComponent("Text")
txttable[2] = l_remainCount:GetComponent("Text")
txttable[3] = l_best_player_name:GetComponent("Text")
txttable[4] = l_best_player_time:GetComponent("Text")
txttable[5] = l_player_name:GetComponent("Text")
txttable[6] = l_player_time:GetComponent("Text")
txttable[7] = l_timeNow:GetComponent("Text")
end
if EX_HasNotData(crosstable) then
local c_tran = l_passPanel.transform:Find("UIText")
crosstable[1] = c_tran:Find("timetext"):GetComponent("Text")
crosstable[2] = c_tran:Find("moneytext"):GetComponent("Text")
crosstable[3] = c_tran:Find("exptext"):GetComponent("Text")
end
if EX_HasNotData(head_img_table) then
head_img_table[1] = l_best_player_head:GetComponent("Image")
head_img_table[2] = l_player_head:GetComponent("Image")
end
if not EX_HasNotData(txttable) then
txttable[1].text = roundtext
txttable[2].text = (6-round_now).."/5"
end
if not EX_HasNotData(worldbestdata) and not EX_HasNotData(playerdata) and not EX_HasNotData(head_img_table) then
txttable[3].text = worldbestdata.name
txttable[4].text = FormatTime(worldbestdata.time)
txttable[5].text = playerdata.name
txttable[6].text = FormatTime(playerdata.time)
head_img_table[1].sprite = bestplayerheadimg
head_img_table[2].sprite = playerdata.headimg
end
end
--重置游戏也看做游戏开始=.=
function OnGameStart()
--收到开始游戏的消息(做一重判断,判断界面是否开启[掉线处理])
if not UIMgr.Instance:GetUIStateEx(UINameEnum.FanpaiPanel) then
return
end
--重新获取关卡信息和初始化界面
InitDataInfo()
InitPanelInfo()
--确保关闭
l_crossimg:SetActive(false)
l_passPanel:SetActive(false)
l_card_start:SetActive(false)
if not EX_HasNotData(postable) and not EX_HasNotData(gdOpenCards) then
l_startText:GetComponent("Text").text = LanguageMnager.Get(91007)
CS.TimeMgr.Instance:AddTimeInterval("RecordTime", CS.TimerStruct(-1, false,RecordTime,1))--游戏开始记时
for i=1,#postable do
for j = 1,#cardlist do
if cardlist[j].index == i then
local item_tran = GameObject.Instantiate(l_card_back).transform
item_tran:SetParent(l_content.transform)
item_tran.localScale = Vector3.one
item_tran.position = l_startPos.transform.position-Vector3(0,0,0.1*i)
item_tran.name = tonumber(i)
local img_index = cardlist[j].cardtype
local img_name = gdOpenCards[img_index]
item_tran:Find("Image"):GetComponent("Image").sprite = UIDataMgr.LoadSprite(tostring(img_name))
local item_btn = item_tran:GetComponent("Button")
--这里传递的是button脚本 img_index用于判断两张牌是否相同
item_btn.onClick:AddListener(function() OnClickCard(item_btn) end)
cardtable_tran[#cardtable_tran+1] = item_tran
cardtable_btnscript[#cardtable_btnscript+1] = item_tran:GetComponent("Button")
end
end
end
CS.TimeMgr.Instance:AddTimeInterval("GiveCard", CS.TimerStruct(-1, false,GiveCard,0.1)) --游戏开始发牌
end
end
--下一关 显示crosspanel 设置参数
function OnGameNext()
CS.SoundManager.Instance:PlaySound(90054)
l_crossimg:SetActive(false)
local timer = 0
if round_now == 5 then
l_next_text:GetComponent("Text").text = LanguageMnager.Get(82320)
end
l_passPanel:SetActive(true)
ShowFanPaiEff(l_passPanel,eff_table[5])
if not EX_HasNotData(crosstable) then
crosstable[1].text = FormatTime(timer_total)
crosstable[2].text = earn_money
crosstable[3].text = earn_exp
end
OnGameEnd()
end
--当前游戏被重置。结束/panel关闭时候调用
function OnGameEnd()
CS.TimeMgr.Instance:RmvTimeInterval("RecordTime")
CS.TimeMgr.Instance:RmvTimeInterval("GiveCard")
card_num = 0
num_give = 1
cardtable_tran = {}
cardtable_btnscript = {}
if Ex_IsNotNil(oldcard) then
oldcard.transform:EX_DOKill()
end
if Ex_IsNotNil(newcard) then
newcard.transform:EX_DOKill()
end
oldcard = nil
newcard = nil
timer_hour = 0
timer_min = 0
timer_sec = 0
timer_total = 0
if not EX_HasNotData(txttable) then
txttable[7].text = "00.00.00"
end
l_content.transform:EX_ClearChild(1)
end
function OnClickStart()
SendMsgForFanpaiInfo(FuncProp.opencard_start)
end
function OnClickNext()
if round_now == #gdOpendCardIndexs then
CS.UIMgr.Instance:PopUIEx(UINameEnum.FanpaiPanel)
return
end
OnGameEnd()
SendMsgForFanpaiInfo(FuncProp.opencard_start)
end
function OnClickExit()
CS.UIMgr.Instance:PopUIEx(UINameEnum.FanpaiPanel)
end
function OnClickRestart()
OnGameEnd()
SendMsgForFanpaiInfo(FuncProp.opencard_start)
end
function HandEvent(flag)
if flag == true then
LuaEvent.RegEvent(gdGame.EventNameEnum.EVENT_OPEN_CARD,OnMsgFuncCardDataOperatorResponse)
LuaEvent.RegEvent(gdGame.EventNameEnum.EVENT_FANPAI_LUA,OnMsgFuncDataOperatorResponse)
else
LuaEvent.RmvEvent(gdGame.EventNameEnum.EVENT_OPEN_CARD,OnMsgFuncCardDataOperatorResponse)
LuaEvent.RegEvent(gdGame.EventNameEnum.EVENT_FANPAI_LUA,OnMsgFuncDataOperatorResponse)
end
end
function SendMsgForFanpaiInfo(funcid,datax,datay,dataz)
local ret={}
ret.funcid=funcid
ret.datax = datax
ret.datay = datay
ret.dataz = dataz
Networks.Push_msg(Network.MsgFuncDataOperatorRequest,ret)
end
--开始游戏服务器信息cardlist获取
function OnMsgFuncDataOperatorResponse(ret)
if not EX_HasNotData(ret) and not EX_HasNotData(ret.cardlist) then
cardlist = {}
cardlist = ret.cardlist
OnGameStart()
end
end
--点击牌服务器返回被点击牌信息
function OnMsgFuncCardDataOperatorResponse(ret)
--两张牌一样,设置为不可动
if not EX_HasNotData(ret) and Ex_IsNotNil(newcard) and not EX_HasNotData(cardtable_btnscript) and Ex_IsNotNil(newcard) and Ex_IsNotNil(oldcard) then
if ret.state == 2 then
CS.SoundManager.Instance:PlaySound(90052)
--从btn中删除元素,不修改按钮状态
for i=1,#cardtable_btnscript do
if newcard == cardtable_btnscript[i] or oldcard == cardtable_btnscript[i] then
cardtable_btnscript[i].enabled = false
table.remove(cardtable_btnscript,i)
end
end
for i=1,#cardtable_btnscript do
cardtable_btnscript[i].enabled = true
end
ShowFanPaiEff(newcard.gameObject,eff_table[2])
ShowFanPaiEff(oldcard.gameObject,eff_table[2])
RemoveEff(newcard.gameObject,eff_table[1])
RemoveEff(oldcard.gameObject,eff_table[1])
newcard = nil
oldcard = nil
card_num = card_num + 2 --配对成功则+2
if card_num == #cardtable_tran then
OnGameNext()
card_num = 0
end
--两张牌不一样 翻回去可以点击
elseif ret.state == 0 then
--CS.SoundManager.Instance:PlaySound(90053)
local timer = 0
ShowFanPaiEff(l_crossimg,eff_table[5])
RemoveEff(newcard.gameObject,eff_table[1])
RemoveEff(oldcard.gameObject,eff_table[1])
ShowFanPaiEff(newcard.gameObject,eff_table[3])
ShowFanPaiEff(oldcard.gameObject,eff_table[3])
CS.TimeMgr.Instance:AddTimeInterval("ShowFail", CS.TimerStruct(-1, false,function()
timer = timer + 0.1
if timer > 0.3 then
if Ex_IsNotNil(oldcard) then
oldcard.transform:EX_DORotate(Vector3(0,0,0),0.3)
end
if Ex_IsNotNil(newcard) then
newcard.transform:EX_DORotate(Vector3(0,0,0),0.3)
end
for i=1,#cardtable_btnscript do
cardtable_btnscript[i].enabled = true
end
oldcard = nil
newcard = nil
CS.TimeMgr.Instance:RmvTimeInterval("ShowFail")
end
end,0.1))
end
end
end
--点击牌触发事件
function OnClickCard(card)
if not Ex_IsNotNil(oldcard) then --翻第一张牌,设为不可按
oldcard = card
ShowFanPaiEff(card.gameObject,eff_table[1])
oldcard.enabled = false
elseif not Ex_IsNotNil(newcard) and not EX_HasNotData(cardtable_btnscript) and not (oldcard == card) then --翻第二张牌,设所有牌不可按(OnMsgFuncCardDataOperatorResponse判断完会修改状态)
newcard = card
ShowFanPaiEff(card.gameObject,eff_table[1])
for i=1,#cardtable_btnscript do
cardtable_btnscript[i].enabled = false
end
end
--告诉服务器翻转这张牌(按太快state本该返回2变成1)
ShowFanPaiEff(card.gameObject,eff_table[4])
CS.SoundManager.Instance:PlaySound(90051)
card.transform:EX_DOScale(1.2,0.1):EX_OnComplete(function()
card.transform:EX_DOScale(1,0.1)
card.transform:EX_DORotate(Vector3(0,180,0),0.3):EX_OnComplete(function()
SendMsgForFanpaiInfo(FuncProp.opencard_open,card.gameObject.name,timer_total)
end)
end)
--[[card.transform:EX_DORotate(Vector3(0,180,0),0.3):EX_OnComplete(function()
SendMsgForFanpaiInfo(FuncProp.opencard_open,card.gameObject.name,timer_total)
end)--]]
end
--计时器调用方法,倒计时
function RecordTime()
if not EX_HasNotData(txttable) then
txttable[7].text = string.format("%02d.%02d.%02d",timer_hour,timer_min,timer_sec)
end
timer_total = timer_total+1
timer_sec = timer_sec+1
if timer_sec > 60 then
timer_min = math.floor(timer_sec/60) + timer_min
timer_sec = timer_sec % 60
end
if timer_min > 60 then
timer_hour = math.floor(timer_min/60) + timer_hour
timer_min = timer_min % 60
end
end
--秒转换00"00"00 91s->00"01"31
function FormatTime(second)
local min = 0
local hour = 0
min = math.floor(second/60)
second = second % 60
hour = math.floor(min/60)
min = min % 60
local time_text = string.format("%02d.%02d.%02d",hour,min,second)
return time_text
end
--发牌效果实现主要代码
function GiveCard()
if not EX_HasNotData(cardtable_tran) and num_give < (#cardtable_tran+1)then
local cardIndex = tonumber(cardtable_tran[num_give].gameObject.name)
if cardIndex then
l_confirm_pos.transform.localPosition = Vector3(postable[cardIndex].posx,postable[cardIndex].posy,-100)
local endPos = l_confirm_pos.transform.position-Vector3(0,0,num_give*0.1)
cardtable_tran[num_give]:EX_DOMove(endPos,0.3)
local num = num_give
CS.SoundManager.Instance:PlaySound(90055)
cardtable_tran[num_give]:EX_DOScale(1.2,0.2):EX_OnComplete(function()
if cardtable_tran[num] ~= nil then
cardtable_tran[num]:EX_DOScale(1,0.1)
end
end)
num_give = num_give+1
end
else
CS.SoundManager.Instance:PlaySound(90055)
CS.TimeMgr.Instance:RmvTimeInterval("GiveCard")
local count = l_content.transform.childCount-1
for i=0,count do
local img = l_content.transform:GetChild(i):GetComponent("Image")
if img ~= nil then
img.raycastTarget = true
end
end
end
end
--洗牌实现,弃用
--local stuffle_flag = 1
--local stuffle_count = 0
--CS.TimeMgr.Instance:AddTimeInterval("Stuffle", CS.TimerStruct(-1, false,Stuffle,0.6))
--[[function Stuffle()
if not EX_HasNotData(cardtable_tran) then
local endPos
for i=1,#cardtable_tran do
stuffle_flag = stuffle_flag * -1
local pos = cardtable_tran[i].position
endPos = pos+Vector3(stuffle_flag*0.5,0,0)
cardtable_tran[i]:EX_DOMove(endPos,0.1):EX_OnComplete(function()
endPos = pos+Vector3(-0.5*stuffle_flag,0,0)
cardtable_tran[i]:EX_DOMove(endPos,0.2):EX_OnComplete(function()
cardtable_tran[i]:EX_DOMove(pos,0.1)
end)
end)
end
stuffle_count = stuffle_count +1
if stuffle_count >2000 then
CS.TimeMgr.Instance:RmvTimeInterval("Stuffle")
stuffle_count = 0
end
end
end--]]
function ShowFanPaiEff(obj,effname)
EffectMgr:PlayEffect("UI/" .. effname, obj, Vector3(0,0,2), Quaternion.identity, Vector3(1.2,1.2,1), function(eff, dummyParam)
CS.UIDepth.Get(eff):SetValue(5,false)
eff.gameObject.name = effname
eff:EX_SetLayer("UI")
end)
end
function RemoveEff(obj,effname)
local eff = obj.transform:Find(effname)
if Ex_IsNotNil(eff) then
Object.Destroy(eff.gameObject)
end
end
这个界面效果还是很满意的。
加油