【unity进阶知识10】从零手搓一个UI管理器/UI框架,自带一个提示界面,还有自带DOTween动画效果

news2024/11/25 7:04:11

最终效果

在这里插入图片描述

文章目录

  • 最终效果
  • 前言
  • UI管理器
    • 1、新增UI面板层枚举
    • 2、初始化
      • 2.1、用代码创建画布
      • 2.2、用代码创建UI面板的父物体层
      • 2.3、代码添加EventSystem物体
    • 3、ShowPanel显示面板方法
    • 4、HidePanel隐藏面板的方法
    • 5、CloseUI关闭界面的方法
    • 6、UI界面基类
  • 测试调用
  • 优化绑定按钮事件
  • 新增提示框
    • UI绘制
    • 实现
  • 使用DOTween实现动画效果
    • 提示框动画
    • 打开UI面板动画
    • 关闭UI面板动画
  • 完整代码
  • 完结

前言

unity在4.6版本之后,引入了自己的界面显示系统,全称unity graphic user interface,即我们所熟知的ugui。
在这里插入图片描述毕竟是unity的亲儿子,这个系统一经推出,就与其灵活快速可视化,迅速抢占用户市场,逐渐成为unity ui的主流系统,但是它也并不是完美的,对于开发人员来说,使用这套系统往往需要面对如下困境,比如缺乏跨场景的u管理器,界面的上下层关系紊乱三,界面之间的通信手段贫乏等等,上述几个问题大大影响到我们的开发效率。
在这里插入图片描述
针对上述问题,我们可以选择制作一套UI管理器解决。

UI管理器

1、新增UI面板层枚举

/// <summary>
/// UI面板层枚举
/// </summary>
public enum E_UIPanelLayer
{
    None,
    Rearmost,//最后方
    Rear,//后方
    Middle,//中间
    Front,//前方
    Forefront//最前方
}

2、初始化

2.1、用代码创建画布

/// <summary>
/// 创建画布
/// </summary>
void CreateCanvas()
{
    //改Layer
    gameObject.layer = LayerMask.NameToLayer("UI");

    //添加并设置Canvas组件
    Canvas canvas = gameObject.AddComponent<Canvas>();
    canvas.renderMode = RenderMode.ScreenSpaceOverlay;
    canvas.sortingOrder = 30000;

    //添加并设置CanvasScaler组件
    CanvasScaler canvasScaler = gameObject.AddComponent<CanvasScaler>();
    canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
    canvasScaler.referenceResolution = new Vector2(Screen.width, Screen.height);
    //横版屏幕设置为1 竖版屏幕设置为0
    canvasScaler.matchWidthOrHeight = Screen.width > Screen.height ? 1 : 0;

    //添加Graphic Raycaster组件
    gameObject.AddComponent<GraphicRaycaster>();
}

效果
在这里插入图片描述

2.2、用代码创建UI面板的父物体层

// 用于记录每个层的父物体
private Dictionary<E_UIPanelLayer, Transform> layerParents;

/// <summary>
/// 创建UI面板的父物体层
/// </summary>
void CreateLayer()
{
    //Rearmost层的父物体
    Transform rearmost = new GameObject(E_UIPanelLayer.Rearmost.ToString()).transform;
    rearmost.SetParent(transform, false);

    //Rear层的父物体
    Transform rear = new GameObject(E_UIPanelLayer.Rear.ToString()).transform;
    rear.SetParent(transform, false);

    //Middle层的父物体
    Transform middle = new GameObject(E_UIPanelLayer.Middle.ToString()).transform;
    middle.SetParent(transform, false);

    //Fornt层的父物体
    Transform front = new GameObject(E_UIPanelLayer.Front.ToString()).transform;
    front.SetParent(transform, false);

    //Frontmost层的父物体
    Transform foreFront = new GameObject(E_UIPanelLayer.ForeFront.ToString()).transform;
    foreFront.SetParent(transform, false);

    //记录每个层的父物体
    layerParents = new Dictionary<E_UIPanelLayer, Transform>
    {
        { E_UIPanelLayer.Rearmost, rearmost },
        { E_UIPanelLayer.Rear, rear },
        { E_UIPanelLayer.Middle, middle },
        { E_UIPanelLayer.Front, front },
        { E_UIPanelLayer.ForeFront, foreFront }
    };
}

