2015-07-02 19:38:32 Neil3D 阅读数 3969
  • 从这里开始虚幻4-Editor介绍 v4.18

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

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


Unreal Engine 4发布好长好长时间了,直到最近才有时间仔细去看一下。

TimSweeney老大一句话“IF YOU LOVE SOMETHING, SET IT FREE”,原来需要几十万授权金才能拿到的东西,就从$19,变成免费了,而且开源。作为一个国际顶尖的引擎,能走出这一步,对我等普通开发者真是福音啊。如此的牛X,再加上开源,相信Unreal Engine 4会火起来的,你看看最近E3上的产品展示也能感觉到。不过,Unreal的定位毕竟是“国际顶尖”,而非Unity3D那样的“开发大众化”,所以上手是有一定难度的。

下面我把对Unreal Engine 4的初步印象总结一下,特别针对像我一样有Unreal Engine 3的同学,希望更多的同学来已经学习Unreal。


UnrealScript去掉了

开发语言上最大的变化,莫过于把UnrealScript去掉了。
UnrealScript吧,当年来看还是一个非常NB的东西,要知道Unreal一代发布是1998年的事儿,而JAVA语言也就是95年才发布的。据说Tim Sweeney在开始设计Unreal的时候曾经考虑过使用Java作为上层语言,不过那时候Java还不成熟,所以他参考Java,实现了这个一个面向对象的,单根继承的脚本语言。不过,随着时间流转,Epic似乎并没有花太大的力气去演进UnrealScript。在Unreal Engine 3的时代,它确实显得有点老旧了,书写起来比一些现代语言确实有很多不方便的地方。所以,去掉就去掉吧。不过,值得注意的是,官方也留出了整合其他脚本语言的接口,例如LUA。


C++11

底层很多基础代码看上去有很强的亲切感,底层架构设计思路沿用了许多。底层依然是使用C++,不过用了很多C++11的特性,代码看上去简洁了不少。
项目的编译、构建使用UnrealBuildTool,这应该是从3代延续过来;另外,就是增加了一个UnrealHeaderTool工具,猜想是根据UCLASS,UPROPERTY等宏,生成自定义反射信息用的,具体的还待进一步研究。


Blueprint Visual Scripting

据说这是UE4最牛X的改进了。看了看,原来是Kismet的延伸,连源代码很多都是UKismentXXX那一套。UE3里面的Kistmet只限于在一个关卡中使用,而Blueprint扩展了。关卡可以有唯一的一个Level Blueprint,相当于原来的Kismet;另外增加了Blueprint Class,大概就是用Blueprint创建自定义的Actor、Pown之类的,由于有了这个功能所以原来的Archetype顺带也就被替代了。其实,作为老一代屌丝Coder,我一直对Kismet那种表达式层级可视化编程,一直不太感冒(像Unity的PlayMaker那样,提供更高层级抽象的可视化工具更好)。不过,既然是UE4主推的个东东,还是得看看。
不过,总体上给Designer一套可视化编程的东西,让他们自己实现一些关卡逻辑、游戏规则之类的,还真是一个特别好的方法。当然,我们这些Coder的工作还是不会丢掉的,例如游戏框架,游戏一些底层功能、常用模块还是要C++写好(或者使用LUA脚本?),封装给Blueprint来使用的。


AnimTree哪去了

UE3的AnimTree给我震撼太大了,所以特别关心UE4的动画系统。看了一下,貌似被分解成了BlendSpace和AnimGraph。
  • BlendSpace
    好比说“站立、走、跑”这三个动作,在UE3的AnimTree里面是有一个特定的node来混合的,根据移动速度不同。在UE4里,则需要创建一个BlendSpace1D资源,然后暴露出Speed参数。
  • AnimBlueprint
    使用Blueprint,AnimGraph,状态机等等控制角色的动画,怎么看上去和Unity的Mecanim有点像呢,唉~
看来AnimTree是真的不见了,很遗憾,因为我觉得那个使用树形结构来抽象的动画系统,实在是非常清晰而且强大。

渲染系统

基于物理的渲染(PBR:Physically-Based Rendering)效果真的是太NB了,Unity5虽然也是PBR,好像比UE4还是略逊一筹啊!这个无需多言了,各种DEMO视频大家都看了不少了。渲染流程也完全走延迟渲染了。但多线程渲染,SceneProxy、Material之类的基础架构没怎么变。

Behavior Tree

这个东西好像在国外的游戏AI领域这几年挺流行了,是个很高大上的东西,UE4直接做了,太好了。

另外,还有很多重大改进,例如Package,资源导入,增加插件支持等,这里就不一一细说了。推荐看一下官网的文章吧,作为本文的补充偷笑

