2018-11-26 19:36:46 zp288105109a 阅读数 230
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2392 人正在学习 去看看 杨石兴

       自己玩的时候,发现UMG的初始化比PlayerState初始化快。而且UI一直执行NativeTick来刷新UI界面,有点费。研究了一下Unreal的Delegate,发现有点麻烦,还得自己声明一个类型。
       问题代码:

AMainGameMode::AMainGameMode()
{
	DefaultPawnClass = AMainCharacter::StaticClass();
	PlayerStateClass = AMainCharacterState::StaticClass();
	PlayerControllerClass = AMainCharacterController::StaticClass();
}

void AMainGameMode::BeginPlay()
{
	auto tempGameInstance = Cast<UMainGameInstance>(GetGameInstance());
	if (tempGameInstance != nullptr)
		tempGameInstance->ShowWidget((int)EUserWidgetID::MainView);
}

       修改后,Delegate其实可以放在一个单例中来管理,没搜到Unreal单例的实现,就随便拿GameInstance来测试:

       MainGameInstance.h

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInitPlayerState);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnUpdatePlayerState);

public:
	void BoardCast_InitPlayerState();
	void BoardCast_UpdatePlayerState();

public:
	UPROPERTY(BlueprintAssignable, Category = "MainGameInstance")
		FOnInitPlayerState m_OnInitPlayerState;
	UPROPERTY(BlueprintAssignable, Category = "MainGameInstance")
		FOnUpdatePlayerState m_OnUpdatePlayerState;

       MainGameInstance.cpp

void UMainGameInstance::BoardCast_InitPlayerState()
{
	m_OnInitPlayerState.Broadcast();
}

void UMainGameInstance::BoardCast_UpdatePlayerState()
{
	m_OnUpdatePlayerState.Broadcast();
}

       监听就很简单了,就跟普通的OnComponentBeginOverlap事件差不多。在UMG的C++类中声明2个方法:

private:
	UFUNCTION()
		void OnInitPlayerState();
	UFUNCTION()
		void OnUpdatePlayerState();

       添加和移除也很简单:

void UMainUserWidget::AddEvent()
{
	auto mainGameInstance = Cast<UMainGameInstance>(GetGameInstance());
	if (!mainGameInstance) return;

	mainGameInstance->m_OnInitPlayerState.AddDynamic(this, &UMainUserWidget::OnInitPlayerState);
	mainGameInstance->m_OnUpdatePlayerState.AddDynamic(this, &UMainUserWidget::OnUpdatePlayerState);
}

void UMainUserWidget::RemoveEvent()
{
	auto mainGameInstance = Cast<UMainGameInstance>(GetGameInstance());
	if (!mainGameInstance) return;

	mainGameInstance->m_OnInitPlayerState.RemoveAll(this);
	mainGameInstance->m_OnUpdatePlayerState.RemoveAll(this);
}

Multi-cast Delegates官网地址

2018-11-15 17:21:01 xiaoxiaolooi 阅读数 256
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2392 人正在学习 去看看 杨石兴

unreal GIS 模块

unreal4 源代码模块

自从unreal4 开源以来,osg ogre 渐渐不能用来吃饭,于是本着听人劝吃饱饭的思想,转头unreal门下,继续为混口饭事业,投身革命。可是unreal的c++编程基本没有什么例子可看,只好自己从头做起。

  1. 开发者驱动
  2. 编辑器
  3. 工程目录
  4. 基础框架代码
  5. 第三方库

在这里插入图片描述
这个是文档目录,代码量难以阅读,决定从以下三方向入手,第一次写文字,真心不容易。
1.案例编写使用unreal4 的普通界面搭建自定义三维场景 介绍 editor层的基础代码
2.添加GIS地图属性信息 介绍 驱动层的基础代码
3.程序化植物合成 介绍 与unreal基础平台结合
以后会陆续跟新到这里
推荐大家使用 阿里云 https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=ic4sfgeu

2015-11-14 13:03:01 xi_niuniu 阅读数 3151
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2392 人正在学习 去看看 杨石兴

Unreal Engine 4 蓝图脚本学习,根据《Blueprints Visual Scripting for Unreal Engine》学习整理


默认情况下,actor的Transform组件中 移动性属性为“static”,  就是在游戏运行时,actor是不可进行移动和操作的。所以为了实现对象
在游戏中可移动的效果需要把这一属性修改为 "可移动"




为了能够改变脚本以后所附加到的对象同样为可移动的,需要打开蓝图编辑器进行一些修改






为了使物体在游戏世界中能够移动,我们需要知道以下信息

•  Where the cylinder currently is 圆柱体在什么位置
•  What direction it is supposed to move in 想要移动的方向是什么
•  How fast it is supposed to move in that direction 在那个方向上移动的速度是多少

创建速度变量和方向变量