效果
在这里插入图片描述

2.3、代码添加EventSystem物体

/// <summary>
/// 创建EventSystem
/// </summary>
void CreateEventSystem()
{
    //如果场景中已经有一个EventSystem了,则直接返回。
    if (FindObjectOfType<EventSystem>()) return;

    GameObject eventSystem = new GameObject("EventSystem");
    DontDestroyOnLoad(eventSystem);//切换场景不销毁
    eventSystem.AddComponent<EventSystem>();
    eventSystem.AddComponent<StandaloneInputModule>();
}

效果
在这里插入图片描述

3、ShowPanel显示面板方法

//存储加载过的界面的集合
private List<UIBase> uiList = new List<UIBase>();

/// <summary>
/// 显示面板
/// </summary>
/// <typeparam name="T">UI面板脚本,记得UI面板预制体名要和脚本名一样</typeparam>
/// <param name="layer">父级层</param>
/// <returns>UIBase</returns>
public UIBase ShowUI<T>(E_UIPanelLayer layer = E_UIPanelLayer.Middle) where T : UIBase
{
	string uiName = typeof(T).Name;//获取名称
    UIBase ui = Find(uiName);
    if (ui == null)
    {
        //记录该面板要放进哪个层中来显示
        Transform parent = layerParents[layer];

        //集合中没有 需要从Resources/UI文件夹加载
        GameObject obj = Instantiate(Resources.Load("UI/" + uiName), parent) as GameObject;

        //改名字,默认实例化会加上(clone),所以得重命名
        obj.name = uiName;

        //添加需要的脚本
        ui = obj.AddComponent<T>();

        //添加到集合进行存储
        uiList.Add(ui);
    }
    else
    {
        //显示
        ui.Show();
    }
    return ui;
}

调用
在这里插入图片描述

4、HidePanel隐藏面板的方法

/// <summary>
/// 隐藏面板
/// </summary>
/// <param name="uiName">面板名</param>
public void HideUI(string uiName)
{
    UIBase ui = Find(uiName);
    if (ui != null)
    {
        ui.Hide();
    }
}

调用
在这里插入图片描述

5、CloseUI关闭界面的方法

/// <summary>
/// 关闭某个界面
/// </summary>
/// <param name="uiName">面板名</param>
public void CloseUI(string uiName)
{
    UIBase ui = Find(uiName);
    if (ui != null)
    {
        uiList.Remove(ui);
        Destroy(ui.gameObject);
    }
}

6、UI界面基类

/// <summary>
/// UI界面基类
/// </summary>
public class UIBase : MonoBehaviour
{
    //显示
    public virtual void Show()
    {
        gameObject.SetActive(true);
    }

    //隐藏
    public virtual void Hide()
    {

        gameObject.SetActive(false);
    }

    //关闭界面(销毁)
    public virtual void Close()
    {
        UIManager.Instance.CloseUI(gameObject.name);
    }
}

测试调用

欢迎面板
在这里插入图片描述

新增WelcomeUI.cs测试面板代码,注意记得继承UIBase基类

public class WelcomeUI : UIBase {
    void Awake(){
        //绑定按钮事件
        transform.Find("bg/退出按钮").GetComponent<Button>().onClick.AddListener(onCloseBtn);
        transform.Find("bg/确定").GetComponent<Button>().onClick.AddListener(onConfirmBtn);
    }
    void onCloseBtn(){
        //关闭界面
        Close();
    }

    void onConfirmBtn(){
        //隐藏
        Hide();
    }
}

新增UITest ,绘制按钮显示WelcomeUI欢迎面板

