国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Excel與Unity工作流(二):基礎對話框架

這篇具有很好參考價值的文章主要介紹了Excel與Unity工作流(二):基礎對話框架。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

本文將演示在unity中實現類似galgame的對話效果,并且通過Excel進行文本、圖片、選項、賦值、音樂的配置

對話框架效果示意圖

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#
(該圖主要是展示版面和大致目標效果,與本文關系不大) (來源:《無期迷途》)

Excel表格總覽

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

整體框架與主要思路

要實現的效果

每點擊一次鼠標,就出現下一個對話/或者出現選項;

如果出現選項,點擊選項,會有不同的對話;

對話的時候人物的立繪會有改變;

可以進行簡單的數值判斷與賦值;

可以播放音樂與音效

整體思路

通過標志與ID來決定下一個對話播放第幾個

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

標志位

"#"號是普通的對話行,屏幕里會出現名字與人物

"&"號是選項,這一行會以一個選項的方式出現,內容會以選項上的文字表現

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#
(示意圖,來源:《無期迷途》)

以上圖舉例,最底下的文字就是用"#"號行來表現;右側的兩個選項通過兩行"&"號表現,選項上的文字就是那兩行"內容"列里的文字

"end"標志符就是結束整段對話

跳轉

每一行都有自己的ID,也有"跳轉"列。當這一行結束后(一般通過點擊繼續(xù)放下一個),會跳轉到"跳轉列"的ID所在的行

效果與判定

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

判定:在上圖ID為2的行里,"判定"那一列有"好感度>10"的文字,如果此時好感度>=10,那么之后會跳轉到5(跳轉列里"&"符號前面的那一個數字),否則就是跳轉到4

效果:在上圖ID為3-5的行里,有"好感度+-10"的文字,"+"用來區(qū)分數值名與數值改變量,所以是"好感度"這個數值,進行"-10"的操作

?*號行

如果需要多個條件都滿足才能跳轉到下一行呢?

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

ID為7的"是時候打開網抑云了"需要時間晚于23:00,并且活力要大于20,此時我們發(fā)現一行只寫一個判定不夠

故引入"*"號行。這個標志符所代表的行不會出現在游戲的畫面上,不需要玩家點擊才繼續(xù),而是自動觸發(fā)并自動跳轉到下一個要跳轉的行。

"*"號行可以進行效果賦值、條件判斷以及人物清空(這在下文的"人物"板塊會提到)、背景替換等等功能

"*"號行可以多個混合使用,看具體實現情況而定

人物

在對話時,我們需要人物立繪來展現效果(進行激烈的立繪碰撞 bushi)

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#
(示意圖,來源:《無期迷途》)

在Excel示例表中,主要通過"人物立繪圖片","人物位置"進行控制

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

"人物立繪圖片"由人物的底+人物表情組成,通過"&"符號進行分隔

"人物位置"Left就是在左邊出現,Right就是在右邊出現,Clear會清除這個人所有的立繪

音樂音效

通過"背景音樂"和"音效"控制

"背景音樂"會循環(huán)播放

"音效"只播放一次

實現

導入

在寫完需要導入的劇情表格后,另存為csv格式(注意保存為 UTF-8編碼)

這一部分與本系列第一篇類似,這里直接貼代碼

Excel與Unity工作流(一):使用Excel進行屬性配置-CSDN博客

public void SetTextAsset(string ResourcesPath)
    {
        textAsset = Resources.Load<TextAsset>(ResourcesPath);
        textAssetPath = ResourcesPath;
    }

public void ReadText(TextAsset _textAsset)
    {        
        dialogRows = null;        
        dialogRows = _textAsset.text.Split('\n');

        cells = new string[dialogRows.Length][];
        for (int i = 0; i < dialogRows.Length; i++)
        {
            cells[i] = dialogRows[i].Split(',');
        }
    }

對話框架