Speed 为float类型变量

Direction为Vector类型变量


速度设置 为200.0f;



移动方向设置为 y = -10.0f;





Normalizing is a common procedure in vector math that ensures that
the vector is converted to a length of one unit, which will make it compatible with
the rest of our calculations

标准化向量(单位化向量)就是将向量值转化到一个单位长度(向量的模为一)。以便在后序程序运算中相兼容



速度值乘以一个时间值,所以选择 float*float    时间值类型也为float


将StaticMeshComponent组件拖拽到事件图表中  以获取圆柱体当前的位置



GetWorldDeltaSeconds: 获取相邻两帧之间的间隔时间。 这个数值受游戏运行所在的机器性能影响的,性能高的机器时间间隔就较小,反之则较大。为了能够
在不同性能的计算机上表现出相同的移动速度,所以会把速度值乘以DeltaSeconds。



Transform属性中包含对象的 位置、  旋转 和 缩放的信息。 能过GetWorldTransform可以获得当前对象的Transform信息

BreakTransform 可以提取Transform中的不同部分
MakeTransform根据Location、Rotation和Scale "合成" 一个新的Transform


事件Tick每一帧都会触发

SetActorTransform 根据传入的Transform值设置Actor的Transform


这时运行游戏,圆柱体只会朝着一个方向移动。
为了实现圆柱体在游戏中来回移动,向事件图表中添加两个新的Direction 变量 ,选择设置并分别设置y值为10.0  和 -10.0


Delay会根据Duration设置的秒数循环执行
FlipFlop会执行 A 和 B所连接的Node 中的一个,默认先执行A。

播放游戏观察事件图表中数据流的走向


圆柱体在游戏中来回移动

现在通过之前创建的蓝图脚本可以创建更多且有相同属性的游戏对象











2015-12-14 21:14:20 shangguanwaner 阅读数 1423
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2392 人正在学习 去看看 杨石兴

Unreal Engine 4添加自定义Settings到项目设置

在开发的过程中,很多时候需要在项目中应用各种各样的设置。有些人会自己实现一套,其实没必要那么麻烦,虚幻4专门为开发者提供了一套配置系统,方便又省事。效果如下:
这里写图片描述

可以看到Settings是和编辑器的配置是并列的,同样是在项目设置窗口中。
下面将一步一步描述如何具体实现这一功能。
首先创建类MySettings,这个类继承自UObject,代码如下:
MySettings.h

UCLASS(config=MySettings)
class SETTINGSTEST_API UMySettings : public UObject
{
    GENERATED_BODY()

public:
    UMySettings(const FObjectInitializer& obj);

    UPROPERTY(Config, EditAnywhere, Category = Settings)
    int32 SomeIntProperty;

    UPROPERTY(Config, EditAnywhere, Category = Settings)
        bool SomeBoolProperty;
};

MySettings.cpp

UMySettings::UMySettings(const FObjectInitializer& obj)
{
    SomeIntProperty = 0;
    SomeBoolProperty = true;
}

作为演示,UMySettings只包装了两个简单的变量,读者可以按照需要扩展更复杂的配置变量。
接下来,需要在合适的地方注册这个配置对象。

#include "ISettingsModule.h"
//省略。。。
#define LOCTEXT_NAMESPACE "MySettings"

if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
{
    SettingsModule->RegisterSettings("Project", "Plugins", "MySettings",
        LOCTEXT("RuntimeSettingsName", "My Settings Page"),
        LOCTEXT("RuntimeSettingsDescription", "Configure my settings"),
        GetMutableDefault<UMySettings>()
    );
}

代码执行后,可以在项目的Saved/Config/Windows下面发现创建了一个MySettings.ini的配置文件,这里保存的就是咱们自定义的配置信息。

2016-12-03 14:33:30 qq_20309931 阅读数 4443
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2392 人正在学习 去看看 杨石兴

Unreal Engine 4 C++ UMG自定义控件

好记性不如烂笔头啊,还是记录一下!


如果你觉得Unreal Engine里面的控件没有达到你的需求,你需要添加自定控件。


创建Slate控件

如果你还不了解如何创建一个Slate控件,请先阅读:

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(一)

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(二)

Unreal Engine 4 C++ Slate 介绍——用C++和Slate创建菜单(三)

这里用我自己写的作为参考:

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

#pragma once

#include "UI/Slate/ProgressBarExStyle.h"

/**
 *  SProgressBarEx Fill Type 
 */
UENUM(BlueprintType)
namespace EProgressBarExFillType
{
    enum Type
    {
        // will fill up from the left side to the right
        LeftToRight,
        // will fill up from the right side to the left side
        RightToLeft,
        // will fill up from the center to the outer edges
        FillFromCenter,
        // will fill up from the top to the the bottom
        TopToBottom,
        // will fill up from the bottom to the the top
        BottomToTop,
    };
}