public class UITest : MonoBehaviour {
    private void OnGUI()
    {
        // 创建一个新的 GUIStyle
        GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
        // 设置字体大小
        buttonStyle.fontSize = 50; // 替换为你想要的字体大小
        buttonStyle.alignment = TextAnchor.MiddleCenter; // 可选择设置对齐方式

        if (GUI.Button(new Rect(0, 0, 500, 200), "显示欢迎面板", buttonStyle))
        {
            //显示WelcomeUI面板,创建的脚本名字记得跟预制体物体名字一致
            UIManager.Instance.ShowUI<WelcomeUI>("WelcomeUI");
        }
    }
}

效果
在这里插入图片描述

优化绑定按钮事件

每次绑定按钮事件都需要写这么多代码很麻烦,我们可以继续进行封装

新增UIEventTrigger事件监听代码

/// <summary>
/// 事件监听
/// </summary>
public class UIEventTrigger : MonoBehaviour, IPointerClickHandler
{
    //这是一个公共的委托,它接受两个参数,一个是被点击的游戏对象,另一个是关于点击事件的数据。
    public Action<GameObject, PointerEventData> onClick;

    //用于获取或添加 UIEventTrigger 组件
    public static UIEventTrigger Get(GameObject obj)
    {
        UIEventTrigger trigger = obj.GetComponent<UIEventTrigger>();
        if (trigger == null)
        {
            trigger = obj.AddComponent<UIEventTrigger>();
        }
        return trigger;
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        //这是 IPointerClickHandler 接口的方法,当 UI 元素被点击时,它将被调用。
        if (onClick != null) onClick(gameObject, eventData);
    }
}

修改UI界面基类UIBase

//注册事件
public UIEventTrigger Register(string name)
{
    Transform tf = transform.Find(name);
    return UIEventTrigger.Get(tf.gameObject);
}

测试调用

public class WelcomeUI : UIBase {
    void Awake(){
        //绑定按钮事件
        // transform.Find("bg/退出按钮").GetComponent<Button>().onClick.AddListener(onCloseBtn);
        // transform.Find("bg/确定").GetComponent<Button>().onClick.AddListener(onConfirmBtn);

        Register("bg/退出按钮").onClick = onCloseBtn;
        Register("bg/确定").onClick = onConfirmBtn;
    }

    void onCloseBtn(GameObject obj, PointerEventData pData){
        //关闭界面
        Close();
    }

    void onConfirmBtn(GameObject obj, PointerEventData pData){
        //隐藏
        Hide();
    }
}

效果,和前面一样
在这里插入图片描述

新增提示框

UI绘制

背景图片
在这里插入图片描述
配置
在这里插入图片描述

实现

修改UIManager

/// <summary>
/// 提示界面
/// </summary>
/// <param name="msg">文本</param>
/// <param name="color">颜色</param>
/// <param name="callback">完成回调事件</param>
public void ShowTips(string msg, Color color, float showTime = 0.5f, UnityAction callback = null, E_UIPanelLayer layer = E_UIPanelLayer.ForeFront)
{
    UIBase ui = ShowUI<TipsUI>(layer);
    TextMeshProUGUI text = ui.transform.Find("bg/text").GetComponent<TextMeshProUGUI>();
    text.color = color;
    text.text = msg;
}

测试调用

UIManager.Instance.ShowTips("成功!", Color.green);

效果
在这里插入图片描述

使用DOTween实现动画效果

参考:【推荐100个unity插件之2】DoTween动画插件的安装和使用整合(最全)

提示框动画

实现面板先经过0.4sY轴缩放从0变为1,再暂停showTime秒后,经过0.4sY轴缩放从1变回0,动画播放完成调用callback事件

