MMO 地图传送,UI系统框架设计

news2024/11/25 13:50:50

地图传送

 创建传送点

建碰撞器触发

//位置归零

建一个传送门cube放到要传送的位置(这个teleporter1是传出的区域

这是从另一张地图传入时的传送门

创建一个脚本TeleporterObject给每个传送cube都绑上脚本

通过脚本,让传送门在编辑器下面还能绘制出来

给每个传送点编号

注意!这里的传送点cube要设置Layer:Teleport:因为角色(层级是Defalut)会触发传送点;而Default之间不能碰撞

把特效挂在传送点上

//把野外场景的传送也加上(并把传送门的id改了

碰撞检测

TelePorterObject:OnTriggerEnter

private void OnTriggerEnter(Collider other)
{
    PlayerInputController playerInputController=other.GetComponent<PlayerInputController>();
    //传入的对象是否有玩家控制器
    if(playerInputController!=null&&playerInputController.isActiveAndEnabled)
    {
        //得到传送点的ID
        TeleporterDefine teleDefine = DataManager.Instance.Teleporters[this.ID];
        if(teleDefine==null)
        {
            //从角儿控制器取得角色character,第几个传送点
            Debug.LogErrorFormat("TeleporterObject: Character [{0}] Enter Teleporter [{1}] ,But TeleporterDefine not existed", playerInputController.character.Info.Name, this.ID);
            return;
        }
        Debug.LogFormat("TeleporterObject: Character[{0}] Enter Telepoter [{1}:{2}] ",playerInputController.character.Info.Name, teleDefine.ID,teleDefine.Name); ;
        if(teleDefine.LinkTo>0)
        {
            if(DataManager.Instance.Teleporters.ContainsKey(teleDefine.LinkTo))
                MapService.Instance.SendMapTeleporter(this.ID);
            else Debug.LogErrorFormat("Teleporter ID:{0} LinkID {1} error!",teleDefine.ID,teleDefine.LinkTo);   
        }
    }
}

在MapService中发送进入传送点的信息SendMapTeleporter

SendMapTeleporter

public void SendMapTeleport(int teleporterID)
{
    Debug.LogFormat("MapTeleporterRequest :teleporterID:{0}", teleporterID);
    NetMessage message = new NetMessage();
    message.Request = new NetMessageRequest();
    message.Request.mapTeleport = new MapTeleportRequest();
    message.Request.mapTeleport.teleporterId = teleporterID;
    NetClient.Instance.SendMessage(message);
}

向客户端发送有角色进入传送点的信息

message MapTeleportRequest
{
	int32 teleporterId = 1;
}

只需要传一个传送点id即可(也可以传地图的id,再传送点的id)

 服务端的协议处理MapService:OnMapTeleport

在MapService()中, 

订阅:

     MessageDistributer<NetConnection<NetSession>>.Instance.Subscribe<MapTeleportRequest>(this.OnMapTeleport);

void OnMapTeleport(NetConnection<NetSession> sender,MapTeleportRequest request)
{
    //得到客户端进行传送点传送的对象
    Character character=sender.Session.Character;
    Log.InfoFormat("OnMapTeleporter: characterID:{0}:{1} TeleporterId:{2}", character.Id, character.Data, request.teleporterId);

    //没有该传送点
    if(!DataManager.Instance.Teleporters.ContainsKey(request.teleporterId))
    {
        Log.WarningFormat("Source TeleporterID[{0}] not existed", request.teleporterId);
        return;
    }
    

    TeleporterDefine teleportDefine=DataManager.Instance.Teleporters[request.teleporterId]; 
    if(teleportDefine.LinkTo==0||!DataManager.Instance.Teleporters.ContainsKey(teleportDefine.LinkTo))
    {
        Log.WarningFormat("Source TeleporterID [{0}] LinkTo ID [{1}] not existed", request.teleporterId, teleportDefine.LinkTo);
    }

    //从客户端传过来的传送点数据表teleportDefine.LinkTo:6 
    //取的key为6 传送目标点
    TeleporterDefine teleporterDefine1 = DataManager.Instance.Teleporters[teleportDefine.LinkTo];

    //角色所在的地图,角色离开处理
    MapManager.Instance[teleportDefine.MapID].CharacterLeave(character);
    //把新位置信息填充给角色
    character.Position=teleporterDefine1.Position;
    character.Direction=teleporterDefine1.Direction;
    //角色进入新地图
    MapManager.Instance[teleporterDefine1.MapID].CharacterEnter(sender,character);
}

//关于传送点配置表TeleporterDefine:

点击这里查看是否有TeleporterDefine配置表生成

扩展编辑器MapTool

在Asset/Editor目录下:

首先把DataManager(角色,传送门,地图之类的信息加载Load

获取当前场景

获取所有传送点

遍历所有的地图,得到地图文件.unity;打开每个场景

获取传送点,检查所有的传送点id在配置表中是否存在

传送点teleportDefine对应的地图id是否正确

把世界坐标转换成逻辑坐标存到配置表中

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEditor;
using Common.Data;
public class MapTool : MonoBehaviour
{
    [MenuItem("Map Tools/Export Teleportters")]
    //扩展功能:static
    public static void ExportTeleporters()
    {
        DataManager.Instance.Load();

        Scene current=EditorSceneManager.GetActiveScene();
        string currentScene=current.name;
        //把当前场景记录下来,并检查有无保存
        if(current.isDirty)
        {
            EditorUtility.DisplayDialog("提示", "请先保存当前场景", "确定");
            return;
        }

        List<TeleporterObject> allTeleporters=new List<TeleporterObject>();

        foreach(var map in DataManager.Instance.Maps)
        {//根据地图里配置名字生成原始路径
            string sceneFile = "Assets/Levels/" + map.Value.Resource + ".unity";
            if(!System.IO.File.Exists(sceneFile))
            {//判断每一个场景文件是否存在
                Debug.LogWarningFormat("Scene {0} not existed!", sceneFile);
                continue;
            }
            //打开单个场景
            EditorSceneManager.OpenScene(sceneFile,OpenSceneMode.Single);

            //检查所有的传送点
            TeleporterObject[] teleporters=GameObject.FindObjectsOfType<TeleporterObject>();    
            foreach(var teleporter in teleporters)
            {
                Debug.Log("传送点ID" + teleporter.ID);
                if(!DataManager.Instance.Teleporters.ContainsKey(teleporter.ID))
                {//检查传送点的id在配置表中是否存在
                    EditorUtility.DisplayDialog("错误", string.Format("地图:{0} 中配置的 Teleporter:[{1}]中不存在", map.Value.Resource, teleporter.ID), "确定");
                    return;
                }

                TeleporterDefine def=DataManager.Instance.Teleporters[teleporter.ID];
                if (def.MapID != map.Value.ID)
                {//地图配的mapID是否正确
                    EditorUtility.DisplayDialog("错误", string.Format("地图:{0} 中的配置的Teleporter:[{1}] MapID:{2} 错误", map.Value.Resource,teleporter.ID,def.MapID), "确定");
                    return;
                }
                def.Position=GameObjectTool.WorldToLogicN(teleporter.transform.position);
                def.Direction=GameObjectTool.WorldToLogicN(teleporter.transform.forward);
            }
        }
        //Save逻辑写在DataMangaer下,运行时是不会受影响的
        DataManager.Instance.SaveTeleporters();
        EditorSceneManager.OpenScene("Assets/Levels/" + currentScene + ".unity");
        EditorUtility.DisplayDialog("提示", "传送点导出完成", "确定");
    }
    
}

演示:

传送成功;

 传送请求:1号传送点传送到野外的6号点

//从野外传回主城

5号传送点,传LinkTo2号传送点

//但是在野外的相机没有对着角色;在两个场景的切换时,角色会浮空

//Add:可以在场景切换时做一个Loading进度条掩盖

->Map01只有MainPlayerCamera带过来的相机发挥跟随角色的作用//创建角色时相机已经挂上了,删掉野外的一个Camera即可

关于到了新的场景中固定UI没有显示

把UIMainCity做成单例

(在加载新场景时UIMainCity会再创建实例

//可以看到现在加载到另一个场景,显示了UIMainCity和MainPlayerCamera以及UIWorldElementManager等;还有一些在每个场景中必要的GameObject:

//它们都是挂了单例脚本的物体

UI系统框架设计

UI的分类:

UI框架的设计:

补充:断开连接角色处理

 关于在客户端与服务器断开连接,服务器不重启,重启客户端;DisConnected->Connected

登入主城发现客户端界面 有两个角色:因此每次断开连接时,要把数据session全部清理掉

在NetService:Disconnected方法中加上这://作用时清理数据

 在NetSession中做修复Disconnected

删掉角色所有信息

internal void Disconnted()
{
    if(this.Character!=null)
        //角色离开
        UserService.Instance.CharacterLeave(this.Character);    
}

UserService:CharacterCreate

对于用户离开游戏OnGameLeave,里面有RemoveCharacter和map[mapid].CharacterLeave

我们重构这两句

并改成公有的://这样NetSession就可以引用了

演示

没有做断开连接角色处理的服务器页面:

没有角色离开

再进入主城是有上一次客户端数据的残留

进入主城后关掉客户端

已经做角色离开了:CharacterLeave

在启动客户端,进入主城

地图上只有一个角色

 //关于刷新数据

例如小地图的mapImage

//小地图需要在世界场景下加一个BoundingBox;根据当前角色的位置更新在小地图上的位置

需要将每次切换场景时把角色数据都拉一次进来

在UIMinmap.cs中,只有在启动时才加载了小地图

UIMain

UIMainCity更名为UIMain//对应脚本也改掉

把UIMain做成了单例,这样每个场景都能有固定UI(小地图,技能栏;初次出现是在MainCity场景中,后面可以在这个场景下的UIMain节点下做各种UI物体

把initmap改为updatemap

UIMain.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Models;
using Services;
public class UIMain : MonoSingleton<UIMain>
{
    public Text avatarName;
    public Text avatarLevel;
    protected override void OnStart()
    {//在启动时候刷新
        this.UpdateAvatar();
    }

    void UpdateAvatar()
    {
        //User是单例类,存放用户和角色的各种相关信息//CurrentCharacter存储网络传回来的信息(姓名角色等级..)
        this.avatarName.text = string.Format("{0}[{1}]", User.Instance.CurrentCharacter.Name, User.Instance.CurrentCharacter.Id);
        this.avatarLevel.text = User.Instance.CurrentCharacter.Level.ToString();
    }
    void Update()
    {
        
    }
    public void BackToCharSelect()
    {
        SceneManager.Instance.LoadScene("CharSelect");
        UserService.Instance.SendGameLeave();
    }

    
}

切换地图,要换的小地图数据,在MinimapManager中管理这些数据

同时小地图管理器要知道小地图是哪个,这样就能对不同的小地图进行统一管理

现在的MinimapManager:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Analytics;
using Models;
namespace Managers
{
    class MinimapManager : Singleton<MinimapManager>
    {
        public UIMinmap UIminimap;

        private Collider minimapBoundingBox;
        public Collider MinimapBoundingBox
        {
            get { return minimapBoundingBox; }
        }
        public Transform PlayerTransform
        {
            get
            {
                if (User.Instance.CurrentCharacterObject == null)
                    return null;
                return User.Instance.CurrentCharacterObject.transform;
            }
        }
        public Sprite LoadCurrentMinimap()
        {
            //返回图片所在的路径:图片资源放在了Resources下面
            //这里用拼接字符串形成了完整路径
            return Resloader.Load<Sprite>("UI/Minimap/" + User.Instance.CurrentMapData.MiniMap);
        }
       
        public void UpdateMinimap(Collider minimapBoundingBox)
        {
            //minimapBoundingBox change->告诉小地图:他变了

            this.minimapBoundingBox=minimapBoundingBox;
            if (this.UIminimap != null)
                this.UIminimap.UpdateMap();
        }
    }
}

在UIMinmap中引入minimap对象

于是我们就能在MinimapManager管理器中做小地图的更新UpdateMinimap

 public void UpdateMinimap(Collider minimapBoundingBox)
 {
     //minimapBoundingBox change->告诉小地图:他变了

     this.minimapBoundingBox=minimapBoundingBox;
     if (this.minimap != null)
         this.minimap.UpdateMap();
 }

在此方法中又调用UIMinimap中更新小地图的方法:UpdateMap

原来的方法中用的minmapBoundingBox在主城中通过public得到的,现在需要更新它

注意!每次切换地图是角色是重新创建的,角色的信息都会被删除,因此我们要把角色清空掉

如果不清空的话,Update里面的就不会更新了;

注意!现在小地图不要需要这一句:

切换场景(地图变化)时调用UpdateMinimap

MinimapManager:UpdateMinimap
public void UpdateMinimap(Collider minimapBoundingBox)
{
    //minimapBoundingBox change->告诉小地图:他变了

    this.minimapBoundingBox=minimapBoundingBox;
    if (this.UIminimap != null)
        this.UIminimap.UpdateMap();
}

如果每个地图有一个唯一的脚本,地图加载的时候脚本就执行

->在每个场景下创建一个MapRoot,再新建一个地图控制器MapController;

当前地图已经加载了就通知小地图管理器,更新小地图,并传入一个包围盒

MapController
 public Collider minimapBoundingbox;
 void Start()
 {
     MinimapManager.Instance.UpdateMinimap(minimapBoundingbox);
 }
总结

地图控制器把包围传给-----小地图管理器的UpdateMinimap方法,传给-----小地图UpdateMap方法

MapController:

        MinimapManager.Instance.UpdateMinimap(minimapBoundingbox);

MinimapManager:

                this.UIminimap.UpdateMap();

UIminimap

        this.minmapBoundingBox = MinimapManager.Instance.MinimapBoundingBox;

->UIMain是单例,UIMain下面有UIMinimap:

把每一个场景都做一个MapRoot绑上地图控制器拖上包围盒

启动演示:

//Add可以加一个加速按钮(背包里的滑板车//未做
UIManager

//是Singleton单例

各种弹出ui(如商店,NPC对话,任务栏)的共同事件汇总(框架)

UI元素(已经做好的prefab//被放在Resources/UI下面

展示面板:show

关闭面板:close

//里面做一些实例化或销毁

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class UIManager : MonoSingleton<UIManager>
{
    class UIElement
    {//UI元素
        public string Resources;//资源路径
        public bool Cache;
        public GameObject Instance;
    }
    //用来保存定义的UI信息
    private Dictionary<Type,UIElement>UIResources=new Dictionary<Type, UIElement>();

    public UIManager()
    {
        this.UIResources.Add(typeof(UITest),new UIElement() { Resources="UI/UITest",Cache=true});
    }

    ~UIManager()
    {

    }

    public T Show<T>()
    {
        //声音播放
        //SoundManager.Instance.PlaySound("ui_open");
        Type type = typeof(T);
        if(this.UIResources.ContainsKey(type))
        {
            UIElement UIElementinfo=this.UIResources[type];
            if(UIElementinfo.Instance!=null)
            {//如果这个UI元素有实例了,激活
                UIElementinfo.Instance.SetActive(true);
            }
            else
            {//从资源中加载prefab
                UnityEngine.Object prefab=Resources.Load(UIElementinfo.Resources);
                if(prefab==null)
                {
                    return default(T);  
                }//实例化
                UIElementinfo.Instance=(GameObject)GameObject.Instantiate(prefab);  
            }
            return UIElementinfo.Instance.GetComponent<T>();
        }
        return default(T);
    }
    public void Close(Type type)
    {
        //SoundManager.Instance.PlaySound("ui_close");
        if(this.UIResources.ContainsKey(type))
        {
            UIElement UIElementinfo=this.UIResources[type];
            if(UIElementinfo.Cache)//如果启用了Cache则不销毁
                UIElementinfo.Instance.SetActive(false);//?
            else
            {
                GameObject.Destroy(UIElementinfo.Instance);
                UIElementinfo.Instance = null;
            }
        }
    }
}
UIWindows

委托接受UIWindows对象,和WindowsResult结果对象

委托类型 的OnClose事件

获取类型,结果类型

Close方法:有窗口才关闭

yes/no按钮的事件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class UIWindows : MonoBehaviour
{//给所有的UI当父类用
    public delegate void CloseHandler(UIWindows sender, WindowResult result);
    public event CloseHandler OnClose;

    public virtual System.Type Type
    {//获取类型
        get
        {
            return this.GetType();  
        }
    }

    //内置了一个结果类型
    public enum WindowResult
    {
        None=0,
        Yes,
        No,
    }

    public void Close(WindowResult result=WindowResult.None)
    {
        //做UIManager.Close;并且OnClose关闭窗口事件
        UIManager.Instance.Close(this.Type);
        if(this.OnClose!=null)
            this.OnClose(this,result);
        this.OnClose = null;
    }

    public virtual void OnCloseClick()
    {//用来关闭
        this.Close();
    }
    public virtual void OnYesClick()
    {//用来确认
        this.Close(WindowResult.Yes);
    }

    private void OnMouseDown()
    {//一个测试检测鼠标有没有按下
        Debug.LogFormat(this.name + " Clicked");
    }
}

写一个关于UIManager为框架,UIWindows的子类:UITest

UITest

先把UI面板做好prefab放在Resources/UI

 UITest脚本:

//继承UIWindows即可

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UITest : UIWindows
{
}

在UITest画布下要给按钮绑定事件,可以找到UIWindows的按钮事件

把做好的UITest画布放在

在UIManage中:

要先把UITest加到管理器中,管理器才能使用它:
 

        this.UIResources.Add(typeof(UITest),new UIElement() { Resources="UI/UITest",Cache=true});

//后面若有UIShopCanvas;类似该语句添加

测试新加上来的UITest:

在UIMain中加一个按钮可以打开UITest

在UIMain中加一个测试事件

public void OnClickTest()
{
    UIManager.Instance.Show<UITest>();
}

把事件绑到这些按钮上

演示:

在OnClickTest中执行一些UITest的方法

public void OnClickTest()
{
    UITest uitest=UIManager.Instance.Show<UITest>();
    //可以用uitest调用UItest的方法
    uitest.SetTitle("新标题");
}
public class UITest : UIWindows
{
    public Text Title;

    public void SetTitle(string title)
    {
        this.Title.text = title;
    }
}

//注意:UIManager继承的是普通单例,不是mono单例;不需要挂在场景中

Test_OnClose是UIWindows的方法,可以直接获取UITest的信息sender和UI窗口的点击情况

 public void OnClickTest()
 {
     UITest uitest = UIManager.Instance.Show<UITest>();
     //可以用uitest调用UItest的方法
     uitest.SetTitle("新标题");
     uitest.OnClose += Test_OnClose;
 }

 private void Test_OnClose(UIWindows sender,UIWindows.WindowResult result)
 {//OnClose获取结果;即调用者负责获取调用的结果uitest.OnClose
     //例如在改名后点击确认按钮,可以获取到改的名字是什么
     //(sender as UITest).name
     //在调用前或者后可以任意访问UI的各种值
     MessageBox.Show("点击了对话框的:" + result, "对话框响应结果", MessageBoxType.Information);
 }

点击确定和关闭按钮的MessageBox.Show:

 

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

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

相关文章

第三部分:6---进程程序替换

目录 进程替换&#xff1a; execl函数解析&#xff1a; 多进程替换的本质&#xff1a; exec系列函数解析&#xff1a; 进程替换不会替换原进程的环境变量&#xff1a; 进程替换&#xff1a; 通过 fork 创建的进程&#xff0c;在最初会执行父进程代码的一部分&#xff0c;这…

动态规划-最长回文子序列

题目描述 给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列。 示例 1&#xff1a; 输入&#xff1a;s "bcbbab…

图书馆上新了!新华书店×度小满推出“开学季悦读计划”公益活动

2024年9月&#xff0c;新学期伊始&#xff0c;度小满携手新华书店启动“开学季悦读计划”公益行动。本次活动以“开学季&#xff0c;图书馆上新书”为主题&#xff0c;向度小满“小满助力计划”公益项目落地过的五个地区共六所小学和初中捐赠3300余本图书&#xff0c;让孩子们开…

李飞飞团队 ReKep:空间智能机器人可整合 GPT-4o;苹果首款 AI 手机 iPhone 16 发布丨RTE 开发者日报

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

一款专业编曲软件Guitar Pro 8中文版安装激活图文教程

Guitar Pro 8中文版是一款专业编曲软件&#xff0c;帮助所有的吉他爱好者学习、创作、设计、绘谱&#xff0c;指法、音色&#xff0c;了解各种吉他方面的内容&#xff0c;除了吉他还有其他十种乐器可以使用&#xff0c;节省时间&#xff0c;提高效率&#xff0c;有助于学习如何…

LLM大模型学习:AI Agent综述

AI Agent是什么 将LLM思想链接到一起&#xff0c;自主实现用户设定的任何目标。只需要告诉AutoGPT一个目标&#xff0c;能自主生成执行计划。 吴恩达&#xff1a;“与其争论哪些工作才算是真正的 Agent&#xff0c;不如承认系统可以具有不同程度的 Agentic 特性。” 核心在于…

TCP 为什么是三次握手,而不是两次或四次?(通俗易懂)

TCP 三次握手是为了保证&#xff1a;让客户端和服务器都知道自己和对方的发送和接收都没问题。 换句话说&#xff0c;可以 假设客户端和服务端都维护了四个布尔变量&#xff1a;自己发送&#xff0c;自己接收&#xff0c;对方发送&#xff0c;对方接收。 初始值为 false&#…

ROS第三梯:ROS+C++实现速腾Bag包的解析

解决问题&#xff1a;速腾Bag包利用bag_to_pcd生成的pcd文件字段名称存在问题&#xff0c;多了几个异常的"_"&#xff0c;导致强度属性无法在Intensity中显示。 解决方案&#xff1a;利用sensor_msgs库进行数据读取和转换成sensor_msgs::PointCloud格式&#xff0c;再…

避免17个最常见的电子邮件营销错误

我们都曾在电子邮件营销中犯过错。你点击发送&#xff0c;随后那种沉重的感觉袭来。你搞砸了&#xff0c;现在所有人都能看到。就像把信息放入瓶子丢进互联网的浩瀚海洋中&#xff0c;无法收回。 有些电子邮件营销错误显而易见&#xff0c;可能会破坏你投入了大量心血的营销活…

多窗口联系

使用信号和槽实现多个界面的跳转 准备好两个界面 一个界面准备好信号 一个界面准备好槽 连接两个界面的信号和槽 主界面的头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Wi…

俄罗斯电商没有技巧,OZON换季相关爆品

Top1 加热器 Обогреватель кварцевый напольный ИЖЭКО М 800 вт СВ01 энергосберегающий электрообогреватель 商品id&#xff1a;1352359815 月销量&#xff1a;781 OZON选品分析工具&#…

Xilinx系FPGA学习笔记(六)RAM的IP核学习

系列文章目录 文章目录 系列文章目录块RAM生成 块RAM生成 对于RAM来说&#xff0c;也有两种: 在 Memories & Storage Elements 下&#xff0c;一个是 Distributed Memory Generator&#xff0c;另一个是 BlockMemory Generator&#xff0c;这与ROM是类似的 这里的常规接口…

CSP-CCF★★★201812-2小明放学★★★

目录 一、问题描述 二、解答 &#xff08;1&#xff09;注意&#xff1a; &#xff08;2&#xff09;80分版&#xff1a; &#xff08;3&#xff09;100分版&#xff1a; 三、总结 一、问题描述 二、解答 &#xff08;1&#xff09;注意&#xff1a; 题目的n小于等于10的…

9月10(信息差)

&#x1f30d;华为最便宜小折叠&#xff01;华为nova Flip今晚发布&#xff1a;搭载麒麟8000芯片 从曝光的跑分信息来看&#xff0c;nova Flip将搭载麒麟8000处理器&#xff0c;也就是nova 12 Pro/Ultra的同款&#xff0c;采用8核心的134组合&#xff0c;大核是1颗2.4GHz的Cort…

怎么画实体关系图E-R?用这款在线绘图工具简单又好用!

ER图(Entity-Relationship Diagram&#xff0c;即实体-关系图)是一种用于数据库设计的图形化工具&#xff0c;用于描述现实世界的概念模型。它由Peter Chen于1976年首次提出&#xff0c;现已成为数据库建模和系统分析设计中最常用的工具之一。 ER图通过图形化的方式&#xff0…

Mamba模型学习笔记

笔记来源&#xff1a;bilibili Transformer 的死穴 Transformer 结构的核心是自注意力机制层&#xff0c;无论是 encoder 还是 decoder&#xff0c;序列数据都先经过位置编码后喂给这个模块。 但是自注意力机制的计算范围仅限于窗口内&#xff0c;而无法直接处理窗口外的元素…

支持iPhone 16新品预售,饿了么同步上线专人配送等特色服务

9月10日凌晨&#xff0c;2024年 Apple 秋季新品发布会上正式揭晓iPhone 16新机。9月10日一早&#xff0c;饿了么同步宣布&#xff1a;今年将携手近4000家Apple 授权专营店&#xff0c;支持iPhone 16新品预售及现货的同步开售。新机现货首发当日&#xff0c;饿了么消费者最快半小…

Mysql | 知识 | 事务隔离级别

转账案例缘起 我的钱包&#xff0c;共有 100 元。 今天我心情好&#xff0c;我决定给你的转账99元&#xff0c;最后的结果肯定是我的余额变为 1元&#xff0c;你的余额多了99元。 转账这一动作在程序里会涉及到一系列的操作&#xff0c;假设我向你转账 99元 的过程是有下面这…

哪些原因导致ERP成功率这么低?

哪些原因导致ERP成功率这么低&#xff1f; 有一句名言是“幸福的家庭都是相似的&#xff0c;不幸的家庭却各有各的不幸。”&#xff0c;这句名言应用到企业数字化的实施落地中也是适用的&#xff0c;数字化成功实施的企业也都是相似的&#xff0c;数字化实施失败的企业却有各种…

安卓玩机工具-----适合安卓机型的“搞机工具箱” 功能齐全 玩机推荐

搞机工具箱最新版是一款相当出色的电脑端手机工具箱软件&#xff0c;搞机工具箱正式版功能强劲&#xff0c;可以帮助用户不需要root就能够直接对手机进行调节&#xff0c;方便对手机进行更加全面的掌控&#xff0c;搞机工具箱便捷好用&#xff0c;只需要根据文字提示及自己的需…