/** A progress extend bar widget.*/
class TESTMOBILE_API SProgressBarEx : public SLeafWidget
{

public:
    SLATE_BEGIN_ARGS(SProgressBarEx)
        : _Style( nullptr )
        , _BarFillType(EProgressBarExFillType::LeftToRight)
        , _Percent( TOptional<float>() )
        , _FillColorAndOpacity( FLinearColor::White )
        , _BorderPadding( FVector2D(1,0) )
        , _BackgroundImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").BackgroundImage)
        , _IncreaseImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _DecreaseImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _FillImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").FillImage)
        , _MarqueeImage(&FCoreStyle::Get().GetWidgetStyle<FProgressBarStyle>("ProgressBar").MarqueeImage)
        , _RefreshRate(2.0f)
        {}

        /** Style used for the progress bar */
        SLATE_STYLE_ARGUMENT( FProgressBarExStyle, Style )

        /** Defines if this progress bar fills Left to right or right to left*/
        SLATE_ARGUMENT( EProgressBarExFillType::Type, BarFillType )

        /** Used to determine the fill position of the progress bar ranging 0..1 */
        SLATE_ATTRIBUTE( TOptional<float>, Percent )

        /** Fill Color and Opacity */
        SLATE_ATTRIBUTE( FSlateColor, FillColorAndOpacity )

        /** Border Padding around fill bar */
        SLATE_ATTRIBUTE( FVector2D, BorderPadding )
    
        /** The brush to use as the background of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, BackgroundImage)

        /** The brush to use as the increase image of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, IncreaseImage)

        /** The brush to use as the decrease image of the progress bar */
        SLATE_ARGUMENT(const FSlateBrush*, DecreaseImage)
    
        /** The brush to use as the fill image */
        SLATE_ARGUMENT(const FSlateBrush*, FillImage)
    
        /** The brush to use as the marquee image */
        SLATE_ARGUMENT(const FSlateBrush*, MarqueeImage)

        /** Rate at which this widget is ticked when sleeping in seconds */
        SLATE_ARGUMENT(float, RefreshRate)

    SLATE_END_ARGS()

    /**
     * Construct the widget
     * 
     * @param InArgs   A declaration from which to construct the widget
     */
    void Construct(const FArguments& InArgs);

    /** Paint Widget */
    virtual int32 OnPaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override;
    virtual FVector2D ComputeDesiredSize(float) const override;
    virtual bool ComputeVolatility() const override;

    /** See attribute Percent */
    void SetPercent(TAttribute< TOptional<float> > InPercent);

    /** See attribute Style */
    void SetStyle(const FProgressBarExStyle* InStyle);

    /** See attribute BarFillType */
    void SetBarFillType(EProgressBarExFillType::Type InBarFillType);
    
    /** See attribute SetFillColorAndOpacity */
    void SetFillColorAndOpacity(TAttribute< FSlateColor > InFillColorAndOpacity);
    
    /** See attribute BorderPadding */
    void SetBorderPadding(TAttribute< FVector2D > InBorderPadding);
    
    /** See attribute BackgroundImage */
    void SetBackgroundImage(const FSlateBrush* InBackgroundImage);

    /** See attribute IncreaseImage */
    void SetIncreaseImage(const FSlateBrush* InIncreaseImage);

    /** See attribute IncreaseImage */
    void SetDecreaseImage(const FSlateBrush* InDecreaseImage);
    
    /** See attribute FillImage */
    void SetFillImage(const FSlateBrush* InFillImage);
    
    /** See attribute MarqueeImage */
    void SetMarqueeImage(const FSlateBrush* InMarqueeImage);

private:

    /** Controls the speed at which the widget is ticked when in slate sleep mode */
    void SetActiveTimerTickRate(float TickRate);

    /** Widgets active tick */
    EActiveTimerReturnType ActiveTick(double InCurrentTime, float InDeltaTime);

    /** Gets the current background image. */
    const FSlateBrush* GetBackgroundImage() const;

    /** Gets the current increase image */
    const FSlateBrush* GetIncreaseImage() const;

    /** Gets the current decrease image */
    const FSlateBrush* GetDecreaseImage() const;

    /** Gets the current fill image */
    const FSlateBrush* GetFillImage() const;

    /** Gets the current marquee image */
    const FSlateBrush* GetMarqueeImage() const;


private:

    /** The style of the progress bar */
    const FProgressBarExStyle* Style;

    /** The text displayed over the progress bar */
    TAttribute< TOptional<float> > CurrentPercent;
    TAttribute< TOptional<float> > TargetPercent;
    TAttribute< TOptional<float> > MiddlePercent;

    /** The fill type for the progress bar */
    EProgressBarExFillType::Type BarFillType;

    /** Background image to use for the progress bar */
    const FSlateBrush* BackgroundImage;

