Unity教程(二十二)技能系统 分身技能

Unity开发2D类银河恶魔城游戏学习笔记

Unity教程(零)Unity和VS的使用相关内容
Unity教程(一)开始学习状态机
Unity教程(二)角色移动的实现
Unity教程(三)角色跳跃的实现
Unity教程(四)碰撞检测
Unity教程(五)角色冲刺的实现
Unity教程(六)角色滑墙的实现
Unity教程(七)角色蹬墙跳的实现
Unity教程(八)角色攻击的基本实现
Unity教程(九)角色攻击的改进

Unity教程(十)Tile Palette搭建平台关卡
Unity教程(十一)相机
Unity教程(十二)视差背景

Unity教程(十三)敌人状态机
Unity教程(十四)敌人空闲和移动的实现
Unity教程(十五)敌人战斗状态的实现
Unity教程(十六)敌人攻击状态的实现
Unity教程(十七)敌人战斗状态的完善

Unity教程(十八)战斗系统 攻击逻辑
Unity教程(十九)战斗系统 受击反馈
Unity教程(二十)战斗系统 角色反击

Unity教程(二十一)技能系统 基础部分
Unity教程(二十二)技能系统 分身技能


如果你更习惯用知乎
Unity开发2D类银河恶魔城游戏学习笔记目录


文章目录

  • Unity开发2D类银河恶魔城游戏学习笔记
  • 前言
  • 一、概述
  • 二、预制件(Prefab)
    • (1)预制件介绍
    • (2)创建分身预制件
  • 三、分身技能的实现
    • (1)分身技能的创建
    • (2)分身技能的实现
    • (3)分身的消失与销毁
    • (4)补充:将预制件Clone实例化到当前位置
  • 四、分身攻击的实现
    • (1)攻击动画
    • (2)分身攻击的实现
    • (2)分身攻击的实现
  • 总结 完整代码
    • PlayerDashState.cs
    • Clone_Skill.cs
    • Clone_Skill_Controller.cs
    • SkillManager.cs
    • Player.cs


前言

本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记,如有错误,欢迎指正。

本节实现角色分身技能。

Udemy课程地址

对应视频:
Clone Creating Ability
Clone’s Attack


一、概述

本节实现分身技能。
实现解锁技能后,在角色冲刺时产生一个分身,分身会攻击距离最近的一个敌人。
在这里插入图片描述

二、预制件(Prefab)

(1)预制件介绍

Unity的预制件相当于创建一个模板,使得游戏对象作为可重用资源。可以用这个模板在场景中创建新的预制件实例。
详细内容可见Unity官方手册预制件

首先是预制件的创建。
预制件的创建很简单,将一个游戏对象从 Hierarchy 窗口拖入 Project 窗口就可以了。
在这里插入图片描述


预制件的实例化。
最简单的是将预制件资源从 Project 视图拖动到 Hierarchy 或 Scene 视图,创建实例。
在这里插入图片描述

也可通过脚本进行实例化。使用Object的Instantiate函数。


Object Instantiate (Object original);Object Instantiate (Object original, Transform parent);Object Instantiate (Object original, Transform parent, bool instantiateInWorldSpace);Object Instantiate (Object original, Vector3 position, Quaternion rotation);Object Instantiate (Object original, Vector3 position, Quaternion rotation, Transform parent);

参数含义如下表:

参数含义
original要复制的现有对象(如预制件)
position新对象的位置
rotation新对象的方向
parent将指定给新对象的父对象
instantiateInWorldSpace分配父对象时,传递 true 可直接在世界空间中定位新对象。
传递 false 可相对于其新父项来设置对象的位置。

预制件的编辑。 可以在预制件模式下编辑预制件。这种情况可以单独或在上下文中编辑预制件资源。

在这里插入图片描述

在这里插入图片描述
也可以在实例中编辑后覆盖预制体。使用Overrides应用和还原覆盖。

在这里插入图片描述

(2)创建分身预制件

将玩家精灵表第一帧拖入层次面板中并重命名为Clone。

在这里插入图片描述
在这里插入图片描述

创建动画控制器Clone_AC

在这里插入图片描述
将Clone_AC挂载到Clone下面