/// <summary>
/// 提示界面
/// </summary>
/// <param name="msg">文本</param>
/// <param name="color">颜色</param>
/// <param name="showTime">显示时间</param>
/// <param name="callback">完成回调事件</param>
public void ShowTips(string msg, Color color, float showTime = 0.5f, UnityAction callback = null, E_UIPanelLayer layer = E_UIPanelLayer.ForeFront)
{
	DOTween.CompleteAll(true);

    UIBase ui = ShowUI<TipsUI>("TipsUI", layer);
    TextMeshProUGUI text = ui.transform.Find("bg/text").GetComponent<TextMeshProUGUI>();
    text.color = color;
    text.text = msg;
    
    // DOTween动画 方法一
    // Sequence sequence = DOTween.Sequence();
    // sequence.Append(ui.transform.DOScaleY(1, 0.4f).From(0)) // 第一个动画,缩放到 1
    // .Append(DOVirtual.DelayedCall(showTime, () => { })) // 延迟
    // .Append(ui.transform.DOScaleY(0, 0.4f).From(1)) // 第二个动画,缩放到 0
    // .OnComplete(() =>
    // {
    //     ui.gameObject.SetActive(false); // 隐藏 UI
    //     callback?.Invoke(); // 调用回调
    // });

    // DOTween动画 方法二
    ui.transform
    .DOScaleY(1, 0.4f)
    .From(0)
    .OnComplete(() =>
    {
        // 延迟显示时间
        DOVirtual.DelayedCall(showTime, () =>
        {
            ui.transform.DOScaleY(0, 0.4f).From(1)
                .OnComplete(() =>
                {
                    ui.gameObject.SetActive(false);
                    callback?.Invoke();
                });
        });
    });
}

效果
在这里插入图片描述

打开UI面板动画

修改UIManager里的ShowUI方法,新增DOTween代码即可

ui.transform.DOScale(Vector3.one, 0.5f).From(Vector3.zero);

效果
在这里插入图片描述

关闭UI面板动画

//动画
CanvasGroup canvasGroup = ui.transform.GetComponent<CanvasGroup>();
Sequence closeSequence = DOTween.Sequence();
closeSequence.Append(canvasGroup.DOFade(0, 0.8f)) // 淡出
.Join(ui.transform.DOLocalMoveX(2000f, 0.8f)) // 同时移动
.OnComplete(() =>
{
    ui.gameObject.SetActive(false);
});

效果
在这里插入图片描述

完整代码

UIEventTrigger.cs

/// <summary>
/// 事件监听
/// </summary>
public class UIEventTrigger : MonoBehaviour, IPointerClickHandler
{
    //这是一个公共的委托,它接受两个参数,一个是被点击的游戏对象,另一个是关于点击事件的数据。
    public Action<GameObject, PointerEventData> onClick;

    //用于获取或添加 UIEventTrigger 组件
    public static UIEventTrigger Get(GameObject obj)
    {
        UIEventTrigger trigger = obj.GetComponent<UIEventTrigger>();
        if (trigger == null)
        {
            trigger = obj.AddComponent<UIEventTrigger>();
        }
        return trigger;
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        //这是 IPointerClickHandler 接口的方法,当 UI 元素被点击时,它将被调用。
        if (onClick != null) onClick(gameObject, eventData);
    }
}

UIBase.cs

/// <summary>
/// UI界面基类
/// </summary>
public class UIBase : MonoBehaviour
{
    //显示
    public virtual void Show()
    {
        transform.localPosition = Vector3.zero;
        gameObject.SetActive(true);
    }

    //隐藏
    public virtual void Hide()
    {
        UIManager.Instance.HideUI(gameObject.name);
    }

    //关闭界面(销毁)
    public virtual void Close()
    {
        UIManager.Instance.CloseUI(gameObject.name);
    }

    //注册事件
    public UIEventTrigger Register(string name)
    {
        Transform tf = transform.Find(name);
        return UIEventTrigger.Get(tf.gameObject);
    }
}

UIManager.cs

/// <summary>
/// UI管理器
/// </summary>
public class UIManager : SingletonMono<UIManager>
{
    // 用于记录每个层的父物体
    private Dictionary<E_UIPanelLayer, Transform> layerParents;