    /** Increase image to use for the progress bar */
    const FSlateBrush* IncreaseImage;

    /** Decrease image to use for the progress bar */
    const FSlateBrush* DecreaseImage;

    /** Foreground image to use for the progress bar */
    const FSlateBrush* FillImage;

    /** Image to use for marquee mode */
    const FSlateBrush* MarqueeImage;

    /** Value to drive progress bar animation */
    float SpeedRate;

    /** Fill Color and Opacity */
    TAttribute<FSlateColor> FillColorAndOpacity;

    /** Border Padding */
    TAttribute<FVector2D> BorderPadding;

    /** Value to drive progress bar animation */
    float MarqueeOffset;

    /** Reference to the widgets current active timer */
    TWeakPtr<FActiveTimerHandle> ActiveTimerHandle;

    /** Rate at which the widget is currently ticked when slate sleep mode is active */
    float CurrentTickRate;

    /** The slowest that this widget can tick when in slate sleep mode */
    float MinimumTickRate;
};

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

#include "TestMobile.h"
#include "SProgressBarEx.h"

void SProgressBarEx::Construct(const FArguments& InArgs)
{
    check(InArgs._BackgroundImage);
    check(InArgs._IncreaseImage);
    check(InArgs._DecreaseImage);
    check(InArgs._FillImage);
    check(InArgs._MarqueeImage);


    MarqueeOffset = 0.0f;
    Style = InArgs._Style;

    
    TAttribute< TOptional<float> > Percent = InArgs._Percent.Get().IsSet() ? InArgs._Percent : 0.5f;
    SetPercent(Percent);

    SpeedRate = 30.0f;

    BarFillType = InArgs._BarFillType;
    BackgroundImage = InArgs._BackgroundImage;
    IncreaseImage = InArgs._IncreaseImage;
    DecreaseImage = InArgs._DecreaseImage;
    FillImage = InArgs._FillImage;
    MarqueeImage = InArgs._MarqueeImage;

    FillColorAndOpacity = InArgs._FillColorAndOpacity;
    BorderPadding = InArgs._BorderPadding;

    CurrentTickRate = 0.0f;
    MinimumTickRate = InArgs._RefreshRate;

    ActiveTimerHandle = RegisterActiveTimer(CurrentTickRate, FWidgetActiveTimerDelegate::CreateSP(this, &SProgressBarEx::ActiveTick));
}


void SProgressBarEx::SetPercent(TAttribute< TOptional<float> > InPercent)
{
    if (!TargetPercent.IdenticalTo(InPercent))
    {
        CurrentPercent = MiddlePercent = TargetPercent = InPercent;
        Invalidate(EInvalidateWidget::LayoutAndVolatility);
    }
}


