【Daily Games——开发篇】:一个帅气的副本效果之翻牌兑换

xiaoxiao2025-08-27  64

不知不觉已经干了这么久了,看看我完成的界面吧。

一个帅气的翻牌匹配小游戏不是吗,涉及的内容是发牌,位置点确定,翻转匹配

翻转匹配是服务器的返回数据,但是本地同样可以抢先配对。

发牌代码如下:

服务器给的是点的位置,由于最多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

这个界面效果还是很满意的。

加油

 

转载请注明原文地址: https://www.6miu.com/read-5035284.html

最新回复(0)