    //存储加载过的界面的集合
    private List<UIBase> uiList = new List<UIBase>();

    #region 初始化
    void Awake()
    {
        //创建画布
        CreateCanvas();
        //创建UI面板的父物体层
        CreateLayer();
        //创建EventSystem
        CreateEventSystem();
    }

    /// <summary>
    /// 创建画布
    /// </summary>
    void CreateCanvas()
    {
        //改Layer
        gameObject.layer = LayerMask.NameToLayer("UI");

        //添加并设置Canvas组件
        Canvas canvas = gameObject.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        canvas.sortingOrder = 30000;

        //添加并设置CanvasScaler组件
        CanvasScaler canvasScaler = gameObject.AddComponent<CanvasScaler>();
        canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        canvasScaler.referenceResolution = new Vector2(Screen.width, Screen.height);
        //横版屏幕设置为1 竖版屏幕设置为0
        canvasScaler.matchWidthOrHeight = Screen.width > Screen.height ? 1 : 0;

        //添加Graphic Raycaster组件
        gameObject.AddComponent<GraphicRaycaster>();
    }

    /// <summary>
    /// 创建UI面板的父物体层
    /// </summary>
    void CreateLayer()
    {
        //Rearmost层的父物体
        Transform rearmost = new GameObject(E_UIPanelLayer.Rearmost.ToString()).transform;
        rearmost.SetParent(transform, false);

        //Rear层的父物体
        Transform rear = new GameObject(E_UIPanelLayer.Rear.ToString()).transform;
        rear.SetParent(transform, false);

        //Middle层的父物体
        Transform middle = new GameObject(E_UIPanelLayer.Middle.ToString()).transform;
        middle.SetParent(transform, false);

        //Fornt层的父物体
        Transform front = new GameObject(E_UIPanelLayer.Front.ToString()).transform;
        front.SetParent(transform, false);

        //Frontmost层的父物体
        Transform foreFront = new GameObject(E_UIPanelLayer.ForeFront.ToString()).transform;
        foreFront.SetParent(transform, false);

        //记录每个层的父物体
        layerParents = new Dictionary<E_UIPanelLayer, Transform>
        {
            { E_UIPanelLayer.Rearmost, rearmost },
            { E_UIPanelLayer.Rear, rear },
            { E_UIPanelLayer.Middle, middle },
            { E_UIPanelLayer.Front, front },
            { E_UIPanelLayer.ForeFront, foreFront }
        };
    }

    /// <summary>
    /// 创建EventSystem
    /// </summary>
    void CreateEventSystem()
    {
        //如果场景中已经有一个EventSystem了,则直接返回。
        if (FindObjectOfType<EventSystem>()) return;

        GameObject eventSystem = new GameObject("EventSystem");
        DontDestroyOnLoad(eventSystem);//切换场景不销毁
        eventSystem.AddComponent<EventSystem>();
        eventSystem.AddComponent<StandaloneInputModule>();
    }
    #endregion

    /// <summary>
    /// 显示面板
    /// </summary>
    /// <typeparam name="T">UI面板脚本,记得UI面板预制体名要和脚本名一样</typeparam>
    /// <param name="layer">父级层</param>
    /// <param name="doTween">是否使用doTween动画</param>
    /// <returns>UIBase</returns>
    public UIBase ShowUI<T>(E_UIPanelLayer layer = E_UIPanelLayer.Middle, bool doTween = true) where T : UIBase
    {
        DOTween.CompleteAll(true);
        string uiName = typeof(T).Name;//获取名称
        UIBase ui = Find(uiName);
        if (ui == null)
        {
            //记录该面板要放进哪个层中来显示
            Transform parent = layerParents[layer];

            //集合中没有 需要从Resources/UI文件夹加载
            GameObject obj = Instantiate(Resources.Load("UI/" + uiName), parent) as GameObject;

            //改名字,默认实例化会加上(clone),所以得重命名
            obj.name = uiName;

            //添加需要的脚本
            ui = obj.AddComponent<T>();

            //添加CanvasGroup组件,用于后面渐变使用
            obj.AddComponent<CanvasGroup>();

            //添加到集合进行存储
            uiList.Add(ui);
        }
        else
        {
            //显示
            ui.Show();
        }

        //透明度设置为1
        CanvasGroup canvasGroup = ui.transform.GetComponent<CanvasGroup>();
        canvasGroup.alpha = 1f;

        //动画
        if (doTween) ui.transform.DOScale(Vector3.one, 0.5f).From(Vector3.zero);

        return ui;
    }