2016-11-05 20:21:54 kcetry 阅读数 1443
  • 从这里开始虚幻4-Editor介绍 v4.18

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

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

Unreal Engine

Welcome to the Unreal Engine source code!
欢迎来到 Unreal Engine 源码的世界!

From this repository you can build the Unreal Editor for Windows and Mac, compile Unreal Engine games for Android, iOS, Playstation 4, Xbox One, HTML5 and Linux,
and build tools like Unreal Lightmass and Unreal Frontend. Modify them in any way you can imagine, and share your changes with others!
在这个源码仓库里,你可以编译出Windows,Mac平台下的Unreal编辑器,并且可以编译出运行在Android,iOS,Playstation 4,Xbox One,HTML5和Linux下的游戏,也可以编译出Unreal Lightmass和Unreal Frontend等工具。

We have a heap of documentation available for the engine on the web. If you’re looking for the answer to something, you may want to start here:
在网站上,我们有大量的可利用的文档,如果你在寻找某些事情的答案,你可能希望从这里开始

If you need more, just ask! A lot of Epic developers hang out on the forums or AnswerHub,
and we’re proud to be part of a well-meaning, friendly and welcoming community of thousands.
如果你需要更多帮助,开口就是了! 许多Epic的开发者都会逛逛论坛或者AnswerHub,我们非常荣幸成为了有善意,友好,热情社区的一员。

Branches

分支

We publish source for the engine in three rolling branches:
我们发布的引擎源码有三个滚动的分支

The release branch is extensively tested by our QA team and makes a great starting point for learning the engine or
making your own games. We work hard to make releases stable and reliable, and aim to publish new releases every few months.
正式版分支经过我们QA团队大量测试,并且为学习引擎和制作个人游戏打造了一个良好的起点。我们为正式版的稳定可靠而努力,目标是每隔几个月就发布新的版本。

The promoted branch is updated with builds for our artists and designers to use. We try to update it daily
(though we often catch things that prevent us from doing so) and it’s a good balance between getting the latest cool stuff and knowing most things work.
升级版分支为我们的艺术家和设计者的使用而更新。我们努力做到每天更新(尽管我们会遭遇各种阻力),它是在获得最新功能和了解工作原理之间一个良好的平衡点。

The master branch tracks live changes by our engine team.
This is the cutting edge and may be buggy - it may not even compile. Battle-hardened developers eager to work lock-step with us on the latest and greatest should head here.
主分支记录了我们团队的实时改动,最前沿并且可能有许多bug,它甚至不能编译通过,老练的开发者急切想和我们一起同步工作,最新和最优秀的变化在这里。

Other short-lived branches may pop-up from time to time as we stabilize new releases or hotfixes.
当我们让新的正式版或补丁变得稳定时,其它短暂的分支可能会偶尔出现。

Getting up and running

启动并运行

The steps below will take you through cloning your own private fork, then compiling and running the editor yourself:
以下步骤将会带你亲自克隆出你私人分支,然后编译并运行编辑器。

Windows

  1. Install GitHub for Windows then fork and clone our repository.
    To use Git from the command line, see the Setting up Git and Fork a Repo articles.
    安装 GitHub for Windows 然后新建分支并clone我们的仓库。在命令行使用Git请参见Git安装和新建分支等文章。

    If you’d prefer not to use Git, you can get the source with the ‘Download ZIP’ button on the right. The built-in Windows zip utility will mark the contents of zip files
    downloaded from the Internet as unsafe to execute, so right-click the zip file and select ‘Properties…’ and ‘Unblock’ before decompressing it. Third-party zip utilities don’t normally do this.
    如果你不喜欢使用Git,你可以从右侧的’Download ZIP’按钮下载源码。Windows内置的zip程序将会标记zip文件的内容。执行从Internet下载的文件并不安全,所以在你解压前,建议右键zip文件并选择’属性’ 然后’解锁’。第三方zip程序通常不需要这么做。

  2. Install Visual Studio 2015.
    安装Visual Studio 2015

    All desktop editions of Visual Studio 2015 can build UE4, including Visual Studio Community 2015, which is free for small teams and individual developers.
    Be sure to include C++ support as part of the install, which is disabled by default.
    所有Visual Studio 2015的桌面版都可以编译UE4,包括Visual Studio Community 2015,小型团队和独立开发者可以免费使用该版本。
    在安装时请确保添加C++的支持,默认是不支持的。

  3. Open your source folder in Explorer and run Setup.bat.
    This will download binary content for the engine, as well as installing prerequisites and setting up Unreal file associations.
    On Windows 8, a warning from SmartScreen may appear. Click “More info”, then “Run anyway” to continue.
    打开源码文件夹并运行Setup.bat。这将会下载引擎的二进制内容,同时会安装依赖的文件并且设置Unreal文件关联。
    在Windows 8,可能会一个警告从小窗口弹出来,点击“更多信息”,然后点击“无论如何都运行”并继续。

    A clean download of the engine binaries is currently 3-4gb, which may take some time to complete.
    Subsequent checkouts only require incremental downloads and will be much quicker.
    目前下载的纯净的引擎源码大概3-4gb,将会花一些时间来完善它。随后的文件校验将会随着下载进行,这将会加快下载速度。

  4. Run GenerateProjectFiles.bat to create project files for the engine. It should take less than a minute to complete.
    运行GenerateProjectFiles.bat来创建项目文件,这不会超过1分钟。

  5. Load the project into Visual Studio by double-clicking on the UE4.sln file. Set your solution configuration to Development Editor and your solution
    platform to Win64, then right click on the UE4 target and select Build. It may take anywhere between 10 and 40 minutes to finish compiling, depending on your system specs.
    通过双击UE4.sln加载项目到Visual Studio。设置你的方案配置为Development Editor,目标平台为Win64,然后右键UE4项目,选择编译。这会花费10-40分钟,取决于你的系统配置。

  6. After compiling finishes, you can load the editor from Visual Studio by setting your startup project to UE4 and pressing F5 to debug.
    完成编译后,你可以通过设置启动项目为UE4来启动编辑器,F5调试。