在这里插入图片描述
这时我们发现Clone的图像被遮挡了。

在这里插入图片描述
调整SpriteRenderer中的层次顺序,使Clone位于敌人之前,玩家之后。

在这里插入图片描述
给Clone添加动画,这里我们不需要重新建立动画,只需要把原来Player的动画复用。
打开Clone的Aniamtor面板,将PlayerIdle拖入作为默认状态,再拖入PlayerAttack1、PlayerAttack2、PlayerAttack3。

在这里插入图片描述
创建Prefabs文件夹存放预制件。

在这里插入图片描述
将层次面板中的Clone拖入文件夹,预制件创建完成。

在这里插入图片描述
把层次面板中的Clone删除,后续我们用到它时会在脚本中创建。

三、分身技能的实现

分身技能Clone_Skill继承自Skill基类。我们要实现按下冲刺键后,在玩家冲刺的位置创建一个分身,因此我们需要在PlayerDashState开始时传入Player的位置创建分身。

实现时还要创建一个分身技能的控制器Clone_Skill_Controller,将它挂载到Clone预制件下,控制分身的位置。这里让人容易疑惑,为什么要大费周章再创建一个控制器脚本。个人理解,更多是因为马上要实现的分身攻击,攻击时需要触发动画事件,因此必须有个脚本挂在Clone预制体下面。这里就把控制分身位置的功能也写进去了。

此外,还可在实例化时就指定分身位置,这种形式也会在下面写一下。

(1)分身技能的创建

在Scripts文件夹中创建Skills文件夹存放技能相关脚本。
在这里插入图片描述
创建分身技能脚本Clone_Skill,它继承自Skill基类,将它挂到技能管理器下。

在这里插入图片描述
在这里插入图片描述

在技能管理器脚本中创建分身技能并赋值。

    public Clone_Skill clone { get; private set; }private void Start(){dash = GetComponent<Dash_Skill>();clone = GetComponent<Clone_Skill>();}

(2)分身技能的实现

创建分身技能控制器Clone_Skill_Controller,创建函数SetupClone设置分身信息。
在这里插入图片描述
双击预制件Clone,在面板中点击Add Component添加组件。
注意:脚本是添加在预制件上的。

在这里插入图片描述

在Clone_Skill_Controller中添加设置分身信息的函数。

//Clone_Skill_Controller:分身技能控制器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Clone_Skill_Controller : MonoBehaviour
{//设置分身信息public void SetupClone(Transform _newTransform){transform.position = _newTransform.position;}
}

在Clone_Skill脚本中添加实例化预制体的函数,并调用SetupClone设置分身信息。
//Clone_Skill:分身技能
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Clone_Skill : Skill
{[SerializeField] private GameObject clonePerfab;public void CreateClone(Transform _clonePosition){GameObject newClone = Instantiate(clonePerfab);newClone.GetComponent<Clone_Skill_Controller>().SetupClone(_clonePosition);}
}

为预制体赋值
在这里插入图片描述


在Player中创建SkillManager方便管理。
    public SkillManager skill;// 设置初始状态protected override void Start(){base.Start();skill = SkillManager.instance;StateMachine.Initialize(idleState);}

接着在PlayerDashState的中调用CreateClone,使得冲刺后在玩家位置创建一个分身。

    //进入状态public override void Enter(){base.Enter();player.skill.clone.CreateClone(player.transform);//设置冲刺持续时间stateTimer = player.dashDuration;}

效果如下:
在这里插入图片描述

基本功能已经实现,但有个很明显的问题,创建的分身没有回收。

(3)分身的消失与销毁

此技能需要让分身持续一段时间后逐渐消失,可以使clone预制件的图像随时间透明度逐渐降低实现,最后透明度降到0时销毁分身。这需要用到计时器,而且要设置分身持续的时长和消失的速度。

我们把经常需要变动修改的变量放在CloneSkill中方便管理,这里将分身持续时长cloneDuration放在里面。

public class Clone_Skill : Skill
{[Header("Clone Info")][SerializeField] private GameObject clonePerfab;[SerializeField] private float cloneDuration;public void CreateClone(Transform _clonePosition){GameObject newClone = Instantiate(clonePerfab);newClone.GetComponent<Clone_Skill_Controller>().SetupClone(_clonePosition, cloneDuration);}
}