    /// <summary>
    /// 隐藏面板
    /// </summary>
    /// <param name="uiName">面板名</param>
    public void HideUI(string uiName, bool doTween = true)
    {
        DOTween.CompleteAll(true);

        UIBase ui = Find(uiName);
        if (ui == null) return;
        if (doTween)
        {
            //动画
            CanvasGroup canvasGroup = ui.transform.GetComponent<CanvasGroup>();
            Sequence closeSequence = DOTween.Sequence();
            closeSequence.Append(canvasGroup.DOFade(0, 0.8f)) // 淡出
            .Join(ui.transform.DOLocalMoveX(2000f, 0.8f)) // 同时移动
            .OnComplete(() =>
            {
                ui.gameObject.SetActive(false);
            });
        }
        else
        {
            ui.gameObject.SetActive(false);
        }
    }
    /// <summary>
    /// 关闭某个界面
    /// </summary>
    /// <param name="uiName">面板名</param>
    public void CloseUI(string uiName, bool doTween = true)
    {
        DOTween.CompleteAll(true);

        UIBase ui = Find(uiName);
        if (ui == null) return;
        if (doTween)
        {
            //动画
            CanvasGroup canvasGroup = ui.transform.GetComponent<CanvasGroup>();
            Sequence closeSequence = DOTween.Sequence();
            closeSequence.Append(canvasGroup.DOFade(0, 0.8f)) // 淡出
             .Join(ui.transform.DOLocalMoveX(2000f, 0.8f)) // 同时移动
             .OnComplete(() =>
            {
                uiList.Remove(ui);
                Destroy(ui.gameObject);
            });
        }
        else
        {
            uiList.Remove(ui);
            Destroy(ui.gameObject);
        }
    }

    //关闭所有界面
    public void CloseAllUI()
    {
        for (int i = uiList.Count - 1; i >= 0; i--)
        {
            Destroy(uiList[i].gameObject);
        }
        uiList.Clear();//清空合集
    }

    /// <summary>
    /// 从集合中找到名字对应的界面脚本
    /// </summary>
    /// <param name="uiName">面板名</param>
    /// <returns>UIBase</returns>
    public UIBase Find(string uiName)
    {
        for (int i = 0; i < uiList.Count; i++)
        {
            if (uiList[i].name == uiName) return uiList[i];
        }
        return null;
    }

    /// <summary>
    /// 提示界面
    /// </summary>
    /// <param name="msg">文本</param>
    /// <param name="color">颜色</param>
    /// <param name="showTime">显示时间</param>
    /// <param name="callback">完成回调事件</param>
    public void ShowTips(string msg, Color color, float showTime = 0.5f, UnityAction callback = null, E_UIPanelLayer layer = E_UIPanelLayer.ForeFront)
    {
        DOTween.CompleteAll(true);

        UIBase ui = ShowUI<TipsUI>(layer, false);
        TextMeshProUGUI text = ui.transform.Find("bg/text").GetComponent<TextMeshProUGUI>();
        text.color = color;
        text.text = msg;

        //动画
        Sequence sequence = DOTween.Sequence();
        sequence.Append(ui.transform.DOScaleY(1, 0.4f).From(0)) // 第一个动画,缩放到 1
        .Append(DOVirtual.DelayedCall(showTime, () => { })) // 延迟
        .Append(ui.transform.DOScaleY(0, 0.4f).From(1)) // 第二个动画,缩放到 0
        .OnComplete(() =>
        {
            ui.gameObject.SetActive(false); // 隐藏 UI
            callback?.Invoke(); // 调用回调
        });
    }
}

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言初步介绍(初学者,大学生)【上】