void SProgressBarEx::SetStyle(const FProgressBarExStyle* InStyle)
{
    Style = InStyle;

    if (Style == nullptr)
    {
        FArguments Defaults;
        Style = Defaults._Style;
    }

    check(Style);

    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBarFillType(EProgressBarExFillType::Type InBarFillType)
{
    BarFillType = InBarFillType;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetFillColorAndOpacity(TAttribute< FSlateColor > InFillColorAndOpacity)
{
    FillColorAndOpacity = InFillColorAndOpacity;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBorderPadding(TAttribute< FVector2D > InBorderPadding)
{
    BorderPadding = InBorderPadding;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetBackgroundImage(const FSlateBrush* InBackgroundImage)
{
    BackgroundImage = InBackgroundImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetIncreaseImage(const FSlateBrush* InIncreaseImage)
{
    IncreaseImage = InIncreaseImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetDecreaseImage(const FSlateBrush* InDecreaseImage)
{
    DecreaseImage = InDecreaseImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetFillImage(const FSlateBrush* InFillImage)
{
    FillImage = InFillImage;
    Invalidate(EInvalidateWidget::Layout);
}


void SProgressBarEx::SetMarqueeImage(const FSlateBrush* InMarqueeImage)
{
    MarqueeImage = InMarqueeImage;
    Invalidate(EInvalidateWidget::Layout);
}


const FSlateBrush* SProgressBarEx::GetBackgroundImage() const
{
    return &Style->BackgroundImage ? &Style->BackgroundImage : BackgroundImage;
}


const FSlateBrush* SProgressBarEx::GetIncreaseImage() const
{
    return &Style->IncreaseImage ? &Style->IncreaseImage : IncreaseImage;
}


const FSlateBrush* SProgressBarEx::GetDecreaseImage() const
{
    return &Style->DecreaseImage ? &Style->DecreaseImage : DecreaseImage;
}


const FSlateBrush* SProgressBarEx::GetFillImage() const
{
    return &Style->FillImage ? &Style->FillImage : FillImage;
}


const FSlateBrush* SProgressBarEx::GetMarqueeImage() const
{
    return &Style->MarqueeImage ? &Style->MarqueeImage : MarqueeImage;
}


int32 SProgressBarEx::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const
{
    // Used to track the layer ID we will return.
    int32 RetLayerId = LayerId;

    bool bEnabled = ShouldBeEnabled( bParentEnabled );
    const ESlateDrawEffect::Type DrawEffects = bEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;

    const FSlateBrush* CurrentFillImage = GetFillImage();
    const FLinearColor FillColorAndOpacitySRGB(InWidgetStyle.GetColorAndOpacityTint() * FillColorAndOpacity.Get().GetColor(InWidgetStyle) * CurrentFillImage->GetTint(InWidgetStyle));
    const FLinearColor ColorAndOpacitySRGB = InWidgetStyle.GetColorAndOpacityTint();

    // Paint inside the border only. 
    // Pre-snap the clipping rect to try and reduce common jitter, since the padding is typically only a single pixel.
    FSlateRect SnappedClippingRect = FSlateRect(FMath::RoundToInt(MyClippingRect.Left), FMath::RoundToInt(MyClippingRect.Top), FMath::RoundToInt(MyClippingRect.Right), FMath::RoundToInt(MyClippingRect.Bottom));
    const FSlateRect ForegroundClippingRect = SnappedClippingRect.InsetBy(FMargin(BorderPadding.Get().X, BorderPadding.Get().Y));

    // Paint background image
    const FSlateBrush* CurrentBackgroundImage = GetBackgroundImage();
    FSlateDrawElement::MakeBox(
        OutDrawElements,
        RetLayerId++,
        AllottedGeometry.ToPaintGeometry(),
        CurrentBackgroundImage,
        SnappedClippingRect,
        DrawEffects,
        InWidgetStyle.GetColorAndOpacityTint() * CurrentBackgroundImage->GetTint( InWidgetStyle )
    );

    TOptional<float> TargetPercentFraction = TargetPercent.Get();
    TOptional<float> MiddlePercentFraction = MiddlePercent.Get();
    TOptional<float> CurrentPercentFraction = CurrentPercent.Get();

    if ( TargetPercentFraction.IsSet() && MiddlePercentFraction.IsSet() && CurrentPercentFraction.IsSet() )
    {
        // Get percent value
        float TargetPercentValue = FMath::Clamp(TargetPercentFraction.GetValue(), 0.0f, 1.0f);
        float MiddlePercentValue = FMath::Clamp(MiddlePercentFraction.GetValue(), 0.0f, 1.0f);
        float CurrentPercentValue = FMath::Clamp(CurrentPercentFraction.GetValue(), 0.0f, 1.0f);

        // Get paint order
        const FSlateBrush* TopBrush;
        const FSlateBrush* CenterBrush;
        const FSlateBrush* BottomBrush;
        float TopValue;
        float CenterValue;
        float BottomValue;
       

        TopBrush = GetFillImage();
        TopValue = MiddlePercentValue;
        CenterBrush = GetIncreaseImage();
        CenterValue = TargetPercentValue;
        BottomBrush = GetDecreaseImage();
        BottomValue = CurrentPercentValue;


        

        switch (BarFillType)
        {
        case EProgressBarExFillType::RightToLeft:
            break;
        case EProgressBarExFillType::FillFromCenter:
            break;
        case EProgressBarExFillType::TopToBottom:
            break;
        case EProgressBarExFillType::BottomToTop:
            break;
        case EProgressBarExFillType::LeftToRight:
        default:
            // Draw bottom layer
            FSlateRect ClippedAllotedGeometry = FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * BottomValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                BottomBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );

            // Draw center layer
            ClippedAllotedGeometry =  FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * CenterValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                CenterBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );

            // Draw top layer
            ClippedAllotedGeometry =  FSlateRect(AllottedGeometry.AbsolutePosition, AllottedGeometry.AbsolutePosition + AllottedGeometry.Size * AllottedGeometry.Scale);
            ClippedAllotedGeometry.Right = ClippedAllotedGeometry.Left + ClippedAllotedGeometry.GetSize().X * TopValue;
            FSlateDrawElement::MakeBox(
                OutDrawElements,
                RetLayerId++,
                AllottedGeometry.ToPaintGeometry(
                    FVector2D::ZeroVector,
                    FVector2D( AllottedGeometry.Size.X, AllottedGeometry.Size.Y )),
                TopBrush,
                ForegroundClippingRect.IntersectionWith(ClippedAllotedGeometry),
                DrawEffects,
                FillColorAndOpacitySRGB
                );
            break;
        }
    }
    else
    {

    }

    return RetLayerId - 1;
}


FVector2D SProgressBarEx::ComputeDesiredSize(float) const
{
    return GetMarqueeImage()->ImageSize;
}


bool SProgressBarEx::ComputeVolatility() const
{
    return SLeafWidget::ComputeVolatility() || TargetPercent.IsBound();
}


void SProgressBarEx::SetActiveTimerTickRate(float TickRate)
{
    if (CurrentTickRate != TickRate || !ActiveTimerHandle.IsValid())
    {
        CurrentTickRate = TickRate;

        TSharedPtr<FActiveTimerHandle> SharedActiveTimerHandle = ActiveTimerHandle.Pin();
        if (SharedActiveTimerHandle.IsValid())
        {
            UnRegisterActiveTimer(SharedActiveTimerHandle.ToSharedRef());
        }

        ActiveTimerHandle = RegisterActiveTimer(TickRate, FWidgetActiveTimerDelegate::CreateSP(this, &SProgressBarEx::ActiveTick));
    }
}


EActiveTimerReturnType SProgressBarEx::ActiveTick(double InCurrentTime, float InDeltaTime)
{
    MarqueeOffset = InCurrentTime - FMath::FloorToDouble(InCurrentTime);

    TOptional<float> TargetPercentFraction = TargetPercent.Get();
    if (TargetPercentFraction.IsSet())
    {
        SetActiveTimerTickRate(MinimumTickRate);
    }
    else
    {
        SetActiveTimerTickRate(0.0f);
    }

    return EActiveTimerReturnType::Continue;
}

这个是一个多层进度条的Slate控件,紧接着要为他写个Slate样式。

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

#pragma once

#include "SlateWidgetStyleContainerBase.h"
#include "SlateWidgetStyle.h"
#include "SlateBasics.h"
#include "ProgressBarExStyle.generated.h"


/**
 * Represents the appearance of an SProgressBarEx
 */
USTRUCT(BlueprintType)
struct TESTMOBILE_API FProgressBarExStyle : public FSlateWidgetStyle
{
    GENERATED_USTRUCT_BODY()

    FProgressBarExStyle();

    virtual ~FProgressBarExStyle() {}

    virtual void GetResources( TArray< const FSlateBrush* >& OutBrushes ) const override;

    static const FName TypeName;
    virtual const FName GetTypeName() const override { return TypeName; };

    static const FProgressBarExStyle& GetDefault();

    /** Background image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush BackgroundImage;
    FProgressBarExStyle& SetBackgroundImage( const FSlateBrush& InBackgroundImage ){ BackgroundImage = InBackgroundImage; return *this; }

    /** Increase image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush IncreaseImage;
    FProgressBarExStyle& SetIncreaseImage( const FSlateBrush& InIncreaseImage ){ IncreaseImage = InIncreaseImage; return *this; }

    /** Decrease image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush DecreaseImage;
    FProgressBarExStyle& SetDecreaseImage( const FSlateBrush& InDecreaseImage ){ DecreaseImage = InDecreaseImage; return *this; }

    /** Foreground image to use for the progress bar */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush FillImage;
    FProgressBarExStyle& SetFillImage( const FSlateBrush& InFillImage ){ FillImage = InFillImage; return *this; }

    /** Image to use for marquee mode */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Appearance)
    FSlateBrush MarqueeImage;
    FProgressBarExStyle& SetMarqueeImage( const FSlateBrush& InMarqueeImage ){ MarqueeImage = InMarqueeImage; return *this; }
};
  • ProgressBarExStyle.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "TestMobile.h"
#include "ProgressBarExStyle.h"

FProgressBarExStyle::FProgressBarExStyle()
{
}

void FProgressBarExStyle::GetResources( TArray< const FSlateBrush* >& OutBrushes ) const
{
    OutBrushes.Add( &BackgroundImage );
    OutBrushes.Add( &IncreaseImage );
    OutBrushes.Add( &DecreaseImage );
    OutBrushes.Add( &FillImage );
    OutBrushes.Add( &MarqueeImage );
}

const FName FProgressBarExStyle::TypeName( TEXT("FProgressBarExStyle") );

const FProgressBarExStyle& FProgressBarExStyle::GetDefault()
{
    static FProgressBarExStyle Default;
    return Default;
}

到此我们就结束了Slate控件的编写,只是写了个基本的多层进度条。


添加到UMG编辑器中

首先需要给样式加上一个基础容器,并且要反射给UMG的编辑器

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

#pragma once

#include "Styling/SlateWidgetStyleContainerBase.h"
#include "UI/Slate/ProgressBarExStyle.h"
#include "ProgressExWidgetStyle.generated.h"

/**
 * 
 */
UCLASS(BlueprintType, hidecategories=Object, MinimalAPI)
class UProgressExWidgetStyle : public USlateWidgetStyleContainerBase
{
    GENERATED_BODY()

public:

    /** The actual data describing the button's appearance. */
    UPROPERTY(Category="Style", EditAnywhere, BlueprintReadWrite, meta=(ShowOnlyInnerProperties))
    FProgressBarExStyle ProgressBarExStyle;
    
    virtual const struct FSlateWidgetStyle* const GetStyle() const override
    {
        return static_cast< const struct FSlateWidgetStyle* >( &ProgressBarExStyle );
    }
};

然后要让编辑器能看到我们的Slate控件:

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

#pragma once

#include "Widget.h"
#include "ProgressExWidgetStyle.h"
#include "UI/Slate/SProgressBarEx.h"
#include "ProgressBarEx.generated.h"

class USlateBrushAsset;

/**
 *  ProgressBarEx
 */
UCLASS()
class TESTMOBILE_API UProgressBarEx : public UWidget
{
    GENERATED_BODY()

public:

    /** The progress bar ex default setting */
    UProgressBarEx(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
    
    /** The progress bar ex style */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Style", meta=( DisplayName="Style" ))
    FProgressBarExStyle WidgetStyle;

    /** Style used for the progress bar */
    UPROPERTY()
    USlateWidgetStyleAsset* Style_DEPRECATED;

    /** The brush to use as the background of the progress bar */
    UPROPERTY()
    USlateBrushAsset* BackgroundImage_DEPRECATED;

    /** The brush to use as the increase image of the progress bar */
    UPROPERTY()
    USlateBrushAsset* IncreaseImage_DEPRECATED;

    /** The brush to use as the decrease image of the progress bar */
    UPROPERTY()
    USlateBrushAsset* DecreaseImage_DEPRECATED;

    /** The brush to use as the fill image */
    UPROPERTY()
    USlateBrushAsset* FillImage_DEPRECATED;

    /** The brush to use as the marquee image */
    UPROPERTY()
    USlateBrushAsset* MarqueeImage_DEPRECATED;

    /** Used to determine the fill position of the progress bar ranging 0..1 */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress, meta=( UIMin = "0", UIMax = "1" ))
    float Percent;

    /** Defines if this progress bar fills Left to right or right to left */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress)
    TEnumAsByte<EProgressBarExFillType::Type> BarFillType;
    
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Progress)
    bool bIsMarquee;

    /** A bindable delegate to allow logic to drive the text of the widget */
    UPROPERTY()
    FGetFloat PercentDelegate;

    /** Fill Color and Opacity */
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Appearance)
    FLinearColor FillColorAndOpacity;

    /** */
    UPROPERTY()
    FGetLinearColor FillColorAndOpacityDelegate;
    
public:
    
    /** Sets the current value of the ProgressBar. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetPercent(float InPercent);

    /** Sets the fill color of the progress bar. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetFillColorAndOpacity(FLinearColor InColor);

    /** Sets the progress bar to show as a marquee. */
    UFUNCTION(BlueprintCallable, Category="Progress")
    void SetIsMarquee(bool InbIsMarquee);

    //TODO UMG Add Set BarFillType.

public:

    //~ Begin UWidget Interface
    virtual void SynchronizeProperties() override;
    //~ End UWidget Interface

    //~ Begin UVisual Interface
    virtual void ReleaseSlateResources(bool bReleaseChildren) override;
    //~ End UVisual Interface

    //~ Begin UObject Interface
    virtual void PostLoad() override;
    //~ End UObject Interface

#if WITH_EDITOR

    //~ Begin UWidget Interface
    virtual const FText GetPaletteCategory() override;
    virtual void OnCreationFromPalette() override;
    //~ End UWidget Interface

#endif

protected:

    /** Native Slate Widget */
    TSharedPtr<SProgressBarEx> MyProgressBar;

    //~ Begin UWidget Interface
    virtual TSharedRef<SWidget> RebuildWidget() override;
    //~ End UWidget Interface
};

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

#include "TestMobile.h"
#include "UMG.h"
#include "UMGStyle.h"
#include "Slate/SlateBrushAsset.h"
#include "ProgressBarEx.h"

#define LOCTEXT_NAMESPACE "UMG"

/////////////////////////////////////////////////////
// UProgressBarEx

UProgressBarEx::UProgressBarEx(const FObjectInitializer& ObjectInitializer /*= FObjectInitializer::Get()*/)
    : Super(ObjectInitializer)
{
    // SProgressBarEx::FArguments SlateDefaults;
    // WidgetStyle = *SlateDefaults._Style;
    // WidgetStyle = FMenuStyles::Get().GetWidgetStyle<FProgressBarExStyle>("HPBarStyle");
    // WidgetStyle.FillImage.TintColor = FLinearColor::White;
    
    BarFillType = EProgressBarExFillType::LeftToRight;
    bIsMarquee = false;
    Percent = 0;
    FillColorAndOpacity = FLinearColor::White;
}


void UProgressBarEx::SetIsMarquee(bool InbIsMarquee)
{
    bIsMarquee = InbIsMarquee;
    if ( MyProgressBar.IsValid() )
    {
        MyProgressBar->SetPercent(bIsMarquee ? TOptional<float>() : Percent);
    }
}

void UProgressBarEx::SetFillColorAndOpacity(FLinearColor Color)
{
    FillColorAndOpacity = Color;
    if (MyProgressBar.IsValid())
    {
        MyProgressBar->SetFillColorAndOpacity(FillColorAndOpacity);
    }
}

void UProgressBarEx::SetPercent(float InPercent)
{
    Percent = InPercent;
    if ( MyProgressBar.IsValid() )
    {
        MyProgressBar->SetPercent(InPercent);
    }
}


void UProgressBarEx::SynchronizeProperties()
{
    Super::SynchronizeProperties();

    TAttribute< TOptional<float> > PercentBinding = OPTIONAL_BINDING_CONVERT(float, Percent, TOptional<float>, ConvertFloatToOptionalFloat);
    TAttribute<FSlateColor> FillColorAndOpacityBinding = OPTIONAL_BINDING(FSlateColor, FillColorAndOpacity);


    // MyProgressBar->SetStyle(&WidgetStyle);

    SProgressBarEx::FArguments SlateDefaults;
    MyProgressBar->SetBackgroundImage(SlateDefaults._BackgroundImage);
    MyProgressBar->SetIncreaseImage(SlateDefaults._IncreaseImage);
    MyProgressBar->SetDecreaseImage(SlateDefaults._DecreaseImage);
    MyProgressBar->SetFillImage(SlateDefaults._FillImage);
    MyProgressBar->SetMarqueeImage(SlateDefaults._MarqueeImage);

    MyProgressBar->SetStyle(&WidgetStyle);

    MyProgressBar->SetBarFillType(BarFillType);
    MyProgressBar->SetPercent(bIsMarquee ? TOptional<float>() : PercentBinding);
    MyProgressBar->SetFillColorAndOpacity(FillColorAndOpacityBinding);
}

void UProgressBarEx::PostLoad()
{
    Super::PostLoad();

    if ( GetLinkerUE4Version() < VER_UE4_DEPRECATE_UMG_STYLE_ASSETS )
    {
        if ( Style_DEPRECATED != nullptr )
        {
            const FProgressBarExStyle* StylePtr = Style_DEPRECATED->GetStyle<FProgressBarExStyle>();
            if ( StylePtr != nullptr )
            {
                WidgetStyle = *StylePtr;
            }

            Style_DEPRECATED = nullptr;
        }

        if ( BackgroundImage_DEPRECATED != nullptr )
        {
            WidgetStyle.BackgroundImage = BackgroundImage_DEPRECATED->Brush;
            BackgroundImage_DEPRECATED = nullptr;
        }

        if ( IncreaseImage_DEPRECATED != nullptr )
        {
            WidgetStyle.IncreaseImage = IncreaseImage_DEPRECATED->Brush;
            IncreaseImage_DEPRECATED = nullptr;
        }

        if ( DecreaseImage_DEPRECATED != nullptr )
        {
            WidgetStyle.DecreaseImage = DecreaseImage_DEPRECATED->Brush;
            DecreaseImage_DEPRECATED = nullptr;
        }

        if ( FillImage_DEPRECATED != nullptr )
        {
            WidgetStyle.FillImage = FillImage_DEPRECATED->Brush;
            FillImage_DEPRECATED = nullptr;
        }

        if ( MarqueeImage_DEPRECATED != nullptr )
        {
            WidgetStyle.MarqueeImage = MarqueeImage_DEPRECATED->Brush;
            MarqueeImage_DEPRECATED = nullptr;
        }
    }
}


void UProgressBarEx::ReleaseSlateResources(bool bReleaseChildren)
{
    Super::ReleaseSlateResources(bReleaseChildren);

    MyProgressBar.Reset();
}


TSharedRef<SWidget> UProgressBarEx::RebuildWidget()
{
    MyProgressBar = SNew(SProgressBarEx)
        .BorderPadding(FVector2D(0.0f, 0.0f));

    return MyProgressBar.ToSharedRef();
}


#if WITH_EDITOR

const FText UProgressBarEx::GetPaletteCategory()
{
    return LOCTEXT("Common", "Common");
}

void UProgressBarEx::OnCreationFromPalette()
{
    FillColorAndOpacity = FLinearColor(0, 0.5f, 1.0f);
}

#endif


/////////////////////////////////////////////////////

#undef LOCTEXT_NAMESPACE

其中RebuildWidgetSynchronizeProperties函数很重要。

编译代码后,打开UMG的编辑器,你会发现Common组件下多了一个Progress Bar Ex的控件:

自定义Slate控件

unreal

阅读数 239

没有更多推荐了,返回首页