具體的unity內部圖片與按鈕放置可以看參考鏈接視頻(本文的對話框架就是基于那個視頻進行的修改添加)

https://www.bilibili.com/video/BV1v5411D79x/文章來源地址http://www.zghlxwxcb.cn/news/detail-851274.html

string textAssetPath;
    [SerializeField] TextAsset textAsset;//輸入的文本文件CSU

    [Header("分支選項")]
    [SerializeField] GameObject OptionalButton;
    [SerializeField] Transform buttonGroup;


    [Header("普通對話")]
    [SerializeField] GameObject chatPanel;
    [SerializeField] GameObject talkBox;
    TMP_Text dialogText;
    [SerializeField] Image backGroundPic;

    int dialogIndex = 0;
    int beginID = 0;

    string[][] cells;
    string[] dialogRows;
    bool isBegin;
    bool canNext;
    public void BeginChat()
    {
        {
            chatPanel.transform.Find("Sprite").gameObject.SetActive(true);
            talkBox.gameObject.SetActive(true);

            //把所有圖片換成透明(具體方法在下文的"圖片"中)
            ClearAllPic();
            ClearAllChoices();
            ClearImageLiHui();

        }
        print("BeginChat" + textAssetPath + "beginID" + beginID);
        isBegin = true;
        //這里的TextAsset會為null
        if (textAsset == null)
        {
            SetTextAsset(textAssetPath);
        }
        ReadText(textAsset);
        dialogIndex = beginID;
        ShowDialogRow();
        canNext = true;
    }


    public void ShowDialogRow()
    {
        for (int i = 1; i < dialogRows.Length; i++)//遍歷來尋找正確的一行 首行是列名當然不含信息 所以i從1開始
        {
            if (int.Parse(cells[i][1]) == dialogIndex)
            {
                //播放音樂
                if (cells[i].Length > 10)
                {
                    if (cells[i][10] != "")
                    {
                        PlayBackGroundMusic(cells[i][10]);
                    }
                }

                //播放音效
                if (cells[i].Length > 11)
                {
                    if (cells[i][11] != "")
                    {
                        print("PlayEffectMusic" + cells[i][11]);
                        PlayEffectMusic(cells[i][11]);
                    }
                }

                if (cells[i][0] == "*")
                {

                    UpdateBackGround(cells[i][9]);
                    UpdateImage(cells[i][7], cells[i][8]);
                    if (cells[i][5] != "")
                    {
                        OptionEffect(cells[i][5]);
                    }


                    if (cells[i][4].Contains('&'))
                    {
                        string[] judge = cells[i][6].Split('>');
                        string[] jump = cells[i][4].Split('&');
                        OptionJudge(judge[0], judge[1], int.Parse(jump[0]), int.Parse(jump[1]));
                    }
                    else
                    {
                        dialogIndex = int.Parse(cells[i][4]);
                        ShowDialogRow();
                    }
                    break;
                }
                if (cells[i][0] == "#")
                {
                    UpdateBackGround(cells[i][9]);

                    UpdateImage(cells[i][7], cells[i][8]);
                    UpdateText(cells[i][2], cells[i][3]);


                    if (cells[i][5] != "")
                    {
                        OptionEffect(cells[i][5]);
                    }
                    if (cells[i][4].Contains('&'))
                    {
                        string[] judge = cells[i][6].Split('>');
                        string[] jump = cells[i][4].Split('&');
                        OptionJudge(judge[0], judge[1], int.Parse(jump[0]), int.Parse(jump[1]));
                    }
                    else
                    {
                        dialogIndex = int.Parse(cells[i][4]);
                    }
                    break;
                }
                if (cells[i][0] == "&")
                {
                    canNext = false;
                    GenerateOption(i);

                    break;
                }
                if (cells[i][0] == "end")
                {

                    EndChat();
                    break;
                }
            }
        }
    }
    public void EndChat()
    {
        print("EndChat" + textAsset.name);
        canNext = false;
        dialogIndex = 0;
        isBegin = false;

        if (chatPanel != null)
        {
            ClearAllPic();
            ClearAllChoices();
            //把所有Prefb消除
            ClearImageLiHui();
            ClearChatBoxText();
            chatPanel.transform.Find("Sprite").gameObject.SetActive(false);
            if (talkBox.activeSelf)
            {
                talkBox.gameObject.SetActive(false);
            }
        }
        //把當前path清空
        textAssetPath = null;
    }