1.C语⾔是什么&#xff1f; ⼈和⼈交流使⽤的是⾃然语⾔&#xff0c;如&#xff1a;汉语、英语、⽇语 那⼈和计算机是怎么交流的呢&#xff1f;使⽤ 计算机语⾔ 。 ⽬前已知已经有上千种计算机语⾔&#xff0c;⼈们是通过计算机语⾔写的程序&#xff0c;给计算机下达指令&am…

【AIGC产品经理】面试7家,拿到2个offer,薪资中上水平

Hello&#xff0c;大家好&#xff0c;我是一名不知名的5年B端金融产品经验的产品经理&#xff0c;成功转行AI产品经理&#xff0c;前期面试了北京百度、阿里、理想汽车、百川智能、华为、OPPO等多家大厂面试&#xff0c;但是由于已定居成都&#xff0c;主动终止了后续需要线下的…

ubuntu 系统安装

使用VMware虚拟机上进行实现 官网下载地址&#xff1a; https://cn.ubuntu.com/download https://releases.ubuntu.com 操作系统手册&#xff1a; https://ubuntu.com/server/docs/ &#xff08;里面包含安装文档&#xff09; 安装指南&#xff08;详细&#xff09;&#xff1a…

一手信息:用ai怎么做短视频赚钱。

AI制作短视频赚钱的具体数据与分析如下&#xff1a; 数据展示 ​ 更多实操教程和AI绘画工具,可以扫描下方,免费获取 \1. 收入情况&#xff1a; - 有案例显示&#xff0c;通过AI生成历史解说视频&#xff0c;半年内可以赚取64万人民币。 - 另一个案例则是通过AI生成电影解说…

鸿蒙 Next 实战: 环境搭建

前言 作为独立开发者&#xff0c;如果我们错过了传统移动 App&#xff0c;和后起小程序的红利&#xff0c;那万物互联 AI 的应用开发就得抓住了。 虽然个人上架应用平台难易都差不多&#xff0c;但是鸿蒙生态当前正需要广大开发者参与&#xff0c;一旦上架&#xff0c;相比其…

AI绘画ComfyUI 完全入门:基本功能完全掌握!

前言 大家好&#xff0c;我是每天分享AI应用的萤火君&#xff01; 在AI绘画领域&#xff0c;Stable Diffusion 因其开源特性而受到广泛的关注和支持&#xff0c;背后聚拢了一大批的应用开发者和艺术创作者&#xff0c;是AI绘画领域当之无愧的王者。 目前使用 Stable Diffusi…

外国钞票面值检测系统源码分享

外国钞票面值检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

新版AndroidStudio log使用

从Android Studio Dophin开始&#xff0c;Android Studio中的默认展示了新版的logcat。新版的logcat色彩上是更加的好看了&#xff0c;不同的tag会有不同的颜色&#xff0c;不同level等级的log默认也有不同的颜色。log过滤修改的更简洁了&#xff0c;当然使用起来也更加复杂了。…

系统开发基础错题解析一【软考】

目录 前言1.开发模型1.1快速原型模型优点1.2敏捷统一模型1.3增量模型的优缺点1.4极限编程1.5螺旋模型 2.软件开发方法3.数据流图与数据字典3.1判定表3.2数据流图绘制3.3决策树 4.概要设计和详细设计5.内聚性6.耦合性 前言 本文专门用来记录本人在做软考中有关系统开发基础的错…

基于SpringBoot+Vue的宠物店管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

0基础跟德姆(dom)一起学AI 机器学习03-线性回归