Mac

  1. Install GitHub for Mac then fork and clone our repository.
    To use Git from the Terminal, see the Setting up Git and Fork a Repo articles.
    If you’d rather not use Git, use the ‘Download ZIP’ button on the right to get the source directly.
    安装 GitHub for Mac 然后新建分支并clone我们的仓库。在命令行使用Git请参见Git安装和新建分支等文章。如果你不喜欢使用Git,可以从右侧的‘Download ZIP’按钮直接下载源码。

  2. Install the latest version of Xcode.
    安装最新版的Xcode

  3. Open your source folder in Finder and double-click on Setup.command to download binary content for the engine. You can close the Terminal window afterwards.
    打开源码所在的文件夹,双击Setup.command下载引擎相关的二进制内容,然后你可以关闭终端。

    If you downloaded the source as a .zip file, you may see a warning about it being from an unidentified developer (because .zip files on GitHub aren’t digitally signed).
    To work around it, right-click on Setup.command, select Open, then click the Open button.
    如果你下载的是zip文件,你可能会看到关于来自身份不明开发商的警告(因为GitHub的zip文件没有经过数字签名)

  4. In the same folder, double-click GenerateProjectFiles.command. It should take less than a minute to complete.
    在该目录下,双击GenerateProjectFiles.command。执行完成应该不会超过一分钟。

  5. Load the project into Xcode by double-clicking on the UE4.xcworkspace file. Select the ShaderCompileWorker for My Mac target in the title bar,
    then select the ‘Product > Build’ menu item. When Xcode finishes building, do the same for the UE4 for My Mac target. Compiling may take anywhere between 15 and 40 minutes, depending on your system specs.
    双击UE4.xcworkspace加载项目到Xcode,在标题栏选择ShaderCompileWorker为My Mac。
    然后选择 ‘产品 > 编译’ 菜单项。当Xcode完成编译,同样选择UE4为 ‘My Mac’

  6. After compiling finishes, select the ‘Product > Run’ menu item to load the editor.
    完成编译后,选择’产品 > 运行’启动编辑器。

Linux

  1. Set up Git and fork our repository.
    If you’d prefer not to use Git, use the ‘Download ZIP’ button on the right to get the source as a zip file.
    安装Git并fork我们的仓库。如果你不喜欢使用Git,可以从右侧的‘Download ZIP’按钮直接下载源码。

  2. Open your source folder and run Setup.sh to download binary content for the engine.
    打开源码所在文件夹并运行Setup.sh下载引擎相关的二进制内容。

  3. Both cross-compiling and native builds are supported.
    同时支持跨平台编译和本地编译。

    Cross-compiling is handy when you are a Windows (Mac support planned too) developer who wants to package your game for Linux with minimal hassle, and it requires a cross-compiler toolchain to be installed (see the Linux cross-compiling page on the wiki).
    如果你是Windows开发者(Mac也即将支持),并且想快捷打包可在linux运行的游戏的话,跨平台编译是非常方便的,它需要安装跨平台编译工具链(参见Linux cross-compiling page on the wiki)。

    Native compilation is discussed in a separate README and community wiki page.
    本地编译的方法位于单独的README文件和community wiki page中。

Additional target platforms

其它的目标平台

