13.4 GAS与攻击

news2025/3/1 16:59:37

目录

      • 1. 由GA砍出的第一刀
      • 2. 挥剑时的命中检测
      • 3. 完善:UI显示当前血量
      • 参考:

1. 由GA砍出的第一刀

有了前面章节的经验,我们可以很容易创建一个专用于攻击的GA:

在这里插入图片描述

其中PlayMontageAndWait任务节点负责攻击动画及相应回调的绑定。

在这里插入图片描述
但是仅仅这样并不足以支撑整个技能,因为缺少伤害的触发和判定。比如说技能触发,砍中一的一刻,应该要有伤害GE的触发,可以使用射线检测进行砍中事件的检测,然后发送相应事件。所以最优先的,需要扩展技能任务PlayMontageAndWait的功能,使其支持更多类型的回调(扩展为PlayMontageAndWaitForEvent,使其具备监听特定事件的特性)。

参照GASDocumentation的PlayMontageAndWaitForEvent的写法:

#pragma once

#include "CoreMinimal.h"
#include "Abilities/Tasks/AbilityTask.h"
#include "AT_PlayMontageAndWaitForEvent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FPlayMontageAndWaitForEventDelegate, FGameplayTag, EventTag, FGameplayEventData, EventData);

/**
 * 
 */
UCLASS()
class INSIDEGAS_API UAT_PlayMontageAndWaitForEvent : public UAbilityTask
{
	GENERATED_BODY()

	public:
	UAT_PlayMontageAndWaitForEvent(const FObjectInitializer& ObjectInitializer);
	
	virtual void Activate() override;
	virtual void ExternalCancel() override;
	virtual FString GetDebugString() const override;
	virtual void OnDestroy(bool AbilityEnded) override;
	
	UPROPERTY(BlueprintAssignable)
	FPlayMontageAndWaitForEventDelegate OnCompleted;
	
	UPROPERTY(BlueprintAssignable)
	FPlayMontageAndWaitForEventDelegate OnBlendOut;
	
	UPROPERTY(BlueprintAssignable)
	FPlayMontageAndWaitForEventDelegate OnInterrupted;
	
	UPROPERTY(BlueprintAssignable)
	FPlayMontageAndWaitForEventDelegate OnCancelled;
	
	UPROPERTY(BlueprintAssignable)
	FPlayMontageAndWaitForEventDelegate EventReceived;
	
	UFUNCTION(BlueprintCallable, Category = "Ability|Tasks", meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE"))
	static UAT_PlayMontageAndWaitForEvent* PlayMontageAndWaitForEvent(
			UGameplayAbility* OwningAbility,
			FName TaskInstanceName,
			UAnimMontage* MontageToPlay,
			FGameplayTagContainer EventTags,
			float Rate = 1.f,
			FName StartSection = NAME_None,
			bool bStopWhenAbilityEnds = true,
			float AnimRootMotionTranslationScale = 1.f);

private:
	UPROPERTY()
	UAnimMontage* MontageToPlay;
	
	UPROPERTY()
	FGameplayTagContainer EventTags;
	
	UPROPERTY()
	float Rate;
	
	UPROPERTY()
	FName StartSection;
	
	UPROPERTY()
	float AnimRootMotionTranslationScale;
	
	UPROPERTY()
	bool bStopWhenAbilityEnds;
	
	bool StopPlayingMontage();
	
	UAbilitySystemComponent* GetTargetASC();

	void OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted);
	void OnAbilityCancelled();
	void OnMontageEnded(UAnimMontage* Montage, bool bInterrupted);
	void OnGameplayEvent(FGameplayTag EventTag, const FGameplayEventData* Payload);

	FOnMontageBlendingOutStarted BlendingOutDelegate;
	FOnMontageEnded MontageEndedDelegate;
	FDelegateHandle CancelledHandle;
	FDelegateHandle EventHandle;
};

相应的cpp文件:

#include "AT_PlayMontageAndWaitForEvent.h"

#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "GameFramework/Character.h"