线性回归 线性回归介绍 【理解】举个栗子 假若有了身高和体重数据&#xff0c;来了播仔的身高&#xff0c;你能预测播仔体重吗? 这是一个回归问题&#xff0c;该如何求解呢? **思路**:先从已知身高X和体重Y中找规律&#xff0c;再预测 •数学问题&#xff1a;用一条线来拟…

【LeetCode】每日一题 2024_10_7 最低加油次数(堆、贪心)

前言 每天和你一起刷 LeetCode 每日一题~ 大家国庆节快乐呀~ LeetCode 启动&#xff01; 国庆最后一天&#xff0c;力扣还在加油站&#xff0c;怕不是国庆回家路上堵车了 题目&#xff1a;最低加油次数 代码与解题思路 func minRefuelStops(target int, startFuel int, st…

失业的程序员除了找工作,还有哪些赚钱的路子?零基础入门到精通,收藏这篇就够了_网络开发怎么赚钱

看到一个平台上的博主&#xff0c;目前在做独立开发者&#xff0c;开发了20多个网站&#xff0c;网站的类型主要是工具型和信息整理型&#xff0c;谷歌广告的收益一个月1万多。 目前他除了依靠谷歌广告的收入外&#xff0c;也在做自媒体&#xff0c;拓展这一块的收入&#xff…

41亿收购百年零部件巨头,「果链一哥」欲再造千亿规模新版图?

、 为了进一步拓展汽车业务版图&#xff0c;果链一哥立讯精密再次开启“买买买”模式。 日前&#xff0c;立讯精密发布公告称&#xff0c;计划以5.25亿欧元&#xff08;约41.3亿元人民币&#xff09;的价格收购Leoni AG&#xff08;以下简称“莱尼公司”&#xff09;50.1%股权…

打卡第五天 P3916 图的遍历

今天是我打卡第五天&#xff0c;做个普及/提高−题吧(#^.^#) 原题链接&#xff1a;图的遍历 - 洛谷 题目描述 给出 N 个点&#xff0c;M 条边的有向图&#xff0c;对于每个点 v&#xff0c;求 A(v)A(v) 表示从点 v 出发&#xff0c;能到达的编号最大的点。 输入格式 第 1 …

Golang反射解说

在Go语言中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时检查、修改和操作变量的类型信息。 反射主要用于处理那些在编译时无法确定类型的情况&#xff0c;比如处理接口类型的值、实现通用的函数等。 Go语言中反射的基本…

OpenAI 旧金山开发者大会发布五大创新功能 实时语音、视觉微调、模型蒸馏

在10月1日的 OpenAI 旧金山开发者大会&#xff08; DevDay&#xff09; 上 。OpenAI 公布了五项重大创新&#xff0c;其中“实时 API”&#xff08;Realtime API&#xff09;的新功能&#xff0c;使得开发者能够创建具有低延迟、AI 生成的语音响应功能的应用程序。尽管这一功能…

C++ | Leetcode C++题解之第461题汉明距离

题目&#xff1a; 题解&#xff1a; class Solution { public:int hammingDistance(int x, int y) {int s x ^ y, ret 0;while (s) {s & s - 1;ret;}return ret;} };

MySQL 篇-深入了解视图、SQL 优化(主键优化、order by 优化、group by 优化、update 优化等)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 SQL 优化 1.1 SQL 优化 - 插入数据 1.2 SQL 优化 - 主键优化 1.2.1 页分裂 1.2.2 页合并 1.2.3 主键设计原则 1.3 SQL 优化 - order by 优化 1.3.1 单字段排序 1.…

JS设计模式之职责链模式:优雅地处理请求流程

一. 前言 在前端开发中&#xff0c;我们经常会遇到需要按照一定的顺序处理一系列请求或操作的情况&#xff0c;如果将每一步处理都硬编码在一起&#xff0c;会导致代码臃肿&#xff0c;可维护性和可扩展性都会大大降低。而职责链模式恰好提供了一种优雅的解决方案。 无论你是…