在Clone_Skill_Controller中设置计时器,实现图像透明度递减,并在透明度为0时销毁对象。
public class Clone_Skill_Controller : MonoBehaviour
{private SpriteRenderer sr;[SerializeField] private float colorLosingSpeed;private float cloneTimer;private void Awake(){sr = GetComponent<SpriteRenderer>();}private void Update(){cloneTimer -= Time.deltaTime;if(cloneTimer < 0){sr.color = new Color(1, 1, 1, sr.color.a - Time.deltaTime * colorLosingSpeed);if (sr.color.a <= 0)Destroy(gameObject);}}//设置分身信息public void SetupClone(Transform _newTransform, float _cloneDuration){transform.position = _newTransform.position;cloneTimer = _cloneDuration;}
}

设置合适的技能持续时间和消失速度
在这里插入图片描述
在这里插入图片描述
效果如下:
在这里插入图片描述

(4)补充:将预制件Clone实例化到当前位置

只需在实例化时直接传入位置参数即可,其他函数要随着做一些更改。
在Clone_Skill中

    public void CreateClone(Transform _clonePosition){GameObject newClone = Instantiate(clonePerfab,_clonePosition);newClone.GetComponent<Clone_Skill_Controller>().SetupClone(cloneDuration);}

在Clone_Skill_Controller中

    //设置分身信息public void SetupClone(float _cloneDuration){cloneTimer = _cloneDuration;}

四、分身攻击的实现

(1)攻击动画

进入预制件Clone的编辑,在Animator中创建空状态用于空闲和攻击状态过渡。创建Int型变量AttackNumber用于确定攻击段数。
在这里插入图片描述
连接playerIdle与Empty状态,当AttackNumber>0时,进入Empty。
PlayerIdle->Empty, 加条件变量并更改设置

在这里插入图片描述
分别连接Empty和三个攻击状态,在AttackNumber等于1时进入playerAttack1,同理等于2、3时分别进入其他两个状态
在这里插入图片描述

(2)分身攻击的实现

在技能树中分身攻击技能解锁后才可使用,这里我们先实现功能部分,所以先在Clone_Skill中添加一个变量canAttack用于测试。

public class Clone_Skill : Skill
{[Header("Clone Info")][SerializeField] private GameObject clonePerfab;[SerializeField] private float cloneDuration;[Space][SerializeField] private bool canAttack;public void CreateClone(Transform _clonePosition){GameObject newClone = Instantiate(clonePerfab);newClone.GetComponent<Clone_Skill_Controller>().SetupClone(_clonePosition, cloneDuration,canAttack);}
}

当解锁分身攻击技能时,在Clone_Skill_Controller中实现分身攻击的设置。

设置Animator中的条件变量AttackNumber为1-3中随机一个数,播放相应攻击动画。
注意:在Unity中Random.Range(a, b) 生成的是 [ a, b ) 区间内的整数。

private Animator anim;private void Awake(){sr = GetComponent<SpriteRenderer>();anim = GetComponent<Animator>();}//设置分身信息public void SetupClone(Transform _newTransform, float _cloneDuration, bool _canAttack){if (_canAttack)anim.SetInteger("AttackNumber", Random.Range(1, 4));transform.position = _newTransform.position;cloneTimer = _cloneDuration;}

效果如下:
在这里插入图片描述

现在分身攻击是连续不断地没有结束攻击的部分,我们可以复用攻击动画以前的事件实现。
在这里插入图片描述
参照PlayerAnimationTriggers里函数的写法,在Clone_Skill_Controller中添加AnimationTrigger和AttackTrigger两个函数,分别用于结束攻击和触发攻击效果。
AnimatonTrigger会将计时器设置为小于0的数,相当于分身技能持续时间直接结束,开始逐渐消失。
AttackTrigger与玩家攻击的实现逻辑一样,检查攻击范围内的敌人,造成伤害效果。
添加如下代码:

    [SerializeField] private Transform attackCheck;[SerializeField] private float attackCheckRadius = 0.8f;private void AnimationTrigger(){cloneTimer = -0.1f;}private void AttackTrigger(){Collider2D[] colliders = Physics2D.OverlapCircleAll(attackCheck.position, attackCheckRadius);foreach (var hit in colliders){if (hit.GetComponent<Enemy>() != null)hit.GetComponent<Enemy>().Damage();}}

