水果机,夺宝动画实现

效果(动画不流畅是gif帧率低造成的)

GIF 2025-7-27 16-47-46

 

 入口代码

Assets/FruitMachine/FruitMachineDemo.cs

这个脚本挂在Layer节点上

public class FruitMachineDemo : MonoBehaviour
{
    private LuaEnv m_LuaEnv;
    private RectTransform m_Layer;
    private List<Action> m_Actions = new List<Action>();

    void Awake()
    {
        m_Layer = (RectTransform)transform;
    }

    void Start()
    {
        m_LuaEnv = new LuaEnv();
        m_LuaEnv.AddLoader((ref string filePath) =>
        {
            filePath = filePath.Replace('.', '/');
            var assetFilePath = $"Assets/{filePath}.lua.txt";
#if UNITY_EDITOR
            filePath = Path.GetFullPath(assetFilePath);
#endif
            var txtAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(assetFilePath);
            return Encoding.UTF8.GetBytes(txtAsset.text);
        });

        m_LuaEnv.Global.Set("FruitMachineDemoInst", this); //在lua中增加一个全局变量,可以在lua中用FruitMachineDemoInst来访问c#对象
        m_LuaEnv.DoString("require('FruitMachine.Main')");
    }

    void OnDestroy()
    {
        m_Actions.Clear();
        m_Actions = null;
        if (null != m_LuaEnv)
        {
            m_LuaEnv.Dispose();
            m_LuaEnv = null;
        }
    }

    public RectTransform GetLayerRoot()
    {
        return m_Layer;
    }

    public void AddAction(Action action)
    {
        if (null != action)
            m_Actions.Add(action);
    }

    public void RemoveAction(Action action)
    {
        if (null != action)
            m_Actions.Remove(action);
    }

    void Update()
    {
        if (m_Actions.Count > 0)
        {
            foreach (var act in m_Actions)
            {
                act();
            }
        }
    }
    
}

 

Assets/FruitMachine/Main.lua.txt

require("Lua.LuaCoMgr")
local Type_Button = typeof(CS.UnityEngine.UI.Button)

---@type FruitMachineAnim
local m_FruitMachineAnim = require("FruitMachine.FruitMachineAnim").new()

-- //////////

local Inner = {}

local m_RootTrans = FruitMachineDemoInst:GetLayerRoot()

local m_ItemUIs = {}
local m_CurItemIndex = 1

local m_BlinkCoId = 0

-- //////////

m_RootTrans:Find("btn_Start"):GetComponent(Type_Button).onClick:AddListener(function()
    if 0 == m_BlinkCoId then
        m_FruitMachineAnim:StartForResult(5)
    end
end)

for i=1,8 do
    local itemTrans = m_RootTrans:Find("item_"..i)
    m_ItemUIs[i] = {
        selFrame = itemTrans:Find("selFrame").gameObject,
    }
end

m_FruitMachineAnim:Prepare(8, function(flag, sender)
    local oldItemIndex = m_CurItemIndex
    m_CurItemIndex = m_FruitMachineAnim:GetCurIndex()

    m_ItemUIs[oldItemIndex].selFrame:SetActive(false)
    m_ItemUIs[m_CurItemIndex].selFrame:SetActive(true)

    if "ItemChange" == flag then
    elseif "ShowResult" == flag then
        m_BlinkCoId = LuaCoMgr.Start(function()
            for i=1,3 do
                LuaCoMgr.WaitForSeconds(0.1)
                m_ItemUIs[m_CurItemIndex].selFrame:SetActive(false)
                LuaCoMgr.WaitForSeconds(0.1)
                m_ItemUIs[m_CurItemIndex].selFrame:SetActive(true)
            end
            LuaCoMgr.WaitForSeconds(1)
            m_BlinkCoId = 0
            m_FruitMachineAnim:StartForIdle()
        end)
    end
end)
m_FruitMachineAnim:StartForIdle()

function Inner.Update()
    LuaCoMgr.OnUpdate()
    m_FruitMachineAnim:OnUpdate()
end

FruitMachineDemoInst:AddAction(Inner.Update)

 

LuaCoMgr看这边:xlua - lua协程模拟Unity协程

 

动画代码

 Assets/FruitMachine/FruitMachineAnim.lua.txt

local _Time = CS.UnityEngine.Time

---@class FruitMachineAnim
local FruitMachineAnim = {}
FruitMachineAnim.__index = FruitMachineAnim

local Inner = {}