選項與賦值

int likeValue;
    int energyValue;
    int[] time;
    //選擇按鈕
    public void OnOptionClick(int _id)
    {
        dialogIndex = _id;
        for (int i = 0; i < buttonGroup.childCount; i++)
        {
            Destroy(buttonGroup.GetChild(i).gameObject);
            canNext = true;
        }
        ShowDialogRow();

    }
    public void GenerateOption(int _index)//此處的——index是總的序列號
    {
        string[] cells = dialogRows[_index].Split(',');
        if (cells[0] == "&")
        {
            GameObject button = Instantiate(OptionalButton, buttonGroup);
            button.GetComponentInChildren<TMP_Text>().text = cells[3];
            button.GetComponent<Button>().onClick.AddListener(
                delegate
                {
                    if (cells[6] != "")
                    {
                        string[] judge = cells[6].Split('>');
                        string[] jump = cells[4].Split('&');
                        OptionJudge(judge[0], judge[1], int.Parse(jump[0]), int.Parse(jump[1]));
                    }
                    else if (cells[5] != "")
                    {
                        OptionEffect(cells[5]);
                        OnOptionClick(int.Parse(cells[4]));
                    }
                    else if (cells[5] == "")
                    {
                        OnOptionClick(int.Parse(cells[4]));
                    }
                }
                            );
            GenerateOption(_index + 1);
        }
    }

    /// <summary>
    /// 選項賦值效果
    /// </summary>
    /// <param name="_effect">哪個值改變</param>
    /// <param name="_param">值改變的大小</param>
    public void OptionEffect(string effect)
    {
        string[] effects = effect.Split('+');
        string _effect = effects[0];
        int _param = int.Parse(effects[1]);
        if (_effect == "好感度")
        {
            likeValue += _param;
            print("好感度" + _param);
        }
        if (_effect == "活力")
        {
            energyValue += _param;
            print("活力" + _param);
        }
    }

    /// <summary>
    /// 根據文件中的條件來判斷應該跳轉到哪;一般是>=這個條件的跳轉到位置1,否則跳轉到位置2
    /// </summary>
    /// <param name="_judge">判斷的條件</param>
    /// <param name="_param2">條件的大小</param>
    /// <param name="_jump1">跳轉的位置1</param>
    /// <param name="_jump2">跳轉的位置2</param>
    void OptionJudge(string _judge, string _param2, int _jump1, int _jump2)
    {
        if (_judge == "好感度")
        {
            if (likeValue >= int.Parse(_param2))
            {
                OnOptionClick(_jump1);
            }
            else
            {
                OnOptionClick(_jump2);
            }

        }
        else if (_judge == "時間")
        {
            string[] timeJudge = _param2.Split(':');

            if (time[0] >= int.Parse(timeJudge[0]) && time[1] >= int.Parse(timeJudge[1]))
            {
                OnOptionClick(_jump1);
            }
            else
            {
                OnOptionClick(_jump2);
            }

        }
        else if (_judge == "活力")
        {
            if (energyValue >= int.Parse(_param2))
            {
                OnOptionClick(_jump1);
            }
            else
            {
                OnOptionClick(_jump2);
            }
        }
    }

/// <summary>
    /// 把所有選項都刪除
    /// </summary>
    void ClearAllChoices()
    {
        Transform[] childs = buttonGroup.transform.GetComponentsInChildren<Transform>();
        //第0個是這個物體本身
        for (int i = 1; i < childs.Length; i++)
        {
            Destroy(childs[i].gameObject);
        }
    }

