第八天 AI开发:NavMesh导航系统 对话系统:使用ScriptableObject存储对话数据 存档系统:JSON序列化保存数据
一、智能导航系统:NavMesh实战指南
1.1 导航网格基础配置
-
在Unity编辑器中:
- 选择场景中的静态物体
- 勾选Navigation Static属性
- 打开Window > AI > Navigation窗口
-
烘焙参数设置:
NavMeshBuildSettings settings = NavMesh.GetSettingsByID(0); settings.agentRadius = 0.5f; // 代理半径 settings.agentHeight = 2.0f; // 代理高度 settings.agentSlope = 45; // 最大坡度 NavMeshBuilder.BuildNavMeshAsync(settings);
1.2 NavMeshAgent组件控制
public class NPCMovement : MonoBehaviour
{public Transform target;private NavMeshAgent agent;void Start(){agent = GetComponent<NavMeshAgent>();agent.speed = 3.5f; // 移动速度agent.angularSpeed = 360; // 旋转速度agent.stoppingDistance = 1f; // 停止距离}void Update(){if(target != null){agent.SetDestination(target.position);// 到达目标后执行动作if(!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance){OnReachDestination();}}}void OnReachDestination(){// 触发对话或执行其他逻辑}
}
1.3 动态障碍物处理
// 动态添加障碍物
NavMeshObstacle obstacle = gameObject.AddComponent<NavMeshObstacle>();
obstacle.shape = NavMeshObstacleShape.Capsule;
obstacle.carving = true; // 实时更新导航网格
obstacle.size = new Vector3(1f, 2f, 1f);
二、对话系统:ScriptableObject高级应用
2.1 对话数据结构设计
[CreateAssetMenu(fileName = "New Dialogue", menuName = "Dialogue System/Dialogue")]
public class DialogueData : ScriptableObject
{[System.Serializable]public class DialogueNode{public string speakerName;[TextArea(3,5)] public string content;public DialogueOption[] options;}[System.Serializable]public class DialogueOption{public string optionText;public DialogueData nextDialogue;}public DialogueNode[] dialogueNodes;
}
2.2 对话管理器实现
public class DialogueManager : MonoBehaviour
{public static DialogueManager Instance;public Text speakerText;public Text contentText;public GameObject[] optionButtons;private DialogueData currentDialogue;private int currentNodeIndex;void Awake(){Instance = this;HideDialogue();}public void StartDialogue(DialogueData dialogue){currentDialogue = dialogue;currentNodeIndex = 0;ShowDialogue();DisplayNode(currentDialogue.dialogueNodes[currentNodeIndex]);}void DisplayNode(DialogueData.DialogueNode node){speakerText.text = node.speakerName;contentText.text = node.content;for(int i=0; i<optionButtons.Length; i++){if(i < node.options.Length){optionButtons[i].SetActive(true);optionButtons[i].GetComponentInChildren<Text>().text = node.options[i].optionText;}else{optionButtons[i].SetActive(false);}}}public void SelectOption(int optionIndex){DialogueData.DialogueOption selectedOption = currentDialogue.dialogueNodes[currentNodeIndex].options[optionIndex];if(selectedOption.nextDialogue != null){StartDialogue(selectedOption.nextDialogue);}else{HideDialogue();}}
}
三、游戏存档:JSON序列化实战
3.1 存档数据结构设计
[System.Serializable]
public class SaveData
{public Vector3 playerPosition;public Quaternion playerRotation;public string currentScene;public Dictionary<string, bool> completedQuests = new Dictionary<string, bool>();// JSON序列化辅助方法public string ToJson(){return JsonUtility.ToJson(this);}public void LoadFromJson(string json){JsonUtility.FromJsonOverwrite(json, this);}
}
3.2 存档管理器实现
public class SaveSystem : MonoBehaviour
{private static string SAVE_PATH => Path.Combine(Application.persistentDataPath, "save.sav");public static void SaveGame(){SaveData data = new SaveData();// 收集需要保存的数据GameObject player = GameObject.FindGameObjectWithTag("Player");data.playerPosition = player.transform.position;data.playerRotation = player.transform.rotation;data.currentScene = SceneManager.GetActiveScene().name;// 序列化并加密存储string json = data.ToJson();byte[] encryptedData = Encrypt(json);File.WriteAllBytes(SAVE_PATH, encryptedData);}public static bool LoadGame(){if(File.Exists(SAVE_PATH)){byte[] encryptedData = File.ReadAllBytes(SAVE_PATH);string json = Decrypt(encryptedData);SaveData data = new SaveData();data.LoadFromJson(json);// 应用加载的数据SceneManager.LoadScene(data.currentScene);GameObject player = GameObject.FindGameObjectWithTag("Player");player.transform.position = data.playerPosition;player.transform.rotation = data.playerRotation;return true;}return false;}private static byte[] Encrypt(string data){// 实现AES加密逻辑return Encoding.UTF8.GetBytes(data);}private static string Decrypt(byte[] data){// 实现AES解密逻辑return Encoding.UTF8.GetString(data);}
}
四、综合实践:完整游戏系统搭建
4.1 第三人称角色控制升级版
public class AdvancedThirdPersonController : MonoBehaviour
{[Header("Movement")]public float moveSpeed = 5f;public float sprintMultiplier = 1.5f;public float jumpForce = 5f;[Header("Camera")]public CinemachineVirtualCamera followCamera;private CharacterController controller;private Vector3 moveDirection;private float verticalVelocity;void Start(){controller = GetComponent<CharacterController>();Cursor.lockState = CursorLockMode.Locked;}void Update(){HandleMovement();HandleCamera();}void HandleMovement(){float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");bool isSprinting = Input.GetKey(KeyCode.LeftShift);Vector3 forward = followCamera.transform.forward;Vector3 right = followCamera.transform.right;forward.y = 0f;right.y = 0f;Vector3 move = forward.normalized * vertical + right.normalized * horizontal;float speed = isSprinting ? moveSpeed * sprintMultiplier : moveSpeed;if(controller.isGrounded){verticalVelocity = -0.5f;if(Input.GetButtonDown("Jump")){verticalVelocity = jumpForce;}}else{verticalVelocity += Physics.gravity.y * Time.deltaTime;}move.y = verticalVelocity;controller.Move(move * speed * Time.deltaTime);}void HandleCamera(){float mouseX = Input.GetAxis("Mouse X");float mouseY = Input.GetAxis("Mouse Y");transform.Rotate(Vector3.up * mouseX * 2f);followCamera.transform.RotateAround(transform.position, transform.right, -mouseY * 2f);}
}
4.2 系统集成示例
public class GameManager : MonoBehaviour
{public DialogueData startDialogue;public Transform npcDestination;void Start(){// 加载存档if(SaveSystem.LoadGame()){Debug.Log("存档加载成功");}else{// 新游戏初始化StartCoroutine(StartNewGame());}}IEnumerator StartNewGame(){yield return new WaitForSeconds(1f);DialogueManager.Instance.StartDialogue(startDialogue);// NPC开始移动NPCMovement npc = FindObjectOfType<NPCMovement>();npc.target = npcDestination;}void OnApplicationQuit(){SaveSystem.SaveGame();}
}
五、调试与优化技巧
5.1 NavMesh调试工具
void OnDrawGizmos()
{if(Application.isPlaying){NavMeshAgent agent = GetComponent<NavMeshAgent>();Gizmos.color = Color.red;Gizmos.DrawLine(transform.position, agent.destination);// 显示路径NavMeshPath path = agent.path;for(int i=0; i<path.corners.Length-1; i++){Gizmos.DrawLine(path.corners[i], path.corners[i+1]);}}
}
5.2 存档系统安全增强
- 数据校验机制:
public class SaveData {public string checksum;public void GenerateChecksum(){checksum = CalculateMD5(JsonUtility.ToJson(this));}public bool Validate(){string temp = checksum;checksum = "";string current = CalculateMD5(JsonUtility.ToJson(this));checksum = temp;return current == temp;} }
5.3 对话系统性能优化
- 对象池技术实现:
public class DialoguePool : MonoBehaviour {public GameObject optionPrefab;private Queue<GameObject> pool = new Queue<GameObject>();public GameObject GetOption(){if(pool.Count > 0){return pool.Dequeue();}return Instantiate(optionPrefab);}public void ReturnOption(GameObject option){option.SetActive(false);pool.Enqueue(option);} }
结语
通过本教程的学习,我们实现了从角色控制到AI行为、从交互系统到数据管理的完整开发流程。建议进行以下扩展练习:
- 实现多语言对话系统
- 添加NPC巡逻路径功能
- 开发云存档系统
- 制作任务进度追踪界面
相关文章:
第八天 AI开发:NavMesh导航系统 对话系统:使用ScriptableObject存储对话数据 存档系统:JSON序列化保存数据
一、智能导航系统:NavMesh实战指南 1.1 导航网格基础配置 在Unity编辑器中: 选择场景中的静态物体勾选Navigation Static属性打开Window > AI > Navigation窗口 烘焙参数设置: NavMeshBuildSettings settings NavMesh.GetSettingsBy…...
Spring AI Alibaba-02-多轮对话记忆、持久化消息记录
Spring AI Alibaba-02-多轮对话记忆、持久化消息记录 Lison <dreamlison163.com>, v1.0.0, 2025.04.19 文章目录 Spring AI Alibaba-02-多轮对话记忆、持久化消息记录多轮对话对话持久-Redis 本次主要聚焦于多轮对话功能的实现,后续会逐步增加更多实用内容&…...
联邦元学习实现个性化物联网的框架
随着数据安全和隐私保护相关法律法规的出台,需要直接在中央服务器上收集和处理数据的集中式解决方案,对于个性化物联网而言,训练各种特定领域场景的人工智能模型已变得不切实际。基于此,中山大学,南洋理工大学…...
做虚拟化应该怎么选择美国服务器?
选择适合做虚拟化的美国服务器,需要综合考虑硬件性能、网络质量、稳定性、价格和服务支持等多个方面。以下是详细的选购指南,适合准备搭建VPS、虚拟主机、分销业务、开发测试环境、容器集群等用途的用户参考。 一、为什么美国服务器适合虚拟化? 美国机房…...
实验1 温度转换与输入输出强化
知识点:input()/print()、分支语句、字符串处理(教材2.1-2.2) 实验任务: 1. 实现摄氏温度与华氏温度互转(保留两位小数) 2. 扩展功能:输入错误处理(如非数字输入提示重新输入&#x…...
MongoDB 集合名称映射问题
项目场景 在使用 Spring Data MongoDB 进行开发时,定义了一个名为 CompetitionSignUpLog 的实体类,并创建了对应的 Repository 接口。需要明确该实体类在 MongoDB 中实际对应的集合名称是 CompetitionSignUpLog 还是 competitionSignUpLog。 问题描述 …...
【AI】SpringAI 第五弹:接入千帆大模型
1. 添加依赖 <dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-qianfan</artifactId> </dependency> 2. 编写 yml 配置文件 spring:ai:qianfan:api-key: 你的api-keysecret-key: 你的secr…...
【编码规范】原生开发 与 Vue+组件库开发
原生开发 vs Vue组件库开发对比 一、原生开发常用方法 DOM操作: document.getElementById()document.querySelector()element.addEventListener()classList API操作类名 事件处理: 直接事件绑定事件委托 document.body.addEventListener(click, functi…...
[Godot] C#2D平台游戏基础移动和进阶跳跃代码
本文章给大家分享一下如何实现基本的移动和进阶的跳跃(跳跃缓冲、可变跳跃、土狼时间)以及相对应的重力代码,大家可以根据自己的需要自行修改 实现效果 场景搭建 因为Godot不像Unity,一个节点只能绑定一个脚本,所以我…...
【Unity笔记】Unity + OpenXR项目无法启动SteamVR的排查与解决全指南
图片为AI生成 一、前言 随着Unity在XR领域全面转向OpenXR标准,越来越多的开发者选择使用OpenXR来构建跨平台的VR应用。但在项目实际部署中发现:打包成的EXE程序无法正常启动SteamVR,或者SteamVR未能识别到该应用。本文将以“Unity OpenXR …...
使用 rebase 轻松管理主干分支
前言 最近遇到一个技术团队的 dev 环境分支错乱,因为是多人合作大家各自提交信息,导致出现很多交叉合并记录,让对应 log 看起来非常混乱,难以阅读。 举例说明 假设我们有一个项目,最初develop分支有 3 个提交记录&a…...
【愚公系列】《Python网络爬虫从入门到精通》063-项目实战电商数据侦探(主窗体的数据展示)
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! …...
HttpSessionListener 的用法笔记250417
HttpSessionListener 的用法笔记250417 以下是关于 HttpSessionListener 的用法详解,涵盖核心方法、实现步骤、典型应用场景及注意事项,帮助您全面掌握会话(Session)生命周期的监听与管理: 1. 核心功能 HttpSessionLi…...
火山RTC 5 转推CDN 布局合成规则
实时音视频房间,转推CDN,文档: 转推直播--实时音视频-火山引擎 一、转推CDN 0、前提 * 在调用该接口前,你需要在[控制台](https://console.volcengine.com/rtc/workplaceRTC)开启转推直播功能。<br> * 调…...
Spark两种运行模式与部署
1. Spark 的运行模式 部署Spark集群就两种方式,单机模式与集群模式 单机模式就是为了方便开发者调试框架的运行环境。但是生产环境中,一般都是集群部署。 现在Spark目前支持的部署模式: (1)Local模式:在本地…...
react 父子组件通信 子 直接到父, 父 forwardref子
React核心概念:单向数据流(Unidirectional Data Flow) React 中数据的流动像瀑布一样,只能从上层组件(父组件)流向下层组件(子组件)。 子组件无法直接反向修改父组件的数据&#x…...
qt画一朵花
希望大家的生活都更加美好,画一朵花送给大家 效果图 void FloatingArrowPubshButton::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing);QPen pen;pen.setColor("green");pen.setWidth(5);QBrush…...
服务器上安装maven
1.安装 下载安装包 https://maven.apache.org/download.cgi 解压安装包 cd /opt/software tar -xzvf apache-maven-3.9.9-bin.tar.gz 安装目录(/opt/maven/) mv /opt/software/apache-maven-3.9.9 /opt/ 3.权限设置 把/opt/software/apache-maven-3.9.9 文件夹重命名为ma…...
UOS+N 卡 + CUDA 环境下 X86 架构 DeepSeek 基于 vLLM 部署与 Dify 平台搭建指南
一、文档说明 本文档是一份关于 DeepSeek 在X86架构下通vLLM工具部署的操作指南,主要面向需要在UOSN卡CUDA环境中部署DeepSeek的技术人员,旨在指导文档使用者完成从 Python 环境升级、vLLM 库安装、模型部署到 Dify 平台搭建的全流程操作。 二、安装Pyt…...
MySQL终章(8)JDBC
目录 1.前言 2.正文 2.1JDBC概念 2.2三种编码方式 2.2.1第一种 2.2.2第二种(优化版) 2.2.3第三种(更优化版) 3.小结 1.前言 哈喽大家好吖,今天来给大家带来Java中的JDBC的讲解,之前学习的都是操作…...
点云数据处理开源C++方案
一、主流开源库对比 库名称特点适用场景开源协议活跃度PCL功能最全,算法丰富科研、工业级应用BSD★★★★★Open3D现代API,支持Python绑定快速开发、深度学习MIT★★★★☆CGAL计算几何算法强大网格处理、高级几何运算GPL/LGPL★★★☆☆PDAL专注于点云…...
Python 爬虫如何伪装 Referer?从随机生成到动态匹配
一、Referer 的作用与重要性 Referer 是 HTTP 请求头中的一个字段,用于标识请求的来源页面。它在网站的正常运行中扮演着重要角色,例如用于统计流量来源、防止恶意链接等。然而,对于爬虫来说,Referer 也可能成为被识别为爬虫的关…...
【MySQL】表的约束(主键、唯一键、外键等约束类型详解)、表的设计
目录 1.数据库约束 1.1 约束类型 1.2 null约束 — not null 1.3 unique — 唯一约束 1.4 default — 设置默认值 1.5 primary key — 主键约束 自增主键 自增主键的局限性:经典面试问题(进阶问题) 1.6 foreign key — 外键约束 1.7…...
基于STC89C52RC和8X8点阵屏、独立按键的小游戏《打砖块》
目录 系列文章目录前言一、效果展示二、原理分析三、各模块代码1、8X8点阵屏2、独立按键3、定时器04、定时器1 四、主函数总结 系列文章目录 前言 用的是普中A2开发板,外设有:8X8LED点阵屏、独立按键。 【单片机】STC89C52RC 【频率】12T11.0592MHz 效…...
数字电子技术基础(五十)——硬件描述语言简介
目录 1 硬件描述语言简介 1.1 硬件描述语言简介 1.2 硬件编程语言的发展历史 1.3 两种硬件描述的比较 1.4 硬件描述语言的应用场景 1.5 基本程序结构 1.5.1 基本程序结构 1.5.2 基本语句和描述方法 1.5.3 仿真 1 硬件描述语言简介 1.1 硬件描述语言简介 硬件描述语…...
【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件common.py解读
【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件common.py解读 文章目录 【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件common.py解读前言autopad函数Conv类__init__成员函数forward成员函数forward_fuse成员函数 Bottleneck类__init__成员…...
16.Chromium指纹浏览器开发教程之WebGPU指纹定制
WebGPU指纹概述 WebGPU是下一代的Web图形和计算API,旨在提供高性能的图形渲染和计算能力。它是WebGL的后继者,旨在利用现代GPU的强大功能,使得Web应用能够实现接近原生应用的图形和计算性能。而且它是一个低级别的API,可以直接与…...
示例:spring 纯xml配置
以下是一个完整的 纯 XML 配置开发示例,涵盖 DAO、Service、Controller 层,通过 Spring XML 配置实现依赖注入和事务管理,无需任何注解。 1. 项目结构 src/main/java ├── com.example.dao │ └── UserDao.java # DAO 接口…...
SQL预编译——预编译真的能完美防御SQL注入吗
SQL注入原理 sql注入是指攻击者拼接恶意SQL语句到接受外部参数的动态SQL查询中,程序本身 未对插入的SQL语句进行过滤,导致SQL语句直接被服务端执行。 拼接的SQL查询例如,通过在id变量后插入or 11这样的条件,来绕过身份验证&#…...
系统架构师2025年论文《论基于UML的需求分析》
论基于构件的软件开发 摘要: 2011 年 3 月,我有幸参加了某市医院预约挂号系统项目的开发工作,并担任系统架构师一职,负责系统的架构设计及核心构件的开发工作。该项目是某市医院为提升患者就医体验、优化挂号流程而委托开发的,项目于 2011 年底验收,满足了医院及患者提…...