在Clone下创建一个空物体并重命名为attackCheck,将它移动到分身前方合适的位置。然后用它为变量attackCheck赋值。
进行修改时可以在预制体的编辑里,也可以将预制体拖到场景中修改完再覆盖原来的预制体。
在这里插入图片描述
在这里插入图片描述
做完这些你会发现分身可以攻击敌人了,但攻击还是接连不断。
在这里插入图片描述
因为这次在Animator中没有将PlayerAttack连到Exit状态,没有退出,所以动画会循环播放。
将三个攻击动画的lLoop Time勾掉就可以了。

在这里插入图片描述
现在每次冲刺产生分身就是正常攻击一次了。
在这里插入图片描述

(2)分身攻击的实现

最后一个需要解决的问题是分身面向现在是固定朝右的,我们需要再添加一个让分身朝向最近敌人攻击的功能。
在分身一定范围内检测敌人,比较后选取离分身最近的一个。如果它在分身左侧,则翻转分身让它面向左侧。

    private Transform closestEnemy;//设置分身信息public void SetupClone(Transform _newTransform, float _cloneDuration, bool _canAttack){if (_canAttack)anim.SetInteger("AttackNumber", Random.Range(1, 4));transform.position = _newTransform.position;cloneTimer = _cloneDuration;FaceClosestTarget();}private void FaceClosestTarget(){Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 25);float closestDistace = Mathf.Infinity;foreach(var hit in colliders){if (hit.GetComponent<Enemy>() != null){float distanceToEnemy = Vector2.Distance(transform.position, hit.transform.position);if (distanceToEnemy < closestDistace){closestDistace = distanceToEnemy;closestEnemy = hit.transform;}}}if(closestEnemy != null){if (closestEnemy.position.x < transform.position.x)transform.Rotate(0, 180, 0);}}

效果如下:

在这里插入图片描述

总结 完整代码

PlayerDashState.cs

添加分身的创建。

//PlayerDashState:冲刺状态
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerDashState : PlayerState
{//构造函数public PlayerDashState(PlayerStateMachine _stateMachine, Player _player, string _animBoolName) : base(_stateMachine, _player, _animBoolName){}//进入状态public override void Enter(){base.Enter();player.skill.clone.CreateClone(player.transform);//设置冲刺持续时间stateTimer = player.dashDuration;}//退出状态public override void Exit(){base.Exit();}//更新public override void Update(){base.Update();//切换滑墙状态if(!player.isGroundDetected() && player.isWallDetected()) stateMachine.ChangeState(player.wallSlideState);//设置冲刺速度player.SetVelocity(player.dashDir * player.dashSpeed, 0);//切换到空闲状态if (stateTimer < 0)stateMachine.ChangeState(player.idleState);}
}

Clone_Skill.cs

创建分身,添加经常需要在面板上更改的相关变量。

//Clone_Skill:分身技能
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Clone_Skill : Skill
{[Header("Clone Info")][SerializeField] private GameObject clonePerfab;[SerializeField] private float cloneDuration;[Space][SerializeField] private bool canAttack;public void CreateClone(Transform _clonePosition){GameObject newClone = Instantiate(clonePerfab);newClone.GetComponent<Clone_Skill_Controller>().SetupClone(_clonePosition, cloneDuration,canAttack);}
}

Clone_Skill_Controller.cs

设置分身信息,实现分身逐渐消失,实现分身攻击,将分身改为面向最近的敌人。