圖片

圖片讀取(運用圖集Atlas實現)

//所有圖片,包括人物立繪與場景,都放在這個圖集里
    SpriteAtlas _atals;
    string atlasResourcesPath = "Atalas/ChatAtalas";
    public Sprite LoadAtlasSprite(string _atalsname, string spriteName)
    {
        LoadAtalas();
        switch (_atalsname)
        {
            case "_atals":
                return LoadAtlasSprite(_atals, spriteName);
        }
        return null;
    }
    Sprite LoadAtlasSprite(SpriteAtlas _atals, string spriteName)
    {
        if (_atals == null)
        {
            Debug.Log(_atals.name + "_atals == null");
            return null;
        }
        if (_atals.GetSprite(spriteName) != null)
        {
            return _atals.GetSprite(spriteName);
        }
        Debug.Log("NotGetAtlasPic");
        return null;
    }

    void LoadAtalas()
    {
        if (_atals == null)
        {
            _atals = Resources.Load<SpriteAtlas>(atlasResourcesPath);
        }
    }

圖片與對話系統(tǒng)接入

圖片層級參考

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

立繪Prefb層級參考

Excel與Unity工作流(二):基礎對話框架,excel,unity,游戲引擎,c#

[SerializeField] Image leftPic;
    [SerializeField] Image rightPic;

    [Header("全屏對話的人物Prefb")]
    [SerializeField] GameObject aPrefb;
    [SerializeField] GameObject bPrefb;

    /// <summary>
    /// 只針對全屏對話
    /// </summary>
    /// <param name="picName"></param>
    /// <param name="picturePos"></param>
    void UpdateImage(string picName, string picturePos)
    {
        LoadImageLiHui(picName, picturePos);
    }

    /// <summary>
    /// 根據圖片名稱給出準確的底圖+表情
    /// </summary>
    void LoadImageLiHui(string combineName, string picturePos)
    {
        string[] s = combineName.Split("&");
        if (s.Length < 1) return;

        if (picturePos == "Clear")
        {
            //遍歷Sprite的所有子物體,看哪個子物體里面有s[0]
            foreach (Transform child in transform.Find("Sprite").GetComponentInChildren<Transform>())
            {
                if (child.childCount > 0)
                {
                    //如果這個節(jié)點里有這個名字,就刪掉這個子物體
                    if (child.GetChild(0).name.Contains(s[0]))
                    {
                        Destroy(child.GetChild(0).gameObject);
                    }
                }
            }
            return;
        }
        GameObject talkerObj = null;
        GameObject prefb = null;
        //print(combineName + picturePos);
        //print("s[0]" + s[0]);
        switch (s[0])
        {
            case "A":
                prefb = aPrefb;
                break;
            case "B":
                prefb = bPrefb;
                break;
        }
        if (prefb == null) return;
        //prefab先根據位置生成
        switch (picturePos)
        {
            //如果這個原本沒有prefb,就生成新的,如果有,就刪掉之前的,生成一個新的;如果是同名的prefb,就改表情和其他Adding
            //每個角色都應該有一個“默認”表情
            case "Left":
                talkerObj = ChangePosLiHui(leftPic.transform, prefb, s[0]);
                break;            
            case "Right":
                talkerObj = ChangePosLiHui(rightPic.transform, prefb, s[0]);
                break;            
        }
        //print("talkerObj.transform.parent.name" + talkerObj.transform.parent.name);
        //根據Excell里的拆分文字換不同圖片
        //大部分角色有一個默認表情,如果沒有表情,就用默認的
        if (s.Length == 1) return;
        //換表情
        if (LoadAtlasSprite("_atals", s[0] + "_" + s[1]) != null)
        {
            talkerObj.transform.Find("Emotion").GetComponent<Image>().sprite = LoadAtlasSprite("_atals", s[0] + "_" + s[1]);
        }
    }
    /// <summary>
    /// /改變制定位置的立繪
    /// </summary>
    GameObject ChangePosLiHui(Transform pos, GameObject prefb, string name)
    {
        GameObject talkerObj = null;
        if (pos.childCount == 0)
        {
            //print("pos.childCount == 0");
            talkerObj = Instantiate(prefb, pos);
        }
        else
        {
            if (pos.GetChild(0).name.Contains(prefb.name))
            {
                //print("pos.GetChild(0).name.Contains(prefb.name)");
                talkerObj = pos.GetChild(0).gameObject;
                LiHuiReturnToDefalt(talkerObj, name);
            }
            else
            {
                //print("pos.GetChild(0).name.Don't Contains(prefb.name)");
                Destroy(pos.transform.GetChild(0).gameObject);
                talkerObj = Instantiate(prefb, pos);
            }
        }
        return talkerObj;
    }

    /// <summary>
    /// 立繪返回默認狀態(tài)
    /// </summary>
    void LiHuiReturnToDefalt(GameObject talkerObj, string name)
    {
        //print("LiHuiReturnToDefalt" + name);
        //換成默認表情
        if (LoadAtlasSprite("_atals", name + "_默認") == null)
        {
            return;
        }
        talkerObj.transform.Find("Emotion").GetComponent<Image>().sprite = LoadAtlasSprite("_atals", name + "_默認");
    }


    /// <summary>
    /// 把所有的圖片全都換成透明(全屏對話)
    /// </summary>
    public void ClearAllPic()
    {
        leftPic.sprite = LoadAtlasSprite("_atals", "透明");
        rightPic.sprite = LoadAtlasSprite("_atals", "透明");
        backGroundPic.sprite = LoadAtlasSprite("_atals", "透明");
    }
    void ClearImageLiHui()
    {
        //遍歷Sprite的所有子物體,看哪個子物體里面有s[0]
        foreach (Transform child in chatPanel.transform.Find("Sprite").GetComponentInChildren<Transform>())
        {
            if (child.childCount > 0)
            {
                Destroy(child.GetChild(0).gameObject);
            }
        }
    }

    
    public void UpdateBackGround(string picName)
    {
        if (picName == "Clear")
        {

            backGroundPic.sprite = null;
            //backGroundPic.sprite= backgroundDic["透明"];
            backGroundPic.sprite = LoadAtlasSprite("_atals", "透明");

        }
        else if (picName != "")
        {

            //backGroundPic.sprite = backgroundDic[picName];
            //print("picName" + picName);
            backGroundPic.sprite = LoadAtlasSprite("_atals", picName);

        }
    }

