[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"page-UMG-1":3,"page-count-UMG":662},[4,204,371,457,545],{"id":5,"title":6,"body":7,"date":180,"description":13,"extension":181,"meta":182,"navigation":185,"path":197,"seo":198,"stem":199,"tags":200,"__hash__":203},"blogs\u002F_legacy\u002F2018\u002F2018-02-26-ue4-note-2018-01.md","UE4年初笔记汇总",{"type":8,"value":9,"toc":170},"minimark",[10,14,17,20,25,28,31,34,37,40,51,54,60,63,70,74,77,80,83,86,92,95,98,101,105,108,112,115,118,124,127,133,136,139,142,145,150,153,156,167],[11,12,13],"p",{},"18年转眼马上过去两个月了，却有种还什么都没有做的感觉呢。",[11,15,16],{},"这里是最近的一些记录内容，由于比较零碎细小，干脆就合在一起了。",[11,18,19],{},"使用的UE4版本为UE4.15。",[21,22,24],"h2",{"id":23},"widgetbind","WidgetBind",[11,26,27],{},"这个是一个Meta，在UMG的数据绑定时很有用。",[11,29,30],{},"虽然UMG的逻辑大部分可以在蓝图中完成，而且控件也有自己的UPROPERTY和UFUNCTION绑定机制。",[11,32,33],{},"但是在需要进行复杂的UI逻辑编写时还是会需要在代码中进行控制。",[11,35,36],{},"这个时候就会遇到需要对应的UMG控件的指针的问题，虽然可以通过事先定义的UPROPERTY指针然后再在蓝图中进行赋值等一些方法进行。但在使用上多少会有不便之处。",[11,38,39],{},"其实，UE4内部是有提供方便这种情况的Meta方便使用的：",[41,42,47],"pre",{"className":43,"code":45,"language":46},[44],"language-text","UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (BindWidget))\nUImage* ImgBinded;\n","text",[48,49,45],"code",{"__ignoreMap":50},"",[11,52,53],{},"只要这样定义了之后，再做继承了的蓝图中拉出目标控件然后命名为ImgBinded就可以了。同时也可以将控件指定为可选的，例如：",[41,55,58],{"className":56,"code":57,"language":46},[44],"UPROPERTY(meta=(BindWidget, OptionalWidget=true))\n",[48,59,57],{"__ignoreMap":50},[11,61,62],{},"如果不指定为可选又没有在蓝图中添加对应名称的控件的话，就会报错",[11,64,65],{},[66,67],"img",{"alt":68,"src":69},"image","\u002Fwp-content\u002Fuploads\u002F2018\u002F02\u002Fimage_thumb.png",[21,71,73],{"id":72},"console","Console",[11,75,76],{},"这个也是最近遇到的麻烦，当程序的业务逻辑越来越复杂，往往会多出很多功能上的限制，导致在测试时遇到麻烦。",[11,78,79],{},"每次都要额外的添加测试UI，将一些C++函数暴露到蓝图，最后测试功能就一片混乱了。此时就可以添加一些Console来方便在编辑器中调试，由于Shipping模式默认是没有Console的，也不用担心一不小心测试代码被放到终端用户手中的尴尬情况。",[11,81,82],{},"同时，将Console代码进行一定程度的管理，也可以方便将调试功能整合在一起，避免不必要的混乱。",[11,84,85],{},"UE4的Console系统非常的易于扩展，使用起来也没有什么副作用：",[41,87,90],{"className":88,"code":89,"language":46},[44],"void HandleDbNextMap()\n{\n    \u002F** \u003C一些调试功能 *\u002F;\n}\n\nstatic FAutoConsoleCommand CVarDbGoNext(\n    TEXT(\"db.map.jmp\"),\u002F** \u003CConsole的指令 *\u002F\n    TEXT(\"Jump to nextmap\\n\"),\u002F** \u003C显示的帮助信息 *\u002F\n    FConsoleCommandDelegate::CreateStatic(&HandleDbNextMap)\n);\n",[48,91,89],{"__ignoreMap":50},[11,93,94],{},"使用UE4提供的帮助类，能够非常快速的定义Console指令。ConsoleCommand的使用和通常的Delegate是一样的，添加上面的代码后。",[11,96,97],{},"就可以在Console中输入db.map.jmp来使用了。",[11,99,100],{},"对于需要输入参数的情况，其实FAutoConsoleCommand还有其他的变体是可以携带参数的，详情可以参考其定义。",[21,102,104],{"id":103},"media-frame-work","Media Frame Work",[11,106,107],{},"UE4默认使用WMF在Windows上进行视频播放的操作，但是在使用上还是会有些细节的部分。",[109,110,111],"h3",{"id":111},"二次播放杂音",[11,113,114],{},"这个Bug一般是自己使用C++进行播放控制时容易出现，使用蓝图进行播放时没有遇到这个问题。",[11,116,117],{},"问题在于，MediaPlayer的声音播放并不会自动的跟随MediaPlayer的停止、播放、重新开启操作被控制，虽然表面上声音的播放确实停止了，但是重新开始播放声音的话就会出现状态重置不明确的问题，因此需要自己对事件进行绑定会进行控制。",[41,119,122],{"className":120,"code":121,"language":46},[44],"void UStreamPlayer::HandleMediaPlayerMediaEvent(EMediaEvent Event)\n{\n    if ((AudioComponent == nullptr) \u002F*|| !CurrentSoundWave.IsValid()*\u002F)\n    {\n        return;\n    }\n\n    switch (Event)\n    {\n    case EMediaEvent::PlaybackEndReached:\n    case EMediaEvent::PlaybackSuspended:\n        AudioComponent->Stop();\n        break;\n    case EMediaEvent::PlaybackResumed:\n        AudioComponent->Play();\n        break;\n    }\n}\n",[48,123,121],{"__ignoreMap":50},[11,125,126],{},"然后找一个时机绑定到MediaPlayer上去就可以了",[41,128,131],{"className":129,"code":130,"language":46},[44],"m_pMediaPlayer->OnMediaEvent().AddUObject(this, &UStreamPlayer::HandleMediaPlayerMediaEvent);\n",[48,132,130],{"__ignoreMap":50},[11,134,135],{},"这个是在4.15上遇到的，记得之后的版本更新中MediaPlayer有过改动，不知是不是就没有这样的问题了。",[109,137,138],{"id":138},"打包后无法播放",[11,140,141],{},"首先要检查的是打包时对应的视频文件有没有被拷贝到发布目录中，由于UE4打包的时候只会对进行了链接注册的资源进行打包，所以如果视频文件没有被蓝图或者C++显式的引用的话，并不会被自动拷贝到发布目录中去。",[11,143,144],{},"所以需要在打包设置中进行设置，保证视频目录中的视频都被拷贝到了发行版中。",[11,146,147],{},[66,148],{"alt":68,"src":149},"\u002Fwp-content\u002Fuploads\u002F2018\u002F02\u002Fadditional-pack.jpg",[11,151,152],{},"当然，也可以手动将资源拷贝到对应的目录中去，不过这样不方便管理，容易忘记……",[11,154,155],{},"另外就是要检查系统本身的Wmf相关的设定了，最主要就是检查下WindowsMediaPlayer能否正常的播放视频，因为wmp和ue4一样都依赖wmf进行视频播放，所以容易排查问题。主要是有的Ghost的系统会有不必要的精简，导致wmf功能不正常。",[11,157,158,159,166],{},"如果你使用的是最新版本的引擎的话，也可以考虑社区提供的[",[160,161,165],"a",{"href":162,"rel":163},"https:\u002F\u002Fgithub.com\u002Fue4plugins\u002FVlcMedia",[164],"nofollow","VlcMedia","]的插件，经过测试4.18版本下工作很正常，不过由于这边使用的是4.15版本，就没有办法了呢。",[11,168,169],{},"同时Vlc还支持更多的播放格式和方式，例如Vlc是支持m3u8的，而wmf并不支持很多流播放的功能。",{"title":50,"searchDepth":171,"depth":172,"links":173},2,3,[174,175,176],{"id":23,"depth":171,"text":24},{"id":72,"depth":171,"text":73},{"id":103,"depth":171,"text":104,"children":177},[178,179],{"id":111,"depth":172,"text":111},{"id":138,"depth":172,"text":138},"2018-02-26","md",{"layout":183,"status":184,"published":185,"author":186,"author_login":188,"author_email":189,"wordpress_id":190,"wordpress_url":191,"date_gmt":192,"excerpt":193},"post","publish",true,{"display_name":187,"login":188,"email":189,"url":50},"风铃","flinkor","flinkor@foxmail.com",2264,"\u002F?p=2264","2018-02-25 16:00:00 +0000",{"type":8,"value":194},[195],[11,196,13],{},"\u002F2018-02-26-ue4-note-2018-01",{"title":6,"description":13},"_legacy\u002F2018\u002F2018-02-26-ue4-note-2018-01",[201,202],"UE4","UMG","MMR8srEpeInDZHJaVZNbZRX20WDch0GtTv8IohtGnOo",{"id":205,"title":206,"body":207,"date":355,"description":211,"extension":181,"meta":356,"navigation":185,"path":365,"seo":366,"stem":367,"tags":368,"__hash__":370},"blogs\u002F_legacy\u002F2018\u002F2018-01-01-ue4-project-notes.md","UE4项目笔记汇总",{"type":8,"value":208,"toc":344},[209,212,215,218,221,224,227,230,238,241,244,248,251,254,257,260,263,266,269,275,278,281,284,287,290,296,299,303,306,310,313,316,322,325,329,332,335,341],[11,210,211],{},"这里是过去一段与项目有关的笔记汇总，把一些零零碎碎的给合在了一起。",[11,213,214],{},"由于项目一直停留在4.15，所以本文所有内容都是基于UE4.15.3的。",[21,216,217],{"id":217},"物理相关",[11,219,220],{},"由于做的项目对运动的精度要求比较高，所以和物理打了很长一段时间的交道。",[11,222,223],{},"在用UE4之前基本没接触过3D的物理引擎。好在之前有用过Box2D，一些基本的物理引擎原理还是有些了解的。",[109,225,226],{"id":226},"球体运动",[11,228,229],{},"遇到的第一个问题是球体运动相关的，Physx对球体运动的模拟有些糟糕。",[11,231,232,233,237],{},"主要表现是Friction对球体的速度影响相当的微妙，导致球的运动很难停下来。而如果使用LinearDumping和AngularDumping来进行速度制御的话，由于其并不是匀减速的，而且即便与Friction没有关系，运动也不真实。这部分的解决方案之前已经记录在[",[160,234,236],{"href":235},"\u002F2017-05-03-ue4-physx-and-substepping\u002F","UE4中的Physx物理","]这篇文章中了，总之就是自己接管物理的部分运算。",[11,239,240],{},"更加区域的注册自己添加上摩擦力和反弹。途中遇到过很多问题，现在回头看的话，发现代码的实现还是不够简洁。",[11,242,243],{},"而且虽然一开始坚持想要存依靠公式来进行运动控制，但最后还是往里面添加了不少“黑魔法”……",[109,245,247],{"id":246},"foliage碰撞","Foliage碰撞",[11,249,250],{},"后面出现的一个需求是关于Foliage的碰撞的，总体而言就是需要树的不同部分表现出不同的碰撞特性。",[11,252,253],{},"比如树叶区域进行Overlap，而树干区域进行Block。但是由于Foliage本身是一种Instanced的Actor，UE4在实现时，对于同一个FoliageType只能使用一个碰撞配置。",[11,255,256],{},"不过Instance主要是针对渲染而进行的一种优化方案，既然Foliage是可以进行碰撞的，那么在Physx world中肯定是有注册碰撞形态的。",[11,258,259],{},"几经探索之后终于找到解决方案，通过UE4提供的Physx底层Api，将Foliage Type实例化之后的碰撞形态取出，单独将Capsule的碰撞形态重新注册到Physx中去。",[11,261,262],{},"这里本来是想直接对PxActor的碰撞配置进行修改的，但是UE4在上层有封装，无法将Overlap的物体的碰撞响应传递出去。所以只有采取取出重新注册的方案。",[11,264,265],{},"但是由于场景中的Foliage实在是太多，在地图载入时进行整体性操作会导致不可接受的时间消耗，最后采用动态转化的方案，将玩家周围的Foliage取出，并拉取出Capsule来实现。",[11,267,268],{},"这里面有遇到一个困扰了很久的问题，那就是Capsule取出之后怎么都无法找到正确的对应Roation。几经周折才发现UE4中的Capsule和Physx中的Capsule是有不同的默认朝向的，需要手动进行一次转化才行：",[41,270,273],{"className":271,"code":272,"language":46},[44],"static const PxQuat CapsuleRotator(0.f, 0.707106781f, 0.f, 0.707106781f);\n\nPxQuat ConvertToPhysXCapsuleRot(const FQuat& GeomRot)\n{\n  \u002F\u002F Rotation required because PhysX capsule points down X, we want it down Z\n  return U2PQuat(GeomRot) * CapsuleRotator;\n}\n\nFQuat ConvertToUECapsuleRot(const PxQuat & PGeomRot)\n{\n return P2UQuat(PGeomRot * CapsuleRotator.getConjugate());\n}\n",[48,274,272],{"__ignoreMap":50},[21,276,277],{"id":277},"屏幕偏移",[11,279,280],{},"就是要让FOV的计算有一个Offset，当时查了很多资料。只在AnswerHub找到一个旧版本的不是很完全的实现。",[11,282,283],{},"好在通过那个页面里的讨论找到了解决的方向，而不用自己深入到UE4的渲染代码中去找Hack Point。",[11,285,286],{},"最主要的问题是，讨论最后给出的Viewport的转换矩阵是错的，转换之后的结果并不能让人满意。UE4的渲染实现并不“标准”，所以使用通用的摄像投影矩阵还是无法实现类似视点中心偏移的效果。",[11,288,289],{},"最后终于在代码深处的BlendCamera中找到了UE4本身对视角偏移的处理，得出了“正确”的偏移矩阵",[41,291,294],{"className":292,"code":293,"language":46},[44],"\u002F** 计算投影矩阵 *\u002F\nfloat t_fRatio = InCamera->AspectRatio;\nif (!InCamera->bConstrainAspectRatio)\n{\n t_fRatio = t_ScreenSize.X \u002F t_ScreenSize.Y;\n}\n\nfloat t_fFov = InCamera->FieldOfView;\nfloat t_fNear = GNearClippingPlane;\n\nresult = FReversedZPerspectiveMatrix(t_fFov * PI \u002F 360.0f, t_fRatio, 1.0f, t_fNear);\n\nif (Offset.IsZero())\n{\n return true;\n}\n\n\u002F** 将Offset规范到百分比 *\u002F\nOffset.X \u002F= (t_ScreenSize.X \u002F 2.0f);\nOffset.Y \u002F= (t_ScreenSize.Y \u002F 2.0f);\n\n\u002F** Clamp以避免“过度”偏移 *\u002F\nOffset = FMath::Clamp(Offset, FVector2D(-1, -1), FVector2D(1, 1));\n\nconst float Left = -1.0f + Offset.X;\nconst float Right = Left + 2.0f;\nconst float Bottom = -1.0f + Offset.Y;\nconst float Top = Bottom + 2.0f;\n\nresult.M[2][0] = (Left + Right) \u002F (Left - Right);\nresult.M[2][1] = (Bottom + Top) \u002F (Bottom - Top);\n",[48,295,293],{"__ignoreMap":50},[11,297,298],{},"不过，当时由于实现的比较急切，直接沿用讨论的方向，对Viewport类进行了重载，也使用了一些“黑魔法，虽然至今没有观测到副作用，但是现在想来，其实还是有其他的解决方案的。",[21,300,302],{"id":301},"ui相关","UI相关",[11,304,305],{},"UMG只实现了默认的几种常见的Widget，所以有很多需要实现的自定义控件。这个也算是UI开发的常态了，但是当时有两个问题还是困扰了一段时间。",[109,307,309],{"id":308},"slate的序列帧","Slate的序列帧",[11,311,312],{},"UMG的序列帧实现在社区可以找到，但是当需要在LoadingScreen上播放序列帧时就会有麻烦。因为那个时候UMG系统还没有初始化完成，只能使用Slate。",[11,314,315],{},"在参考了UE4的进度条实现之后，找到了相关的接口：",[41,317,320],{"className":318,"code":319,"language":46},[44],"FVector2D Min(FrameSize.X * Column, FrameSize.Y * Row);\nFVector2D Max = Min + FrameSize;\nFBox2D UVCoordinates(Min \u002F TextureSize, Max \u002F TextureSize);\nUVCoordinates.bIsValid = true;\n\nBrush.SetUVRegion(MoveTemp(UVCoordinates));\n",[48,321,319],{"__ignoreMap":50},[11,323,324],{},"这样就可以实现序列帧的切换了。",[109,326,328],{"id":327},"_2d画线","2D画线",[11,330,331],{},"FSlateDrawElement::MakeLines有一个问题，那就是不知为何最后实现的时候Thickness这个参数是不起作用的。",[11,333,334],{},"因此要画粗线就必须自己想办法，虽然试过很多方法，包括参考UE4内部的线段AA实现，但是最后还是采用了最不优雅的解决方案：多画几次。",[41,336,339],{"className":337,"code":338,"language":46},[44],"FVector2D DrawPosition;\nfor (; aTimes > 0; --aTimes)\n{\n DrawPosition = FVector2D::ZeroVector;\n if (m_bIsVert) DrawPosition.Y = aTimes;\n else DrawPosition.X = aTimes;\n\n FSlateDrawElement::MakeLines(\n  InContext.OutDrawElements,\n  InContext.MaxLayer,\n  InContext.AllottedGeometry.ToPaintGeometry(DrawPosition, FVector2D(1.0f,1.0f), 1.0f),\n  tLine,\n  InContext.MyClippingRect,\n  ESlateDrawEffect::None,\n  color,\n  true,\n  0.1f);\n}\n",[48,340,338],{"__ignoreMap":50},[11,342,343],{},"因为这样画出来的才是最平滑的，好在对粗细的要求并不高，否则可能会加大绘制的负担。",{"title":50,"searchDepth":171,"depth":172,"links":345},[346,350,351],{"id":217,"depth":171,"text":217,"children":347},[348,349],{"id":226,"depth":172,"text":226},{"id":246,"depth":172,"text":247},{"id":277,"depth":171,"text":277},{"id":301,"depth":171,"text":302,"children":352},[353,354],{"id":308,"depth":172,"text":309},{"id":327,"depth":172,"text":328},"2018-01-01",{"layout":183,"status":184,"published":185,"author":357,"author_login":188,"author_email":189,"wordpress_id":358,"wordpress_url":359,"date_gmt":360,"excerpt":361},{"display_name":187,"login":188,"email":189,"url":50},2170,"\u002F\u002F?p=2170","2017-12-31 16:01:50 +0000",{"type":8,"value":362},[363],[11,364,211],{},"\u002F2018-01-01-ue4-project-notes",{"title":206,"description":211},"_legacy\u002F2018\u002F2018-01-01-ue4-project-notes",[201,202,369],"物理","8GIMwwB_ylWoPujHfm3zYlq3ZQOiZ_ohYp777ox0kVk",{"id":372,"title":373,"body":374,"date":438,"description":378,"extension":181,"meta":439,"navigation":185,"path":451,"seo":452,"stem":453,"tags":454,"__hash__":456},"blogs\u002F_legacy\u002F2015\u002F2015-09-11-uwidget-wrap-swidget-to-umg.md","UWidget封装SWidget到UMG",{"type":8,"value":375,"toc":436},[376,379,382,385,388,391,394,397,403,406,409,415,418,421,424,427,430,433],[11,377,378],{},"为了使用UMG中的一些高级或便利特性，需要将制作好的Slate控件封装到UWidget中去。",[11,380,381],{},"当前UE4版本4.8.3。",[11,383,384],{},"将Slate封装到UMG中去有很多的好处，因为在代码中对需要重用的控件进行不断的重新布局是一件非常繁琐的事情。同时，UMG也有在3D空间中进行显示这样的高级功能。",[11,386,387],{},"由于UMG本身就是对Slate的封装，所以这个过程可以参照UE4的源代码进行研究。",[11,389,390],{},"这里所做的是尝试对上一回所做的文件目录树进行封装。",[11,392,393],{},"直接上代码",[11,395,396],{},"CListViewWidget.h",[41,398,401],{"className":399,"code":400,"language":46},[44],"#pragma once\n#include \"CListViewWidget.generated.h\"\nUCLASS()\nclass TEST_MP_API UCListViewWidget : public UWidget\n{\n  GENERATED_UCLASS_BODY()\npublic:\n\n#if WITH_EDITOR\n  \u002F\u002F UWidget interface\n  virtual const FSlateBrush* GetEditorIcon() override;\n  virtual const FText GetPaletteCategory() override;\n  virtual void OnCreationFromPalette() override;\n  \u002F\u002F End UWidget interface\n#endif\n\nprotected:\n  \u002F\u002F UWidget interface\n  virtual TSharedRef\u003CSWidget> RebuildWidget() override;\n  virtual void OnBindingChanged(const FName& Property) override;\n  \u002F\u002F End of UWidget interface\n\nprotected:\n  TSharedPtr\u003Cclass SDDFileTree> MyFileTree;\n};\n",[48,402,400],{"__ignoreMap":50},[11,404,405],{},"封装类直接继承自UWidget即可，剩下的就是对UWidget中的函数进行实现。",[11,407,408],{},"CListViewWidget.cpp",[41,410,413],{"className":411,"code":412,"language":46},[44],"#include \"Test_mp.h\"\n#include \"SDDFileTree.h\"\n#include \"CListViewWidget.h\"\n\n\u002F** GENERATED_UCLASS_BODY() *\u002F\nUCListViewWidget::UCListViewWidget(const FObjectInitializer& ObjectInitializer)\n: Super(ObjectInitializer)\n{\n  bIsVariable = false;\n}\n\n\u002F** \u003C编辑器属性 *\u002F\n#if WITH_EDITOR\n\n\u002F\u002F \u003C图标\nconst FSlateBrush* UCListViewWidget::GetEditorIcon()\n{\n  return FUMGStyle::Get().GetBrush(\"Widget.TextBlock\");\n}\n\n\u002F\u002F \u003C分类目录\nconst FText UCListViewWidget::GetPaletteCategory()\n{\n  return NSLOCTEXT(\"Testmp\", \"Custom\", \"Ch_Custom\");\n}\n\n\u002F\u002F \u003C创建时的默认值\nvoid UCListViewWidget::OnCreationFromPalette()\n{\n;\n}\n\n#endif\n\nTSharedRef\u003CSWidget> UCListViewWidget::RebuildWidget()\n{\n  MyFileTree = SNew(SDDFileTree).OwnerHUD(nullptr);\n\n  return MyFileTree.ToSharedRef();\n}\n\nvoid UCListViewWidget::OnBindingChanged(const FName& Property)\n{\n  Super::OnBindingChanged(Property);\n\n  if (MyFileTree.IsValid())\n  {\n    ;\n  }\n}\n",[48,414,412],{"__ignoreMap":50},[11,416,417],{},"在所有的函数中，RebuildWidget()是最重要的。",[11,419,420],{},"参看UWidget的源代码可以发现，所有对被封装的SWidget的引用都是通过这个函数获得的，因此在这里面写上SWidget对应的构造生成就可以了。",[11,422,423],{},"OnBindingChanged函数是用于属性代理通知的，这里是简单的封装，没有提供属性代理，因此直接return也是可以的。",[11,425,426],{},"在WITH_EDITOR宏中的是编辑器属性，用于封装后的UWidget在蓝图编辑器中显示。具体每一个函数的含义已经在注释中了。",[11,428,429],{},"将上面的代码编译通过之后，就可以在UMG的编辑器中看到我们添加的控件了：",[11,431,432],{},"将CListViewWidget拖动到控件蓝图上，并在HUD中展示此控件蓝图，就能在项目中与其他UMG控件一样使用了：",[11,434,435],{},"这样以来Slate的使用就会变得方便很多。",{"title":50,"searchDepth":171,"depth":172,"links":437},[],"2015-09-11",{"layout":183,"status":184,"published":185,"author":440,"author_login":441,"author_email":442,"author_url":443,"wordpress_id":444,"wordpress_url":445,"date_gmt":446,"excerpt":447},{"display_name":441,"login":441,"email":442,"url":443},"chaoshikari","chaoshikari@gmail.com","\u002F",1457,"\u002F\u002F?p=1457","2015-09-11 11:11:13 +0000",{"type":8,"value":448},[449],[11,450,378],{},"\u002F2015-09-11-uwidget-wrap-swidget-to-umg",{"title":373,"description":378},"_legacy\u002F2015\u002F2015-09-11-uwidget-wrap-swidget-to-umg",[201,202,455],"Slate","mPzjKCXtbWWXkWThfinkYHexD0dpoqD6gvqKCUaR4v0",{"id":458,"title":459,"body":460,"date":530,"description":464,"extension":181,"meta":531,"navigation":185,"path":540,"seo":541,"stem":542,"tags":543,"__hash__":544},"blogs\u002F_legacy\u002F2014\u002F2014-11-30-umg%e5%9c%a84-6-0%e7%89%88%e6%9c%ac%e4%b8%ad%e7%9a%84%e5%8d%87%e7%ba%a7%e5%8f%98%e5%8a%a8.md","UMG在4.6.0版本中的升级变动",{"type":8,"value":461,"toc":528},[462,465,468,475,478,483,486,491,496,499,504,509,512,517,520,525],[11,463,464],{},"UE4目前处在一个非常活跃的开发阶段，在升级到4.6.0版本之后。UMG功能已经离开了实验性功能模块，同时这个版本已经支持中文语言了。",[11,466,467],{},"才过了1个多月就有这么大的变动，就只能从断掉的地方从新开始了。好在UMG本身从上一次到现在这个版本并没有什么大的变动。对原有的代码进行检查，目前能找到的变动有下面这些。",[469,470,471],"ol",{},[472,473,474],"li",{},"按钮的绑定函数改为了事件绑定",[11,476,477],{},"原有的绑定函数的形式不再有效，所以要在蓝图中作出相应的修改。",[11,479,480],{},[66,481],{"alt":68,"src":482},"\u002Fwp-content\u002Fuploads\u002F2014\u002F11\u002Fimage_thumb.png",[11,484,485],{},"修改为了事件模式之后，按钮和响应函数之间的关系变得更加直观了。",[11,487,488],{},[66,489],{"alt":68,"src":490},"\u002Fwp-content\u002Fuploads\u002F2014\u002F11\u002Fimage_thumb1.png",[469,492,493],{"start":171},[472,494,495],{},"Border的颜色属性变动",[11,497,498],{},"Border现在默认是白色不透明了，如果原来有使用Border进行布局的话升级之后就会看到界面一片白了。要使用透明效果就必须对颜色修改：",[11,500,501],{},[66,502],{"alt":68,"src":503},"\u002Fwp-content\u002Fuploads\u002F2014\u002F11\u002Fimage_thumb2.png",[469,505,506],{"start":172},[472,507,508],{},"Add to Viewport 函数变更",[11,510,511],{},"AddtoViewPort函数中原本的Modal和Show Cursor参数已经没有了。要实现这两个功能，就必须通过PlayerController进行控制。模态的控制如下：",[11,513,514],{},[66,515],{"alt":68,"src":516},"\u002Fwp-content\u002Fuploads\u002F2014\u002F11\u002Fimage_thumb3.png",[11,518,519],{},"模态相关的话是一个Game和UI的控制权分配问题，通过下面的这组函数进行控制：",[11,521,522],{},[66,523],{"alt":68,"src":524},"\u002Fwp-content\u002Fuploads\u002F2014\u002F11\u002Fimage_thumb4.png",[11,526,527],{},"对上面的改动进行相应的修正之后，原本的代码就可以在新的版本中正常的工作 了。",{"title":50,"searchDepth":171,"depth":172,"links":529},[],"2014-11-30",{"layout":183,"status":184,"published":185,"author":532,"author_login":441,"author_email":442,"author_url":443,"wordpress_id":533,"wordpress_url":534,"date_gmt":535,"excerpt":536},{"display_name":441,"login":441,"email":442,"url":443},1079,"\u002F\u002F?p=1079","2014-11-30 05:08:11 +0000",{"type":8,"value":537},[538],[11,539,464],{},"\u002F2014-11-30-umg在4-6-0版本中的升级变动",{"title":459,"description":464},"_legacy\u002F2014\u002F2014-11-30-umg%e5%9c%a84-6-0%e7%89%88%e6%9c%ac%e4%b8%ad%e7%9a%84%e5%8d%87%e7%ba%a7%e5%8f%98%e5%8a%a8",[201,202],"211uQ_hHtqukg9a475OoGFpORkJgoSXNDZZUDjoLQh0",{"id":546,"title":547,"body":548,"date":647,"description":552,"extension":181,"meta":648,"navigation":185,"path":657,"seo":658,"stem":659,"tags":660,"__hash__":661},"blogs\u002F_legacy\u002F2014\u002F2014-09-28-ue4%e5%ae%98%e6%96%b9ui%e5%ba%93umg%e7%ae%80%e5%8d%95%e8%8f%9c%e5%8d%95%e6%90%ad%e5%bb%ba.md","UE4官方UI库UMG简单菜单搭建",{"type":8,"value":549,"toc":645},[550,553,556,561,564,569,572,575,580,583,588,591,596,599,604,607,612,615,620,623,628,631,634,639,642],[11,551,552],{},"UMG在当前UE4版本中仍然是实验功能，不过已经能基本满足日常UI的制作需求了。于是参考官方教程对UMG的UI的制作进行了熟悉。",[11,554,555],{},"首先要做的是在引擎中打开UMG功能：",[11,557,558],{},[66,559],{"alt":68,"src":560},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb2.png",[11,562,563],{},"打开之后就能在新建菜单中看到UMG相关的项目了，如果看不到的话重启一下引擎就可以了",[11,565,566],{},[66,567],{"alt":68,"src":568},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb3.png",[11,570,571],{},"选择Wdiget  BluePrint就可以新建一个UMG的UI了。",[11,573,574],{},"在这里我们先新建一个Slate Blush以作背景用",[11,576,577],{},[66,578],{"alt":68,"src":579},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb4.png",[11,581,582],{},"Slate Brush内部很单纯，选择一张已经导入的图片即可。",[11,584,585],{},[66,586],{"alt":68,"src":587},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb5.png",[11,589,590],{},"创建完Brush之后到刚刚新建的Wdiget里面，删掉默认添加的元件。按照下面的元件顺序添加即可",[11,592,593],{},[66,594],{"alt":68,"src":595},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb6.png",[11,597,598],{},"背景图片的配置在Border的属性中",[11,600,601],{},[66,602],{"alt":68,"src":603},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb7.png",[11,605,606],{},"基本上使用起来和普通的UI编辑器没什么大的区别，也就是拖拖调调就可以了。事件的绑定在右边的属性栏里面都能够找到。",[11,608,609],{},[66,610],{"alt":68,"src":611},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb8.png",[11,613,614],{},"新建的事件处理函数名称是可以修改的。给Quit按钮绑定退出功能：",[11,616,617],{},[66,618],{"alt":68,"src":619},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb9.png",[11,621,622],{},"这样的话UMG菜单部分就完成了。接下来只要找一个合适的时机将菜单弹出即可，可以选择在level blueprint的beginplay弹出。这里选择在Hud里面弹出：",[11,624,625],{},[66,626],{"alt":68,"src":627},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb10.png",[11,629,630],{},"这里面有两个需要注意的地方。选中modal可以防止菜单后面的3d界面得到控制权，就是普通ui中的模态。show cursor可以让UI界面中显示鼠标指针，而不用到controller里面去关闭全局的鼠标隐藏。",[11,632,633],{},"完成之后的界面如下，为了直观将背景图片去掉了：",[11,635,636],{},[66,637],{"alt":68,"src":638},"\u002Fwp-content\u002Fuploads\u002F2014\u002F09\u002Fimage_thumb11.png",[11,640,641],{},"以上就是全部的步骤了，最后吐槽下UE的暂停游戏功能。在当前版本下，不使用C++进行处理的情况下，暂停游戏的那行文字提示是去不掉的。不过使用模态来处理的话，基本的应用情境中是不需要暂停游戏的。但是暂停菜单的话……",[11,643,644],{},"总体而言UMG的功能很容易上手，没有想象中的那么复杂。",{"title":50,"searchDepth":171,"depth":172,"links":646},[],"2014-09-28",{"layout":183,"status":184,"published":185,"author":649,"author_login":441,"author_email":442,"author_url":443,"wordpress_id":650,"wordpress_url":651,"date_gmt":652,"excerpt":653},{"display_name":441,"login":441,"email":442,"url":443},1043,"\u002F\u002F?p=1043","2014-09-28 12:55:58 +0000",{"type":8,"value":654},[655],[11,656,552],{},"\u002F2014-09-28-ue4官方ui库umg简单菜单搭建",{"title":547,"description":552},"_legacy\u002F2014\u002F2014-09-28-ue4%e5%ae%98%e6%96%b9ui%e5%ba%93umg%e7%ae%80%e5%8d%95%e8%8f%9c%e5%8d%95%e6%90%ad%e5%bb%ba",[201,202],"BQd5f503SbSHEZMn43WMjG44sJksfuBw9wt09EXA-ow",5,1788763179357]