UE4 Slate 环形图学习笔记

// Fill out your copyright notice in the Description page of Project Settings.

#include "CircleWidget.h"

int32 UCircleWidget::NativePaint(const FPaintArgs& Args,
	const FGeometry& AllottedGeometry,
	const FSlateRect& MyCullingRect,
	FSlateWindowElementList& OutDrawElement,
	int32 LayerId,
	const FWidgetStyle& InWidgetStyle,
	bool bParentEnable)	const
{
	DrawCirclePart(
		OutDrawElement,
		AllottedGeometry,
		LayerId,
		InnerR,
		OuterR,
		StartAngle,
		EndAngle,
		CircleColor
	);
	
	return LayerId++;
}

void UCircleWidget::DrawCirclePart(
	FSlateWindowElementList& OutDrawElement,
	const FGeometry& AllottedGeometry,
	int LayerId, float IR, float OR,
	int32 InBeginAngle, int32 InEndAngle,
	const FColor& InColor) const
{
	if(InEndAngle <= InBeginAngle)	return ;//如果开始角都小于结束角则退出

	FVector2D CenterPosition = FVector2D(OuterR, OuterR);	

	TArray<FSlateVertex> SlateVertexes;//创建一个顶点数组,用于存放绘制的顶点
	TArray<SlateIndex> SlateIndexes;//创建一个下标数组

	for(int32 Angle = InBeginAngle; Angle <= InEndAngle; Angle++)//每过一个角度进行一次,角度四个顶点的运算
	{
		//声明内弧与外弧的四个顶点
		FSlateVertex CurrentOVertex;
		FSlateVertex NextOVextex;
		FSlateVertex CurrentIVertex;
		FSlateVertex NextIVertex;

		//为四个顶点着色
		CurrentOVertex.Color = InColor;
		NextOVextex.Color = InColor;
		CurrentIVertex.Color = InColor;
		NextIVertex.Color = InColor;

		//计算内弧、外弧四个顶点的位置
		FVector2D CurrentIVPosition = FVector2D(
			CenterPosition.X + IR * FMath::Cos(FMath::DegreesToRadians(Angle)),
			CenterPosition.Y - IR * FMath::Sin(FMath::DegreesToRadians(Angle))
		);

		FVector2D NextIVPosition = FVector2D(
			CenterPosition.X + IR * FMath::Cos(FMath::DegreesToRadians(Angle + 1)),
			CenterPosition.Y - IR * FMath::Sin(FMath::DegreesToRadians(Angle + 1))
		);

		FVector2D CurrentOVPosition = FVector2D(
			CenterPosition.X + OR * FMath::Cos(FMath::DegreesToRadians(Angle)),
			CenterPosition.Y - OR * FMath::Sin(FMath::DegreesToRadians(Angle))
		);

		FVector2D NextOVPosition = FVector2D(
			CenterPosition.X + OR * FMath::Cos(FMath::DegreesToRadians(Angle + 1)),
			CenterPosition.Y - OR * FMath::Sin(FMath::DegreesToRadians(Angle + 1))
		);

		//从本地空间变换到渲染空间
		const FSlateRenderTransform& SlateRenderTransform = AllottedGeometry.ToPaintGeometry().GetAccumulatedRenderTransform();
		CurrentOVPosition = SlateRenderTransform.TransformPoint(CurrentOVPosition);
		NextOVPosition = SlateRenderTransform.TransformPoint(NextOVPosition);
		CurrentIVPosition = SlateRenderTransform.TransformPoint(CurrentIVPosition);
		NextIVPosition = SlateRenderTransform.TransformPoint(NextIVPosition);

		//给四个顶点的位置赋值(渲染空间的值)
		CurrentOVertex.Position = CurrentOVPosition;
		NextOVextex.Position = NextOVPosition;
		CurrentIVertex.Position = CurrentIVPosition;
		NextIVertex.Position = NextIVPosition;

		//将顶点信息放入数组并将其索引给到对应值
		int32 IndexOfCurrentOV = SlateVertexes.Add(CurrentOVertex);
		int32 IndexOfNextOV = SlateVertexes.Add(NextOVextex);
		int32 IndexOfCurrentIV = SlateVertexes.Add(CurrentIVertex);
		int32 IndexOfNextIV = SlateVertexes.Add(NextIVertex);

		//利用索引画出对应两个三角形,放入索引数组,第一个三角形
		SlateIndexes.Add(IndexOfCurrentOV);
		SlateIndexes.Add(IndexOfNextOV);
		SlateIndexes.Add(IndexOfCurrentIV);

		//第二个三角形
		SlateIndexes.Add(IndexOfCurrentIV);
		SlateIndexes.Add(IndexOfNextIV);
		SlateIndexes.Add(IndexOfNextOV);
	}

	//设置uv值
	for(FSlateVertex& SlateVertex : SlateVertexes)
	{
		SlateVertex.TexCoords[0] = 0.f;
		SlateVertex.TexCoords[1] = 0.f;
	}

	//开始获取各个顶点进行图形绘制
	const FSlateBrush* Brush = FCoreStyle::Get().GetBrush("ColorSpectrum.Specturm");
	FSlateResourceHandle ResourcedHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(*Brush);
	FSlateDrawElement::MakeCustomVerts(
		OutDrawElement,
		LayerId,
		ResourcedHandle,
		SlateVertexes,
		SlateIndexes,
		nullptr,
		0,
		0
	);
}
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CircleWidget.generated.h"

