109. UE5 GAS RPG 实现检查点的存档功能
在这一篇文章里,我们接着实现存档的功能,保存当前玩家的生成位置,游戏里有很多中方式去实现玩家的位置存储,这里我们采用检查点的方式,当玩家接触到当前检查点后,我们可以通过检查点进行保存玩家的状态,后续也能够实现检查点移动玩家等等功能。
实现定义角色生成位置
存档加载关卡后,需要一个出生位置,如果场景里有多个PlayerStart,我们如何确定让角色在哪个PlayerStart生成呢?
答案是,我们可以为每个PlayerStart设置标签,然后覆写GameMode的选择初始点的函数来实现。
首先,我们实现对数据的全局存储,这里需要使用到GameInstance,我们将其作为父类,实现一个派生类,来实现自定义的需求。
设置自定义命名
在类里,我们存储几个值,一个是切换关卡时需要获取的PlayerStart的标签命名,另外就是如果需要保存,所需的存档名称和索引。
UCLASS()
class RPG_API URPGGameInstance : public UGameInstance
{GENERATED_BODY()public://角色进入关卡后默认生成的PlayerStart的TagUPROPERTY()FName PlayerStartTag = FName();//当前使用的或后续保存内容到的存档名称UPROPERTY()FString LoadSlotName = FString();//当前使用活后续保存的存档索引UPROPERTY()int32 LoadSlotIndex = 0;
};
然后在我们自定义的GameMode里增加一个参数用于设置玩家生成的PlayerStart的标签
//角色切换关卡后默认生成位置的PlayerStart的标签UPROPERTY(EditDefaultsOnly)FName DefaultPlayerStartTag;//覆写父类的选择PlayerStart函数,修改为可以通过Tag获取生成位置virtual AActor* ChoosePlayerStart_Implementation(AController* Player) override;
函数实现这里,我们会获取到关卡里的所有的PlayerStart,然后从GameInstance获取需要生成的标签,遍历获取到对应的PlayerStart生成,所以,只需要在进入关卡前,将GameInstance的标签修改了然后进入场景时,就可以自动寻找对应的PlayerStart去生成。
AActor* ARPGGameMode::ChoosePlayerStart_Implementation(AController* Player)
{const URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(GetGameInstance());//获取关卡里的所有PlayerStart实例TArray<AActor*> Actors;UGameplayStatics::GetAllActorsOfClass(GetWorld(), APlayerStart::StaticClass(), Actors);if(Actors.Num() > 0){//获取到第一个实例对象AActor* SelectedActor = Actors[0];for(AActor* Actor : Actors){if(APlayerStart* PlayerStart = Cast<APlayerStart>(Actor)){//判断PlayerStart的Tag设置是否为指定的Tagif(PlayerStart->PlayerStartTag == RPGGameInstance->PlayerStartTag){SelectedActor = PlayerStart;break;}}}return SelectedActor;}return nullptr;
}
添加PlayerStart标签配置
我们需要在存档里实现对关卡里的开始标签的存储,在读取存档进入关卡时,可以明确知道角色需要在哪里生成。
所以,我们需要在LoadScreenSaveMode(存档类)和存档ViewModel视图模型里增加PlayerStart标签配置属性。
//存储玩家关卡出生位置的标签UPROPERTY()FName PlayerStartTag;
在创建新存档时,使用GameMode设置的默认PlayerStart标签
接着在GameMode存储存档时,将存档的视图模型的中的PlayerStart标签存储到存档
存储没问题了,就是读取存档时,将存档里存储的PlayerStart标签设置给存档的视图模型
最后,在我们在加载界面视图模型进入游戏的函数里,在调用加载关卡之前,将PlayerStart标签存储到GameInstance里,进入关卡后,然后再通过我们覆写的函数获取对应标签的PlayerStart
void UMVVM_LoadScreen::EnterGameButtonPressed(const int32 Slot)
{ARPGGameMode* RPGGameMode = Cast<ARPGGameMode>(UGameplayStatics::GetGameMode(this));//设置全局数据,方便后续使用URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(RPGGameMode->GetGameInstance());RPGGameInstance->LoadSlotName = LoadSlots[Slot]->GetSlotName();RPGGameInstance->LoadSlotIndex = LoadSlots[Slot]->SlotIndex;RPGGameInstance->PlayerStartTag = LoadSlots[Slot]->PlayerStartTag;//进入场景RPGGameMode->TravelToMap(LoadSlots[Slot]);
}
创建蓝图
接下来,我们编译打开UE,在BP_GameMode里设置默认选择的PlayerStart的标签
接着,我们基于GameInstance类创建一个蓝图
设置命名
在项目设置里,将默认的GameInstance修改为我们所需的GameInstance
最后,我们在场景里设置PlayerStart的标签,注意,如果多个PlayerStart设置了相同的对应的标签,角色将在第一个获取的PlayerStart的位置生成。
创建检查点
在正常游戏流程里,为了保存游戏进度,开发者会使用某种方式让进度保存下来,比如到达某个进度后自动保存,又或者像生化危机里的打字机。
这里,我们将实现一种检查点的类,在角色接触后,自动保存当前进度。
命名为检查点类,我们将在里面增加一些额外的内容。
在类里,我们将增加两个属性,用于显示检查点的模型和触发保存游戏的碰撞盒子
private://检查点显示的模型UPROPERTY(VisibleAnywhere)TObjectPtr<UStaticMeshComponent> CheckpointMesh;//检查点模型使用的碰撞体UPROPERTY(VisibleAnywhere)TObjectPtr<USphereComponent> Sphere;
然后增加一个函数,用于玩家角色和碰撞球碰撞后的逻辑处理
/*** 球碰撞体和物体发生碰撞后的回调* @param OverlappedComponent 发生重叠事件的自身的碰撞体对象* @param OtherActor 目标的actor对象* @param OtherComp 目标的碰撞体组件* @param OtherBodyIndex 目标身体的索引* @param bFromSweep 是否为瞬移检测到的碰撞* @param SweepResult 如果位置发生过瞬移(直接设置到某处),两个位置中间的内容会记录到此对象内*/UFUNCTION()virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
接着增加一个函数,玩家角色碰撞后的函数处理,主要里面是创建了一个新的材质实例,修改自发光,表示检查点已经激活。
//当玩家角色和检测点产生碰撞后,检查点被激活触发此函数void HandleGlowEffects();
由于自发光亮起需要时间轴,这个比较方便在蓝图里实现,我们再增加一个需蓝图实现的函数。
/*** 检查点激活后的处理,需要在蓝图中对其实现* @param DynamicMaterialInstance 传入检查点模型的材质实例*/UFUNCTION(BlueprintImplementableEvent)void CheckpointReached(UMaterialInstanceDynamic* DynamicMaterialInstance);
以下是整个.h文件
// 版权归暮志未晚所有。#pragma once#include "CoreMinimal.h"
#include "GameFramework/PlayerStart.h"
#include "CheckPoint.generated.h"class USphereComponent;
/*** */
UCLASS()
class RPG_API ACheckPoint : public APlayerStart
{GENERATED_BODY()public://构造函数ACheckPoint(const FObjectInitializer& ObjectInitializer);protected:virtual void BeginPlay() override;/*** 球碰撞体和物体发生碰撞后的回调* @param OverlappedComponent 发生重叠事件的自身的碰撞体对象* @param OtherActor 目标的actor对象* @param OtherComp 目标的碰撞体组件* @param OtherBodyIndex 目标身体的索引* @param bFromSweep 是否为瞬移检测到的碰撞* @param SweepResult 如果位置发生过瞬移(直接设置到某处),两个位置中间的内容会记录到此对象内*/UFUNCTION()virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);/*** 检查点激活后的处理,需要在蓝图中对其实现* @param DynamicMaterialInstance 传入检查点模型的材质实例*/UFUNCTION(BlueprintImplementableEvent)void CheckpointReached(UMaterialInstanceDynamic* DynamicMaterialInstance);//当玩家角色和检测点产生碰撞后,检查点被激活触发此函数void HandleGlowEffects();
private://检查点显示的模型UPROPERTY(VisibleAnywhere)TObjectPtr<UStaticMeshComponent> CheckpointMesh;//检查点模型使用的碰撞体UPROPERTY(VisibleAnywhere)TObjectPtr<USphereComponent> Sphere;
};
在cpp里,我们对函数进行实现,首先在构造函数里,我们实例化模型和碰撞体。
ACheckPoint::ACheckPoint(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
{//关闭帧更新PrimaryActorTick.bCanEverTick = false;//创建检测点显示模型CheckpointMesh = CreateDefaultSubobject<UStaticMeshComponent>("CheckpointMesh");CheckpointMesh->SetupAttachment(GetRootComponent());CheckpointMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); //设置查询并产生物理CheckpointMesh->SetCollisionResponseToChannels(ECR_Block); //设置阻挡所有物体与其重叠//设置球碰撞体Sphere = CreateDefaultSubobject<USphereComponent>("Sphere");Sphere->SetupAttachment(CheckpointMesh);Sphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly); //设置其只用作查询使用Sphere->SetCollisionResponseToChannels(ECR_Ignore); //设置其忽略所有碰撞检测Sphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); //设置其与Pawn类型物体产生重叠事件
}
在游戏开始时,绑定球碰撞体的重叠函数
void ACheckPoint::BeginPlay()
{Super::BeginPlay();//绑定重叠事件Sphere->OnComponentBeginOverlap.AddDynamic(this, &ACheckPoint::OnSphereOverlap);
}
接着实现重叠函数,在触发重叠时,我们需要实现保存当前的检查点标签,然后在调用碰撞后处理函数
void ACheckPoint::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{//if(OtherActor->ActorHasTag("Player")) //如果只需要判断是不是玩家角色通过标签判断即可if(OtherActor->Implements<UPlayerInterface>()){//修改存档当的检测点IPlayerInterface::Execute_SaveProgress(OtherActor, PlayerStartTag);//如果与碰撞体重叠的是HandleGlowEffects();}
}
然后我们取消碰撞检测,提升性能,并创建一个新的材质实例,调用蓝图函数实现渐变发光效果。
void ACheckPoint::HandleGlowEffects()
{//取消碰撞检查Sphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);//创建一个新材质实例,修改效果UMaterialInstanceDynamic* DynamicMaterialInstance = UMaterialInstanceDynamic::Create(CheckpointMesh->GetMaterial(0), this);CheckpointMesh->SetMaterial(0, DynamicMaterialInstance);CheckpointReached(DynamicMaterialInstance); //触发检查点修改材质后的回调
}
编译代码,打开UE,创建一个基于类的蓝图
在检测点里,我们需要修改碰撞体大小和检查点的模型
大致效果如下,可以按需设置
在平视角,我们需要将PlayerStart和模型水平,这样保证放置的时候,防止PlayerStart的位置靠下,生成角色生成到地面以下。
拖入场景中,点击End建,检测点将会自动附着到地面,青蓝色箭头是玩家在检查点生成位置和朝向,黄色碰撞球是激活检测点范围。
接着,我们修改材质,增加自发光相关节点,设置GlowEnd最大亮度,以及GlowControl来控制进度,GlowControl值为1时,将达到亮度的最大值。
接着,我们创建一个实例,去调节对应的参数。
接着,在蓝图里,实现碰撞函数回调,使用时间轴修改GlowControl
在时间轴里去修改更新的值
我们将放置到场景里的检查点的设置其标签,可以用来实现保存通过标签去寻找位置。
实现PlayerStart标签的保存
我们要实现玩家角色在场景中接触到检查点后,更新存档,将当前的检查点的值保存到存档里。
首先在GameMode类里增加两个函数,一个用于获取当前使用的存档,另一个是将修改后的存档保存下来。
//获取到当前游戏进行中所使用的存档数据ULoadScreenSaveGame* RetrieveInGameSaveData() const;/*** 保存游戏中的进度* @param SaveObject 需要保存的数据*/void SaveInGameProgressData(ULoadScreenSaveGame* SaveObject) const;
实现这里,我们可以在GameInstance身上获取到存档使用的Name和Index,通过这两项获取到存档数据。
保存函数这里,我们还需要使用存档的标签去修改GameInstance身上的PlayerStart的标签。然后保存。
ULoadScreenSaveGame* ARPGGameMode::RetrieveInGameSaveData() const
{const URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(GetGameInstance());//从游戏实例获取到存档名称和索引const FString InGameLoadSlotName = RPGGameInstance->LoadSlotName;const int32 InGameLoadSlotIndex = RPGGameInstance->LoadSlotIndex;//获取已保存的存档数据return GetSaveSlotData(InGameLoadSlotName, InGameLoadSlotIndex);
}void ARPGGameMode::SaveInGameProgressData(ULoadScreenSaveGame* SaveObject) const
{URPGGameInstance* RPGGameInstance = Cast<URPGGameInstance>(GetGameInstance());//修改下一次复活的检测点RPGGameInstance->PlayerStartTag = SaveObject->PlayerStartTag;//从游戏实例获取到存档名称和索引const FString InGameLoadSlotName = RPGGameInstance->LoadSlotName;const int32 InGameLoadSlotIndex = RPGGameInstance->LoadSlotIndex;//保存存档UGameplayStatics::SaveGameToSlot(SaveObject, InGameLoadSlotName, InGameLoadSlotIndex);
}
接着在玩家角色接口这里增加一个函数,用于碰撞触发后保存存档使用
//保存游戏进度UFUNCTION(BlueprintNativeEvent, BlueprintCallable)void SaveProgress(const FName& CheckpointTag);
在玩家基类里覆写
virtual void SaveProgress_Implementation(const FName& CheckpointTag) override;
实现这里,我们获取到GameMode,然后获取存档,修改存档数据,并保存回去。
void ARPGHero::SaveProgress_Implementation(const FName& CheckpointTag)
{if(const ARPGGameMode* GameMode = Cast<ARPGGameMode>(UGameplayStatics::GetGameMode(this))){//获取存档ULoadScreenSaveGame* SaveGameData = GameMode->RetrieveInGameSaveData();if(SaveGameData == nullptr) return;//修改存档数据SaveGameData->PlayerStartTag = CheckpointTag;//保存存档GameMode->SaveInGameProgressData(SaveGameData);}
}
我们在与检查点碰撞时,已经调用此函数,实现了存档的修改保存。
最后,我们在场景里多加几个检查点,来测试效果。创建文档,角色会生成在一个检查点上,然后我们走到另一个检查点上,重新进入游戏,查看角色下一次会不会生成在最后退出的检查点旁边,如果能够证明代码无误。
实现角色已经激活的检测点一直高亮
我们现在制作的当前检查点效果,还没有实现的一项是,让玩家已经激活的检查点一直保持高亮状态,这样,如果玩家迷路了,可以清除的得知这一段路之前探索过。
为了实现这个效果,我们需要将之前已经探索到的检查点都记录下来,然后在进入场景后,每次激活,将信息记录到存档里。在进入一个新关卡时,在GameMode的BeginPlayer会触发,我们会在此函数里处理检查点是否需要高亮。
首先,我们在SaveGame类增加一个参数,用于存储检查点数组,用于存储角色已经激活的检查点
//当前已经激活的检测点UPROPERTY()TArray<FName> ActivatedPlayerStatTags = TArray<FName>();
然后将检查点类的激活函数修改为public,这样,可以在类以外调用
接着,我们增加一个私有函数用于高亮已经激活的检查点
private://高亮已经激活的检查点void HighlightEnabledCheckpoints(TArray<AActor*> CheckPoints) const;
函数实现,我们将获取存档,并遍历所有的检查点,如果检查点的Tag存在于已激活的数组内,我们将检查点进行高亮显示。
void ARPGGameMode::HighlightEnabledCheckpoints(TArray<AActor*> CheckPoints) const
{//获取存档ULoadScreenSaveGame* SaveGameData = RetrieveInGameSaveData();if(SaveGameData == nullptr) return;//遍历关卡内的所有的检查点,如果数组里存在,将高亮显示for(AActor* Actor : CheckPoints){if(ACheckPoint* CheckPoint = Cast<ACheckPoint>(Actor)){if(SaveGameData->ActivatedPlayerStatTags.Contains(CheckPoint->PlayerStartTag)){CheckPoint->HandleGlowEffects();}}}
}
在关卡打开后,生成角色时,我们调用此函数,进行场景关卡的检查点进行初始化高亮
最后,还有保存已经激活的检查点,我们可以选择在保存角色的存档时候,将当前检查点的标签保存进去。
重点,你每个添加到关卡的检查点,要做到全局不同,也就是每个关卡的检查点都不要重名,我们可以考虑关卡+检查点的索引方式去设置检查点的tag。
相关文章:

109. UE5 GAS RPG 实现检查点的存档功能
在这一篇文章里,我们接着实现存档的功能,保存当前玩家的生成位置,游戏里有很多中方式去实现玩家的位置存储,这里我们采用检查点的方式,当玩家接触到当前检查点后,我们可以通过检查点进行保存玩家的状态&…...

springboot005基于springboot学生心理咨询评估系统得设计与实现。
项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…...

ESC算法/逃生:一种基于人群疏散行为的优化方法
文章介绍了一种有用的算法,称为逃生或逃生算法(ESC),受人群疏散行为的启发,用于解决现实世界的案例和基准问题。ESC算法模拟了疏散过程中人群的行为,其中人群在探索阶段被分为平静、羊群和恐慌组࿰…...

构建安全的数据库环境:群晖NAS安装MySQL和phpMyAdmin详细步骤
文章目录 前言1. 安装MySQL2. 安装phpMyAdmin3. 修改User表4. 本地测试连接MySQL5. 安装cpolar内网穿透6. 配置MySQL公网访问地址7. 配置MySQL固定公网地址8. 配置phpMyAdmin公网地址9. 配置phpmyadmin固定公网地址 前言 本文将详细讲解如何在群晖NAS上安装MySQL及其数据库管理…...
【人工智能】深入理解图神经网络(GNN):用Python实现社交网络节点分类与分子结构分析
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 图神经网络(Graph Neural Network, GNN)是近年来在深度学习领域迅速发展的新兴方向,主要用于处理图结构数据。GNN在社交网络分析、化学分…...
Qt 日志文件的滚动写入
Qt 日志文件的滚动写入 flyfish 日志文件的滚动写入功能。在日志文件达到10MB时创建新的日志文件,并且在总日志文件大小达到10GB时开始覆盖最早的日志文件 以监控一个文件夹的写日志为例 日志文件创建与管理 初始化日志文件:在FileMonitor类的构造函…...
【c语言】数据包捕获和分析工具
请解释一下数据包捕获和分析工具(如Wireshark)的工作原理和用途。 数据包捕获和分析工具,如Wireshark(前身为Ethereal),是一种网络协议分析软件,它允许用户实时监控、抓取并分析计算机网络中的网…...

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——14.哈希(2)(模拟实现)
1.概念介绍 1.1开散列 开散列(Open Hashing),也叫链地址法,是一种解决哈希冲突的方法。每个哈希表槽位保存一个链表,所有散列到同一位置的元素都存储在该链表中。当插入元素发生冲突时,将新元素添加到相应…...
请描述一下JVM(Java虚拟机)的生命周期及其对应用程序性能的影响
1、请描述一下JVM(Java虚拟机)的生命周期及其对应用程序性能的影响。 JVM(Java虚拟机)的生命周期主要涉及以下几个阶段:加载、验证、准备、解析、执行、卸载。每个阶段都有其特定的作用和影响。 加载:JVM…...

展会邀约|加速科技与您相约IC China 2024!
第二十一届中国国际半导体博览会( IC China 2024)将于 2024 年11月18日—11月20日在北京国家会议中心举行。加速科技将携高性能测试机ST2500EX、ST2500E、eATE及全系测试解决方案亮相E2馆B150展位。博览会期间,将同期举办"半导体产业前沿…...

鸿蒙中服务卡片数据的获取和渲染
1. 2.在卡片中使用LocalStorageProp接受传递的数据 LocalStorageProp("configNewsHead") configNewsHeadLocal: ConfigNewsHeadInfoItem[] [] 注意:LocalStorageProp括号中的为第一步图片2中的键 3.第一次在服务卡片的第一个卡片中可能会获取不到数据…...
运维篇-修复centos7无法下载docker问题
修复centos7无法下载docker问题 1、安装docker时报错2、docker无法下载镜像 1、安装docker时报错 linux的centos系统,安装docker时会报错 –> Finished Dependency Resolution Error: Package: glibc-2.17-307.el7.1.i686 (base) Requires: glibc-common 2.17…...

【论文阅读】WaDec: Decompiling WebAssembly Using Large Language Model
论文阅读笔记:WaDec: Decompiling WebAssembly Using Large Language Model 1. 来源出处 论文标题: WaDec: Decompiling WebAssembly Using Large Language Model作者: Xinyu She, Yanjie Zhao, Haoyu Wang会议: 39th IEEE/ACM International Conference on Automated Softwar…...

redis类型介绍
1. 字符串(String): • 简介:最基础的数据类型,可以存储任何形式的字符串,包括文本数据和数字数据。 • 常用操作:SET、GET、INCR、DECR等。 2. 列表(List): …...
kubernetes如何配置默认存储
如果不想每次都创建PV,希望k8s集群中能够配置号默认存储,然后根据你的PVC自动创建PV,就需要安装一个默认存储,也就是storageclass 什么是storageclass Kubernetes提供了一套可以自动创建PV的机制,即:Dyna…...
【微服务】Spring AI 使用详解
目录 一、前言 二、Spring AI 概述 2.1 什么是Spring AI 2.2 Spring AI 特点 2.3 Spring AI 带来的便利 2.4 Spring AI 应用领域 2.4.1 聊天模型 2.4.2 文本到图像模型 2.4.3 音频转文本 2.4.4 嵌入大模型使用 2.4.5 矢量数据库支持 2.4.6 数据工程ETL框架 三、Sp…...

DataGrip 连接 dm
参考链接 使用DataGrip链接达梦数据库_datagrip连接达梦数据库-CSDN博客 下载 jdbc 驱动包 第一种 通过链接下载:下载 第二种【特指 window 安装包】 在达梦安装包 iso 文件里面 source/drivers/jdbc 将驱动添加进 DataGrip 选中 jdbc 驱动包,然后选…...

数据库监控工具DBdoctor v3.2.4.3版本发布,新增对openGauss、Vastbase G100的支持!
新引擎扩展 新增对openGauss数据库的支持:支持对openGauss数据库的SQL审核、实例巡检、性能洞察、锁透视、根因诊断、基础监控、索引推荐、存储分析; 新增对Vastbase G100数据库的支持:支持对Vastbase G100数据库的SQL审核、实例巡检、性能洞…...
Git 常用命令大全与详解
Git 是一种广泛使用的分布式版本控制系统。无论是管理个人项目还是进行团队协作,掌握 Git 的常用命令都是开发者必备的技能之一。本文将介绍一些常用的 Git 命令,并对其进行详细说明。 1. 基础命令 初始化仓库 git init:在当前目录下初始化…...

执行flink sql连接clickhouse库
手把手教学,flink connector打通clickhouse大数据库,通过下发flink sql,来使用ck。 组件版本jdk1.8flink1.17.2clickhouse23.12.2.59 1.背景 flink官方不支持clickhouse连接器,工作中难免会用到。 2.方案 利用GitHub大佬提供…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...
Java并发编程实战 Day 11:并发设计模式
【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能…...