function FruitMachineAnim.new()
    local obj = {}
    setmetatable(obj, FruitMachineAnim)
    obj:ctor()
    return obj
end

function FruitMachineAnim:ctor()
    self.m_RunningFlag = 0
end

function FruitMachineAnim:GetCurIndex()
    return self.m_CurIndex
end

function FruitMachineAnim:Prepare(cnt, cb)
    if 0 ~= self.m_RunningFlag then
        --要在运行前调用
        return
    end
    
    self.m_Cnt = cnt
    self.m_Callback = cb
    self.m_ElapseTime = 0
    self.m_CurIndex = 0
end

function FruitMachineAnim:StartForIdle()
    if 0 ~= self.m_RunningFlag then
        --播放动画中
        return
    end

    self.m_RunningFlag = 1
    self.m_ResultIndex = -1
    self.m_ItemChangeInterval = 0.7
end

function FruitMachineAnim:StartForResult(resultIndex)
    if 2 == self.m_RunningFlag then
        --播放抽奖动画中
        return
    end

    self.m_RunningFlag = 2
    self.m_ResultIndex = resultIndex
    self.m_ShowResultFlag = false
    LuaCoMgr.Start(Inner.DoSpeedUpAndDown, self)
end

function FruitMachineAnim:StopForIdle()
    if 2 == self.m_RunningFlag then
        --播放抽奖动画中, 不能强制停止
        return
    end
    
    self.m_RunningFlag = 0
end

function FruitMachineAnim:IsPlayIdle()
    return 1 == self.m_RunningFlag
end

function FruitMachineAnim:IsPlayResult()
    return 2 == self.m_RunningFlag
end

---@param self FruitMachineAnim
function Inner.DoSpeedUpAndDown(self)
    self.m_ItemChangeInterval = 0.7

    -- ///// 加速
    local initInterval = 0.7 --初始切换间隔
    local speedUpInterval = 0.03 --加速到最快时的切换间隔

    local speedUpCnt = 10 -- 加速次数
    local speedUpTotalTime = 0.5 --加速总共用时

    local speedUpStep = (initInterval - speedUpInterval) / speedUpCnt
    local speedUpPerTime = speedUpTotalTime / speedUpCnt
    for i=1,speedUpCnt do
        LuaCoMgr.WaitForSeconds(speedUpPerTime)
        self.m_ItemChangeInterval = self.m_ItemChangeInterval - speedUpStep
    end
    local speedUpDur = 2 --达到最快后持续时长
    LuaCoMgr.WaitForSeconds(speedUpDur)
    -- /////

    -- ///// 减速
    local speedDownInterval = 0.2 --减速到最慢时的切换间隔
    local speedDownCnt = 10 --减速次数
    local speedDownTotalTime = 2 --减速总共用时

    local speedDownStep = (speedDownInterval - speedUpInterval) / speedDownCnt
    local speedDownPerTime = speedDownTotalTime / speedDownCnt
    for i=1,speedDownCnt do
        LuaCoMgr.WaitForSeconds(speedDownPerTime)
        self.m_ItemChangeInterval = self.m_ItemChangeInterval + speedDownStep
    end
    local speedDownDur = 0.5
    LuaCoMgr.WaitForSeconds(speedDownDur)
    -- /////

    self.m_ShowResultFlag = true
end

function FruitMachineAnim:OnUpdate()
    if 0 == self.m_RunningFlag then
        return
    end
    
    self.m_ElapseTime = self.m_ElapseTime + _Time.unscaledDeltaTime

    if self.m_ElapseTime >= self.m_ItemChangeInterval then
        self.m_ElapseTime = self.m_ElapseTime - self.m_ItemChangeInterval
        self.m_CurIndex = self.m_CurIndex + 1
        if self.m_CurIndex > self.m_Cnt then
            self.m_CurIndex = 1
        end
        
        if self.m_ShowResultFlag then --结果出来了
            if self.m_CurIndex == self.m_ResultIndex then
                self.m_RunningFlag = 0
                self.m_ShowResultFlag = false
                if self.m_Callback then
                    self.m_Callback("ShowResult", self)
                end
            else
                if self.m_Callback then
                    self.m_Callback("ItemChange", self)
                end
            end
        else --结果还没出来
            if self.m_Callback then
                self.m_Callback("ItemChange", self)
            end
        end
    end
end

return FruitMachineAnim

 

posted @ 2025-07-27 17:01  yanghui01  阅读(9)  评论(0)    收藏  举报