/**
 * 
 */
UCLASS()
class MYPROJECT_API UCircleWidget : public UUserWidget
{
	GENERATED_BODY()

protected:
	virtual int32 NativePaint(
		const FPaintArgs& Args,
		const FGeometry& AllottedGeometry,
		const FSlateRect& MyCullingRect,
		FSlateWindowElementList& OutDrawElement,
		int32 LayerId,
		const FWidgetStyle& InWidgetStyle,
		bool bParentEnable) const override;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 360))
	float EndAngle;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 360))
	float StartAngle;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 960))
	float InnerR;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 960))
	float OuterR;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FColor CircleColor;
	
private:
	void DrawCirclePart(FSlateWindowElementList& OutDrawElement,
		const FGeometry& AllottedGeometry,
		int LayerId, float IR, float OR,
		int32 InBeginAngle, int32 InEndAngle,
		const FColor& InColor) const;
};

可以用于吃鸡回血的这个动画:


// Fill out your copyright notice in the Description page of Project Settings.

#include "CircleWidget.h"

#include <vehicle/PxVehicleSDK.h>

int32 UCircleWidget::NativePaint(const FPaintArgs& Args,
                                 const FGeometry& AllottedGeometry,
                                 const FSlateRect& MyCullingRect,
                                 FSlateWindowElementList& OutDrawElement,
                                 int32 LayerId,
                                 const FWidgetStyle& InWidgetStyle,
                                 bool bParentEnable)	const
{
	float TotalValue = 0.f;
	for(int32 Index = 0; Index < Angles.Num(); Index++)	TotalValue += Angles[Index];
	TArray<float> CircleAngles;
	for(int32 Index = 0; Index < Angles.Num(); Index++)
	{
		int32 Angle = (Angles[Index] / TotalValue) * 360;
		CircleAngles.Add(Angle);
	}
	int32 AddAngle = 0;
	int LoopSize = FMath::Min(Angles.Num(), CircleColor.Num());
	for(int32 Index = 0; Index < LoopSize; Index++)
	{
		DrawCirclePart(
			OutDrawElement,
			AllottedGeometry,
			LayerId,
			InnerR,
			OuterR,
			AddAngle,
			AddAngle + CircleAngles[Index],
			CircleColor[Index]
		);
		AddAngle += CircleAngles[Index];
	}
	
	return LayerId++;
}