音頻

[SerializeField] AudioSource backgroundSource;//背景音樂
    [SerializeField] AudioSource effectSource;//音效音樂
    /// <summary>
    /// 默認循環(huán),開始播放就會切掉其他的音樂
    /// </summary>
    public void PlayBackGroundMusic(string musicName)
    {
        //print("play" + musicName);
        AudioClip audioClip = Resources.Load<AudioClip>("Audio/" + musicName);
        if (backgroundSource == null)//針對沒有UI的測試Scene
        {
            print("backgroundSource == null");
            backgroundSource = GetComponent<AudioSource>();
        }
        if (audioClip == null) return;
        backgroundSource.clip = audioClip;
        backgroundSource.Play();
        backgroundSource.loop = true;
    }

    /// <summary>
    /// 播放音效 只播放一次
    /// </summary>
    public void PlayEffectMusic(string musicName)
    {
        AudioClip audioClip = Resources.Load<AudioClip>("Audio/" + musicName);
        if (audioClip == null)
        {
            //print(musicName + "audioClip == null");
            return;
        }
        //如果沒有Canvas,或者Canvas里面沒有EffectSource
        if (effectSource == null)
        {
            effectSource = GameObject.Find("Canvas").transform.Find("EffectSound").GetComponent<AudioSource>();
            if (effectSource == null)
            {
                //print("effectSource == null" + musicName);
                return;
            }
        }
        effectSource.clip = audioClip;
        effectSource.Play();
        effectSource.loop = false;
    }

