Unity实现Root Motion动画的Navigation自动导航
Root motion动画可以将角色的根节点(通常是角色的骨盆或脚部)的运动直接应用到游戏对象上,从而实现角色的自然移动和旋转,避免出现脚底打滑的现象。采用Root motion动画的游戏对象,通常是重载了onAnimatorMove函数,在脚本中来设置动画的速度,从而实现角色的移动。Unity的Navigation系统是一个用于实现游戏世界中的寻路和导航功能的组件。它允许游戏角色在复杂的游戏环境中自动找到从一点到另一点的最短路径。如果我们对采用Root motion动画的游戏对象应用Navigation,就会产生冲突,因为这两个组件都会尝试控制游戏对象的移动。有两个解决方式:
一是让动画跟随Navigation agent,通过获取agent.velocity来设置root motion的速度,从而大致匹配Agent的移动到动画的移动。这个方式最简单,但是可能会出现脚底打滑的现象。
二是让Agent跟随动画,关闭agent的updatePosition和updateRotation,通过计算agent的nextPosition和动画根节点的rootPosition的插值来进行控制。这种方式比方式一要复杂,但是效果更好。以下将以一个游戏场景为例子,详细介绍一下如何实现方式二。
游戏场景
在游戏中,对于NPC角色,当前设置了几个状态,分别是漫游Wander,瞄准Aim以及追踪Chase。NPC刚开始是漫游状态,在场景中自由地进行移动,这时是通过Root motion来驱动的。当NPC检测到玩家时,会进入瞄准状态。如果玩家进行躲避NPC,则NPC会进入追踪状态,自动跑到上一次发现玩家的位置,这时NPC是由Navigation来驱动,实现自动寻路。可见对于NPC是需要按照不同的场景来用Root motion或Navigation来驱动的。
Animator设置
建立一个名为Enemy的Animator,包含了两个状态,分别是Aim和Move,设置如下:
添加两个Trigger,分别为Aim和Walk,用于切换状态。定义一个名为Speed的Float变量,用于控制Root motion的移动速度。
Move状态是一个BlendTree,通过Speed来进行Idle,Walk,Run这三种动作的混合,改变Speed的值,可以看到人物动作的改变。
Unity Blendtree动画
改变Speed的值,可以看到人物的动作的改变。
实现漫游状态
现在给游戏对象增加一个名为EnemyAI的脚本文件,实现游戏对象在场景中漫游。代码如下:
public class EnemyAI : MonoBehaviour
{[Header("Enemy eyeview")]public float eyeviewDistance = 500.0f;public float viewAngle = 120f;public float obstacleRange = 3.0f;[Header("Enemy Property")]public float enemyHeight = 1.8f;public float enemyWidth = 1.2f;public float rotateSpeed = 2.0f;public float maxDetectDistance = 10f;private float _walkSpeed = 1.5f;private float _runSpeed = 3.5f;private Animator _animator;private Transform _transform;private float _currentSpeed;private float _targetSpeed;private float _statusDuration = 1.0f;private bool _isStatusTimerEnds = true;private bool _isDetectTimerEnds = true;[Flags]private enum EnemyStatus {Aim,Shoot,Wander,Chase}private EnemyStatus _enemyStatus;void Start(){_animator = GetComponent<Animator>();_rb = GetComponent<Rigidbody>();_transform = transform;_enemyStatus = EnemyStatus.Wander;rayCastOffset = new Vector3(0f, enemyHeight - 0.6f, 0f);}void Update(){if (_enemyStatus == EnemyStatus.Wander) {Wander();} Detect();}private void OnAnimatorMove() {if (_currentSpeed != _targetSpeed) {if (Mathf.Abs(_currentSpeed - _targetSpeed) > 0.1) {_currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);} else {_currentSpeed = _targetSpeed;} }_animator.SetFloat("Speed", _currentSpeed); Vector3 speed = new Vector3(_animator.velocity.x, _rb.velocity.y, _animator.velocity.z);_rb.velocity = speed;}void Wander() {if (_isStatusTimerEnds) {_targetSpeed = UnityEngine.Random.Range(0, 2) == 0 ? 0f : _walkSpeed;_statusDuration = UnityEngine.Random.Range(5f, 10f);_isStatusTimerEnds = false;StartCoroutine(StatusTimer());}}IEnumerator StatusTimer() {float timer = 0;while (timer < _statusDuration) {timer += Time.deltaTime;yield return null; }_isStatusTimerEnds = true;}IEnumerator DetectTimer() {float timer = 0;while (timer < _detectDuration) {timer += Time.deltaTime;yield return null; }_isDetectTimerEnds = true;}float DetectObstacle(float angle) {RaycastHit hit;int layerMask = ~(1 << 8);Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.up);bool hitDetect = Physics.BoxCast(_transform.position + rayCastOffset, new Vector3(enemyWidth/2, rayCastOffset.y/2, 0.2f), rotation * _transform.forward, out hit,transform.rotation * rotation,maxDetectDistance,layerMask);if (hitDetect) {return hit.distance;} else {return 9999.0f;}}void Detect() {if (_isDetectTimerEnds) {_isDetectTimerEnds = false;StartCoroutine(DetectTimer());if (_currentSpeed > 0.2) {float distance = DetectObstacle(0f);if (distance < obstacleRange) {float leftDistance = DetectObstacle(-90f);float rightDistance = DetectObstacle(90f);float startAngle = -45f;float endAngle = -110f;if (rightDistance < obstacleRange && leftDistance < obstacleRange) {startAngle = 180f;endAngle = 180.01f;} else {if (leftDistance < rightDistance) {startAngle *= -1f;endAngle *= -1f;} }_targetAngle = UnityEngine.Random.Range(startAngle, endAngle);_currentAngle = 0f;}}} else {if (Mathf.Abs(_currentAngle - _targetAngle) > 0.1) {_prevAngle = _currentAngle;_currentAngle = Mathf.Lerp(_currentAngle, _targetAngle, rotateSpeed * Time.deltaTime);_transform.Rotate(0, _currentAngle - _prevAngle, 0);} else {_currentAngle = _targetAngle;}}}
}
以上代码大致逻辑是一开始设置状态为漫游状态,然后通过一个StatusTimer来计时,每次计时器到时就随机设置一个速度值。在onAnimatorMove函数中通过插值的方法来平滑改变速度值,并设置Animator的speed值,实现通过root motion动画来驱动游戏对象。另外还设置一个DetectTimer来计时,定期调用DetectObstacle函数来检测游戏对象行进方向上是否有障碍物,如有则进行随机转向。运行场景,可以看到游戏对象在场景中可以自由地进行漫步。
实现瞄准状态
现在我们要增加一个检测玩家的功能,让游戏对象在漫步过程中能发现玩家,并且进入瞄准状态。对以上代码做改动
public class EnemyAI : MonoBehaviour
{...void Update(){if (_enemyStatus == EnemyStatus.Aim) {_prevAngle = _currentAngle;_currentAngle = Mathf.Lerp(_currentAngle, _targetAngle, rotateSpeed * Time.deltaTime);_transform.Rotate(0, _currentAngle - _prevAngle, 0);if (Mathf.Abs(_currentAngle - _targetAngle) < 0.5) {_currentAngle = _targetAngle;}} ...}bool DetectPlayer() {bool findPlayer = false;Vector3 position = _transform.position + new Vector3(0f, enemyHeight-0.2f, 0f);_spottedPlayers = Physics.OverlapSphere(position, eyeviewDistance, LayerMask.GetMask("Character"));for (int i=0;i<_spottedPlayers.Length;i++) {Vector3 playerPosition = _spottedPlayers[i].transform.position;float angle = Vector3.SignedAngle(transform.forward, playerPosition - position, Vector3.up);if (angle <= viewAngle/2 && angle >= -viewAngle/2) {RaycastHit info;int layermask = LayerMask.GetMask("Character", "Default");Physics.Raycast(position, playerPosition - position, out info, eyeviewDistance, layermask);if (info.collider == _spottedPlayers[i]) {if (_currentSpeed >= 0.1) {_targetSpeed = 0f;_currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.75f);_animator.SetFloat("Speed", _currentSpeed);} else {_prevPlayerPosition = playerPosition;_foundPlayer = true;_enemyStatus = EnemyStatus.Aim;_animator.SetTrigger("Aim");_currentAngle = 0;_targetAngle = angle;_currentSpeed = 0f;findPlayer = true;}}}}return findPlayer;} void Detect() {if (_isDetectTimerEnds) {...DetectPlayer()}...}
}
在原来的Detect代码中增加一个对检测玩家的DetectPlayer的调用,当检测到玩家时,设置状态为Aim,并且设置Animator的Aim触发器,播放瞄准动作。
实现追踪状态
当游戏对象检测到玩家之后,玩家可以躲避游戏对象的瞄准,例如跑到一旁的障碍物隐藏。游戏对象找不到玩家,这时应该跑去之前发现玩家的地方,进行搜索。要实现这个功能,简单的一个想法是通过Unity的Navigation自动寻路功能来实现,让游戏对象自行寻路,而不是通过代码来控制。但是如前面提到的,Navigation和Root motion同时驱动游戏对象就会产生冲突,因此我们可以采取方式二来解决,即让Navigation agent跟随动画来移动。
给游戏对象增加一个Navmesh agent组件,然后对代码进行如下改动:
public class EnemyAI : MonoBehaviour
{...private NavMeshAgent _agent;Vector2 smoothDeltaPosition = Vector2.zero;Vector2 velocity = Vector2.zero;void Start(){..._agent = GetComponent<NavMeshAgent>();_agent.updatePosition = false;_agent.speed = _runSpeed;}void Update(){...if (_enemyStatus == EnemyStatus.Chase) {Vector3 worldDeltaPosition = _agent.nextPosition - _transform.position;// Map 'worldDeltaPosition' to local spacefloat dx = Vector3.Dot(_transform.right, worldDeltaPosition);float dy = Vector3.Dot(_transform.forward, worldDeltaPosition);Vector2 deltaPosition = new Vector2(dx, dy);// Low-pass filter the deltaMovefloat smooth = Mathf.Min(1.0f, Time.deltaTime/0.15f);smoothDeltaPosition = Vector2.Lerp (smoothDeltaPosition, deltaPosition, smooth);// Update velocity if time advancesif (Time.deltaTime > 1e-5f)velocity = smoothDeltaPosition / Time.deltaTime;//Debug.LogFormat("Chase, speed:{0}", velocity.magnitude);_animator.SetFloat("Speed", velocity.magnitude); _transform.LookAt(_agent.steeringTarget + transform.forward);if (_agent.remainingDistance < _agent.radius) {_enemyStatus = EnemyStatus.Wander;}}Detect()}private void OnAnimatorMove() {if (_enemyStatus == EnemyStatus.Chase) {_transform.position = _agent.nextPosition;}else {if (_currentSpeed != _targetSpeed) {if (Mathf.Abs(_currentSpeed - _targetSpeed) > 0.1) {_currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);} else {_currentSpeed = _targetSpeed;} }_animator.SetFloat("Speed", _currentSpeed); Vector3 speed = new Vector3(_animator.velocity.x, _rb.velocity.y, _animator.velocity.z);_rb.velocity = speed;}}void Detect() {if (_isDetectTimerEnds) {...//DetectPlayer();if (!DetectPlayer()) {if (_foundPlayer) {_foundPlayer = false;_agent.nextPosition = _transform.position;_agent.destination = _prevPlayerPosition;_enemyStatus = EnemyStatus.Chase;_animator.SetTrigger("Walk");_targetSpeed = _runSpeed;}} ...}
}
以上的代码值得详细讲解一下,在Start函数中,设置了agent的updatePosition为false,即不让agent来移动游戏对象,同时设置agent的最大速度不要超过runspeed。在Update函数中,判断如果当前是Chase状态,那么计算agent的nextPosition与当前位置的差值,然后计算在deltaTime时间间隔中,需要以什么速度来移动,并设置animator的speed,使得游戏对象的动作与移动速度保持同步,不会出现脚底打滑的现象。在onAnimatorMove函数中,通过设置transform的位置为agent的nextPosition来实现移动。在Detect函数中进行修改,如果之前发现玩家,但现在没有发现,则进入Chase状态, 把之前发现玩家的位置设置为agent的目的地,让agent来进行自动寻路。注意在进入Chase状态时需要更新一下agent的nextPosition为当前游戏对象的位置,因为我们之前设置了updatePostion为false,所以agent的当前位置并不同步。
实现效果
Root Motion动画与Navigation结合
FPS教程
另外我之前也写了一系列文章介绍如何实现FPS游戏,有兴趣的可以了解一下
Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客
Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客
Unity开发一个FPS游戏之三-CSDN博客
Unity开发一个FPS游戏之四_unity fps-CSDN博客
Unity开发一个FPS游戏之五-CSDN博客
相关文章:
Unity实现Root Motion动画的Navigation自动导航
Root motion动画可以将角色的根节点(通常是角色的骨盆或脚部)的运动直接应用到游戏对象上,从而实现角色的自然移动和旋转,避免出现脚底打滑的现象。采用Root motion动画的游戏对象,通常是重载了onAnimatorMove函数&…...
vulnhub靶场【DriftingBlues】之9 final
前言 靶机:DriftingBlues-6,IP地址192.168.1.66 攻击:kali,IP地址192.168.1.16 都采用虚拟机,网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24 信息收集 使用nmap扫描端口 网站探测 访…...
Python连接和操作Elasticsearch详细指南
Python连接和操作Elasticsearch详细指南 一、服务器端配置1. 修改 Elasticsearch 配置文件2. 开放防火墙端口 二、本地 Python 连接 Elasticsearch1. 连接 Elasticsearch2. 索引操作3. 文档操作4. 搜索内容5. 聚合查询6. 批量操作 三、注意事项四、故障排除结论 Elasticsearch …...
JMeter 使用详解
JMeter 使用详解 Apache JMeter 是一款开源的性能测试工具,可用于对静态和动态资源(如 Web 应用、数据库、REST API 等)进行负载测试和性能测试。以下是 JMeter 的详细使用指南: 1. JMeter 安装 下载 JMeter: 从 Apac…...
[SZ901]程序固化工具速度对比
SZ901高速下载器提供程序固化工具,能够快速将bin文件烧写到FLASH中。 相对传统方式有以下优点 1,固化时间是传统方式的1/2 到1/5,flash,程序越大,,效果越明显 2,操作简单,自动脚本…...
类OCSP靶场-Kioptrix系列-Kioptrix Level 4
一、前情提要 二、实战打靶 1. 信息收集 1.1. 主机发现 1.2. 端口扫描 1.3.目录遍历 1.4. 敏感信息 2.漏洞发现 2.1.登录框万能密码 2.2.系统用户密码-ssh链接 2.3.mysql-udf提权 一、前情提要 kali黑客-利用searchsploit搜索exp一键化攻击-CSDN博客 一篇文章带你理…...
C++ ——— 类的 6 个默认成员函数之 取地址函数 以及 const取地址操作符重载函数
目录 前言 取地址函数 const 取地址操作符重载函数 前言 在前几章学习了类的 6 个默认成员函数中的 4 个函数,也是最重要的 4 个 C ——— 类的 6 个默认成员函数之 构造函数-CSDN博客 C ——— 类的 6 个默认成员函数之 析构函数_结构体构析函数-CSDN博客 C…...
【C语言】头文件”“和<>的详解
前言 作者在刚开始学C语言的时候,都是用的< >去引用头文件,但在学习STM32的时候发现,程序中大量使用" "去引用双引号。 那么二者有什么区别呢? 无论使用哪种方式,头文件的目的都是为了引用你需要的文件供你编程使…...
sql server 字符集和排序
英文: Latin1_General_CI_AS 中文:Chinese_PRC_CI_AS 影响字符存储,解释用户存在单字节字符类型(char,varchar等)里面的数据 字符排序规则(是否区分大小写等) 中国的用户一定要注意…...
【linux】shell(39)-定时任务
在 Linux 和 Unix 系统中,定时任务是通过 cron 服务 和 crontab 工具 实现的,它允许用户在指定的时间自动执行命令或脚本。本教程将深入介绍 crontab 的工作原理、配置、常见用法和注意事项,帮助你高效地管理自动化任务。 1. cron 和 crontab…...
C# 基本信息介绍
总目录 前言 对 C# 做一个基本信息介绍,让我们对 C# 有个基本的认识。 在进行本文的阅读之前,可以瞧瞧 编程基础知识简述 简单的入个门儿。 一、C# 1. C# 概述 C#是由微软公司发布的一种由C和C衍生出来的面向对象的编程语言。 2. C# 详细介绍 C#&am…...
告别机器人味:如何让ChatGPT写出有灵魂的内容
目录 ChatGPT的一些AI味道小问题 1.提供编辑指南 2.提供样本 3.思维链大纲 4.融入自己的想法 5.去除重复增加多样性 6.删除废话 ChatGPT的一些AI味道小问题 大多数宝子们再使用ChatGPT进行写作时,发现我们的老朋友ChatGPT在各类写作上还有点“机器人味”太重…...
ECharts柱状图-柱图38,附视频讲解与代码下载
引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我将带大家一起实现一个柱状图图表,通过该图表我们可以直观地展示和分析数据。此外,我还将提供…...
SAP ALV选择列排序时弹出定义排序顺序窗口问题
需求场景 使用REUSE_ALV_GRID_DISPLAY_LVC生成ALV,发现一个问题:使用it_events的时候选择列排序时会弹出定义排序顺序窗口,如下图所示。(正常选择某一列再使用排序功能时会直接排序,不用再选择列) CLASS l…...
HTML零基础入门教学
目录 一. HTML语言 二. HTML结构 三. HTML文件基本结构 四. 准备开发环境 五. 快速生成代码框架 六. HTML常见标签 6.1 注释标签 6.2 标题标签:h1-h6 6.3 段落标签:p 6.4 换行标签:br 6.5 格式化标签 6.6 图片标签&a…...
AI-PR曲线
PR曲线 人工智能里面的一个小概念。 2.3 性能度量(查全率,查准率,F1,PR曲线与ROC曲线) 预测出来的是一个概率,不能根据概率来说它是正类还是负类,要有一个阈值。 查准率(Precision&…...
[创业之路-199]:《华为战略管理法-DSTE实战体系》- 3 - 价值转移理论与利润区理论
目录 一、价值转移理论 1.1. 什么是价值? 1.2. 什么价值创造 (1)、定义 (2)、影响价值创造的因素 (3)、价值创造的三个过程 (4)、价值创造的实践 (5&…...
问题解决: python 调用存储过程获取不到返回值
python 调用存储过程获取不到返回值 1. 检查存储过程是否有副作用(例如关闭结果集)2. 在 Python 代码中,确保在执行存储过程时按正确的顺序操作:3. 使用游标检查结果集 1. 检查存储过程是否有副作用(例如关闭结果集&am…...
AI前沿分析:Github Copilot 推出免费版本,AI + 编程更高效!
名人说:莫听穿林打叶声,何妨吟啸且徐行。—— 苏轼 Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、GitHub Copilot:AI编程的“革命性”助力二、免费版本上线:AI编程的普及时代&…...
浅谈仓颉语言的优劣
仓颉语言,作为华为自研的新一代编程语言,以其高效、安全、现代化的特点,引起了广泛的关注。 仓颉语言的优势 高效并发 仓颉语言的一大亮点是其轻松并发的能力。它实现了轻量化用户态线程和并发对象库,使得高效并发变得轻松。仓颉…...
AI证件照制作 API 快速生成证件照
本文将介绍一种 AI证件照制作 API 对接说明,它是可以通过输入人像照片URL以及自己喜欢的模板来制作各种风格的证件照。 接下来介绍下 AI证件照制作 API 的对接说明。 申请流程 要使用 API,需要先到 AI证件照制作 API 对应页面申请对应的服务ÿ…...
Java.10--IO流
JavaSE(Java Standard Edition)中的IO(输入输出)库提供了用于读写数据的类和接口。 这些功能可以用来处理文件、网络连接、内存中的数据结构等。 一、IO流分类 Java中的IO(输入输出)库可以按照不同的标准…...
Firewalld 防火墙全面解析与配置指南
在当今网络环境中,网络安全至关重要,而防火墙作为网络安全的关键防线,在Linux系统中扮演着极其重要的角色。本文将深入探讨Firewalld防火墙,涵盖其基础概念,优势特点,配置方法等多面内容,为您提供全面的Firewalld防火墙知识体系 一,Linux防火墙基础 (一) 防火墙内核…...
Javascript-web API-day02
文章目录 01-事件监听02-点击关闭广告03-随机点名案例04-鼠标经过或离开事件05-可点击的轮播图06-小米搜索框07-键盘类型事件08-键盘事件-发布评论案例09-focus选择器10-评论回车发布11-事件对象12-trim方法13-环境对象14-回调函数15-tab栏切换 01-事件监听 <!DOCTYPE html…...
Python爬虫之代理的设置
【1】urllib中使用公开代理 import urllib.requesturl http://www.baidu.com/s?wdipheaders {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 }# 请求对象的定制 request urllib.req…...
Qt:QMetaObject::connectSlotsByName实现信号槽自动关联
简介 在Qt中,QMetaObject::connectSlotsByName 是一个便利的方法,它可以根据对象的对象名(objectName)自动将信号和槽连接起来。但是,要使用这个方法,必须确保: 1 控件(如按钮&…...
芝法酱学习笔记(2.1)——sql性能优化1
一、前言 做程序员这行,相信大家都会接触到性能优化这个概念。并且多数程序员,为自己能参与到性能优化的工作而感到自豪。 在普通应用系统的业务开发中,程序的性能瓶颈往往在数据库查询的IO上,所以优化数据库查询则是重中之重的工…...
【Mysql】Java的JDBC编程
本节目标 数据库驱动 JDBC的概念及作用 掌握JDBC的工作原理 掌握JDBC中几个常用接口和类 掌握基于数据库的应用程序开发流程 一. 数据库编程的必备条件 编程语言,如Java,C、C、Python等 数据库,如Oracle,MySQL,S…...
PHPUnit使用指南:编写高效的单元测试
PHPUnit使用指南:编写高效的单元测试 单元测试是软件开发中不可或缺的一部分,它能够帮助开发者确保代码的正确性和稳定性。PHPUnit是PHP中最流行的单元测试框架之一,提供了一套强大的工具和功能来编写和运行测试。本文将详细介绍如何使用PHP…...
二、HTML5
一、HTML5简介 1、什么是HTML5 HTML5 是新一代的 HTML 标准,2014年10月由万维网联盟(W3C)完成标准制定。 官网地址: W3C 提供: https://www.w3.org/TR/html/index.html WHATW…...
授权模型MAC
MAC(Mandatory Access Control)是一种授权模型,用于实现对系统资源访问的强制控制。在MAC模型中,授权是基于预先定义的安全策略,且该策略由系统管理员来配置和管理。 在MAC模型中,每个用户和每个资源都被赋…...
GaussDB数据库迁移方案介绍
云数据库GaussDB提供了多种数据迁移方案,可满足从MySQL数据库、Oracle数据库、GaussDB数据库、PostgreSQL数据库、DB2 for LUW、RDS for SQL Server、Microsoft SQL Server数据库到云数据库GaussDB的迁移。 数据迁移工具有DRS、DAS和gs_loader。推荐使用DRS&#x…...
web3跨链桥协议-Nomad
项目介绍 Nomad是一个乐观跨链互操作协议。通过Nomad协议,Dapp能够在不同区块链间发送数据(包括rollups),Dapp通过Nomad的合约和链下的代理对跨链数据、消息进行验证、传输。其安全通过乐观验证机制和欺诈证明制约验证者实现&…...
白话java设计模式
创建模式 单例模式(Singleton Pattern): 就是一次创建多次使用,它的对象不会重复创建,可以全局来共享状态。 工厂模式(Factory Method Pattern): 可以通过接口来进行实例化创建&a…...
代码的注释
代码注释是程序开发中至关重要的一部分,良好的注释能够大大提升代码的可读性、可维护性和团队协作效率。注释帮助开发人员理解代码的逻辑、目的和背后的设计思想,尤其是在面对复杂的业务逻辑或算法时,注释可以帮助未来的开发人员快速理解并有…...
Java中的Consumer接口应该如何使用(通俗易懂图解)
应用场景: 第一次程序员A写好了个基础的遍历方法: public class Demo1 {public static void main(String[] args) {//假设main方法为程序员B写的,此时需要去调用A写好的一个遍历方法//1.如果此时B突然发现想将字符串以小写的形式打印出来,则…...
数据库设计的基础与进阶:1NF、2NF、3NF及BCNF解析
目录 什么是数据库范式? 1. 第一范式(1NF) 2. 第二范式(2NF) 3. 第三范式(3NF) 4. 博茨-科德范式(BCNF) 总结 在数据库设计中,范式是为了确保数据存储结…...
ARM Cortex-A7 MPCore 架构
1、Cortex-A7 MPCore 简介 Cortex-A7 MPcore 处理器支持 1~4 核,通常是和 Cortex-A15 组成 big.LITTLE 架构的, Cortex-A15 作为大核负责高性能运算,比如玩游戏啥的, Cortex-A7 负责普通应用,因为 CortexA7 省电。 Cortex-A7 本身性能也不弱,不要看它叫做 Cortex-A7 但是…...
【操作系统】数据集合集!
本文将为您介绍经典、热门的数据集,希望对您在选择适合的数据集时有所帮助。 1 HarmonyOS 更新时间:2024-07-20 访问地址: GitHub 描述: 是首个基于微内核的全场景分布式操作系统,是华为自主研发的操作系统,华为将率…...
原生js图片预览
下面的图片预览是从一个JSON文件中加载图片列表,并且支持点击缩略图预览大图,还可以使用鼠标滚轮进行图片缩放。接下来了给大家把html、css、js一个一个的讲解一下 首先是html <div class"container"></div><div id"imag…...
【系统】Mac crontab 无法退出编辑模式问题
【系统】Mac crontab 无法退出编辑模式问题 背景一、问题回答1.定位原因:2.确认编辑器类型3.确保编辑器进入正确3.1 确认是否有crontab调度任务3.2 进入编辑器并确保编辑器正常3.3 保存操作 4.确认crontab任务存在5.确保脚本的可执行性和正确性 二、后续 背景 之前…...
【进程篇】04.进程的状态与优先级
一、进程的状态 1.1 进程的状态 1.1.1 并行与并发 • 并行: 多个进程在多个CPU下分别,同时进行运行 • 并发: 多个进程在一个CPU下采用进程切换的方式,在一个时间片内,让多个进程都得以推进 1.1.2 时间片的概念 LInux/windows这些民用级别…...
linux下蓝牙调试工具hcitool的使用
hcitool 是一个用于蓝牙设备管理的命令行工具,主要用于查看和管理蓝牙设备。以下是一些常见的用法和示例: 1. 查看本地蓝牙适配器信息 使用 hcitool dev 命令可以查看本地蓝牙适配器的信息。 hcitool dev示例输出: Devices:hci0 00:11:22…...
【RAG实战】Prompting vs. RAG vs. Finetuning: 如何选择LLM应用选择最佳方案
在构建基于大型语言模型(LLM)的应用时,通常不可能立即使用模型而无需任何调整。为了保持高实用性,我们可以选择以下几种方法之一: Prompt Engineering(提示工程)Fine-tuning(微调&a…...
EasyExcel 动态设置表格的背景颜色和排列
项目中使用EasyExcel把数据以excel格式导出,其中设置某一行、某一列单元格的背景颜色、排列方式十分常用,记录下来方便以后查阅。 1. 导入maven依赖: <dependency><groupId>com.alibaba</groupId><artifactId>easy…...
python俄罗斯方块.py
俄罗斯方块.py import pygame import random# 初始化游戏 pygame.init()# 设置游戏窗口的大小 screen_width 800 screen_height 600 play_width 300 play_height 600 block_size 30top_left_x (screen_width - play_width) // 2 top_left_y screen_height - play_heigh…...
IP协议详解
目录 一. IP协议概述 1. 概念 2. 特点 (1) 无连接性 (2) 不可靠传输 (3) 数据包分片和重组 二. IP协议报文格式 1. 版本 (4位) 2. 首部长度 (4位) 3. 服务类型 (8位) 4. 总长度 (16位) 5. 标识, 标志位, 片偏移 6. 生存时间 (8位) 7. 协议 (8位) 8. 首部检验和 (1…...
青少年编程与数学 02-004 Go语言Web编程 02课题、依赖管理
青少年编程与数学 02-004 Go语言Web编程 02课题、依赖管理 课题摘要:一、项目结构各目录说明: 二、依赖项三、依赖管理任务四、依赖管理步骤1. 初始化Go Modules项目2. 添加依赖3. 指定依赖版本4. 更新依赖5. 清理未使用的依赖6. 离线工作7. 模块隔离8. 可重现构建 …...
代码生成器
源码 表结构 代码的目录结构 后端代码 前端代码 查询数据库的表 前端 后端 只查询当前数据库的表去除掉定时任务和生成器的表格去除掉已经导入的表格<select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult"…...
MySQL 性能调优:打造高效数据库
SQL 语句层面的性能调优策略 合理选择字段属性 在创建 MySQL 表时,为了获取更好的性能,选择合适的字段属性至关重要。 首先,要依据实际情况合理设置字段的类型及宽度。例如,对于像手机号码这类固定长度为 11 位的字段ÿ…...