Android support will be downloaded by the setup script if you have the Android NDK installed. See the Android getting started guide.
如果你安装了Android NDK,Android平台的支持将会通过安装脚本下载,参见Android入门指南。

iOS programming requires a Mac. Instructions are in the iOS getting started guide.
iOS编程需要一台Mac。相关的步骤在iOS入门指南里面。

HTML5 support will be downloaded by the setup script if you have Emscripten installed. Please see the HTML5 getting started guide.
如果你安装了Emscripten,HTML5的支持将会通过安装脚本下载。请参见HTML5入门指南。

Playstation 4 or XboxOne development require additional files that can only be provided after your registered developer status is confirmed by Sony or Microsoft. See the announcement blog post for more information.
Playstation 4 或者 XboxOne 的开发需要额外的文件,只有当Sony或者微软确认你的开发者身份后才能被下载。更多信息请参见博客上传声明。

Licensing and Contributions

许可和贡献

Your access to and use of Unreal Engine on GitHub is governed by the Unreal Engine End User License Agreement. If you don’t agree to those terms, as amended from time to time, you are not permitted to access or use Unreal Engine.
在GitHub获取Unreal Engine以及使用表明你接受Unreal Engine最终用户许可协议。如果不同意这些条款,当你偶然修改了源码后,将不被允许获取和使用Unreal Engine。

We welcome any contributions to Unreal Engine development through pull requests on GitHub. Most of our active development is in the master branch, so we prefer to take pull requests there (particularly for new features). We try to make sure that all new code adheres to the Epic coding standards. All contributions are governed by the terms of the EULA.
我们欢迎任何提交pull请求,为Unreal Engine的开发作出贡献。我们大多数活跃的开发工作都在主分支,所以我们更乐意在这里接受你的pull请求(特别是新特性)。我们努力确保所有的新代码都遵循Epic编程标准。所有的贡献受EULA团队管辖。

Additional Notes

注意事项

The first time you start the editor from a fresh source build, you may experience long load times.
The engine is optimizing content for your platform to the derived data cache, and it should only happen once.
当你第一次运行编译自干净源码的编辑器时,你可能经历较长的加载时间

Your private forks of the Unreal Engine code are associated with your GitHub account permissions.
If you unsubscribe or switch GitHub user names, you’ll need to re-fork and upload your changes from a local copy.
你的Unreal Engine私人分支已经和你的GitHub账户的权限相关联。如果你取消关联或者切换了GitHub的用户名,你将需要重新建立分支并且从你的本地备份上传你的更改。

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

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

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

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控件

2019-03-10 15:32:47 zjq709918448 阅读数 414
  • 从这里开始虚幻4-Editor介绍 v4.18

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

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

Unreal Engine 4简介

一、什么是虚幻引擎(Unreal Engine 4)?

虚幻引擎4是由全球顶级游戏EPIC公司虚幻引擎的最新版本。是一个面向下一代游戏机和DirectX 9个人电脑的完整的游戏开发平台,提供了游戏开发者需要的大量的核心技术、数据生成工具和基础支持。

二、什么是Unreal Engine编程?

“用Unreal Engine制作游戏”时,有两大必不可少的部分。


一是“制作3D游戏场景”。Unreal Engine中,为我们准备了可以高度渲染3D图形的工具,运用这些功能就可以制作逼真唯美的3D游戏场景。但仅凭这个是做不出游戏的。


制作游戏还有一个必不可少的重要操作,那就是“编程”。Unreal Engine软件包含了显是3D图形和让3D图形动起来的各项功能。

三、Unreal Engine编程的形式

Unreal Engine编程可以被分为两部分,分别是C++和蓝图。

  • C++

C++作为一种规范的编程语言被广泛使用,它以C语言为基础并大大强化了其功能,应用于应用程序开发等这种对编程要求较高的领域。
很多熟悉C++的程序员可以很快地投入开发,但对于没有编程经验的工作人员来说,直接上手C++恐怕会比较艰难。但不用担心,Unreal Engine还为开发者准备了另一种更直观地编程形式,让使用者能够轻松上手。

  • 蓝图

蓝图是Unreal Engine中的一种可视化语言。它事先将各种可执行的处理以“节点”的形式创建,然后只需要用鼠标拖拽将其排列、连接就可以实现编程。
蓝图是从Unreal Engine 4起搭载的一种非常新的功能,Unreal Engine的开发者也将蓝图和C++并列定位为开发的两大支柱。所以,不必抱有“蓝图只能实现简单的内容吧”这样的担心哦。

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

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

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

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。

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


圆柱体在游戏中来回移动

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











Unreal Engine 4切换默认Camera实现

博文 来自: shangguanwaner
没有更多推荐了,返回首页