文本

[SerializeField] GameObject nameObj;
    [SerializeField] TMP_Text nameText;
    /// <summary>
    /// 更新對話框
    /// </summary>
    /// <param name="_name"></param>
    /// <param name="_text"></param>
    void UpdateText(string _name, string _text)
    {
        if (_name == "")
        {
            print("_name == 空");
            nameObj.SetActive(false);
        }
        else
        {
            nameObj.SetActive(true);
        }
        nameText.text = _name;
        dialogText.text = _text;
    }

    public void ClearChatBoxText()
    {
        //清空內容
        dialogText.text = "";
        nameText.text = "";
    }

生命周期

void Start()
    {
        BeginChat();
    }

    // Update is called once per frame
    void Update()
    {
        //按空格鍵繼續(xù)對話
        if ((Input.GetKeyDown(KeyCode.Space)||Input.GetMouseButtonDown(0) )&& canNext)
        {
            ShowDialogRow();
        }
    }

拓展

Excel與Unity工作流(三):對話框架拓展:Excel表內變量導入 賦值 判斷-CSDN博客

Excel與Unity工作流(四):對話框架拓展:結合MVE實現Excel調用函數與批量支線導入管理思路-CSDN博客

參考:

https://www.bilibili.com/video/BV1v5411D79x/