//Clone_Skill_Controller:分身技能控制器
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;public class Clone_Skill_Controller : MonoBehaviour
{private SpriteRenderer sr;private Animator anim;[SerializeField] private float colorLosingSpeed;private float cloneTimer;[SerializeField] private Transform attackCheck;[SerializeField] private float attackCheckRadius = 0.8f;private Transform closestEnemy;private void Awake(){sr = GetComponent<SpriteRenderer>();anim = GetComponent<Animator>();}private void Update(){cloneTimer -= Time.deltaTime;if(cloneTimer < 0){sr.color = new Color(1, 1, 1, sr.color.a - Time.deltaTime * colorLosingSpeed);if (sr.color.a <= 0)Destroy(gameObject);}}//设置分身信息public void SetupClone(Transform _newTransform, float _cloneDuration, bool _canAttack){if (_canAttack)anim.SetInteger("AttackNumber", Random.Range(1, 4));transform.position = _newTransform.position;cloneTimer = _cloneDuration;FaceClosestTarget();}private void AnimationTrigger(){cloneTimer = -0.1f;}private void AttackTrigger(){Collider2D[] colliders = Physics2D.OverlapCircleAll(attackCheck.position, attackCheckRadius);foreach (var hit in colliders){if (hit.GetComponent<Enemy>() != null)hit.GetComponent<Enemy>().Damage();}}private void FaceClosestTarget(){Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 25);float closestDistance = Mathf.Infinity;foreach(var hit in colliders){if (hit.GetComponent<Enemy>() != null){float distanceToEnemy = Vector2.Distance(transform.position, hit.transform.position);if (distanceToEnemy < closestDistance){closestDistance = distanceToEnemy;closestEnemy = hit.transform;}}}if(closestEnemy != null){if (closestEnemy.position.x < transform.position.x)transform.Rotate(0, 180, 0);}}
}

SkillManager.cs

创建分身技能。

//SkillManager:玩家管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SkillManager : MonoBehaviour
{public static SkillManager instance;public Dash_Skill dash { get; private set; }public Clone_Skill clone { get; private set; }private void Awake(){if (instance != null && instance != this){Destroy(this.gameObject);}else{instance = this;}}private void Start(){dash = GetComponent<Dash_Skill>();clone = GetComponent<Clone_Skill>();}
}

Player.cs

创建并初始化技能管理器。

