95. UE5 GAS RPG 实现创建多段飞弹攻击敌人
从这篇开始,我们将实现一些技能,比如多段火球术,闪电链等等。
在这一篇里,我们先实现多段火球术,技能可以通过配置发射出多个火球术进行攻击。
创建多段火球函数
首先在我们之前创建的RPGFireBolt.h类里面增加一个生成多段火球的函数,使用之前的配置。
然后可以设置最大火球数量以及最大攻击角度
UFUNCTION(BlueprintCallable, Category="Projectile")void SpawnProjectiles(const FVector& ProjectileTargetLocation, const FGameplayTag& SocketTag, const FName SocketName, const bool bOverridePitch = false, const float PitchOverride = 0.f, AActor* HomingTarget = nullptr);protected:UPROPERTY(EditDefaultsOnly, Category="FireBolt")float ProjectileSpread = 90.f; //攻击角度UPROPERTY(EditDefaultsOnly, Category="FireBolt")int32 MaxNumProjectiles = 5; //最大生成火球数量
然后在实现里,我们通过等级和最大火球数量取最小值,如果是1级,就只能发射一个火球。那么,还是按之前默认的发射单个技能的函数去实现。
如果数量大于1,那么,我们需要计算多段,然后在这一段角度里,获取到中间角度,生成一段火球。
具体逻辑,就是获取到每一段的角度,然后,获取到角色最左侧的角度,根据最左侧开始递归,生成每一个火球。
void URPGFireBolt::SpawnProjectiles(const FVector& ProjectileTargetLocation, const FGameplayTag& SocketTag, const FName SocketName, const bool bOverridePitch, const float PitchOverride, AActor* HomingTarget)
{const bool bIsServer = GetAvatarActorFromActorInfo()->HasAuthority(); //判断此函数是否在服务器运行if (!bIsServer) return;if (GetAvatarActorFromActorInfo()->Implements<UCombatInterface>()){//限制产生火球的最大数量NumProjectiles = FMath::Min(MaxNumProjectiles, GetAbilityLevel()); //根据可生成数量进行逻辑判断if(NumProjectiles > 1){//获取释放位置const FVector SocketLocation = ICombatInterface::Execute_GetCombatSocketLocationByTag(GetAvatarActorFromActorInfo(), SocketTag, SocketName);FRotator Rotation = (ProjectileTargetLocation - SocketLocation).Rotation(); //将方向转为旋转if(bOverridePitch) Rotation.Pitch = PitchOverride; //覆写发射角度const float DeltaSpread = ProjectileSpread / NumProjectiles; //技能分的段数const FVector LeftOfSpread = Rotation.Vector().RotateAngleAxis(-ProjectileSpread / 2.f, FVector::UpVector); //获取到最左侧的角度for(int32 i = 0; i<NumProjectiles; i++){const FVector Direction = LeftOfSpread.RotateAngleAxis(DeltaSpread * (i + 0.5f), FVector::UpVector); //获取当前分段的角度FTransform SpawnTransform;SpawnTransform.SetLocation(SocketLocation);SpawnTransform.SetRotation(Direction.Rotation().Quaternion());//SpawnActorDeferred将异步创建实例,在实例创建完成时,相应的数据已经应用到了实例身上AProjectile* Projectile = GetWorld()->SpawnActorDeferred<AProjectile>(ProjectileClass,SpawnTransform,GetOwningActorFromActorInfo(),Cast<APawn>(GetAvatarActorFromActorInfo()),ESpawnActorCollisionHandlingMethod::AlwaysSpawn);Projectile->DamageEffectParams = MakeDamageEffectParamsFromClassDefaults();//确保变换设置被正确应用Projectile->FinishSpawning(SpawnTransform);UKismetSystemLibrary::DrawDebugArrow(GetAvatarActorFromActorInfo(), SocketLocation, SocketLocation + Direction * 100.f, 5, FLinearColor::Green, 120, 5);}}else{SpawnProjectile(ProjectileTargetLocation, SocketTag, SocketName, bOverridePitch, PitchOverride);}}
}
编译打开蓝图,在蓝图里,我们使用新创建的函数来实现火球术的生成。
将技能生成5级,查看效果
然后我们修改角度,查看不一样的效果。
实现分段函数
由于在一定角度范围内,平均角度,获取多个角度的函数通用性比较高,所以我们将在函数库里增加两个函数,用于生成多段角度和多段向量。
所以,我们创建两个函数,用于获取相应内容,这里我将函数库里所有的函数都添加了对应的注释,方便查看,如果有需要的理解的朋友可以在文章底部加群里了解更多。
/*** 这个函数根据传入的值计算均匀分布的多段角度,** @param Forward 正前方向* @param Axis 基于旋转的轴* @param Spread 角度范围* @param NumRotators 分段数** @return TArray<FRotator&> 返回每段角度的中间角度的数组** @note 这个函数用于在技能生成投掷物的函数逻辑中。*/UFUNCTION(BlueprintPure, Category="RPGAbilitySystemLibrary|GameplayMechanics")static TArray<FRotator> EvenlySpacedRotators(const FVector& Forward, const FVector & Axis, float Spread, int32 NumRotators);/*** 这个函数根据传入的值计算均匀分布的多段朝向** @param Forward 正前方向* @param Axis 基于旋转的轴* @param Spread 角度范围* @param NumVectors 分段数** @return TArray<FVector&> 返回每段角度的中间角度的朝向数组** @note 这个函数用于在技能生成投掷物的函数逻辑中。*/UFUNCTION(BlueprintPure, Category="RPGAbilitySystemLibrary|GameplayMechanics")static TArray<FVector> EvenlyRotatedVectors(const FVector& Forward, const FVector & Axis, float Spread, int32 NumVectors);
实现这里,也没什么好说的,就是将一部分逻辑抽离出来,这两个函数区别就是一个返回的是旋转角度,另一个是返回的朝向向量。
TArray<FRotator> URPGAbilitySystemLibrary::EvenlySpacedRotators(const FVector& Forward, const FVector& Axis, float Spread, int32 NumRotators)
{TArray<FRotator> Rotators;const FVector LeftOfSpread = Forward.RotateAngleAxis(-Spread / 2.f, Axis); //获取到最左侧的角度if(NumRotators > 1){const float DeltaSpread = Spread / NumRotators; //技能分的段数for(int32 i=0; i<NumRotators; i++){const FVector Direction = LeftOfSpread.RotateAngleAxis(DeltaSpread * (i + 0.5f), Axis); //获取当前分段的角度Rotators.Add(Direction.Rotation());}}else{//如果只需要一个,则将朝向放入即可Rotators.Add(Forward.Rotation());}return Rotators;
}TArray<FVector> URPGAbilitySystemLibrary::EvenlyRotatedVectors(const FVector& Forward, const FVector& Axis, float Spread, int32 NumVectors)
{TArray<FVector> Vectors;const FVector LeftOfSpread = Forward.RotateAngleAxis(-Spread / 2.f, Axis); //获取到最左侧的角度if(NumVectors > 1){const float DeltaSpread = Spread / NumVectors; //技能分的段数for(int32 i=0; i<NumVectors; i++){const FVector Direction = LeftOfSpread.RotateAngleAxis(DeltaSpread * (i + 0.5f), Axis); //获取当前分段的角度Vectors.Add(Direction);}}else{//如果只需要一个,则将朝向放入即可Vectors.Add(Forward);}return Vectors;
}
实现了对应的函数后,我们修改生成多段火球术的代码,将生成内容修改为通过调用函数库的方法获取多段角度,并生成火球。
void URPGFireBolt::SpawnProjectiles(const FVector& ProjectileTargetLocation, const FGameplayTag& SocketTag, const FName SocketName, const bool bOverridePitch, const float PitchOverride, AActor* HomingTarget)
{const bool bIsServer = GetAvatarActorFromActorInfo()->HasAuthority(); //判断此函数是否在服务器运行if (!bIsServer) return;if (GetAvatarActorFromActorInfo()->Implements<UCombatInterface>()){//限制产生火球的最大数量NumProjectiles = FMath::Min(MaxNumProjectiles, GetAbilityLevel());//获取释放位置const FVector SocketLocation = ICombatInterface::Execute_GetCombatSocketLocationByTag(GetAvatarActorFromActorInfo(), SocketTag, SocketName);FRotator Rotation = (ProjectileTargetLocation - SocketLocation).Rotation(); //将方向转为旋转if(bOverridePitch) Rotation.Pitch = PitchOverride; //覆写发射角度const FVector Forward = Rotation.Vector(); //获取朝向向量//根据函数获取到所有生成的转向TArray<FRotator> Rotations = URPGAbilitySystemLibrary::EvenlySpacedRotators(Forward, FVector::UpVector, ProjectileSpread, NumProjectiles);//遍历所有朝向,并生成火球术for(FRotator& Rot : Rotations){FTransform SpawnTransform;SpawnTransform.SetLocation(SocketLocation);SpawnTransform.SetRotation(Rot.Quaternion());//SpawnActorDeferred将异步创建实例,在实例创建完成时,相应的数据已经应用到了实例身上AProjectile* Projectile = GetWorld()->SpawnActorDeferred<AProjectile>(ProjectileClass,SpawnTransform,GetOwningActorFromActorInfo(),Cast<APawn>(GetAvatarActorFromActorInfo()),ESpawnActorCollisionHandlingMethod::AlwaysSpawn);Projectile->DamageEffectParams = MakeDamageEffectParamsFromClassDefaults();//确保变换设置被正确应用Projectile->FinishSpawning(SpawnTransform);//Debug//UKismetSystemLibrary::DrawDebugArrow(GetAvatarActorFromActorInfo(), SocketLocation, SocketLocation + Rot.Vector() * 100.f, 5, FLinearColor::Green, 120, 5);}}
}
实现飞弹跟随目标
在上面,我们实现了释放技能可以一次性生成多个火球去攻击敌人,但是现在有一个问题,就是生成的火球术是一种扩散的方式向外射出,无法准确的攻击到敌人,所以,我们需要实现给生成的飞弹设置攻击目标,并且飞弹可以朝向目标飞行。
实现这个效果,我们需要使用到ProjectileMovement->HomingTargetComponent组件,可以给飞弹的发射组件设置攻击目标。接下来,我们将实现这个功能。
首先,我们在火球术技能类里增加三个参数,用于设置朝向目标移动时的最大速度和最小速度,火球术将在最大值和最小值中随机一个值来设置,并添加一个技能是否需要朝向目标移动的布尔,这些值都可以在技能蓝图中配置
UPROPERTY(EditDefaultsOnly, Category="FireBolt")float HomingAccelerationMin = 1600.f; //移动朝向目标的最小加速度UPROPERTY(EditDefaultsOnly, Category="FireBolt")float HomingAccelerationMax = 3200.f; //移动朝向目标的最大加速度UPROPERTY(EditDefaultsOnly, Category="FireBolt")bool bLaunchHomingProjectiles = true; //设置生成的飞弹是否需要朝向目标飞行
接下来,我们在飞弹类里增加一个场景组件,这个组件在无法找到攻击目标时,我们也能够实现它能够朝向目标位置飞行,并且这个值在飞弹被销毁时,也能够被正确的垃圾回收(ProjectileMovement->HomingTargetComponent是弱引用,ProjectileMovement销毁时,不会去销毁HomingTargetComponent)。
UPROPERTY() //一个场景组件,用于确定当前投掷物的攻击目标(在没有默认目标时,有默认目标直接设置目标的根组件)TObjectPtr<USceneComponent> HomingTargetSceneComponent;
接下来,我们在生成多重飞弹的函数里,增加对攻击目标的设置,如果目标继承战斗接口,我们直接获取它的根组件设置给HomingTargetComponent ,如果没有,我们就创建一个,并将目标位置应用。
然后设置朝向目标的加速度,和开启朝向目标移动变量。
//根据目标类型设置HomingTargetComponent,此内容必须在飞弹被生成后设置
if(HomingTarget && HomingTarget->Implements<UCombatInterface>())
{//设置攻击的位置为攻击对象的根位置Projectile->ProjectileMovement->HomingTargetComponent = HomingTarget->GetRootComponent();
}
else
{//如果没有获取到攻击目标,则创建一个可销毁的并应用Projectile->HomingTargetSceneComponent = NewObject<USceneComponent>(USceneComponent::StaticClass());Projectile->HomingTargetSceneComponent->SetWorldLocation(ProjectileTargetLocation); //设置组件位置Projectile->ProjectileMovement->HomingTargetComponent = Projectile->HomingTargetSceneComponent;
}
//设置飞弹朝向目标时的加速度
Projectile->ProjectileMovement->HomingAccelerationMagnitude = FMath::FRandRange(HomingAccelerationMin, HomingAccelerationMax);
Projectile->ProjectileMovement->bIsHomingProjectile = bLaunchHomingProjectiles; //设置为true,飞弹将加速飞向攻击目标
完整代码如下
void URPGFireBolt::SpawnProjectiles(const FVector& ProjectileTargetLocation, const FGameplayTag& SocketTag, const FName SocketName, const bool bOverridePitch, const float PitchOverride, AActor* HomingTarget)
{const bool bIsServer = GetAvatarActorFromActorInfo()->HasAuthority(); //判断此函数是否在服务器运行if (!bIsServer) return;if (GetAvatarActorFromActorInfo()->Implements<UCombatInterface>()){//限制产生火球的最大数量NumProjectiles = FMath::Min(MaxNumProjectiles, GetAbilityLevel());//获取释放位置const FVector SocketLocation = ICombatInterface::Execute_GetCombatSocketLocationByTag(GetAvatarActorFromActorInfo(), SocketTag, SocketName);FRotator Rotation = (ProjectileTargetLocation - SocketLocation).Rotation(); //将方向转为旋转if(bOverridePitch) Rotation.Pitch = PitchOverride; //覆写发射角度const FVector Forward = Rotation.Vector(); //获取朝向向量//根据函数获取到所有生成的转向TArray<FRotator> Rotations = URPGAbilitySystemLibrary::EvenlySpacedRotators(Forward, FVector::UpVector, ProjectileSpread, NumProjectiles);//遍历所有朝向,并生成火球术for(FRotator& Rot : Rotations){FTransform SpawnTransform;SpawnTransform.SetLocation(SocketLocation);SpawnTransform.SetRotation(Rot.Quaternion());//SpawnActorDeferred将异步创建实例,在实例创建完成时,相应的数据已经应用到了实例身上AProjectile* Projectile = GetWorld()->SpawnActorDeferred<AProjectile>(ProjectileClass,SpawnTransform,GetOwningActorFromActorInfo(),Cast<APawn>(GetAvatarActorFromActorInfo()),ESpawnActorCollisionHandlingMethod::AlwaysSpawn);Projectile->DamageEffectParams = MakeDamageEffectParamsFromClassDefaults();//根据目标类型设置HomingTargetComponent,此内容必须在飞弹被生成后设置if(HomingTarget && HomingTarget->Implements<UCombatInterface>()){//设置攻击的位置为攻击对象的根位置Projectile->ProjectileMovement->HomingTargetComponent = HomingTarget->GetRootComponent();}else{//如果没有获取到攻击目标,则创建一个可销毁的并应用Projectile->HomingTargetSceneComponent = NewObject<USceneComponent>(USceneComponent::StaticClass());Projectile->HomingTargetSceneComponent->SetWorldLocation(ProjectileTargetLocation); //设置组件位置Projectile->ProjectileMovement->HomingTargetComponent = Projectile->HomingTargetSceneComponent;}//设置飞弹朝向目标时的加速度Projectile->ProjectileMovement->HomingAccelerationMagnitude = FMath::FRandRange(HomingAccelerationMin, HomingAccelerationMax);Projectile->ProjectileMovement->bIsHomingProjectile = bLaunchHomingProjectiles; //设置为true,飞弹将加速飞向攻击目标//确保变换设置被正确应用Projectile->FinishSpawning(SpawnTransform);//Debug//UKismetSystemLibrary::DrawDebugArrow(GetAvatarActorFromActorInfo(), SocketLocation, SocketLocation + Rot.Vector() * 100.f, 5, FLinearColor::Green, 120, 5);}}
}
完成以后,我们还需要去修改技能蓝图的逻辑,设置飞弹移动的目标。
我们修改蓝图,将鼠标拾取到的目标Actor保存为变量,在生成飞弹时,将变量传入。
我们现在可以覆写发射垂直角度,让飞弹先朝某个角度飞行,然后再朝向目标飞行
在飞弹蓝图里,我们可以修改它的初始速度和最大速度,是否受重力影响来实现不同的效果。
如果你想让飞弹能够准确的朝向目标飞行,那么将发射物的重力范围设置为0,它将不受重力影响,并且准确向目标攻击。
相关文章:

95. UE5 GAS RPG 实现创建多段飞弹攻击敌人
从这篇开始,我们将实现一些技能,比如多段火球术,闪电链等等。 在这一篇里,我们先实现多段火球术,技能可以通过配置发射出多个火球术进行攻击。 创建多段火球函数 首先在我们之前创建的RPGFireBolt.h类里面增加一个生…...

分布式集群下如何做到唯一序列号
优质博文:IT-BLOG-CN 分布式架构下,生成唯一序列号是设计系统常常会遇到的一个问题。例如,数据库使用分库分表的时候,当分成若干个sharding表后,如何能够快速拿到一个唯一序列号,是经常遇到的问题。实现思…...
在 Vue 2 中使用 Axios 发起 POST 和 GET 请求
Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 node.js,它提供了一种非常方便的方式来发送异步 HTTP 请求。在 Vue 2 应用中,Axios 可以帮助我们轻松地与后端 API 进行通信。本文将介绍如何在 Vue 2 项目中引入 Axios,并…...

Linux内核初始化过程中加载TCP/IP协议栈
Linux内核初始化过程中加载TCP/IP协议栈 Linux内核初始化过程中加载TCP/IP协议栈,从start_kernel、kernel_init、do_initcalls、inet_init,找出Linux内核初始化TCP/IP的入口位置,即为inet_init函数。 Linux内核启动过程 之前的实验中我们设…...
Mysql树形结构表-查询所有子集数据
表结构,这里只是个例子,所有的树形结构表均可用: CREATE TABLE zhkt_course_chapter (id bigint NOT NULL COMMENT 唯一id,course_id bigint NOT NULL COMMENT 所属课程id,name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general…...
Vue 3 Composition API进阶指南
在上一篇文章中,我们介绍了Vue 3的Composition API基础,包括如何使用setup函数、ref和reactive来创建响应式数据,以及使用watchEffect来监控数据变化。本文将继续深入探讨Composition API的高级用法,帮助你更好地理解和利用Vue 3的…...
C++学习,多继承
多继承,一个子类可以有多个父类,它继承了多个父类的特性。这种机制提供了强大的灵活性,但也带来了复杂性,特别是当涉及到基类中的同名成员(包括成员函数和变量)时。 C 类从多个类继承成员,语法如…...
苹果研究人员提出了一种新颖的AI算法来优化字节级表示以自动语音识别(ASR),并将其与UTF-8表示进行比较
端到端(E2E)神经网络已成为多语言自动语音识别(ASR)的灵活且准确的模型。然而,随着支持的语言数量增加,尤其是像中文、日语、韩语(CJK)这样大字符集的语言,输出层的大小显…...

2024年重磅报告!国内AI大模型产业飞速发展!
伴随人工智能技术的加速演进,AI 大模型已成为全球科技竞争的新高地、未来产业的新赛道、经济发展的新引擎,发展潜力大、应用前景广。近年来,我国高度重视人工智能的发展,将其上升为国家战略,出台一系列扶持政策和规划&…...

Sentinel 安装
一、下载jar包 下载地址:Releases alibaba/Sentinel GitHub 二、运行 将jar包放在任意非中文、不包含特殊字符的目录下,启动 启动命令:运行cmd 使用一下命令 java -Dserver.port8090 -Dcsp.sentinel.dashboard.serverlocalhost:8090 -D…...

大佬,简单解释下“嵌入式软件开发”和“嵌入式硬件开发”的区别
在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!首先,嵌入式硬…...

04 奇偶分家
题目: 代码: #include<iostream> using namespace std; #include<stdlib.h> #include<stdio.h>int main() {int N;cin>>N;int jicount0,oucount0;for(int i0;i<N;i){int temp;cin>>temp;if(temp%20){oucount;}else if…...

普通人秒变AI专家:李沐创业同款RAG微调实战,打造专属外卖评论大模型
8月14日晚上,李沐发布了一篇关于他创业一年的复盘文章《创业一年,人间三年》,引起了广泛关注。这篇文章中,李沐分享了从创业初期到现在的心路历程,许多读者读后都倍感激动。 创业之初,李沐的团队原本打算利用大语言模型(LLM)开发生产力工具。然而,在张一鸣的建议下,…...

微模块冷通道动环监控:智能化数据中心管理利器@卓振思众
在现代数据中心和机房管理中,微模块冷通道动环监控系统的引入,标志着对冷却和环境管理的新纪元。这一系统不仅提升了数据中心的运维效率,还对设备的安全性和稳定性提供了强有力的保障。本文将详细探讨微模块冷通道动环监控的功能和其在数据中…...

【Linux】进程调度与切换
【Linux】进程调度与切换 1. 基本概念2. 进程切换3. 进程调度3.1运行队列实现优先级设计3.2 处理效率问题3.3 活动队列与过期队列3.4 如何解决饥饿问题3.5 active指针和expired指针 1. 基本概念 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个&am…...
SAM 2:分割图像和视频中的任何内容
文章目录 摘要1 引言2 相关工作3 任务:可提示视觉分割4 模型5 数据5.1 数据引擎5.2 SA-V数据集6 零样本实验6.1 视频任务6.1.1 提示视频分割6.1.2 半监督视频对象分割6.1.3 公平性评估6.2 图像任务7 与半监督VOS的最新技术的比较8 数据和模型消融8.1 数据消融8.2 模型架构消融…...

【免越狱】iOS任意版本号APP下载
下载地址 https://pan.quark.cn/s/570e928ee2c4 软件介绍 下载iOS旧版应用,简化繁琐的抓包流程。一键生成去更新IPA(手机安装后,去除App Store的更新检测)。 软件界面 使用方法 一、直接搜索方式 搜索APP,双击选…...

告别植物神经紊乱,这5种运动让你身心平衡,活力满满!♀️✨
Hey小伙伴们~👋 最近是不是感觉压力山大,晚上辗转反侧,白天又无精打采?😴😔 这可能是植物神经紊乱在悄悄作祟哦!别怕,今天就来给大家种草几个超有效的运动方式,帮你找回那…...

又一个iPhone时代开始
今年的苹果秋季发布会在昨晚召开了,今天早上我们也看到了很多相关的新闻。我猜你看完后的感觉可能是,这不过又是一次普普通通的参数升级。又是提升了百分之多少,又是增加了多少倍——非常简单的一些更新。比如说芯片升级了、相机的摄像头一会…...
在 CentOS 中永久关闭防火墙的步骤
在 CentOS 中永久关闭防火墙的步骤 在 CentOS 系统中,防火墙通常由 firewalld 服务管理。如果你希望在系统中永久关闭防火墙,可以按照以下步骤操作: 1. 停止防火墙服务 首先,你需要停止当前正在运行的防火墙服务。可以使用以下…...

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

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...

边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...