到了這里,關于Excel與Unity工作流(二):基礎對話框架的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【activiti】工作流入門基礎概念

    為什么使用activiti 狀態(tài)--------------------------------------------------引擎engin(業(yè)務變動不影響程序的進行) 每個人只能看到個人負責的,流程變更困難 bpmn建模語言 activiti流程步驟 步驟: 1、部署流程 2、定義流程 3、部署流程定義:使用activiti中的API把流程定義存儲,在Acitivti執(zhí)行過

    2024年02月16日
    瀏覽(43)
  • 生信工作流框架搭建 | 04-nextflow與Slurm高性能計算

    生信工作流框架搭建 | 04-nextflow與Slurm高性能計算

    本篇為biodoge《生信工作流框架搭建》系列筆記的第5篇,該系列將持續(xù)更新。 上回生信工作流框架搭建 | 03-nextflow與AWS批量計算為大家提供了nextflow上云的實用教程。雖然AWS批量計算技術含量較大,但畢竟在國內應用場景較少,下面將為大家介紹另一種更為常用的應用:阿里云

    2024年02月15日
    瀏覽(20)
  • 【Unity】搭建Jenkins打包工作流,遠程打熱更、構建App

    【Unity】搭建Jenkins打包工作流,遠程打熱更、構建App

    Jenkins是團隊協作項目打包常用的工作流,不多做介紹。 Jenkins的部署Unity打包環(huán)境還是非常簡單的: 工作流程如下: 1. 在Jenkins中添加打包配置參數(如: 版本號, 目標平臺等), 參數將以UI的形式顯示在Jenkins Web界面以便打包前填寫參數; 2. 用.bat批處理代碼將步驟1的參數保存到

    2024年02月03日
    瀏覽(44)
  • Asp.net基于工作流引擎的系統(tǒng)框架設計開發(fā)(源代碼+論文)

    工作流就是一系列相互銜接、自動進行的業(yè)務活動或任務。工作流引擎是工作流管理系統(tǒng)的核心,它的主要功能是通過計算機技術的支持去定義、執(zhí)行和管理工作流,協調工作流執(zhí)行過程中工作之間以及群體成員之間的信息交互。 論文主要講述了工作流引擎的基本功能及設計

    2024年02月12日
    瀏覽(30)
  • Unity & PS Linear Workflow - Unity 和 PS 的線性工作流實踐 - 簡單配置示例

    Unity & PS Linear Workflow - Unity 和 PS 的線性工作流實踐 - 簡單配置示例

    因為 新的 Unity 項目人物走寫實PBR風格 所以鐵定基于 Linear Workflow 比基于 Gamma Workflow 的渲染效果更好 但是 Linear Workflow 下對 美術工作流不太友好,下面就實驗并總結一些方案的優(yōu)缺點 供大家選取 先看看不同 Color Space 下的 PBR 選擇差異有多大 在 Unity Linear Color Space 渲染質量接

    2023年04月08日
    瀏覽(22)
  • Flutter 中的單元測試:從工作流基礎到復雜場景

    Flutter 中的單元測試:從工作流基礎到復雜場景

    對 Flutter 的興趣空前高漲——而且早就應該出現了。 Google 的開源 SDK 與 Android、iOS、macOS、Web、Windows 和 Linux 兼容。單個 Flutter 代碼庫支持所有這些。單元測試有助于交付一致且可靠的 Flutter 應用程序,通過在組裝之前先發(fā)制人地提高代碼質量來確保不會出現錯誤、缺陷和缺

    2024年02月08日
    瀏覽(24)
  • 兩小時快速入門 TypeScript 基礎(一)工作流、基本類型、高級類型

    兩小時快速入門 TypeScript 基礎(一)工作流、基本類型、高級類型

    個人簡介 ?? 個人主頁: 前端雜貨鋪 ???♂? 學習方向: 主攻前端方向,也會涉及到服務端(Node.js 等) ?? 個人狀態(tài): 2023屆本科畢業(yè)生,已拿多個前端 offer(秋招) ?? 未來打算: 為中國的工業(yè)軟件事業(yè)效力 n 年 ?? 推薦學習:??前端面試寶典 ??Vue2 ??Vue3 ??Vue2/

    2024年02月11日
    瀏覽(26)
  • 一個開源的汽修rbac后臺管理系統(tǒng)項目,基于若依框架,實現了activiti工作流,附源碼

    一個開源的汽修rbac后臺管理系統(tǒng)項目,基于若依框架,實現了activiti工作流,附源碼

    為了更加熟悉activiti工作流的使用和實戰(zhàn)而改造的項目,歡迎大家參考和提出問題建議一起學習~ 源碼gitee倉庫地址:Yuzaki-NASA / Activiti7_test_car_rbac master分支是穩(wěn)定版,dev分支是后來加了個新的并行審核流程和客戶管理,個人測了多遍沒啥問題,建議拉dev的代碼。 sql文件在car

    2024年03月23日
    瀏覽(21)
  • Java spring boot 全解Camunda 7,從 0 到 1 構建工作流平臺——第一節(jié):各個開源框架對比

    Java spring boot 全解Camunda 7,從 0 到 1 構建工作流平臺——第一節(jié):各個開源框架對比

    引言:最近公司在做工作流這一塊相關的東西,我是技術主要負責人之一。想著既然在公司做,用的是開源框架做的二開,反正也不涉及公司保密協議,也不涉及其它相關的法律問題,所以這里將自己做的那一部分公開出來,讓后來者可以借鑒一二,或者給我斧正一二。 Ca

    2024年02月05日
    瀏覽(27)
  • 【工作流】Activiti工作流簡介以及Spring Boot 集成 Activiti7

    【工作流】Activiti工作流簡介以及Spring Boot 集成 Activiti7

    什么是工作流? 工作流指通過計算機對業(yè)務流程進行自動化管理,實現多個參與者按照預定義的流程去自動執(zhí)行業(yè)務流程。 文章源碼托管:https://github.com/OUYANGSIHAI/Activiti-learninig Activiti5是由Alfresco軟件在2010年5月17日發(fā)布的業(yè)務流程管理(BPM)框架,它是覆蓋了業(yè)務流程管理、

    2024年02月08日
    瀏覽(31)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包