UAT_PlayMontageAndWaitForEvent::UAT_PlayMontageAndWaitForEvent(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	Rate = 1.f;
	bStopWhenAbilityEnds = true;
}

UAbilitySystemComponent* UAT_PlayMontageAndWaitForEvent::GetTargetASC()
{
	return Cast<UAbilitySystemComponent>(AbilitySystemComponent);
}

void UAT_PlayMontageAndWaitForEvent::OnMontageBlendingOut(UAnimMontage* Montage, bool bInterrupted)
{
	if (Ability && Ability->GetCurrentMontage() == MontageToPlay)
	{
		if (Montage == MontageToPlay)
		{
			AbilitySystemComponent->ClearAnimatingAbility(Ability);

			// Reset AnimRootMotionTranslationScale
			ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
			if (Character && (Character->GetLocalRole() == ROLE_Authority ||
				(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
			{
				Character->SetAnimRootMotionTranslationScale(1.f);
			}

		}
	}

	if (bInterrupted)
	{
		if (ShouldBroadcastAbilityTaskDelegates())
		{
			OnInterrupted.Broadcast(FGameplayTag(), FGameplayEventData());
		}
	}
	else
	{
		if (ShouldBroadcastAbilityTaskDelegates())
		{
			OnBlendOut.Broadcast(FGameplayTag(), FGameplayEventData());
		}
	}
}

void UAT_PlayMontageAndWaitForEvent::OnAbilityCancelled()
{

	if (StopPlayingMontage())
	{
		// Let the BP handle the interrupt as well
		if (ShouldBroadcastAbilityTaskDelegates())
		{
			OnCancelled.Broadcast(FGameplayTag(), FGameplayEventData());
		}
	}
}

void UAT_PlayMontageAndWaitForEvent::OnMontageEnded(UAnimMontage* Montage, bool bInterrupted)
{
	if (!bInterrupted)
	{
		if (ShouldBroadcastAbilityTaskDelegates())
		{
			OnCompleted.Broadcast(FGameplayTag(), FGameplayEventData());
		}
	}

	EndTask();
}

void UAT_PlayMontageAndWaitForEvent::OnGameplayEvent(FGameplayTag EventTag, const FGameplayEventData* Payload)
{
	if (ShouldBroadcastAbilityTaskDelegates())
	{
		FGameplayEventData TempData = *Payload;
		TempData.EventTag = EventTag;

		EventReceived.Broadcast(EventTag, TempData);
	}
}

UAT_PlayMontageAndWaitForEvent* UAT_PlayMontageAndWaitForEvent::PlayMontageAndWaitForEvent(UGameplayAbility* OwningAbility,
	FName TaskInstanceName, UAnimMontage* MontageToPlay, FGameplayTagContainer EventTags, float Rate, FName StartSection, bool bStopWhenAbilityEnds, float AnimRootMotionTranslationScale)
{
	UAbilitySystemGlobals::NonShipping_ApplyGlobalAbilityScaler_Rate(Rate);

	UAT_PlayMontageAndWaitForEvent* MyObj = NewAbilityTask<UAT_PlayMontageAndWaitForEvent>(OwningAbility, TaskInstanceName);
	MyObj->MontageToPlay = MontageToPlay;
	MyObj->EventTags = EventTags;
	MyObj->Rate = Rate;
	MyObj->StartSection = StartSection;
	MyObj->AnimRootMotionTranslationScale = AnimRootMotionTranslationScale;
	MyObj->bStopWhenAbilityEnds = bStopWhenAbilityEnds;

	return MyObj;
}

void UAT_PlayMontageAndWaitForEvent::Activate()
{
	if (Ability == nullptr)
	{
		return;
	}

	bool bPlayedMontage = false;
	UAbilitySystemComponent* GDAbilitySystemComponent = GetTargetASC();

	if (GDAbilitySystemComponent)
	{
		const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
		UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();
		if (AnimInstance != nullptr)
		{
			// Bind to event callback
			EventHandle = GDAbilitySystemComponent->AddGameplayEventTagContainerDelegate(EventTags, FGameplayEventTagMulticastDelegate::FDelegate::CreateUObject(this, &UAT_PlayMontageAndWaitForEvent::OnGameplayEvent));

			if (GDAbilitySystemComponent->PlayMontage(Ability, Ability->GetCurrentActivationInfo(), MontageToPlay, Rate, StartSection) > 0.f)
			{
				// Playing a montage could potentially fire off a callback into game code which could kill this ability! Early out if we are  pending kill.
				if (ShouldBroadcastAbilityTaskDelegates() == false)
				{
					return;
				}

				CancelledHandle = Ability->OnGameplayAbilityCancelled.AddUObject(this, &UAT_PlayMontageAndWaitForEvent::OnAbilityCancelled);

				BlendingOutDelegate.BindUObject(this, &UAT_PlayMontageAndWaitForEvent::OnMontageBlendingOut);
				AnimInstance->Montage_SetBlendingOutDelegate(BlendingOutDelegate, MontageToPlay);

				MontageEndedDelegate.BindUObject(this, &UAT_PlayMontageAndWaitForEvent::OnMontageEnded);
				AnimInstance->Montage_SetEndDelegate(MontageEndedDelegate, MontageToPlay);

				ACharacter* Character = Cast<ACharacter>(GetAvatarActor());
				if (Character && (Character->GetLocalRole() == ROLE_Authority ||
					(Character->GetLocalRole() == ROLE_AutonomousProxy && Ability->GetNetExecutionPolicy() == EGameplayAbilityNetExecutionPolicy::LocalPredicted)))
				{
					Character->SetAnimRootMotionTranslationScale(AnimRootMotionTranslationScale);
				}

				bPlayedMontage = true;
			}
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("UGDAbilityTask_PlayMontageAndWaitForEvent call to PlayMontage failed!"));
		}
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("UGDAbilityTask_PlayMontageAndWaitForEvent called on invalid AbilitySystemComponent"));
	}

	if (!bPlayedMontage)
	{
		UE_LOG(LogTemp, Warning, TEXT("UGDAbilityTask_PlayMontageAndWaitForEvent called in Ability %s failed to play montage %s; Task Instance Name %s."), *Ability->GetName(), *GetNameSafe(MontageToPlay), *InstanceName.ToString());
		if (ShouldBroadcastAbilityTaskDelegates())
		{
			//ABILITY_LOG(Display, TEXT("%s: OnCancelled"), *GetName());
			OnCancelled.Broadcast(FGameplayTag(), FGameplayEventData());
		}
	}

	SetWaitingOnAvatar();
}

void UAT_PlayMontageAndWaitForEvent::ExternalCancel()
{
	check(AbilitySystemComponent);

	OnAbilityCancelled();

	Super::ExternalCancel();
}

void UAT_PlayMontageAndWaitForEvent::OnDestroy(bool AbilityEnded)
{
	// Note: Clearing montage end delegate isn't necessary since its not a multicast and will be cleared when the next montage plays.
	// (If we are destroyed, it will detect this and not do anything)

	// This delegate, however, should be cleared as it is a multicast
	if (Ability)
	{
		Ability->OnGameplayAbilityCancelled.Remove(CancelledHandle);
		if (AbilityEnded && bStopWhenAbilityEnds)
		{
			StopPlayingMontage();
		}
	}

	UAbilitySystemComponent* GDAbilitySystemComponent = GetTargetASC();
	if (GDAbilitySystemComponent)
	{
		GDAbilitySystemComponent->RemoveGameplayEventTagContainerDelegate(EventTags, EventHandle);
	}

	Super::OnDestroy(AbilityEnded);

}

bool UAT_PlayMontageAndWaitForEvent::StopPlayingMontage()
{
	const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
	if (!ActorInfo)
	{
		return false;
	}

	UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();
	if (AnimInstance == nullptr)
	{
		return false;
	}

	// Check if the montage is still playing
	// The ability would have been interrupted, in which case we should automatically stop the montage
	if (AbilitySystemComponent && Ability)
	{
		if (AbilitySystemComponent->GetAnimatingAbility() == Ability
			&& AbilitySystemComponent->GetCurrentMontage() == MontageToPlay)
		{
			// Unbind delegates so they don't get called as well
			FAnimMontageInstance* MontageInstance = AnimInstance->GetActiveInstanceForMontage(MontageToPlay);
			if (MontageInstance)
			{
				MontageInstance->OnMontageBlendingOutStarted.Unbind();
				MontageInstance->OnMontageEnded.Unbind();
			}

			AbilitySystemComponent->CurrentMontageStop();
			return true;
		}
	}

	return false;
}

FString UAT_PlayMontageAndWaitForEvent::GetDebugString() const
{
	UAnimMontage* PlayingMontage = nullptr;
	if (Ability)
	{
		const FGameplayAbilityActorInfo* ActorInfo = Ability->GetCurrentActorInfo();
		UAnimInstance* AnimInstance = ActorInfo->GetAnimInstance();

		if (AnimInstance != nullptr)
		{
			PlayingMontage = AnimInstance->Montage_IsActive(MontageToPlay) ? MontageToPlay : AnimInstance->GetCurrentActiveMontage();
		}
	}

	return FString::Printf(TEXT("PlayMontageAndWaitForEvent. MontageToPlay: %s  (Currently Playing): %s"), *GetNameSafe(MontageToPlay), *GetNameSafe(PlayingMontage));
}

这样就得到一个全新的节点(相比于原生的PlayMontageAndWait,多了待接收事件的Tag的过滤器,以及相应的EventReceived回调):

在这里插入图片描述
如此,我们对劈砍技能进一步玩善,添加砍中后的一系列处理,如伤害,命中特效:

在这里插入图片描述
伤害的处理是在一个特定的伤害GE中去进行处理的,写法在前面章节提到过。

在这里插入图片描述
同样,我这里是简要处理,并没有为角色赋予攻击力抑或是伤害能力的属性,这里暂时使用一个hardcode来充当伤害。

命中特效是利用GC来实现,更具体来说,是利用GCN_Burst_Latent这个GAS内置的Actor类,我们将碰撞那一刻的位置和法线传入,令特效和声效等能够在希望的位置触发。更具体的,这里使用了一个Niagara特效,一个声效,一个CameraShake效果,还有一个ForceFeedback(手柄的震动力反馈):

在这里插入图片描述

GA里的逻辑部分到这里就算是准备就绪,我们下面要考虑砍中那一刻相关的内容了。

2. 挥剑时的命中检测

在武器下设置检测点(SceneComponent),只要适时根据依照这个轨迹线去探测是否集中某个物体就可以按照需要发送命中事件。
在这里插入图片描述

在这里插入图片描述
在BeginPlay做轨迹球的初始化,并利用变量WeaponTraceControl来作为检测的开关(默认关闭):

在这里插入图片描述
在这里插入图片描述
相应的Tick阶段利用WeaponTraceControl变量进行流程控制:

在这里插入图片描述
开启检测后,如果有命中,则利用SendGameplayEventToActor发送命中事件,这里使用DoOnce,意义在一次挥剑我只希望去单次触发命中事件;WeaponHitResult用来存储命中结果,供GA访问使用(如使用命中的位置,法线等信息)。此外在关闭检测后,需要完成一些清理工作。
在这里插入图片描述
最后利用Montage里的NotifyState来进行射线检测控制的开关:

在这里插入图片描述
主要就是在ReceivedNotifyBeginReceivedNotifyEnd两个时间节点控制WeaponTraceControl变量:

在这里插入图片描述
在这里插入图片描述
到这里,一个能造成伤害,能触发攻击命中效果的技能就完成了。

在这里插入图片描述

3. 完善:UI显示当前血量

血条的核心在于血量与最大血量的比值,这个比值和ProgressBar结合可以很快构建出血条的效果:

在这里插入图片描述
然后利用WidgetComponent挂载到角色身上简单配置即可。

在这里插入图片描述

参考:

属性 - Attributes

属性集 - Attribute Set

游戏效果 - Gameplay Effects

游戏技能 - Gameplay Abilities

技能任务 - Ability Tasks

游戏反馈 - Gameplay Cues

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

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

相关文章

向毕业妥协系列之深度学习笔记(二)深层神经网络

目录 一.深层神经网络 二.前向和反向传播 三.深层网络中的前向传播 四.核对矩阵的维数 五.为什么使用深层表示 六.参数VS超参数 一.深层神经网络 就是好多层。 二.前向和反向传播 三.深层网络中的前向传播 四.核对矩阵的维数 略 五.为什么使用深层表示 我们都知道深度…

在淘宝开店后,如何发布宝贝?从哪发布?

近期&#xff0c;有几位在淘宝新开店的店主&#xff0c;来向我们咨询了一些问题&#xff0c;总结来说可以将问题归为一个&#xff1a;在淘宝开店后&#xff0c;怎样上传宝贝&#xff1f;从哪上传&#xff1f;下面&#xff0c;小编来给大家简单的说一下发布宝贝时要注意什么&…

AD域 - 自动为域颁发证书

自动为域用户颁发数字证书 ———————————— 进入CA证书颁发机构 在“证书颁发机构”窗口中,鼠标右键点击“证书模板”,在弹出的快捷菜单中点击“管理” 在“证书模板控制台”窗口中,鼠标右键点击右侧列表中的“用户”,在弹出的快捷菜单中点击“复制模板

【Redis】Redis数据库的实现原理

在之前的文章我们介绍过&#xff0c;Redis服务器在启动之初&#xff0c;会初始化RedisServer的实例&#xff0c;在这个实例中存在很多重要的属性结构&#xff0c;同理本篇博客中介绍的数据库实现原理也会和其中的某些属性相关&#xff0c;我们继续看一下吧。 1.服务器和客户端…

【设计模式】 - 创建者模式 - 原型模式

目录标题1. 原型模式1.1 概述1.2 结构1.3 实现1.4 浅克隆Demo1&#xff1a;基本类型Demo2&#xff1a;引用类型浅克隆总结&#xff1a;1.5 深克隆实现方式1&#xff1a;浅克隆嵌套1. Address类实现Cloneable接口&#xff0c;重写clone方法;2. 在Customer类的clone方法中调用Add…

[附源码]SSM计算机毕业设计智慧教室预约JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

2019年1+X 证书 Web 前端开发中级理论考试——易错题、陌生但又会考到的题目原题+答案

文章目录 &#x1f3af;关于1X标准 &#x1f3af;关于中级考点 ❗❗❗注意&#xff1a; 理论题题型包括单选题、多选题、判断题。 ❗注意&#xff1a;题目序号没有修改 ❗红色的选项才是正确答案 ❗如果题目后面没有红色的选项&#xff0c;那么括号里面的答案是正确的 …

Unity游戏Mod/插件制作教程01 - BepInEx的安装和使用

前言 本章节为没有使用过BepInEx的同学进行BepInEx的安装和使用方面的介绍&#xff0c;如果你之前已经使用过并了解如何使用&#xff0c;可以直接跳过本章节。 BepInEx下载 BepInEx的Github链接 https://github.com/BepInEx/BepInEx/releases 一共有3种版本&#xff0c;BepIn…

Hive环境搭建

3.1 Hive环境搭建 3.1.1 Hive引擎简介 Hive引擎包括&#xff1a;默认MR、tez、spark Hive on Spark&#xff1a;Hive既作为存储元数据又负责SQL的解析优化&#xff0c;语法是HQL语法&#xff0c;执行引擎变成了Spark&#xff0c;Spark负责采用RDD执行。 Spark on Hive : Hi…

人人开源后台项目maven构建(yyds)

人人开源后台项目maven构建(yyds) npm run serve 和 npm run dev 的区别在日常运行vue 项目中 在终端 运行命令有时用到 npm run serve 有时是 npm run dev。那么&#xff0c;什么时候用到 serve &#xff0c;什么时候用到 dev 呢&#xff1f; 他们的区别是什么&#xff1f;一…

【学习笔记】《Python深度学习》第四章:机器学习基础

文章目录1 机器学习的四个分支1.1 监督学习1.2 无监督学习1.3 自监督学习1.4 强化学习2 评估机器学习模型2.1 训练集、验证集和测试集2.2 注意事项3 数据预处理、特征工程和特征学习3.1 神经网络的数据预处理3.2 特征工程4 过拟合与欠拟合4.1 减小网络大小4.2 添加权重正则化4.…

postgresql安装配置和基本操作

1.安装 linux上安装 最好是centos7.6或者7.8&#xff0c; 参考官网 PGSQL的官方地址&#xff1a;PostgreSQL: The worlds most advanced open source database PGSQL的国内社区&#xff1a;PostgreSQL中文社区:: 世界上功能最强大的开源数据库... 点击download PostgreSQ…

【Struts2】二_Struts2参数映射、核心配置文件struts.xml中的标签与属性的使用

文章目录Struts2一、参数映射&#xff1a;▶传递基本数据类型&#xff1a;▶传递对象二、核心配置文件struts.xml&#xff1a;2.1、constant标签2.2、package标签2.3、action标签三、Action配置&#xff1a;3.1、Action简介&#xff1a;3.2、继承ActionSupport类&#xff1a;3.…

JAVA初阶——继承和多态

目录 一、继承 1、定义&#xff1a; 2、用法&#xff1a; 3、使用从父类继承的成员 &#xff08;1&#xff09;、子类使用从父类继承的成员变量 &#xff08;2&#xff09;、子类使用从父类继承的成员方法 4、super &#xff08;1&#xff09;、定义&#xff1a; 5、子…

ID3算法

目录 ID3算法 例子 ID算法总结 ID3算法 ID3算法是在每个结点处选取能获得最高信息增益的分支属性进行分裂 在每个决策结点处划分分支、选取分支属性的目的是将整个决策树的样本纯度提升 衡量样本集合纯度的指标则是熵&#xff1b; 举例来说&#xff0c;如果有一个大小为10的…

被裁后,狂刷607页JUC源码分析笔记,立马拿蚂蚁offer

前言 可能大家最近&#xff0c;在公众号&#xff0c;或者各大自媒体平台&#xff0c;都能够刷到&#xff0c;因为疫情美国经济面临结构性衰退&#xff0c;美联储疯狂印钞导致世界性经济波动&#xff0c;导致国际环境不是很好&#xff0c;也间接影响到了中国&#xff0c;中国也…

跟艾文学编程《Python基础》(2)Python 容器

作者&#xff1a; 艾文&#xff0c;计算机硕士学位&#xff0c;企业内训讲师和金牌面试官&#xff0c;公司资深算法专家&#xff0c;现就职BAT一线大厂。 邮箱&#xff1a; 1121025745qq.com 博客&#xff1a;https://wenjie.blog.csdn.net/ 内容&#xff1a;跟艾文学编程《Pyt…

JAVA微服务场景下分布式日志收集排查问题实战

问题产生的根由&#xff1f;不同服务的日志存在哪里&#xff1f;我们怎么去排查线上问题&#xff1f; 问题场景&#xff1a;我们部署的java服务可能有几十个&#xff0c;不同的项目里面他是看不到别的服务的日志&#xff0c;只有服务的返回msg消息&#xff0c;相比传统的单体服…

计算机体系结构:1.1.系统加速比计算例题

文章目录题目内容题目分析题目求解题目内容 假设在某程序的执行过程中&#xff0c;浮点操作时间占整个执行时间的10%&#xff0c;现希望对浮点 操作加速 。 &#xff08;1&#xff09;设对浮点操作的加速比为Sf&#xff0c;请推导出程序总的加速比S和Sf之间的关系表达式&#…

IoU的计算实现详解(基于Python)

文章目录1. 交并比&#xff08;IoU&#xff09;2.原理3.代码实现1. 交并比&#xff08;IoU&#xff09; 具体来说&#xff0c;它是两边界框相交部分面积与相并部分面积之比&#xff0c;如下所示&#xff1a; 也就是两个框的交集和两个框的并集之比。 2.原理 这里详细解释一…