//Player:玩家
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Player : Entity
{[Header("Attack details")]public Vector2[] attackMovement;public float counterAttackDuration = 0.2f;public bool isBusy { get; private set; }[Header("Move Info")]public float moveSpeed = 8f;public float jumpForce = 12f;[Header("Dash Info")]public float dashSpeed=25f;public float dashDuration=0.2f;public float dashDir { get; private set; }public SkillManager skill;#region 状态public PlayerStateMachine StateMachine { get; private set; }public PlayerIdleState idleState { get; private set; }public PlayerMoveState moveState { get; private set; }public PlayerJumpState jumpState { get; private set; }public PlayerAirState airState { get; private set; }public PlayerDashState dashState { get; private set; }public PlayerWallSlideState wallSlideState { get; private set; }public PlayerWallJumpState wallJumpState { get; private set; }public PlayerPrimaryAttackState primaryAttack { get; private set; }public PlayerCounterAttackState counterAttack { get; private set; }#endregion//创建对象protected override void Awake(){base.Awake();StateMachine = new PlayerStateMachine();idleState = new PlayerIdleState(StateMachine, this, "Idle");moveState = new PlayerMoveState(StateMachine, this, "Move");jumpState = new PlayerJumpState(StateMachine, this, "Jump");airState = new PlayerAirState(StateMachine, this, "Jump");dashState = new PlayerDashState(StateMachine, this, "Dash");wallSlideState = new PlayerWallSlideState(StateMachine, this, "WallSlide");wallJumpState = new PlayerWallJumpState(StateMachine, this, "Jump");primaryAttack = new PlayerPrimaryAttackState(StateMachine, this, "Attack");counterAttack = new PlayerCounterAttackState(StateMachine, this, "CounterAttack");}// 设置初始状态protected override void Start(){base.Start();skill = SkillManager.instance;StateMachine.Initialize(idleState);}// 更新protected override void Update(){base.Update();StateMachine.currentState.Update();CheckForDashInput();}public IEnumerator BusyFor(float _seconds){isBusy = true;yield return new WaitForSeconds(_seconds);isBusy = false;}//设置触发器public void AnimationTrigger() => StateMachine.currentState.AnimationFinishTrigger();//检查冲刺输入public void CheckForDashInput(){if (Input.GetKeyDown(KeyCode.LeftShift) && SkillManager.instance.dash.CanUseSkill()){dashDir = Input.GetAxisRaw("Horizontal");if (dashDir == 0)dashDir = facingDir;StateMachine.ChangeState(dashState);}}}

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

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

相关文章

深入解析Java面向对象三大特征之多态、final、抽象类与接口

面向对象编程&#xff08;OOP&#xff09;的三大核心特征为封装、继承、多态&#xff0c;其中多态是最具灵活性和扩展性的特性。本文将从多态的本质出发&#xff0c;结合final关键字、抽象类与接口的设计&#xff0c;深入探讨这些概念的应用场景及其在代码中的实现细节&#xf…

编码器和解码器概念及算法示例【清晰易懂】

编码器&#xff08;Encoder&#xff09;和解码器&#xff08;Decoder&#xff09;是处理信息的一对“搭档”&#xff0c;它们的作用就像是“翻译员”和“逆翻译员”。 1. 编码器&#xff08;Encoder&#xff09;是什么&#xff1f; &#x1f449; 把原始信息变成另一种形式&a…

爬虫逆向:逆向中用到汇编语言详细总结

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、汇编语言基础二、常见汇编指令2.1 数据传输指令2.2 算术指令2.3 逻辑指令2.4 控制流指令2.5 其他指令三、寄存器概述四、调用约定五、栈操作与函数调用六、逆向工程中的汇编分析七、常用逆向工具八、实际案例分析九…

CTF WEB题

[文件包含,少许难度] 地址:攻防世界 代码审计WRONG WAY! <?php include("flag.php"); #包含了一个“flag.php”文件 highlight_file(__FILE__); #来显示当前文件的源代码 if(isset($_GET["file1"]) && isset($_GET["file2"])) #isse…

c++图论(一)之图论的起源和图的概念

C 图论之图论的起源和图的概念 图论&#xff08;Graph Theory&#xff09;是数学和计算机科学中的一个重要分支&#xff0c;其起源可以追溯到 18 世纪 的经典问题。以下是图论的历史背景、核心起源问题及其与基本概念和用途&#xff1a; 借用一下CSDN的图片哈 一、图论的起源&…

Ollama + CherryStudio:构建本地私有知识库

前面我们介绍了Ollama的安装和使用&#xff0c;并通过Open-WebUI进行调用&#xff0c;相信大家对Ollama也有了一定的了解&#xff1b;这篇博文就结合Ollama工具和CherryStudio工具构建一个本地知识库&#xff08;RAG&#xff09;&#xff1b;在进行接下来的操作之前&#xff0c…

【实战ES】实战 Elasticsearch:快速上手与深度实践-8.2.1AWS OpenSearch无服务器方案

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 8.2.1AWS OpenSearch 无服务器方案深度解析与实践指南1. Serverless架构的核心价值与行业趋势1.1 传统Elasticsearch集群的运维挑战1.2 Serverless技术演进路线技术特性对比…

清晰易懂的Java8安装教程

小白也能看懂的 Java 8 安装教程&#xff08;JDK 和 JRE 分目录安装&#xff09; 本教程将手把手教你如何在 Windows 系统上安装 Java 8&#xff08;JDK 1.8&#xff09;&#xff0c;并将 JDK 和 JRE 安装到不同的目录中&#xff0c;同时提供国内 Java 8 下载源和方法。即使你…

图搜索的两种写法,广度优先和深度优先

最近AI的爆发大家都疯了&#xff0c;也确实够疯&#xff0c;前几年谁能天天和AI聊天呢&#xff0c;特别它越来越智能&#xff0c;越来越理解你&#xff0c;你越来越离不开它&#xff0c;我很好奇将来它会不会有情绪&#xff0c;太可怕了&#xff0c;一旦有了这个就有了感情&…

嵌入式八股RTOS与Linux---前言篇

前言 Linux与RTOS是校招八股的时候很喜欢考察的知识,在这里并没有把两个操作系统完全的独立开去讲,放在一起对比或许可能加深印象。我们讲Linux的内核有五部分组成:进程调度、内存管理、文件系统、网络接口、进程间通信,所以我也将从这五方面出发 中断管理去对比和RTOS的不同。…

ChatBI 的技术演进与实践挑战:衡石科技如何通过 DeepSeek 实现商业落地

随着人工智能技术的快速发展&#xff0c;ChatBI&#xff08;基于自然语言交互的商业智能&#xff09;逐渐成为企业数据分析领域的热门话题。作为 BI&#xff08;商业智能&#xff09;领域的新形态&#xff0c;ChatBI 通过自然语言处理&#xff08;NLP&#xff09;技术&#xff…

基于Vue实现Echarts的平滑曲线

在Vue2.x的项目中使用echarts实现如下效果 安装echarts npm install echarts --save组件引入echarts // 在你的Vue组件中 import * as echarts from echarts;在模板中添加一个div元素&#xff0c;用来放置图表 <divref"chart"class"chart"style"…

关于重构分析查询界面的思考(未完)

业务系统里&#xff0c;查询界面很常见&#xff0c;数据分析场景需求普遍而迫切&#xff0c;而新的技术也在不断出现&#xff0c;很有必要重构分析查询界面。 查询筛选 为了尽可能从数据中发现&#xff0c;需要尽可能地将查询条件添加进来&#xff0c;可这样&#xff0c;查询…

在jQuery中DOM操作

&#xff08;一&#xff09;元素选取 各种选择器的使用方法与示例 标签选择器&#xff1a;通过 HTML 标签名称来选取元素。例如&#xff0c;若想选中页面中所有的段落元素&#xff0c;可使用$(‘p’)。假设我们有如下 HTML 结构&#xff1a; 这是第一个段落 这是嵌套在div中的…

Java 集合框架中 `List` 接口及其子类的详细介绍,并用 UML 图表展示层次结构关系,用表格对比各个类的差异。

下面是 Java 集合框架中 List 接口及其子类的详细介绍&#xff0c;并用 UML 图表展示层次结构关系。最后&#xff0c;我会用表格对比各个类的差异。 Java 集合框架中 List 接口及其子类 UML 类图描述 以下是 List 接口及其子类的 UML 类图描述&#xff0c;不包含方法。 详细…

Java面试八股—Redis篇

一、Redis的使用场景 &#xff08;一&#xff09;缓存 1.Redis使用场景缓存 场景&#xff1a;缓存热点数据&#xff08;如用户信息、商品详情&#xff09;&#xff0c;减少数据库访问压力&#xff0c;提升响应速度。 2.缓存穿透 正常的访问是&#xff1a;根据ID查询文章&…

Spring Boot使用线程池创建多线程

在 Spring Boot 2 中&#xff0c;可以使用 Autowired 注入 线程池&#xff08;ThreadPoolTaskExecutor 或 ExecutorService&#xff09;&#xff0c;从而管理线程的创建和执行。以下是使用 Autowired 方式注入线程池的完整示例。 1. 通过 Autowired 注入 ThreadPoolTaskExecuto…

9、交付手段-强化肌肉记忆(随身工具箱)

一、交付工具箱 当临时遇到各类交付棘手问题时&#xff0c;大脑里记住交付工具的使用场景&#xff0c;有利于快速决策&#xff0c;将这些工具转为肌肉记忆&#xff0c;能够快速灵活处理交付中的各类问题&#xff0c;蜕变为交付之星 1、复杂项目&#xff1a;WBS分解、日站会、…

【概念】Node.js,Express.js MongoDB Mongoose Express-Validator Async Handler

1. Node.js 定义&#xff1a;Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境&#xff0c;允许你在服务器端运行 JavaScript 代码。作用&#xff1a;它使得开发者可以使用 JavaScript 编写服务器端代码&#xff0c;从而实现前后端使用同一种语言。比喻&#xff1a…

【GPT入门】第22课 langchain LCEL介绍

【GPT入门】第22课 langchain LCEL介绍 1. LCEL介绍与特点2. 原生API与LCEL的对比2. 简单demo 1. LCEL介绍与特点 LCEL 即 LangChain Expression Language&#xff0c;是 LangChain 推出的一种声明式语言&#xff0c;用于简化和优化在 LangChain 框架内构建复杂链和应用的过程…