void UCircleWidget::DrawCirclePart(
	FSlateWindowElementList& OutDrawElement,
	const FGeometry& AllottedGeometry,
	int LayerId, float IR, float OR,
	int32 InBeginAngle, int32 InEndAngle,
	const FColor& InColor) const
{
	if(InEndAngle <= InBeginAngle)	return ;//如果开始角都小于结束角则退出

	FVector2D CenterPosition = FVector2D(OuterR, OuterR);	

	TArray<FSlateVertex> SlateVertexes;//创建一个顶点数组,用于存放绘制的顶点
	TArray<SlateIndex> SlateIndexes;//创建一个下标数组

	for(int32 Angle = InBeginAngle; Angle <= InEndAngle; Angle++)//每过一个角度进行一次,角度四个顶点的运算
	{
		//声明内弧与外弧的四个顶点
		FSlateVertex CurrentOVertex;
		FSlateVertex NextOVextex;
		FSlateVertex CurrentIVertex;
		FSlateVertex NextIVertex;

		//为四个顶点着色
		CurrentOVertex.Color = InColor;
		NextOVextex.Color = InColor;
		CurrentIVertex.Color = InColor;
		NextIVertex.Color = InColor;

		//计算内弧、外弧四个顶点的位置
		FVector2D CurrentIVPosition = FVector2D(
			CenterPosition.X + IR * FMath::Cos(FMath::DegreesToRadians(Angle)),
			CenterPosition.Y - IR * FMath::Sin(FMath::DegreesToRadians(Angle))
		);

		FVector2D NextIVPosition = FVector2D(
			CenterPosition.X + IR * FMath::Cos(FMath::DegreesToRadians(Angle + 1)),
			CenterPosition.Y - IR * FMath::Sin(FMath::DegreesToRadians(Angle + 1))
		);

		FVector2D CurrentOVPosition = FVector2D(
			CenterPosition.X + OR * FMath::Cos(FMath::DegreesToRadians(Angle)),
			CenterPosition.Y - OR * FMath::Sin(FMath::DegreesToRadians(Angle))
		);

		FVector2D NextOVPosition = FVector2D(
			CenterPosition.X + OR * FMath::Cos(FMath::DegreesToRadians(Angle + 1)),
			CenterPosition.Y - OR * FMath::Sin(FMath::DegreesToRadians(Angle + 1))
		);

		//从本地空间变换到渲染空间
		const FSlateRenderTransform& SlateRenderTransform = AllottedGeometry.ToPaintGeometry().GetAccumulatedRenderTransform();
		CurrentOVPosition = SlateRenderTransform.TransformPoint(CurrentOVPosition);
		NextOVPosition = SlateRenderTransform.TransformPoint(NextOVPosition);
		CurrentIVPosition = SlateRenderTransform.TransformPoint(CurrentIVPosition);
		NextIVPosition = SlateRenderTransform.TransformPoint(NextIVPosition);

		//给四个顶点的位置赋值(渲染空间的值)
		CurrentOVertex.Position = CurrentOVPosition;
		NextOVextex.Position = NextOVPosition;
		CurrentIVertex.Position = CurrentIVPosition;
		NextIVertex.Position = NextIVPosition;

		//将顶点信息放入数组并将其索引给到对应值
		int32 IndexOfCurrentOV = SlateVertexes.Add(CurrentOVertex);
		int32 IndexOfNextOV = SlateVertexes.Add(NextOVextex);
		int32 IndexOfCurrentIV = SlateVertexes.Add(CurrentIVertex);
		int32 IndexOfNextIV = SlateVertexes.Add(NextIVertex);

		//利用索引画出对应两个三角形,放入索引数组,第一个三角形
		SlateIndexes.Add(IndexOfCurrentOV);
		SlateIndexes.Add(IndexOfNextOV);
		SlateIndexes.Add(IndexOfCurrentIV);

		//第二个三角形
		SlateIndexes.Add(IndexOfCurrentIV);
		SlateIndexes.Add(IndexOfNextIV);
		SlateIndexes.Add(IndexOfNextOV);
	}

	//设置uv值
	for(FSlateVertex& SlateVertex : SlateVertexes)
	{
		SlateVertex.TexCoords[0] = 0.f;
		SlateVertex.TexCoords[1] = 0.f;
	}

	//开始获取各个顶点进行图形绘制
	const FSlateBrush* Brush = FCoreStyle::Get().GetBrush("ColorSpectrum.Specturm");
	FSlateResourceHandle ResourcedHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(*Brush);
	FSlateDrawElement::MakeCustomVerts(
		OutDrawElement,
		LayerId,
		ResourcedHandle,
		SlateVertexes,
		SlateIndexes,
		nullptr,
		0,
		0
	);
}

void UCircleWidget::SetValues(TArray<float> InValues, TArray<FColor> Colors)
{
	if(InValues.Num() < 1)	return ;

	Angles.Empty();

	CircleColor = Colors;
	
	float Total = 0;
	for(int32 Index = 0; Index < InValues.Num(); Index++)
	{
		Total += InValues[Index];
	}

	float CurrentTotal = 0;
	for(int32 Index = 0; Index < InValues.Num(); Index++)
	{
		CurrentTotal = InValues[Index];

		int Angle = (CurrentTotal / Total) * 360;
		Angles.Add(Angle);
	}
}
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CircleWidget.generated.h"

/**
 * 
 */
UCLASS()
class MYPROJECT_API UCircleWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable)
	void SetValues(TArray<float> InValues, TArray<FColor> Colors);
	
protected:
	virtual int32 NativePaint(
		const FPaintArgs& Args,
		const FGeometry& AllottedGeometry,
		const FSlateRect& MyCullingRect,
		FSlateWindowElementList& OutDrawElement,
		int32 LayerId,
		const FWidgetStyle& InWidgetStyle,
		bool bParentEnable) const override;

	// UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 360))
	// float EndAngle;
	//
	// UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 360))
	// float StartAngle;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 960))
	float InnerR;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 960))
	float OuterR;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TArray<FColor> CircleColor;

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TArray<float> Angles;
	
private:
	void DrawCirclePart(FSlateWindowElementList& OutDrawElement,
		const FGeometry& AllottedGeometry,
		int LayerId, float IR, float OR,
		int32 InBeginAngle, int32 InEndAngle,
		const FColor& InColor) const;
	
};

同样也能进行动态设置,该类是按照比例来画环形图

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值