Unity任务系统笔记

news2026/5/13 11:34:31
概述任务系统一般基于事件的发布-监听架构。玩家的某些行为发布事件任务对象监听事件且需要传递一些参数不同类型的任务传递的参数不同不同类型任务参数类的字段包括共用字段和专用字段。参数一般包括任务类型对象Id数量更多数据根据任务类型不同数据类型也不同会用一个父类装然后有一些设计细节不同类任务是发布不同的事件名称还是发布同一个事件把任务类型作为事件参数的一部分任务完成的条件类型之前射击游戏任务完成的方式有对话拾取任务物品仅完成任务用无其他作用击杀敌人进入区域之前发布的事件名是写在对话数据类、任务物品、敌人都是写在场景里检查器上。且事件都没有参数完全靠事件名的匹配完成任务。然后又回到上面的问题事件分为事件名和事件参数本质上都是参数信息可以放事件参数也可以玩家操作时把操作类型、物品Id、数量动态生成一个事件名。射击游戏完全靠事件名匹配因为射击游戏的任务通常靠特殊NPC、特殊物品、任务包含的敌人推进进度。而到了经营、生存类游戏的任务有一个很大的不同就是很多任务要做的事是后面要重复做很多次的事不具有特殊性完全是一般操作。在射击游戏的一关中一个对话任务完成了就无法再次触发也无法再次发布事件而生存游戏像捡木材、砍树、种植这些操作一直能做事件是一直在发布的只是有没有任务监听的问题。这导致不可能只用事件名做匹配必须事件名参数任务收到事件还要使用参数判定是否满足更新、完成条件。对于经营、生存类游戏基本的任务完成条件是操作了Id匹配的对象。然后任务系统的进阶功能会需要完成条件有一些更复杂的条件《或》条件比如拾取一个萝卜或玉米的种子条件不是对象的Id而是配置里的其他字段比如拾取一个种子判断种子的条件是选项列表里有Sow选项那么必须设计从Excel表、任务参数到判定程序的一系列设计。首先想到把支持的完成条件类型定义枚举判定方法里switch条件类型执行与条件可以拆成多个任务。一个RPG游戏任务有最基本的任务名称详细描述目的地坐标此外在任务开启、完成时可能触发多种多样的效果对NPC的操作显示、隐藏、移动位置、注入对话且注入的对话会推进任务进度激活敌人或者激活敌人生成器任务相关道具的激活开启下一个任务每种效果要执行不同对象的不同函数且可能有数量、类型不确定的参数。然后面临选择这些是在场景里配置还是在配表配置制作关卡任务的工作流编辑器vsExcel制作关卡任务需要精确放置NPC、敌人、任务等不可能不用编辑器。编辑器和Excel同时用流程又比较复杂。最终选择了编辑器制作导出json。消除任务对其他对象的引用任务会触发多种效果会影响到各种对象但是如果让任务直接引用对象引用是无法序列化的。任务不能持有任何引用只能有string、int、float、bool等简单数据及其嵌套。那么一切调用其他对象的效果都必须通过发布事件。任务类的数据结构设计基本字段string 任务标题任务目的地Vector3或transformtransform更直观string 任务详细描述基本方法开启任务把这个任务加入任务列表完成任务把这个任务移出任务列表触发、完成的条件任务触发和完成的条件都很多样对话、战斗、取得物品、到达地点、刺杀等。要触发任务需要那些可能触发任务的行为能指向任务这些行为都要加上可能触发的任务字段。触发任务可能是特定行为也可能是一个任务完成。也就是说任务系统不是只加一个系统还需要对其他系统的行为加回调。触发、完成的效果开启和完成任务会有各种效果某些NPC的出现、消失、移动位置某些NPC更新可触发的对话、开启下一个任务、生成敌人。讨论到这里可以发现触发、完成任务很相似所以能不能把它们做成相同的结构把可能的效果都包括进去[Serializable] public class MissionEffects{ [Tooltip(要更新对话的NPC)] public NPCTalk npcTalk; [Tooltip(相关NPC要说的对话)] public TalkData triggerTalk; [Tooltip(要移动的NPC)] public ListMoveNPC moveNPCs; [Tooltip(要触发的无线电通话)] public ListMonologData radioTalk; };对对话系统的修改对话可能完成任务任务开启后玩家找相关NPC触发对话时完成任务且把这个任务变量置空防止再次对话再次完成任务。对话也可能开启任务需要在对话结束后开启任务然后NPC不能再触发这段对话可能是触发任务进行中的对话或者没有对话。和上面触发对话完成任务加起来对话的开始和结束都要加一个UnityEvent。消灭名单所有敌人完成的任务字段要消灭的敌人列表敌人列表的每个敌人也记录自己所属的任务每个敌人死时把敌人移出敌人列表然后判断列表是否为空若是则任务完成。有一个列表记录此关依次要执行的任务对象关卡流程会清楚很多但是多任务分支用列表就不行了。消灭指定个数敌人完成的任务敌人有一个字符串列表记录自己死时分发的事件。然后需要一个监听者监听到敌人死亡后计数1达到需要数量后任务完成。为了减少类数量就让任务对象来监听。总结任务的开启、完成可能被场景里的任意方法触发开启效果、完成效果可能会执行场景里的任意方法。两种对话对话分为两类能反复触发的对话对关卡没有推进的对话简称氛围对话对关卡有推进不同阶段触发不同对话的npc简称推进对话。对于推进对话在关卡不同阶段有不同对话在一个任务进行中触发同一个对话如“拜托你了”实际上出现了完成任务和进行中的多分支。这么多对话的存储位置有几种方案。1.用List全部记录在NPC对象上。由任务对象指定完成后NPC该说哪一段对话。这样NPC对象脚本的检查器上会存一大堆对话数据。也难以看出一段对话对应哪个任务是触发任务的对话还是任务进行中的对话。2.NPC上只记录一段对话数据就是当前去找ta会触发的对话。任务对象上记录两段对话任务触发、进行中要说的对话。当关卡进度管理器显示该触发一个任务时任务对象把触发任务对话写入npc脚本的对话变量任务触发后把任务进行中对话写入npc对话变量。这样氛围npc因为没有任务系统修改ta们的对话数据自然就一直触发同一段对话不用修改。很明显2是最优方案既防止推进进度的npc的脚本里的对话数据过多又兼容两种npc而且不推进进度的npc只有一段对话给ta们声明一个一段对话的List完全是浪费。总之对于氛围NPC只有一个一段对话变量对于推进NPC不同任务阶段对话不同对话应该记录在任务对象。问题回复时开启任务 直接把下一个任务NPC要说的话写入了NPC的对话数据导致当前对话变成下一个任务阶段的需要在回复时记下要触发任务这段对话结束后再开启任务。所以在一段对话数据结构里放一个ListUnityEvent回复的结构体里有一个UnityEvent用于在检查器配置回调函数选择该回复时把这个UnityEvent加入列表对话结束后执行。问题如何标记一段对话是氛围的还是推进的氛围对话可以反复触发一般没有回调。推进对话只能触发一次触发后执行回调。那么有没有回调能作为一段对话是氛围还是推进的标记吗会遇到一些问题如果回调是通过unityEvent.AddListener()添加的非永久监听怎么知道有没有非永久监听查了一下要自己记录。unityEvent没有添加过监听也不一定是null无法通过不添加监听然后判断unityEventnull判定没有回调综上没有准确方法通过UnityEvent判断有没有回调。最终我选择规定不使用AddListener()添加非永久监听一律使用检查器添加永久监听使用GetPersistentEventCount()0判断有回调。这意味着不能用代码写“对话完成任务”的功能而必须在检查器配置来完成。然后“对话型任务”这个任务子类也没有必要存在了。任务和对话的关系然后我们发现任务触发可以更新对话、任务完成可以更新对话、对话可以触发任务、对话可以完成任务还有对话的回调在对话开始还是结束时执行的问题。二者可以调用对方现在是任务更新对话对话要触发的下一个任务也记在任务里。面临一些选择问题比如一个任务会给NPC写入一段对话触发对话会在对话开始或结束时完成这个任务完成任务的函数是写在任务完成的UnityEvent还是对话开始或结束的UnityEvent如果还要开启下一个任务那么就是有两个函数要填入两个可能的的UnityEvent选项变多了。有多个子任务的任务每完成一个子任务提示一下任务界面显示X/Y。比如子任务是移动到某区域子任务需要触发器完成后通知父任务更新完成的子任务数任务面板提示一下更新任务列表显示。父任务要能显示X/Y要有子任务的列表检查里面完成的数量和总数。基于事件中心的设计想象关卡开始时开启任务1为一个NPC注入对话和ta发起对话后完成任务1对话结束时开启任务2。任务为NPC注入对话并且让对话开始时完成任务结束时开启下一个任务。那么任务有2个字符串列表分别指定对话开始和结束时触发哪些事件。[Serializable] public class TalkWithEvents { public string talkID; public Liststring startEvents; public Liststring endEvents; }任务记录自己要监听开启和完成的事件名if (!string.IsNullOrEmpty(openEffects.listenToEvent)) { MyEventCenter.Instance.AddListener(openEffects.listenToEvent, Open); } if (!string.IsNullOrEmpty(completeEffects.listenToEvent)) { MyEventCenter.Instance.AddListener(completeEffects.listenToEvent, Complete); }销毁前要解除监听private void OnDestroy() { if (!string.IsNullOrEmpty(openEffects.listenToEvent)) { MyEventCenter.Instance.RemoveListener(openEffects.listenToEvent, Open); } if (!string.IsNullOrEmpty(completeEffects.listenToEvent)) { MyEventCenter.Instance.RemoveListener(completeEffects.listenToEvent, Complete); } }Excel配表设计任务的有一些成员是和场景分不开的包括目的地位置、要注入对话的NPC、各种回调。配表里适合记录一些简单类型数据任务名称、任务描述等。一个游戏有多个关卡一个关卡有多个任务Excel有多个Sheet。我们用一个sheet存一个场景的任务一个游戏用一个Excel存所有任务。sheet名字标记关卡。任务开启、完成效果中赋予对话的NPC、移动NPC的信息、回调都不能拖对象需要用简单数据类型标记然后面临选择每类效果是各用一个字段记录还是所有效果共用一个字段各类效果的参数数量、类型不同需要制定一个指令格式以及解析指令的程序。为了简单可以只记录一个事件名字场景里的管理器维护一个名字-UnityEvent列表。任务列表要完成的功能有按一个键显示当前开启的任务列表再按一次隐藏选中一个任务时该任务选项高亮显示任务详细描述并把目的地标记设为显示为该任务的目的地开启任务时把该任务加入列表任务完成时把该任务移除开启任务时弹出一个提示对追踪中任务的管理对追踪中任务的管理完成的任务是追踪中任务时追踪中任务要更新任务列表有任务则把第一个设置为追踪中任务没有则设null接取任务时如果没有追踪中任务则把这个设为追踪中任务任务对象在hierarchy里的层级所有任务对象放在一个父对象下面比较清楚。但是一些任务在某目标对象的同一位置作为目标对象的子对象然后reset位置比较方便。可以给任务加一个public Transform targetStart()时把自己的位置设置到目标处。问题协程冲突在修改NPC位置等突变操作时我写了一个画面渐变为黑色执行操作再变透明的函数public UnityAction blackoutCallback; [ContextMenu(画面变黑)] public void Blackout(){ StartCoroutine(BlackoutCoroutine(blackoutCallback)); } float fadeSpeed.04f; IEnumerator BlackoutCoroutine(UnityAction callbacknull){ while(blackBack.color.a1){ blackBack.colornew Color(0,0,0,fadeSpeed); yield return 0; } if(callback!null){ callback.Invoke(); } while(blackBack.color.a0){ blackBack.color-new Color(0,0,0,fadeSpeed); yield return 0; } }然后这个函数在ContextMenu调用时正常但是完成任务调用时画面就不变透明了。NPC被正确移动了。然后在第二个while循环里加了个Debug.Log()发现第二个while循环一直在执行但是alpha值没有变。然后又在第一个while循环加了个打印发现两个while循环都在一直执行。在协程开头加打印发现协程被执行了两次。因为一个很笨的错误。这说明写淡入淡出时如果以imag.color.a作为循环条件如果在一个淡入淡出完成前开始另一个两个协程就会打架淡入淡出永远完不成。实际开发中如果无法避免一个淡入淡出进行中开始另一个就根据计算好的循环次数或者直接规定循环次数并且循环结束后直接把alpha值写成目标值因为如果不这么做就算循环能结束最终的alpha会是一个半透明值。改进后的淡入淡出int fadeStep10; IEnumerator BlackoutCoroutine(UnityAction callbacknull){ for(int i0;ifadeStep;i){ blackBack.colornew Color(0,0,0,1/(float)fadeStep); yield return 0; } blackBack.colorColor.black; if(callback!null){ callback.Invoke(); } for(int i0;ifadeStep;i){ blackBack.color-new Color(0,0,0,1/(float)fadeStep); yield return 0; } blackBack.colornew Color(0,0,0,0); }对话完后要让屏幕渐变黑把NPC移到下一个位置并能触发新对话但是现在对话完后立即就打开交互能触发下一段对话了根据设计对话后这一段对话失效应该在屏幕变黑、把NPC移到新位置后再让下一个任务把对话赋值给NPC。当前的设计是对话结束后执行回调。需要改成对话结束后当前对话立即失效而新对话在屏幕变黑、移动NPC后生效。又不能给对话数据设null使对话失效因为对话数据里包含对话结束的回调里面是下一个任务和对话数据。我选择只把对话数据里的句子列表设null而对话数据里的对话结束回调保留。触发对话时也判断对话数据的句子列表长度是否大于0。为此给对话结束回调加一个选项是直接执行回调还是屏幕变黑执行回调。excel配置游戏任务时任务的目的地在场景里的位置是相对于场景的Vector3很不方便获取怎么办稍微复杂的任务完成逻辑我们会遇到这种情况玩家需要去3个可疑地点搜索在任意一个地点找到目标物都算任务完成。玩家可以选择追踪3个地点中的任意一个同时开启3个任务玩家需要都完成才开启后面的任务基于MVC的任务管理器和面板数据比较简单就都放在Controller里了。Controller不引用View数据变化时发布事件。/// summary /// 任务系统控制器 /// /summary public class MissionManager : MonoSingletonMissionManager{ public const string showMissionListshowMissionList; public ListMissionBase initMissions; public MissionBase chasingMission; PlayerCharacter player; Vector3 targetDir; public ListMissionBase missionList; Coroutine coShowMarker; WaitForSeconds waitUpdateMarker new WaitForSeconds(.07f); Rect scale; Rect canvasRT; bool showPanel; //控制器不要去调用面板让面板监听控制器 public event UnityActionVector2,string onUpdateMarker; public event UnityActionMissionBase onMissionOpen;//需要传入任务名称 public event UnityActionMissionBase onMissionDone; public event UnityAction onChasingChanged; public event UnityActionbool onToggleShowMissions; protected override void Awake() { base.Awake(); } void Start() { player MyInput.Single.player; //画布的rect宽高固定为1920*1080即使分辨率只是自由169 //用于解决分辨率不是1920*1080时任务目的地标记位置错误的问题 canvasRT (GameSceneManager.Single.canvas.transform as RectTransform).rect; scale.width canvasRT.width / Screen.width; scale.height canvasRT.height / Screen.height; coShowMarker StartCoroutine(ShowMissionMarkIE()); } IEnumerator ShowMissionMarkIE() { while (true) { if (chasingMission ! null !chasingMission.hideMark) { GetMarkerPos(); } yield return waitUpdateMarker; } } void OnDisable() { if (coShowMarker ! null) { StopCoroutine(coShowMarker); } } public void MissionComplete(MissionBase mission) { if (!missionList.Contains(mission)) { return; } missionList.Remove(mission); if (chasingMission mission)//完成的是正在追踪的任务追踪任务更新 { if (missionList.Count 0) { SetChasing(0); } else { SetChasing(-1); //missionMarker.gameObject.SetActive(false); } } onMissionDone?.Invoke(mission); } void GetMarkerPos() { Vector3 posCamera.main.WorldToScreenPoint(chasingMission.transform.position); if (pos.z 0) { pos.x Mathf.Clamp(pos.x,0, Screen.width); pos.y Mathf.Clamp(pos.y,0, Screen.height); } else { pos.x pos.x Screen.width / 2 ? Screen.width : 0; pos.yScreen.height / 2; } pos new Vector2(pos.x * canvasRT.width / Screen.width, pos.y * canvasRT.height/Screen.height); string distanceHint ((int)Vector3.Distance(player.transform.position, chasingMission.transform.position)).ToString() m; onUpdateMarker?.Invoke(pos, distanceHint); } public void SetChasing(int index) { if (index 0 index missionList.Count) { chasingMission missionList[index]; } else { chasingMission null; } onChasingChanged?.Invoke(); } public void ToggleMissionList(){ showPanel !showPanel; onToggleShowMissions?.Invoke(showPanel); } public void HideMissionList(){ if (showPanel) { ToggleMissionList(); } } public void OpenMission(MissionBase mission){ if (missionList.Contains(mission)) { return; } missionList.Add(mission); if (!chasingMission) { SetChasing(missionList.IndexOf(mission)); } onMissionOpen?.Invoke(mission); } public bool GetMissionPanelOn() { return showPanel; } /// summary /// 把当前任务列表清空开启注入的任务 /// /summary public void InjectMissions(ListMissionBasemissions) { } }View监听Controller的事件。收到输入时调用Controller的public class PanelMission : PanelBase { public const string showMissionList showMissionList; [SerializeField] RectTransform marker; [SerializeField] Text textDistance; Animator animator; [SerializeField] VerticalLayoutGroup missionListRoot; [SerializeField] ListButton missionEntries new(); [SerializeField] VerticalLayoutGroup missionHint; [SerializeField] Button entryPrefab; Button buttonOn; [SerializeField] Image imageDesc; [SerializeField] Text textDesc; [SerializeField] Text missionHintPrefab; const float hintLifeTime 2.5f; protected override void Awake() { base.Awake(); animator GetComponentAnimator(); } protected override void Init() { base.Init(); MissionManager.Single.onUpdateMarker SetMarkerPos; MissionManager.Single.onToggleShowMissions ToggleMissionList; MissionManager.Single.onMissionOpen MissionOpen; MissionManager.Single.onMissionDone MissionDone; } protected override void OnDestroy() { base.OnDestroy(); if (MissionManager.Single) { MissionManager.Single.onUpdateMarker - SetMarkerPos; MissionManager.Single.onToggleShowMissions - ToggleMissionList; MissionManager.Single.onMissionOpen - MissionOpen; MissionManager.Single.onMissionDone - MissionDone; } } /// summary /// 控制任务目的地标志的位置 /// /summary public void SetMarkerPos(Vector2 pos,string distanceHint) { marker.anchoredPosition pos; textDistance.textdistanceHint; } public void RefreshMissionList() { for (int i 0; i missionEntries.Count; i) { Destroy(missionEntries[i].gameObject); } ListMissionBase missions MissionManager.Single.missionList; for (int i 0; i missions.Count; i) { Button mission Instantiate(entryPrefab, missionListRoot.transform); Text desc mission.GetComponentInChildrenText(); desc.text missions[i].missionContent; Button button mission.GetComponentButton(); int index i; button.onClick.AddListener(() { imageDesc.gameObject.SetActive(true); //改变追踪的任务需要VCV MissionManager.Single.SetChasing(index); //这里改一下监听控制器 textDesc.text missions[index].missionDetail; }); } } void UpdateButtonOn(Button button) { if (buttonOn button) { return; } if (buttonOn) { buttonOn.GetComponentImage().color Color.gray; } buttonOn button; buttonOn.GetComponentImage().color Color.white; } /// summary /// 在上方显示一个任务开启、完成的提示。 /// 有多条提示时自动上下排布 /// /summary /// param namemission/param public void ShowMissionOpen(MissionBase mission) { Text hint Instantiate(missionHintPrefab, missionHint.transform); hint.text mission.missionContent; Destroy(hint.gameObject, hintLifeTime); } void ShowMissionDone(MissionBase mission) { Text hint Instantiate(missionHintPrefab, missionHint.transform); hint.text mission.missionContent 完成; Destroy(hint.gameObject, hintLifeTime); } public void ToggleMissionList(bool show) { if (show) { ShowMissionList(); } else { HideMissionList(); } } /// summary /// 开启的任务列表显示出来 /// /summary public void ShowMissionList() { animator.SetBool(showMissionList, true); Cursor.lockState CursorLockMode.None; MyInput.Single.playerInput.SwitchCurrentActionMap(MyInput.actionMapMissionPanel); //int i missionList.IndexOf(chasingMission); //if (i 0) //{ // Button button missionListRoot.transform.GetChild(i).GetComponentButton(); // UpdateButtonOn(button); //} } public void HideMissionList() { animator.SetBool(showMissionList, false); Cursor.lockState CursorLockMode.Locked; MyInput.Single.playerInput.SwitchCurrentActionMap(MyInput.actionMapPlayer); imageDesc.gameObject.SetActive(false); } /// summary /// 有任务开启时做两件事 /// 刷新任务列表上方弹出提示 /// /summary void MissionOpen(MissionBase mission) { RefreshMissionList(); ShowMissionOpen(mission); } void MissionDone(MissionBase mission) { RefreshMissionList(); ShowMissionDone(mission); } }

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…